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