1 //========================================================================
5 // Copyright 2001-2002 Glyph & Cog, LLC
7 //========================================================================
15 #include "parseargs.h"
18 #include "GlobalParams.h"
27 static char *fontTypeNames[] = {
38 static void scanFonts(Dict *resDict, PDFDoc *doc);
39 static void scanFont(GfxFont *font, PDFDoc *doc);
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;
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"},
77 int main(int argc, char *argv[]) {
80 GString *ownerPW, *userPW;
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);
97 printUsage("pdfinfo", "<PDF-file>", argDesc);
101 fileName = new GString(argv[1]);
104 globalParams = new GlobalParams(cfgFileName);
107 if (ownerPassword[0]) {
108 ownerPW = new GString(ownerPassword);
112 if (userPassword[0]) {
113 userPW = new GString(userPassword);
117 doc = new PDFDoc(fileName, ownerPW, userPW);
133 if (lastPage < 1 || lastPage > doc->getNumPages()) {
134 lastPage = doc->getNumPages();
138 printf("name type emb sub uni object ID\n");
139 printf("------------------------------------ ------------ --- --- --- ---------\n");
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);
147 annots = new Annots(doc->getXRef(), page->getAnnots(&obj1));
149 for (i = 0; i < annots->getNumAnnots(); ++i) {
150 if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
151 obj1.streamGetDict()->lookup("Resources", &obj2);
153 scanFonts(obj2.getDict(), doc);
171 // check for memory leaks
172 Object::memCheck(stderr);
178 static void scanFonts(Dict *resDict, PDFDoc *doc) {
179 GfxFontDict *gfxFontDict;
181 Object fontDict, xObjDict, xObj, resObj;
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);
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);
215 static void scanFont(GfxFont *font, PDFDoc *doc) {
217 Object fontObj, nameObj, toUnicodeObj;
219 GBool subset, hasToUnicode;
222 fontRef = *font->getID();
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) {
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
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());
242 hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
247 // check for a font subset name: capital letters followed by a '+'
251 for (i = 0; i < name->getLength(); ++i) {
252 if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
256 subset = i > 0 && i < name->getLength() && name->getChar(i) == '+';
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) {
269 printf(" %6d %2d\n", fontRef.num, fontRef.gen);
275 // add this font to the list
276 if (fontsLen == fontsSize) {
278 fonts = (Ref *)grealloc(fonts, fontsSize * sizeof(Ref));
280 fonts[fontsLen++] = *font->getID();