Bringing apdf from vendor into main branch.
[AROS-Contrib.git] / apdf / xpdf / pdfinfo.cc
blobf8c86fdfe342aa2f21dc12f4ddb8e7088bd39087
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 "Error.h"
31 #include "config.h"
33 static void printInfoString(Dict *infoDict, char *key, char *text,
34 UnicodeMap *uMap);
35 static void printInfoDate(Dict *infoDict, char *key, char *text);
36 static void printBox(char *text, PDFRectangle *box);
38 static int firstPage = 1;
39 static int lastPage = 0;
40 static GBool printBoxes = gFalse;
41 static GBool printMetadata = gFalse;
42 static char textEncName[128] = "";
43 static char ownerPassword[33] = "\001";
44 static char userPassword[33] = "\001";
45 static char cfgFileName[256] = "";
46 static GBool printVersion = gFalse;
47 static GBool printHelp = gFalse;
49 static ArgDesc argDesc[] = {
50 {"-f", argInt, &firstPage, 0,
51 "first page to convert"},
52 {"-l", argInt, &lastPage, 0,
53 "last page to convert"},
54 {"-box", argFlag, &printBoxes, 0,
55 "print the page bounding boxes"},
56 {"-meta", argFlag, &printMetadata, 0,
57 "print the document metadata (XML)"},
58 {"-enc", argString, textEncName, sizeof(textEncName),
59 "output text encoding name"},
60 {"-opw", argString, ownerPassword, sizeof(ownerPassword),
61 "owner password (for encrypted files)"},
62 {"-upw", argString, userPassword, sizeof(userPassword),
63 "user password (for encrypted files)"},
64 {"-cfg", argString, cfgFileName, sizeof(cfgFileName),
65 "configuration file to use in place of .xpdfrc"},
66 {"-v", argFlag, &printVersion, 0,
67 "print copyright and version info"},
68 {"-h", argFlag, &printHelp, 0,
69 "print usage information"},
70 {"-help", argFlag, &printHelp, 0,
71 "print usage information"},
72 {"--help", argFlag, &printHelp, 0,
73 "print usage information"},
74 {"-?", argFlag, &printHelp, 0,
75 "print usage information"},
76 {NULL}
79 int main(int argc, char *argv[]) {
80 PDFDoc *doc;
81 GString *fileName;
82 GString *ownerPW, *userPW;
83 UnicodeMap *uMap;
84 Page *page;
85 Object info;
86 char buf[256];
87 double w, h, wISO, hISO;
88 FILE *f;
89 GString *metadata;
90 GBool ok;
91 int exitCode;
92 int pg, i;
93 GBool multiPage;
95 exitCode = 99;
97 // parse args
98 ok = parseArgs(argDesc, &argc, argv);
99 if (!ok || argc != 2 || printVersion || printHelp) {
100 fprintf(stderr, "pdfinfo version %s\n", xpdfVersion);
101 fprintf(stderr, "%s\n", xpdfCopyright);
102 if (!printVersion) {
103 printUsage("pdfinfo", "<PDF-file>", argDesc);
105 goto err0;
107 fileName = new GString(argv[1]);
109 // read config file
110 globalParams = new GlobalParams(cfgFileName);
111 if (textEncName[0]) {
112 globalParams->setTextEncoding(textEncName);
115 // get mapping to output encoding
116 if (!(uMap = globalParams->getTextEncoding())) {
117 error(-1, "Couldn't get text encoding");
118 delete fileName;
119 goto err1;
122 // open PDF file
123 if (ownerPassword[0] != '\001') {
124 ownerPW = new GString(ownerPassword);
125 } else {
126 ownerPW = NULL;
128 if (userPassword[0] != '\001') {
129 userPW = new GString(userPassword);
130 } else {
131 userPW = NULL;
133 doc = new PDFDoc(fileName, ownerPW, userPW);
134 if (userPW) {
135 delete userPW;
137 if (ownerPW) {
138 delete ownerPW;
140 if (!doc->isOk()) {
141 exitCode = 1;
142 goto err2;
145 // get page range
146 if (firstPage < 1) {
147 firstPage = 1;
149 if (lastPage == 0) {
150 multiPage = gFalse;
151 lastPage = 1;
152 } else {
153 multiPage = gTrue;
155 if (lastPage < 1 || lastPage > doc->getNumPages()) {
156 lastPage = doc->getNumPages();
159 // print doc info
160 doc->getDocInfo(&info);
161 if (info.isDict()) {
162 printInfoString(info.getDict(), "Title", "Title: ", uMap);
163 printInfoString(info.getDict(), "Subject", "Subject: ", uMap);
164 printInfoString(info.getDict(), "Keywords", "Keywords: ", uMap);
165 printInfoString(info.getDict(), "Author", "Author: ", uMap);
166 printInfoString(info.getDict(), "Creator", "Creator: ", uMap);
167 printInfoString(info.getDict(), "Producer", "Producer: ", uMap);
168 printInfoDate(info.getDict(), "CreationDate", "CreationDate: ");
169 printInfoDate(info.getDict(), "ModDate", "ModDate: ");
171 info.free();
173 // print tagging info
174 printf("Tagged: %s\n",
175 doc->getStructTreeRoot()->isDict() ? "yes" : "no");
177 // print page count
178 printf("Pages: %d\n", doc->getNumPages());
180 // print encryption info
181 printf("Encrypted: ");
182 if (doc->isEncrypted()) {
183 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
184 doc->okToPrint(gTrue) ? "yes" : "no",
185 doc->okToCopy(gTrue) ? "yes" : "no",
186 doc->okToChange(gTrue) ? "yes" : "no",
187 doc->okToAddNotes(gTrue) ? "yes" : "no");
188 } else {
189 printf("no\n");
192 // print page size
193 for (pg = firstPage; pg <= lastPage; ++pg) {
194 w = doc->getPageMediaWidth(pg);
195 h = doc->getPageMediaHeight(pg);
196 if (multiPage) {
197 printf("Page %4d size: %g x %g pts", pg, w, h);
198 } else {
199 printf("Page size: %g x %g pts", w, h);
201 if ((fabs(w - 612) < 0.1 && fabs(h - 792) < 0.1) ||
202 (fabs(w - 792) < 0.1 && fabs(h - 612) < 0.1)) {
203 printf(" (letter)");
204 } else {
205 hISO = sqrt(sqrt(2.0)) * 7200 / 2.54;
206 wISO = hISO / sqrt(2.0);
207 for (i = 0; i <= 6; ++i) {
208 if ((fabs(w - wISO) < 1 && fabs(h - hISO) < 1) ||
209 (fabs(w - hISO) < 1 && fabs(h - wISO) < 1)) {
210 printf(" (A%d)", i);
211 break;
213 hISO = wISO;
214 wISO /= sqrt(2.0);
217 printf("\n");
220 // print the boxes
221 if (printBoxes) {
222 if (multiPage) {
223 for (pg = firstPage; pg <= lastPage; ++pg) {
224 page = doc->getCatalog()->getPage(pg);
225 sprintf(buf, "Page %4d MediaBox: ", pg);
226 printBox(buf, page->getMediaBox());
227 sprintf(buf, "Page %4d CropBox: ", pg);
228 printBox(buf, page->getCropBox());
229 sprintf(buf, "Page %4d BleedBox: ", pg);
230 printBox(buf, page->getBleedBox());
231 sprintf(buf, "Page %4d TrimBox: ", pg);
232 printBox(buf, page->getTrimBox());
233 sprintf(buf, "Page %4d ArtBox: ", pg);
234 printBox(buf, page->getArtBox());
236 } else {
237 page = doc->getCatalog()->getPage(firstPage);
238 printBox("MediaBox: ", page->getMediaBox());
239 printBox("CropBox: ", page->getCropBox());
240 printBox("BleedBox: ", page->getBleedBox());
241 printBox("TrimBox: ", page->getTrimBox());
242 printBox("ArtBox: ", page->getArtBox());
246 // print file size
247 #ifdef VMS
248 f = fopen(fileName->getCString(), "rb", "ctx=stm");
249 #else
250 f = fopen(fileName->getCString(), "rb");
251 #endif
252 if (f) {
253 #if HAVE_FSEEKO
254 fseeko(f, 0, SEEK_END);
255 printf("File size: %u bytes\n", (Guint)ftello(f));
256 #elif HAVE_FSEEK64
257 fseek64(f, 0, SEEK_END);
258 printf("File size: %u bytes\n", (Guint)ftell64(f));
259 #else
260 fseek(f, 0, SEEK_END);
261 printf("File size: %d bytes\n", (int)ftell(f));
262 #endif
263 fclose(f);
266 // print linearization info
267 printf("Optimized: %s\n", doc->isLinearized() ? "yes" : "no");
269 // print PDF version
270 printf("PDF version: %.1f\n", doc->getPDFVersion());
272 // print the metadata
273 if (printMetadata && (metadata = doc->readMetadata())) {
274 fputs("Metadata:\n", stdout);
275 fputs(metadata->getCString(), stdout);
276 fputc('\n', stdout);
277 delete metadata;
280 exitCode = 0;
282 // clean up
283 err2:
284 uMap->decRefCnt();
285 delete doc;
286 err1:
287 delete globalParams;
288 err0:
290 // check for memory leaks
291 Object::memCheck(stderr);
292 gMemReport(stderr);
294 return exitCode;
297 static void printInfoString(Dict *infoDict, char *key, char *text,
298 UnicodeMap *uMap) {
299 Object obj;
300 GString *s1;
301 GBool isUnicode;
302 Unicode u;
303 char buf[8];
304 int i, n;
306 if (infoDict->lookup(key, &obj)->isString()) {
307 fputs(text, stdout);
308 s1 = obj.getString();
309 if ((s1->getChar(0) & 0xff) == 0xfe &&
310 (s1->getChar(1) & 0xff) == 0xff) {
311 isUnicode = gTrue;
312 i = 2;
313 } else {
314 isUnicode = gFalse;
315 i = 0;
317 while (i < obj.getString()->getLength()) {
318 if (isUnicode) {
319 u = ((s1->getChar(i) & 0xff) << 8) |
320 (s1->getChar(i+1) & 0xff);
321 i += 2;
322 } else {
323 u = s1->getChar(i) & 0xff;
324 ++i;
326 n = uMap->mapUnicode(u, buf, sizeof(buf));
327 fwrite(buf, 1, n, stdout);
329 fputc('\n', stdout);
331 obj.free();
334 static void printInfoDate(Dict *infoDict, char *key, char *text) {
335 Object obj;
336 char *s;
337 int year, mon, day, hour, min, sec;
338 struct tm tmStruct;
339 char buf[256];
341 if (infoDict->lookup(key, &obj)->isString()) {
342 fputs(text, stdout);
343 s = obj.getString()->getCString();
344 if (s[0] == 'D' && s[1] == ':') {
345 s += 2;
347 if (sscanf(s, "%4d%2d%2d%2d%2d%2d",
348 &year, &mon, &day, &hour, &min, &sec) == 6) {
349 tmStruct.tm_year = year - 1900;
350 tmStruct.tm_mon = mon - 1;
351 tmStruct.tm_mday = day;
352 tmStruct.tm_hour = hour;
353 tmStruct.tm_min = min;
354 tmStruct.tm_sec = sec;
355 tmStruct.tm_wday = -1;
356 tmStruct.tm_yday = -1;
357 tmStruct.tm_isdst = -1;
358 // compute the tm_wday and tm_yday fields
359 if (mktime(&tmStruct) != (time_t)-1 &&
360 strftime(buf, sizeof(buf), "%c", &tmStruct)) {
361 fputs(buf, stdout);
362 } else {
363 fputs(s, stdout);
365 } else {
366 fputs(s, stdout);
368 fputc('\n', stdout);
370 obj.free();
373 static void printBox(char *text, PDFRectangle *box) {
374 printf("%s%8.2f %8.2f %8.2f %8.2f\n",
375 text, box->x1, box->y1, box->x2, box->y2);