]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/pdftotext.cc
kill traces of ltk, incorporate new sources
[evince.git] / pdf / xpdf / pdftotext.cc
1 //========================================================================
2 //
3 // pdftotext.cc
4 //
5 // Copyright 1997-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 "parseargs.h"
15 #include "GString.h"
16 #include "gmem.h"
17 #include "GlobalParams.h"
18 #include "Object.h"
19 #include "Stream.h"
20 #include "Array.h"
21 #include "Dict.h"
22 #include "XRef.h"
23 #include "Catalog.h"
24 #include "Page.h"
25 #include "PDFDoc.h"
26 #include "TextOutputDev.h"
27 #include "CharTypes.h"
28 #include "UnicodeMap.h"
29 #include "Error.h"
30 #include "config.h"
31
32 static void printInfoString(FILE *f, Dict *infoDict, char *key,
33                             char *text1, char *text2, UnicodeMap *uMap);
34 static void printInfoDate(FILE *f, Dict *infoDict, char *key, char *fmt);
35
36 static int firstPage = 1;
37 static int lastPage = 0;
38 static GBool rawOrder = gFalse;
39 static GBool htmlMeta = gFalse;
40 static char textEncName[128] = "";
41 static char textEOL[16] = "";
42 static char ownerPassword[33] = "";
43 static char userPassword[33] = "";
44 static GBool quiet = gFalse;
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 convert"},
52   {"-l",      argInt,      &lastPage,      0,
53    "last page to convert"},
54   {"-raw",    argFlag,     &rawOrder,      0,
55    "keep strings in content stream order"},
56   {"-htmlmeta", argFlag,   &htmlMeta,      0,
57    "generate a simple HTML file, including the meta information"},
58   {"-enc",    argString,   textEncName,    sizeof(textEncName),
59    "output text encoding name"},
60   {"-eol",    argString,   textEOL,        sizeof(textEOL),
61    "output end-of-line convention (unix, dos, or mac)"},
62   {"-opw",    argString,   ownerPassword,  sizeof(ownerPassword),
63    "owner password (for encrypted files)"},
64   {"-upw",    argString,   userPassword,   sizeof(userPassword),
65    "user password (for encrypted files)"},
66   {"-q",      argFlag,     &quiet,         0,
67    "don't print any messages or errors"},
68   {"-cfg",        argString,      cfgFileName,    sizeof(cfgFileName),
69    "configuration file to use in place of .xpdfrc"},
70   {"-v",      argFlag,     &printVersion,  0,
71    "print copyright and version info"},
72   {"-h",      argFlag,     &printHelp,     0,
73    "print usage information"},
74   {"-help",   argFlag,     &printHelp,     0,
75    "print usage information"},
76   {"--help",  argFlag,     &printHelp,     0,
77    "print usage information"},
78   {"-?",      argFlag,     &printHelp,     0,
79    "print usage information"},
80   {NULL}
81 };
82
83 int main(int argc, char *argv[]) {
84   PDFDoc *doc;
85   GString *fileName;
86   GString *textFileName;
87   GString *ownerPW, *userPW;
88   TextOutputDev *textOut;
89   FILE *f;
90   UnicodeMap *uMap;
91   Object info;
92   GBool ok;
93   char *p;
94   int exitCode;
95
96   exitCode = 99;
97
98   // parse args
99   ok = parseArgs(argDesc, &argc, argv);
100   if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) {
101     fprintf(stderr, "pdftotext version %s\n", xpdfVersion);
102     fprintf(stderr, "%s\n", xpdfCopyright);
103     if (!printVersion) {
104       printUsage("pdftotext", "<PDF-file> [<text-file>]", argDesc);
105     }
106     goto err0;
107   }
108   fileName = new GString(argv[1]);
109
110   // read config file
111   globalParams = new GlobalParams(cfgFileName);
112   if (textEncName[0]) {
113     globalParams->setTextEncoding(textEncName);
114   }
115   if (textEOL[0]) {
116     if (!globalParams->setTextEOL(textEOL)) {
117       fprintf(stderr, "Bad '-eol' value on command line\n");
118     }
119   }
120   if (quiet) {
121     globalParams->setErrQuiet(quiet);
122   }
123
124   // get mapping to output encoding
125   if (!(uMap = globalParams->getTextEncoding())) {
126     error(-1, "Couldn't get text encoding");
127     delete fileName;
128     goto err1;
129   }
130
131   // open PDF file
132   if (ownerPassword[0]) {
133     ownerPW = new GString(ownerPassword);
134   } else {
135     ownerPW = NULL;
136   }
137   if (userPassword[0]) {
138     userPW = new GString(userPassword);
139   } else {
140     userPW = NULL;
141   }
142   doc = new PDFDoc(fileName, ownerPW, userPW);
143   if (userPW) {
144     delete userPW;
145   }
146   if (ownerPW) {
147     delete ownerPW;
148   }
149   if (!doc->isOk()) {
150     exitCode = 1;
151     goto err2;
152   }
153
154   // check for copy permission
155   if (!doc->okToCopy()) {
156     error(-1, "Copying of text from this document is not allowed.");
157     exitCode = 3;
158     goto err2;
159   }
160
161   // construct text file name
162   if (argc == 3) {
163     textFileName = new GString(argv[2]);
164   } else {
165     p = fileName->getCString() + fileName->getLength() - 4;
166     if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) {
167       textFileName = new GString(fileName->getCString(),
168                                  fileName->getLength() - 4);
169     } else {
170       textFileName = fileName->copy();
171     }
172     textFileName->append(htmlMeta ? ".html" : ".txt");
173   }
174
175   // get page range
176   if (firstPage < 1) {
177     firstPage = 1;
178   }
179   if (lastPage < 1 || lastPage > doc->getNumPages()) {
180     lastPage = doc->getNumPages();
181   }
182
183   // write HTML header
184   if (htmlMeta) {
185     if (!textFileName->cmp("-")) {
186       f = stdout;
187     } else {
188       if (!(f = fopen(textFileName->getCString(), "wb"))) {
189         error(-1, "Couldn't open text file '%s'", textFileName->getCString());
190         exitCode = 2;
191         goto err3;
192       }
193     }
194     fputs("<html>\n", f);
195     fputs("<head>\n", f);
196     doc->getDocInfo(&info);
197     if (info.isDict()) {
198       printInfoString(f, info.getDict(), "Title", "<title>", "</title>\n",
199                       uMap);
200       printInfoString(f, info.getDict(), "Subject",
201                       "<meta name=\"Subject\" content=\"", "\">\n", uMap);
202       printInfoString(f, info.getDict(), "Keywords",
203                       "<meta name=\"Keywords\" content=\"", "\">\n", uMap);
204       printInfoString(f, info.getDict(), "Author",
205                       "<meta name=\"Author\" content=\"", "\">\n", uMap);
206       printInfoString(f, info.getDict(), "Creator",
207                       "<meta name=\"Creator\" content=\"", "\">\n", uMap);
208       printInfoString(f, info.getDict(), "Producer",
209                       "<meta name=\"Producer\" content=\"", "\">\n", uMap);
210       printInfoDate(f, info.getDict(), "CreationDate",
211                     "<meta name=\"CreationDate\" content=\"\">\n");
212       printInfoDate(f, info.getDict(), "LastModifiedDate",
213                     "<meta name=\"ModDate\" content=\"\">\n");
214     }
215     info.free();
216     fputs("</head>\n", f);
217     fputs("<body>\n", f);
218     fputs("<pre>\n", f);
219     if (f != stdout) {
220       fclose(f);
221     }
222   }
223
224   // write text file
225   textOut = new TextOutputDev(textFileName->getCString(), rawOrder, htmlMeta);
226   if (textOut->isOk()) {
227     doc->displayPages(textOut, firstPage, lastPage, 72, 0, gFalse);
228   } else {
229     delete textOut;
230     exitCode = 2;
231     goto err3;
232   }
233   delete textOut;
234
235   // write end of HTML file
236   if (htmlMeta) {
237     if (!textFileName->cmp("-")) {
238       f = stdout;
239     } else {
240       if (!(f = fopen(textFileName->getCString(), "ab"))) {
241         error(-1, "Couldn't open text file '%s'", textFileName->getCString());
242         exitCode = 2;
243         goto err3;
244       }
245     }
246     fputs("</pre>\n", f);
247     fputs("</body>\n", f);
248     fputs("</html>\n", f);
249     if (f != stdout) {
250       fclose(f);
251     }
252   }
253
254   exitCode = 0;
255
256   // clean up
257  err3:
258   delete textFileName;
259  err2:
260   delete doc;
261   uMap->decRefCnt();
262  err1:
263   delete globalParams;
264  err0:
265
266   // check for memory leaks
267   Object::memCheck(stderr);
268   gMemReport(stderr);
269
270   return exitCode;
271 }
272
273 static void printInfoString(FILE *f, Dict *infoDict, char *key,
274                             char *text1, char *text2, UnicodeMap *uMap) {
275   Object obj;
276   GString *s1;
277   GBool isUnicode;
278   Unicode u;
279   char buf[8];
280   int i, n;
281
282   if (infoDict->lookup(key, &obj)->isString()) {
283     fputs(text1, f);
284     s1 = obj.getString();
285     if ((s1->getChar(0) & 0xff) == 0xfe &&
286         (s1->getChar(1) & 0xff) == 0xff) {
287       isUnicode = gTrue;
288       i = 2;
289     } else {
290       isUnicode = gFalse;
291       i = 0;
292     }
293     while (i < obj.getString()->getLength()) {
294       if (isUnicode) {
295         u = ((s1->getChar(i) & 0xff) << 8) |
296             (s1->getChar(i+1) & 0xff);
297         i += 2;
298       } else {
299         u = s1->getChar(i) & 0xff;
300         ++i;
301       }
302       n = uMap->mapUnicode(u, buf, sizeof(buf));
303       fwrite(buf, 1, n, f);
304     }
305     fputs(text2, f);
306   }
307   obj.free();
308 }
309
310 static void printInfoDate(FILE *f, Dict *infoDict, char *key, char *fmt) {
311   Object obj;
312   char *s;
313
314   if (infoDict->lookup(key, &obj)->isString()) {
315     s = obj.getString()->getCString();
316     if (s[0] == 'D' && s[1] == ':') {
317       s += 2;
318     }
319     fprintf(f, fmt, s);
320   }
321   obj.free();
322 }