]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/pdffonts.cc
Import of Xpdf 2.00 for merge
[evince.git] / pdf / xpdf / pdffonts.cc
1 //========================================================================
2 //
3 // pdffonts.cc
4 //
5 // Copyright 2001-2002 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stddef.h>
13 #include <string.h>
14 #include <math.h>
15 #include "parseargs.h"
16 #include "GString.h"
17 #include "gmem.h"
18 #include "GlobalParams.h"
19 #include "Error.h"
20 #include "Object.h"
21 #include "Dict.h"
22 #include "GfxFont.h"
23 #include "Annot.h"
24 #include "PDFDoc.h"
25 #include "config.h"
26
27 static char *fontTypeNames[] = {
28   "unknown",
29   "Type 1",
30   "Type 1C",
31   "Type 3",
32   "TrueType",
33   "CID Type 0",
34   "CID Type 0C",
35   "CID TrueType"
36 };
37
38 static void scanFonts(Dict *resDict, PDFDoc *doc);
39 static void scanFont(GfxFont *font, PDFDoc *doc);
40
41 static int firstPage = 1;
42 static int lastPage = 0;
43 static char ownerPassword[33] = "";
44 static char userPassword[33] = "";
45 static char cfgFileName[256] = "";
46 static GBool printVersion = gFalse;
47 static GBool printHelp = gFalse;
48
49 static ArgDesc argDesc[] = {
50   {"-f",      argInt,      &firstPage,     0,
51    "first page to examine"},
52   {"-l",      argInt,      &lastPage,      0,
53    "last page to examine"},
54   {"-opw",    argString,   ownerPassword,  sizeof(ownerPassword),
55    "owner password (for encrypted files)"},
56   {"-upw",    argString,   userPassword,   sizeof(userPassword),
57    "user password (for encrypted files)"},
58   {"-cfg",        argString,      cfgFileName,    sizeof(cfgFileName),
59    "configuration file to use in place of .xpdfrc"},
60   {"-v",      argFlag,     &printVersion,  0,
61    "print copyright and version info"},
62   {"-h",      argFlag,     &printHelp,     0,
63    "print usage information"},
64   {"-help",   argFlag,     &printHelp,     0,
65    "print usage information"},
66   {"--help",  argFlag,     &printHelp,     0,
67    "print usage information"},
68   {"-?",      argFlag,     &printHelp,     0,
69    "print usage information"},
70   {NULL}
71 };
72
73 static Ref *fonts;
74 static int fontsLen;
75 static int fontsSize;
76
77 int main(int argc, char *argv[]) {
78   PDFDoc *doc;
79   GString *fileName;
80   GString *ownerPW, *userPW;
81   GBool ok;
82   Page *page;
83   Dict *resDict;
84   Annots *annots;
85   Object obj1, obj2;
86   int pg, i;
87   int exitCode;
88
89   exitCode = 99;
90
91   // parse args
92   ok = parseArgs(argDesc, &argc, argv);
93   if (!ok || argc != 2 || printVersion || printHelp) {
94     fprintf(stderr, "pdfinfo version %s\n", xpdfVersion);
95     fprintf(stderr, "%s\n", xpdfCopyright);
96     if (!printVersion) {
97       printUsage("pdfinfo", "<PDF-file>", argDesc);
98     }
99     goto err0;
100   }
101   fileName = new GString(argv[1]);
102
103   // read config file
104   globalParams = new GlobalParams(cfgFileName);
105
106   // open PDF file
107   if (ownerPassword[0]) {
108     ownerPW = new GString(ownerPassword);
109   } else {
110     ownerPW = NULL;
111   }
112   if (userPassword[0]) {
113     userPW = new GString(userPassword);
114   } else {
115     userPW = NULL;
116   }
117   doc = new PDFDoc(fileName, ownerPW, userPW);
118   if (userPW) {
119     delete userPW;
120   }
121   if (ownerPW) {
122     delete ownerPW;
123   }
124   if (!doc->isOk()) {
125     exitCode = 1;
126     goto err1;
127   }
128
129   // get page range
130   if (firstPage < 1) {
131     firstPage = 1;
132   }
133   if (lastPage < 1 || lastPage > doc->getNumPages()) {
134     lastPage = doc->getNumPages();
135   }
136
137   // scan the fonts
138   printf("name                                 type         emb sub uni object ID\n");
139   printf("------------------------------------ ------------ --- --- --- ---------\n");
140   fonts = NULL;
141   fontsLen = fontsSize = 0;
142   for (pg = firstPage; pg <= lastPage; ++pg) {
143     page = doc->getCatalog()->getPage(pg);
144     if ((resDict = page->getResourceDict())) {
145       scanFonts(resDict, doc);
146     }
147     annots = new Annots(doc->getXRef(), page->getAnnots(&obj1));
148     obj1.free();
149     for (i = 0; i < annots->getNumAnnots(); ++i) {
150       if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
151         obj1.streamGetDict()->lookup("Resources", &obj2);
152         if (obj2.isDict()) {
153           scanFonts(obj2.getDict(), doc);
154         }
155         obj2.free();
156       }
157       obj1.free();
158     }
159     delete annots;
160   }
161
162   exitCode = 0;
163
164   // clean up
165   gfree(fonts);
166  err1:
167   delete doc;
168   delete globalParams;
169  err0:
170
171   // check for memory leaks
172   Object::memCheck(stderr);
173   gMemReport(stderr);
174
175   return exitCode;
176 }
177
178 static void scanFonts(Dict *resDict, PDFDoc *doc) {
179   GfxFontDict *gfxFontDict;
180   GfxFont *font;
181   Object fontDict, xObjDict, xObj, resObj;
182   int i;
183
184   // scan the fonts in this resource dictionary
185   resDict->lookup("Font", &fontDict);
186   if (fontDict.isDict()) {
187     gfxFontDict = new GfxFontDict(doc->getXRef(), fontDict.getDict());
188     for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
189       font = gfxFontDict->getFont(i);
190       scanFont(font, doc);
191     }
192     delete gfxFontDict;
193   }
194   fontDict.free();
195
196   // recursively scan any resource dictionaries in objects in this
197   // resource dictionary
198   resDict->lookup("XObject", &xObjDict);
199   if (xObjDict.isDict()) {
200     for (i = 0; i < xObjDict.dictGetLength(); ++i) {
201       xObjDict.dictGetVal(i, &xObj);
202       if (xObj.isStream()) {
203         xObj.streamGetDict()->lookup("Resources", &resObj);
204         if (resObj.isDict()) {
205           scanFonts(resObj.getDict(), doc);
206         }
207         resObj.free();
208       }
209       xObj.free();
210     }
211   }
212   xObjDict.free();
213 }
214
215 static void scanFont(GfxFont *font, PDFDoc *doc) {
216   Ref fontRef, embRef;
217   Object fontObj, nameObj, toUnicodeObj;
218   GString *name;
219   GBool subset, hasToUnicode;
220   int i;
221
222   fontRef = *font->getID();
223
224   // check for an already-seen font
225   for (i = 0; i < fontsLen; ++i) {
226     if (fontRef.num == fonts[i].num && fontRef.gen == fonts[i].gen) {
227       return;
228     }
229   }
230
231   // get the original font name -- the GfxFont class munges substitute
232   // Base-14 font names into proper form, so this code grabs the
233   // original name from the font dictionary; also look for a ToUnicode
234   // map
235   name = NULL;
236   hasToUnicode = gFalse;
237   if (doc->getXRef()->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
238     if (fontObj.dictLookup("BaseFont", &nameObj)->isName()) {
239       name = new GString(nameObj.getName());
240     }
241     nameObj.free();
242     hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
243     toUnicodeObj.free();
244   }
245   fontObj.free();
246
247   // check for a font subset name: capital letters followed by a '+'
248   // sign
249   subset = gFalse;
250   if (name) {
251     for (i = 0; i < name->getLength(); ++i) {
252       if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
253         break;
254       }
255     }
256     subset = i > 0 && i < name->getLength() && name->getChar(i) == '+';
257   }
258
259   // print the font info
260   printf("%-36s %-12s %-3s %-3s %-3s",
261          name ? name->getCString() : "[none]",
262          fontTypeNames[font->getType()],
263          font->getEmbeddedFontID(&embRef) ? "yes" : "no",
264          subset ? "yes" : "no",
265          hasToUnicode ? "yes" : "no");
266   if (fontRef.gen == 999999) {
267     printf(" [none]\n");
268   } else {
269     printf(" %6d %2d\n", fontRef.num, fontRef.gen);
270   }
271   if (name) {
272     delete name;
273   }
274
275   // add this font to the list
276   if (fontsLen == fontsSize) {
277     fontsSize += 32;
278     fonts = (Ref *)grealloc(fonts, fontsSize * sizeof(Ref));
279   }
280   fonts[fontsLen++] = *font->getID();
281 }