]> git.ipfire.org Git - thirdparty/cups.git/blob - pdftops/PDFDoc.cxx
Merge changes from 1.1.x into 1.2 devel.
[thirdparty/cups.git] / pdftops / PDFDoc.cxx
1 //========================================================================
2 //
3 // PDFDoc.cc
4 //
5 // Copyright 1996 Derek B. Noonburg
6 //
7 //========================================================================
8
9 #ifdef __GNUC__
10 #pragma implementation
11 #endif
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include "GString.h"
18 #include "config.h"
19 #include "Page.h"
20 #include "Catalog.h"
21 #include "Stream.h"
22 #include "XRef.h"
23 #include "Link.h"
24 #include "OutputDev.h"
25 #include "Params.h"
26 #include "Error.h"
27 #include "Lexer.h"
28 #include "Parser.h"
29 #include "PDFDoc.h"
30
31 //------------------------------------------------------------------------
32
33 #define headerSearchSize 1024 // read this many bytes at beginning of
34 // file to look for '%PDF'
35
36 //------------------------------------------------------------------------
37 // PDFDoc
38 //------------------------------------------------------------------------
39
40 PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword,
41 GString *userPassword, GBool printCommandsA) {
42 Object obj;
43 GString *fileName2;
44
45 ok = gFalse;
46
47 file = NULL;
48 str = NULL;
49 xref = NULL;
50 catalog = NULL;
51 links = NULL;
52 printCommands = printCommandsA;
53
54 // try to open file
55 fileName = fileNameA;
56 fileName2 = NULL;
57 #ifdef VMS
58 if (!(file = fopen(fileName->getCString(), "rb", "ctx=stm"))) {
59 error(-1, "Couldn't open file '%s'", fileName->getCString());
60 return;
61 }
62 #else
63 if (!(file = fopen(fileName->getCString(), "rb"))) {
64 fileName2 = fileName->copy();
65 fileName2->lowerCase();
66 if (!(file = fopen(fileName2->getCString(), "rb"))) {
67 fileName2->upperCase();
68 if (!(file = fopen(fileName2->getCString(), "rb"))) {
69 error(-1, "Couldn't open file '%s'", fileName->getCString());
70 delete fileName2;
71 return;
72 }
73 }
74 delete fileName2;
75 }
76 #endif
77
78 // create stream
79 obj.initNull();
80 str = new FileStream(file, 0, -1, &obj);
81
82 ok = setup(ownerPassword, userPassword);
83 }
84
85 PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
86 GString *userPassword, GBool printCommandsA) {
87 ok = gFalse;
88 fileName = NULL;
89 file = NULL;
90 str = strA;
91 xref = NULL;
92 catalog = NULL;
93 links = NULL;
94 printCommands = printCommandsA;
95 ok = setup(ownerPassword, userPassword);
96 }
97
98 GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
99 // check header
100 checkHeader();
101
102 // read xref table
103 xref = new XRef(str, ownerPassword, userPassword);
104 if (!xref->isOk()) {
105 error(-1, "Couldn't read xref table");
106 return gFalse;
107 }
108
109 // read catalog
110 catalog = new Catalog(xref, printCommands);
111 if (!catalog->isOk()) {
112 error(-1, "Couldn't read page catalog");
113 return gFalse;
114 }
115
116 // done
117 return gTrue;
118 }
119
120 PDFDoc::~PDFDoc() {
121 if (catalog) {
122 delete catalog;
123 }
124 if (xref) {
125 delete xref;
126 }
127 if (str) {
128 delete str;
129 }
130 if (file) {
131 fclose(file);
132 }
133 if (fileName) {
134 delete fileName;
135 }
136 if (links) {
137 delete links;
138 }
139 }
140
141 // Check for a PDF header on this stream. Skip past some garbage
142 // if necessary.
143 void PDFDoc::checkHeader() {
144 char hdrBuf[headerSearchSize+1];
145 char *p;
146 int i;
147
148 pdfVersion = 0;
149 for (i = 0; i < headerSearchSize; ++i) {
150 hdrBuf[i] = str->getChar();
151 }
152 hdrBuf[headerSearchSize] = '\0';
153 for (i = 0; i < headerSearchSize - 5; ++i) {
154 if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
155 break;
156 }
157 }
158 if (i >= headerSearchSize - 5) {
159 error(-1, "May not be a PDF file (continuing anyway)");
160 return;
161 }
162 str->moveStart(i);
163 p = strtok(&hdrBuf[i+5], " \t\n\r");
164 pdfVersion = atof(p);
165 if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
166 pdfVersion > supportedPDFVersionNum + 0.0001) {
167 error(-1, "PDF version %s -- xpdf supports version %s"
168 " (continuing anyway)", p, supportedPDFVersionStr);
169 }
170 }
171
172 void PDFDoc::displayPage(OutputDev *out, int page, double zoom,
173 int rotate, GBool doLinks) {
174 Page *p;
175
176 if (printCommands) {
177 printf("***** page %d *****\n", page);
178 }
179 p = catalog->getPage(page);
180 if (doLinks) {
181 if (links) {
182 delete links;
183 }
184 getLinks(p);
185 p->display(out, zoom, rotate, links, catalog);
186 } else {
187 p->display(out, zoom, rotate, NULL, catalog);
188 }
189 }
190
191 void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
192 int zoom, int rotate, GBool doLinks) {
193 int page;
194
195 for (page = firstPage; page <= lastPage; ++page) {
196 displayPage(out, page, zoom, rotate, doLinks);
197 }
198 }
199
200 GBool PDFDoc::isLinearized() {
201 Parser *parser;
202 Object obj1, obj2, obj3, obj4, obj5;
203 GBool lin;
204
205 lin = gFalse;
206 obj1.initNull();
207 parser = new Parser(xref, new Lexer(xref, str->makeSubStream(str->getStart(),
208 -1, &obj1)));
209 parser->getObj(&obj1);
210 parser->getObj(&obj2);
211 parser->getObj(&obj3);
212 parser->getObj(&obj4);
213 if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") &&
214 obj4.isDict()) {
215 obj4.dictLookup("Linearized", &obj5);
216 if (obj5.isNum() && obj5.getNum() > 0) {
217 lin = gTrue;
218 }
219 obj5.free();
220 }
221 obj4.free();
222 obj3.free();
223 obj2.free();
224 obj1.free();
225 delete parser;
226 return lin;
227 }
228
229 GBool PDFDoc::saveAs(GString *name) {
230 FILE *f;
231 int c;
232
233 if (!(f = fopen(name->getCString(), "wb"))) {
234 error(-1, "Couldn't open file '%s'", name->getCString());
235 return gFalse;
236 }
237 str->reset();
238 while ((c = str->getChar()) != EOF) {
239 fputc(c, f);
240 }
241 str->close();
242 fclose(f);
243 return gTrue;
244 }
245
246 void PDFDoc::getLinks(Page *page) {
247 Object obj;
248
249 links = new Links(page->getAnnots(&obj), catalog->getBaseURI());
250 obj.free();
251 }