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;
89 ok = parseArgs(argDesc, &argc, argv);
90 if (!ok || argc != 2 || printVersion || printHelp) {
91 fprintf(stderr, "pdfinfo version %s\n", xpdfVersion);
92 fprintf(stderr, "%s\n", xpdfCopyright);
94 printUsage("pdfinfo", "<PDF-file>", argDesc);
98 fileName = new GString(argv[1]);
101 globalParams = new GlobalParams(cfgFileName);
104 if (ownerPassword[0]) {
105 ownerPW = new GString(ownerPassword);
109 if (userPassword[0]) {
110 userPW = new GString(userPassword);
114 doc = new PDFDoc(fileName, ownerPW, userPW);
129 if (lastPage < 1 || lastPage > doc->getNumPages()) {
130 lastPage = doc->getNumPages();
134 printf("name type emb sub uni object ID\n");
135 printf("------------------------------------ ------------ --- --- --- ---------\n");
137 fontsLen = fontsSize = 0;
138 for (pg = firstPage; pg <= lastPage; ++pg) {
139 page = doc->getCatalog()->getPage(pg);
140 if ((resDict = page->getResourceDict())) {
141 scanFonts(resDict, doc);
143 annots = new Annots(doc->getXRef(), page->getAnnots(&obj1));
145 for (i = 0; i < annots->getNumAnnots(); ++i) {
146 if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
147 obj1.streamGetDict()->lookup("Resources", &obj2);
149 scanFonts(obj2.getDict(), doc);
163 // check for memory leaks
164 Object::memCheck(stderr);
170 static void scanFonts(Dict *resDict, PDFDoc *doc) {
171 GfxFontDict *gfxFontDict;
173 Object fontDict, xObjDict, xObj, resObj;
176 // scan the fonts in this resource dictionary
177 resDict->lookup("Font", &fontDict);
178 if (fontDict.isDict()) {
179 gfxFontDict = new GfxFontDict(doc->getXRef(), fontDict.getDict());
180 for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
181 font = gfxFontDict->getFont(i);
188 // recursively scan any resource dictionaries in objects in this
189 // resource dictionary
190 resDict->lookup("XObject", &xObjDict);
191 if (xObjDict.isDict()) {
192 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
193 xObjDict.dictGetVal(i, &xObj);
194 if (xObj.isStream()) {
195 xObj.streamGetDict()->lookup("Resources", &resObj);
196 if (resObj.isDict()) {
197 scanFonts(resObj.getDict(), doc);
207 static void scanFont(GfxFont *font, PDFDoc *doc) {
209 Object fontObj, nameObj, toUnicodeObj;
211 GBool subset, hasToUnicode;
214 fontRef = *font->getID();
216 // check for an already-seen font
217 for (i = 0; i < fontsLen; ++i) {
218 if (fontRef.num == fonts[i].num && fontRef.gen == fonts[i].gen) {
223 // get the original font name -- the GfxFont class munges substitute
224 // Base-14 font names into proper form, so this code grabs the
225 // original name from the font dictionary; also look for a ToUnicode
228 hasToUnicode = gFalse;
229 if (doc->getXRef()->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
230 if (fontObj.dictLookup("BaseFont", &nameObj)->isName()) {
231 name = new GString(nameObj.getName());
234 hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
239 // check for a font subset name: capital letters followed by a '+'
243 for (i = 0; i < name->getLength(); ++i) {
244 if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
248 subset = i > 0 && i < name->getLength() && name->getChar(i) == '+';
251 // print the font info
252 printf("%-36s %-12s %-3s %-3s %-3s %6d %2d\n",
253 name ? name->getCString() : "[none]",
254 fontTypeNames[font->getType()],
255 font->getEmbeddedFontID(&embRef) ? "yes" : "no",
256 subset ? "yes" : "no",
257 hasToUnicode ? "yes" : "no",
258 fontRef.num, fontRef.gen);
263 // add this font to the list
264 if (fontsLen == fontsSize) {
266 fonts = (Ref *)grealloc(fonts, fontsSize * sizeof(Ref));
268 fonts[fontsLen++] = *font->getID();