# use AROS_LIB/INCLUDES
[AROS-Contrib.git] / arospdf / xpdf / pdffonts.cc
blob434bef253be7eeb98a6794de57f745aacdfa1ba8
1 //========================================================================
2 //
3 // pdffonts.cc
4 //
5 // Copyright 2001-2007 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 <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"
27 // NB: this must match the definition of GfxFontType in GfxFont.h.
28 static char *fontTypeNames[] = {
29 "unknown",
30 "Type 1",
31 "Type 1C",
32 "Type 1C (OT)",
33 "Type 3",
34 "TrueType",
35 "TrueType (OT)",
36 "CID Type 0",
37 "CID Type 0C",
38 "CID Type 0C (OT)",
39 "CID TrueType",
40 "CID TrueType (OT)"
43 static void scanFonts(Dict *resDict, PDFDoc *doc);
44 static void scanFont(GfxFont *font, PDFDoc *doc);
46 static int firstPage = 1;
47 static int lastPage = 0;
48 static char ownerPassword[33] = "\001";
49 static char userPassword[33] = "\001";
50 static char cfgFileName[256] = "";
51 static GBool printVersion = gFalse;
52 static GBool printHelp = gFalse;
54 static ArgDesc argDesc[] = {
55 {"-f", argInt, &firstPage, 0,
56 "first page to examine"},
57 {"-l", argInt, &lastPage, 0,
58 "last page to examine"},
59 {"-opw", argString, ownerPassword, sizeof(ownerPassword),
60 "owner password (for encrypted files)"},
61 {"-upw", argString, userPassword, sizeof(userPassword),
62 "user password (for encrypted files)"},
63 {"-cfg", argString, cfgFileName, sizeof(cfgFileName),
64 "configuration file to use in place of .xpdfrc"},
65 {"-v", argFlag, &printVersion, 0,
66 "print copyright and version info"},
67 {"-h", argFlag, &printHelp, 0,
68 "print usage information"},
69 {"-help", argFlag, &printHelp, 0,
70 "print usage information"},
71 {"--help", argFlag, &printHelp, 0,
72 "print usage information"},
73 {"-?", argFlag, &printHelp, 0,
74 "print usage information"},
75 {NULL}
78 static Ref *fonts;
79 static int fontsLen;
80 static int fontsSize;
82 int main(int argc, char *argv[]) {
83 PDFDoc *doc;
84 GString *fileName;
85 GString *ownerPW, *userPW;
86 GBool ok;
87 Page *page;
88 Dict *resDict;
89 Annots *annots;
90 xObject obj1, obj2;
91 int pg, i;
92 int exitCode;
94 exitCode = 99;
96 // parse args
97 ok = parseArgs(argDesc, &argc, argv);
98 if (!ok || argc != 2 || printVersion || printHelp) {
99 fprintf(stderr, "pdffonts version %s\n", xpdfVersion);
100 fprintf(stderr, "%s\n", xpdfCopyright);
101 if (!printVersion) {
102 printUsage("pdffonts", "<PDF-file>", argDesc);
104 goto err0;
106 fileName = new GString(argv[1]);
108 // read config file
109 globalParams = new GlobalParams(cfgFileName);
111 // open PDF file
112 if (ownerPassword[0] != '\001') {
113 ownerPW = new GString(ownerPassword);
114 } else {
115 ownerPW = NULL;
117 if (userPassword[0] != '\001') {
118 userPW = new GString(userPassword);
119 } else {
120 userPW = NULL;
122 doc = new PDFDoc(fileName, ownerPW, userPW);
123 if (userPW) {
124 delete userPW;
126 if (ownerPW) {
127 delete ownerPW;
129 if (!doc->isOk()) {
130 exitCode = 1;
131 goto err1;
134 // get page range
135 if (firstPage < 1) {
136 firstPage = 1;
138 if (lastPage < 1 || lastPage > doc->getNumPages()) {
139 lastPage = doc->getNumPages();
142 // scan the fonts
143 printf("name type emb sub uni xObject ID\n");
144 printf("------------------------------------ ----------------- --- --- --- ---------\n");
145 fonts = NULL;
146 fontsLen = fontsSize = 0;
147 for (pg = firstPage; pg <= lastPage; ++pg) {
148 page = doc->getCatalog()->getPage(pg);
149 if ((resDict = page->getResourceDict())) {
150 scanFonts(resDict, doc);
152 annots = new Annots(doc->getXRef(), doc->getCatalog(),
153 page->getAnnots(&obj1));
154 obj1.free();
155 for (i = 0; i < annots->getNumAnnots(); ++i) {
156 if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
157 obj1.streamGetDict()->lookup("Resources", &obj2);
158 if (obj2.isDict()) {
159 scanFonts(obj2.getDict(), doc);
161 obj2.free();
163 obj1.free();
165 delete annots;
168 exitCode = 0;
170 // clean up
171 gfree(fonts);
172 err1:
173 delete doc;
174 delete globalParams;
175 err0:
177 // check for memory leaks
178 xObject::memCheck(stderr);
179 gMemReport(stderr);
181 return exitCode;
184 static void scanFonts(Dict *resDict, PDFDoc *doc) {
185 xObject obj1, obj2, xObjDict, xObj, resObj;
186 Ref r;
187 GfxFontDict *gfxFontDict;
188 GfxFont *font;
189 int i;
191 // scan the fonts in this resource dictionary
192 gfxFontDict = NULL;
193 resDict->lookupNF("Font", &obj1);
194 if (obj1.isRef()) {
195 obj1.fetch(doc->getXRef(), &obj2);
196 if (obj2.isDict()) {
197 r = obj1.getRef();
198 gfxFontDict = new GfxFontDict(doc->getXRef(), &r, obj2.getDict());
200 obj2.free();
201 } else if (obj1.isDict()) {
202 gfxFontDict = new GfxFontDict(doc->getXRef(), NULL, obj1.getDict());
204 if (gfxFontDict) {
205 for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
206 if ((font = gfxFontDict->getFont(i))) {
207 scanFont(font, doc);
210 delete gfxFontDict;
212 obj1.free();
214 // recursively scan any resource dictionaries in xObjects in this
215 // resource dictionary
216 resDict->lookup("XObject", &xObjDict);
217 if (xObjDict.isDict()) {
218 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
219 xObjDict.dictGetVal(i, &xObj);
220 if (xObj.isStream()) {
221 xObj.streamGetDict()->lookup("Resources", &resObj);
222 if (resObj.isDict()) {
223 scanFonts(resObj.getDict(), doc);
225 resObj.free();
227 xObj.free();
230 xObjDict.free();
233 static void scanFont(GfxFont *font, PDFDoc *doc) {
234 Ref fontRef, embRef;
235 xObject fontObj, toUnicodeObj;
236 GString *name;
237 GBool emb, subset, hasToUnicode;
238 int i;
240 fontRef = *font->getID();
242 // check for an already-seen font
243 for (i = 0; i < fontsLen; ++i) {
244 if (fontRef.num == fonts[i].num && fontRef.gen == fonts[i].gen) {
245 return;
249 // font name
250 name = font->getOrigName();
252 // check for an embedded font
253 if (font->getType() == fontType3) {
254 emb = gTrue;
255 } else {
256 emb = font->getEmbeddedFontID(&embRef);
259 // look for a ToUnicode map
260 hasToUnicode = gFalse;
261 if (doc->getXRef()->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
262 hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
263 toUnicodeObj.free();
265 fontObj.free();
267 // check for a font subset name: capital letters followed by a '+'
268 // sign
269 subset = gFalse;
270 if (name) {
271 for (i = 0; i < name->getLength(); ++i) {
272 if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
273 break;
276 subset = i > 0 && i < name->getLength() && name->getChar(i) == '+';
279 // print the font info
280 printf("%-36s %-17s %-3s %-3s %-3s",
281 name ? name->getCString() : "[none]",
282 fontTypeNames[font->getType()],
283 emb ? "yes" : "no",
284 subset ? "yes" : "no",
285 hasToUnicode ? "yes" : "no");
286 if (fontRef.gen >= 100000) {
287 printf(" [none]\n");
288 } else {
289 printf(" %6d %2d\n", fontRef.num, fontRef.gen);
292 // add this font to the list
293 if (fontsLen == fontsSize) {
294 fontsSize += 32;
295 fonts = (Ref *)greallocn(fonts, fontsSize, sizeof(Ref));
297 fonts[fontsLen++] = *font->getID();