Various Datatypes.
[AROS-Contrib.git] / arospdf / xpdf / pdfinfo.cc
blob6054a6525e4c2a28d74ed5444a9c173f4f784bad
1 //========================================================================
2 //
3 // pdfinfo.cc
4 //
5 // Copyright 1998-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #include <aconf.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stddef.h>
13 #include <string.h>
14 #include <time.h>
15 #include <math.h>
16 #include "parseargs.h"
17 #include "GString.h"
18 #include "gmem.h"
19 #include "GlobalParams.h"
20 #include "Object.h"
21 #include "Stream.h"
22 #include "Array.h"
23 #include "Dict.h"
24 #include "XRef.h"
25 #include "Catalog.h"
26 #include "Page.h"
27 #include "PDFDoc.h"
28 #include "CharTypes.h"
29 #include "UnicodeMap.h"
30 #include "PDFDocEncoding.h"
31 #include "Error.h"
32 #include "config.h"
34 static void printInfoString(Dict *infoDict, char *key, char *text,
35 UnicodeMap *uMap);
36 static void printInfoDate(Dict *infoDict, char *key, char *text);
37 static void printBox(char *text, PDFRectangle *box);
39 static int firstPage = 1;
40 static int lastPage = 0;
41 static GBool printBoxes = gFalse;
42 static GBool printMetadata = gFalse;
43 static char textEncName[128] = "";
44 static char ownerPassword[33] = "\001";
45 static char userPassword[33] = "\001";
46 static char cfgFileName[256] = "";
47 static GBool printVersion = gFalse;
48 static GBool printHelp = gFalse;
50 static ArgDesc argDesc[] = {
51 {"-f", argInt, &firstPage, 0,
52 "first page to convert"},
53 {"-l", argInt, &lastPage, 0,
54 "last page to convert"},
55 {"-box", argFlag, &printBoxes, 0,
56 "print the page bounding boxes"},
57 {"-meta", argFlag, &printMetadata, 0,
58 "print the document metadata (XML)"},
59 {"-enc", argString, textEncName, sizeof(textEncName),
60 "output text encoding name"},
61 {"-opw", argString, ownerPassword, sizeof(ownerPassword),
62 "owner password (for encrypted files)"},
63 {"-upw", argString, userPassword, sizeof(userPassword),
64 "user password (for encrypted files)"},
65 {"-cfg", argString, cfgFileName, sizeof(cfgFileName),
66 "configuration file to use in place of .xpdfrc"},
67 {"-v", argFlag, &printVersion, 0,
68 "print copyright and version info"},
69 {"-h", argFlag, &printHelp, 0,
70 "print usage information"},
71 {"-help", argFlag, &printHelp, 0,
72 "print usage information"},
73 {"--help", argFlag, &printHelp, 0,
74 "print usage information"},
75 {"-?", argFlag, &printHelp, 0,
76 "print usage information"},
77 {NULL}
80 int main(int argc, char *argv[]) {
81 PDFDoc *doc;
82 GString *fileName;
83 GString *ownerPW, *userPW;
84 UnicodeMap *uMap;
85 Page *page;
86 xObject info;
87 char buf[256];
88 double w, h, wISO, hISO;
89 FILE *f;
90 GString *metadata;
91 GBool ok;
92 int exitCode;
93 int pg, i;
94 GBool multiPage;
96 exitCode = 99;
98 // parse args
99 ok = parseArgs(argDesc, &argc, argv);
100 if (!ok || argc != 2 || printVersion || printHelp) {
101 fprintf(stderr, "pdfinfo version %s\n", xpdfVersion);
102 fprintf(stderr, "%s\n", xpdfCopyright);
103 if (!printVersion) {
104 printUsage("pdfinfo", "<PDF-file>", argDesc);
106 goto err0;
108 fileName = new GString(argv[1]);
110 // read config file
111 globalParams = new GlobalParams(cfgFileName);
112 if (textEncName[0]) {
113 globalParams->setTextEncoding(textEncName);
116 // get mapping to output encoding
117 if (!(uMap = globalParams->getTextEncoding())) {
118 error(-1, "Couldn't get text encoding");
119 delete fileName;
120 goto err1;
123 // open PDF file
124 if (ownerPassword[0] != '\001') {
125 ownerPW = new GString(ownerPassword);
126 } else {
127 ownerPW = NULL;
129 if (userPassword[0] != '\001') {
130 userPW = new GString(userPassword);
131 } else {
132 userPW = NULL;
134 doc = new PDFDoc(fileName, ownerPW, userPW);
135 if (userPW) {
136 delete userPW;
138 if (ownerPW) {
139 delete ownerPW;
141 if (!doc->isOk()) {
142 exitCode = 1;
143 goto err2;
146 // get page range
147 if (firstPage < 1) {
148 firstPage = 1;
150 if (lastPage == 0) {
151 multiPage = gFalse;
152 lastPage = 1;
153 } else {
154 multiPage = gTrue;
156 if (lastPage < 1 || lastPage > doc->getNumPages()) {
157 lastPage = doc->getNumPages();
160 // print doc info
161 doc->getDocInfo(&info);
162 if (info.isDict()) {
163 printInfoString(info.getDict(), "Title", "Title: ", uMap);
164 printInfoString(info.getDict(), "Subject", "Subject: ", uMap);
165 printInfoString(info.getDict(), "Keywords", "Keywords: ", uMap);
166 printInfoString(info.getDict(), "Author", "Author: ", uMap);
167 printInfoString(info.getDict(), "Creator", "Creator: ", uMap);
168 printInfoString(info.getDict(), "Producer", "Producer: ", uMap);
169 printInfoDate(info.getDict(), "CreationDate", "CreationDate: ");
170 printInfoDate(info.getDict(), "ModDate", "ModDate: ");
172 info.free();
174 // print tagging info
175 printf("Tagged: %s\n",
176 doc->getStructTreeRoot()->isDict() ? "yes" : "no");
178 // print page count
179 printf("Pages: %d\n", doc->getNumPages());
181 // print encryption info
182 printf("Encrypted: ");
183 if (doc->isEncrypted()) {
184 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
185 doc->okToPrint(gTrue) ? "yes" : "no",
186 doc->okToCopy(gTrue) ? "yes" : "no",
187 doc->okToChange(gTrue) ? "yes" : "no",
188 doc->okToAddNotes(gTrue) ? "yes" : "no");
189 } else {
190 printf("no\n");
193 // print page size
194 for (pg = firstPage; pg <= lastPage; ++pg) {
195 w = doc->getPageCropWidth(pg);
196 h = doc->getPageCropHeight(pg);
197 if (multiPage) {
198 printf("Page %4d size: %g x %g pts", pg, w, h);
199 } else {
200 printf("Page size: %g x %g pts", w, h);
202 if ((fabs(w - 612) < 0.1 && fabs(h - 792) < 0.1) ||
203 (fabs(w - 792) < 0.1 && fabs(h - 612) < 0.1)) {
204 printf(" (letter)");
205 } else {
206 hISO = sqrt(sqrt(2.0)) * 7200 / 2.54;
207 wISO = hISO / sqrt(2.0);
208 for (i = 0; i <= 6; ++i) {
209 if ((fabs(w - wISO) < 1 && fabs(h - hISO) < 1) ||
210 (fabs(w - hISO) < 1 && fabs(h - wISO) < 1)) {
211 printf(" (A%d)", i);
212 break;
214 hISO = wISO;
215 wISO /= sqrt(2.0);
218 printf("\n");
221 // print the boxes
222 if (printBoxes) {
223 if (multiPage) {
224 for (pg = firstPage; pg <= lastPage; ++pg) {
225 page = doc->getCatalog()->getPage(pg);
226 sprintf(buf, "Page %4d MediaBox: ", pg);
227 printBox(buf, page->getMediaBox());
228 sprintf(buf, "Page %4d CropBox: ", pg);
229 printBox(buf, page->getCropBox());
230 sprintf(buf, "Page %4d BleedBox: ", pg);
231 printBox(buf, page->getBleedBox());
232 sprintf(buf, "Page %4d TrimBox: ", pg);
233 printBox(buf, page->getTrimBox());
234 sprintf(buf, "Page %4d ArtBox: ", pg);
235 printBox(buf, page->getArtBox());
237 } else {
238 page = doc->getCatalog()->getPage(firstPage);
239 printBox("MediaBox: ", page->getMediaBox());
240 printBox("CropBox: ", page->getCropBox());
241 printBox("BleedBox: ", page->getBleedBox());
242 printBox("TrimBox: ", page->getTrimBox());
243 printBox("ArtBox: ", page->getArtBox());
247 // print file size
248 #ifdef VMS
249 f = fopen(fileName->getCString(), "rb", "ctx=stm");
250 #else
251 f = fopen(fileName->getCString(), "rb");
252 #endif
253 if (f) {
254 #if HAVE_FSEEKO
255 fseeko(f, 0, SEEK_END);
256 printf("File size: %u bytes\n", (Guint)ftello(f));
257 #elif HAVE_FSEEK64
258 fseek64(f, 0, SEEK_END);
259 printf("File size: %u bytes\n", (Guint)ftell64(f));
260 #else
261 fseek(f, 0, SEEK_END);
262 printf("File size: %d bytes\n", (int)ftell(f));
263 #endif
264 fclose(f);
267 // print linearization info
268 printf("Optimized: %s\n", doc->isLinearized() ? "yes" : "no");
270 // print PDF version
271 printf("PDF version: %.1f\n", doc->getPDFVersion());
273 // print the metadata
274 if (printMetadata && (metadata = doc->readMetadata())) {
275 fputs("Metadata:\n", stdout);
276 fputs(metadata->getCString(), stdout);
277 fputc('\n', stdout);
278 delete metadata;
281 exitCode = 0;
283 // clean up
284 err2:
285 uMap->decRefCnt();
286 delete doc;
287 err1:
288 delete globalParams;
289 err0:
291 // check for memory leaks
292 xObject::memCheck(stderr);
293 gMemReport(stderr);
295 return exitCode;
298 static void printInfoString(Dict *infoDict, char *key, char *text,
299 UnicodeMap *uMap) {
300 xObject obj;
301 GString *s1;
302 GBool isUnicode;
303 Unicode u;
304 char buf[8];
305 int i, n;
307 if (infoDict->lookup(key, &obj)->isString()) {
308 fputs(text, stdout);
309 s1 = obj.getString();
310 if ((s1->getChar(0) & 0xff) == 0xfe &&
311 (s1->getChar(1) & 0xff) == 0xff) {
312 isUnicode = gTrue;
313 i = 2;
314 } else {
315 isUnicode = gFalse;
316 i = 0;
318 while (i < obj.getString()->getLength()) {
319 if (isUnicode) {
320 u = ((s1->getChar(i) & 0xff) << 8) |
321 (s1->getChar(i+1) & 0xff);
322 i += 2;
323 } else {
324 u = pdfDocEncoding[s1->getChar(i) & 0xff];
325 ++i;
327 n = uMap->mapUnicode(u, buf, sizeof(buf));
328 fwrite(buf, 1, n, stdout);
330 fputc('\n', stdout);
332 obj.free();
335 static void printInfoDate(Dict *infoDict, char *key, char *text) {
336 xObject obj;
337 char *s;
338 int year, mon, day, hour, min, sec, n;
339 struct tm tmStruct;
340 char buf[256];
342 if (infoDict->lookup(key, &obj)->isString()) {
343 fputs(text, stdout);
344 s = obj.getString()->getCString();
345 if (s[0] == 'D' && s[1] == ':') {
346 s += 2;
348 if ((n = sscanf(s, "%4d%2d%2d%2d%2d%2d",
349 &year, &mon, &day, &hour, &min, &sec)) >= 1) {
350 switch (n) {
351 case 1: mon = 1;
352 case 2: day = 1;
353 case 3: hour = 0;
354 case 4: min = 0;
355 case 5: sec = 0;
357 tmStruct.tm_year = year - 1900;
358 tmStruct.tm_mon = mon - 1;
359 tmStruct.tm_mday = day;
360 tmStruct.tm_hour = hour;
361 tmStruct.tm_min = min;
362 tmStruct.tm_sec = sec;
363 tmStruct.tm_wday = -1;
364 tmStruct.tm_yday = -1;
365 tmStruct.tm_isdst = -1;
366 // compute the tm_wday and tm_yday fields
367 if (mktime(&tmStruct) != (time_t)-1 &&
368 strftime(buf, sizeof(buf), "%c", &tmStruct)) {
369 fputs(buf, stdout);
370 } else {
371 fputs(s, stdout);
373 } else {
374 fputs(s, stdout);
379 fputc('\n', stdout);
381 obj.free();
384 static void printBox(char *text, PDFRectangle *box) {
385 printf("%s%8.2f %8.2f %8.2f %8.2f\n",
386 text, box->x1, box->y1, box->x2, box->y2);