1 /* poppler-document.cc: qt interface to poppler
2  * Copyright (C) 2005, Net Integration Technologies, Inc.
3  * Copyright (C) 2005-2009, Albert Astals Cid <aacid@kde.org>
4  * Copyright (C) 2006, Stefan Kebekus <stefan.kebekus@math.uni-koeln.de>
5  * Copyright (C) 2006, Wilfried Huss <Wilfried.Huss@gmx.at>
6  * Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2, or (at your option)
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 #include <poppler-qt.h>
24 #include <qfile.h>
25 #include <GlobalParams.h>
26 #include <Outline.h>
27 #include <PDFDoc.h>
28 #include <PSOutputDev.h>
29 #include <Catalog.h>
30 #include <ErrorCodes.h>
31 #include <SplashOutputDev.h>
32 #include <splash/SplashBitmap.h>
33 #include <DateInfo.h>
34 #include "poppler-private.h"
35 
36 namespace Poppler {
37 
load(const QString & filePath)38 Document *Document::load(const QString &filePath)
39 {
40   if (!globalParams) {
41     globalParams = new GlobalParams();
42   }
43 
44   DocumentData *doc = new DocumentData(new GooString(QFile::encodeName(filePath)), NULL);
45   Document *pdoc;
46   if (doc->doc.isOk() || doc->doc.getErrorCode() == errEncrypted) {
47     pdoc = new Document(doc);
48     if (doc->doc.getErrorCode() == errEncrypted)
49       pdoc->data->locked = true;
50     else
51       pdoc->data->locked = false;
52     pdoc->data->m_fontInfoScanner = new FontInfoScanner(&(doc->doc));
53     return pdoc;
54   }
55   else
56     return NULL;
57 }
58 
Document(DocumentData * dataA)59 Document::Document(DocumentData *dataA)
60 {
61   data = dataA;
62 }
63 
~Document()64 Document::~Document()
65 {
66   delete data;
67 }
68 
isLocked() const69 bool Document::isLocked() const
70 {
71   return data->locked;
72 }
73 
unlock(const QCString & password)74 bool Document::unlock(const QCString &password)
75 {
76   if (data->locked) {
77     /* racier then it needs to be */
78     GooString *filename = new GooString(data->doc.getFileName());
79     GooString *pwd = new GooString(password.data());
80     DocumentData *doc2 = new DocumentData(filename, pwd);
81     delete pwd;
82     if (!doc2->doc.isOk()) {
83       delete doc2;
84     } else {
85       delete data;
86       data = doc2;
87       data->locked = false;
88       data->m_fontInfoScanner = new FontInfoScanner(&(data->doc));
89     }
90   }
91   return data->locked;
92 }
93 
getPageMode(void) const94 Document::PageMode Document::getPageMode(void) const
95 {
96   switch (data->doc.getCatalog()->getPageMode()) {
97     case Catalog::pageModeNone:
98       return UseNone;
99     case Catalog::pageModeOutlines:
100       return UseOutlines;
101     case Catalog::pageModeThumbs:
102       return UseThumbs;
103     case Catalog::pageModeFullScreen:
104       return FullScreen;
105     case Catalog::pageModeOC:
106       return UseOC;
107     default:
108       return UseNone;
109   }
110 }
111 
getNumPages() const112 int Document::getNumPages() const
113 {
114   return data->doc.getNumPages();
115 }
116 
getPage(int index) const117 Page *Document::getPage(int index) const
118 {
119   Page *p = new Page(this, index);
120   if (p->data->page == NULL) {
121     delete p;
122     return NULL;
123   }
124 
125   return p;
126 }
127 
fonts() const128 QValueList<FontInfo> Document::fonts() const
129 {
130   QValueList<FontInfo> ourList;
131   scanForFonts(getNumPages(), &ourList);
132   return ourList;
133 }
134 
scanForFonts(int numPages,QValueList<FontInfo> * fontList) const135 bool Document::scanForFonts( int numPages, QValueList<FontInfo> *fontList ) const
136 {
137   GooList *items = data->m_fontInfoScanner->scan( numPages );
138 
139   if ( NULL == items )
140     return false;
141 
142   for ( int i = 0; i < items->getLength(); ++i ) {
143     QString fontName;
144     if (((::FontInfo*)items->get(i))->getName())
145       fontName = ((::FontInfo*)items->get(i))->getName()->getCString();
146 
147     FontInfo font(fontName,
148                   ((::FontInfo*)items->get(i))->getEmbedded(),
149                   ((::FontInfo*)items->get(i))->getSubset(),
150                   (Poppler::FontInfo::Type)((::FontInfo*)items->get(i))->getType());
151     fontList->append(font);
152   }
153   deleteGooList(items, ::FontInfo);
154   return true;
155 }
156 
157 /* borrowed from kpdf */
getInfo(const QString & type) const158 QString Document::getInfo( const QString & type ) const
159 {
160   // [Albert] Code adapted from pdfinfo.cc on xpdf
161   Object info;
162   if ( data->locked )
163     return NULL;
164 
165   data->doc.getDocInfo( &info );
166   if ( !info.isDict() )
167     return NULL;
168 
169   QString result;
170   Object obj;
171   GooString *s1;
172   GBool isUnicode;
173   Unicode u;
174   int i;
175   Dict *infoDict = info.getDict();
176 
177   if ( infoDict->lookup( (char*)type.latin1(), &obj )->isString() )
178   {
179     s1 = obj.getString();
180     if ( ( s1->getChar(0) & 0xff ) == 0xfe && ( s1->getChar(1) & 0xff ) == 0xff )
181     {
182       isUnicode = gTrue;
183       i = 2;
184     }
185     else
186     {
187       isUnicode = gFalse;
188       i = 0;
189     }
190     while ( i < obj.getString()->getLength() )
191     {
192       if ( isUnicode )
193       {
194 	u = ( ( s1->getChar(i) & 0xff ) << 8 ) | ( s1->getChar(i+1) & 0xff );
195 	i += 2;
196       }
197       else
198       {
199 	u = s1->getChar(i) & 0xff;
200 	++i;
201       }
202       result += unicodeToQString( &u, 1 );
203     }
204     obj.free();
205     info.free();
206     return result;
207   }
208   obj.free();
209   info.free();
210   return NULL;
211 }
212 
213 /* borrowed from kpdf */
getDate(const QString & type) const214 QDateTime Document::getDate( const QString & type ) const
215 {
216   // [Albert] Code adapted from pdfinfo.cc on xpdf
217   if ( data->locked )
218     return QDateTime();
219 
220   Object info;
221   data->doc.getDocInfo( &info );
222   if ( !info.isDict() ) {
223     info.free();
224     return QDateTime();
225   }
226 
227   Object obj;
228   int year, mon, day, hour, min, sec, tz_hour, tz_minute;
229   char tz;
230   Dict *infoDict = info.getDict();
231   QString result;
232 
233   if ( infoDict->lookup( (char*)type.latin1(), &obj )->isString() )
234   {
235     QString s = UnicodeParsedString(obj.getString());
236     // TODO do something with the timezone information
237     if ( parseDateString( s.latin1(), &year, &mon, &day, &hour, &min, &sec, &tz, &tz_hour, &tz_minute ) )
238     {
239       QDate d( year, mon, day );  //CHECK: it was mon-1, Jan->0 (??)
240       QTime t( hour, min, sec );
241       if ( d.isValid() && t.isValid() ) {
242 	obj.free();
243 	info.free();
244 	return QDateTime( d, t );
245       }
246     }
247   }
248   obj.free();
249   info.free();
250   return QDateTime();
251 }
252 
isEncrypted() const253 bool Document::isEncrypted() const
254 {
255   return data->doc.isEncrypted();
256 }
257 
isLinearized() const258 bool Document::isLinearized() const
259 {
260   return data->doc.isLinearized();
261 }
262 
okToPrint() const263 bool Document::okToPrint() const
264 {
265   return data->doc.okToPrint();
266 }
267 
okToChange() const268 bool Document::okToChange() const
269 {
270   return data->doc.okToChange();
271 }
272 
okToCopy() const273 bool Document::okToCopy() const
274 {
275   return data->doc.okToCopy();
276 }
277 
okToAddNotes() const278 bool Document::okToAddNotes() const
279 {
280   return data->doc.okToAddNotes();
281 }
282 
getPDFVersion() const283 double Document::getPDFVersion() const
284 {
285   return data->doc.getPDFMajorVersion () + data->doc.getPDFMinorVersion() / 10.0;
286 }
287 
getPdfVersion(int * major,int * minor) const288 void Document::getPdfVersion(int *major, int *minor) const
289 {
290   if (major)
291     *major = data->doc.getPDFMajorVersion();
292   if (minor)
293     *minor = data->doc.getPDFMinorVersion();
294 }
295 
toc() const296 QDomDocument *Document::toc() const
297 {
298   Outline * outline = data->doc.getOutline();
299   if ( !outline )
300     return NULL;
301 
302   GooList * items = outline->getItems();
303   if ( !items || items->getLength() < 1 )
304     return NULL;
305 
306   QDomDocument *toc = new QDomDocument();
307   if ( items->getLength() > 0 )
308     data->addTocChildren( toc, toc, items );
309 
310   return toc;
311 }
312 
linkDestination(const QString & name)313 LinkDestination *Document::linkDestination( const QString &name )
314 {
315   GooString * namedDest = QStringToGooString( name );
316   LinkDestinationData ldd(NULL, namedDest, data);
317   LinkDestination *ld = new LinkDestination(ldd);
318   delete namedDest;
319   return ld;
320 }
321 
print(const QString & fileName,QValueList<int> pageList,double hDPI,double vDPI,int rotate)322 bool Document::print(const QString &fileName, QValueList<int> pageList, double hDPI, double vDPI, int rotate)
323 {
324   return print(fileName, pageList, hDPI, vDPI, rotate, -1, -1);
325 }
326 
print(const QString & file,QValueList<int> pageList,double hDPI,double vDPI,int rotate,int paperWidth,int paperHeight)327 bool Document::print(const QString &file, QValueList<int> pageList, double hDPI, double vDPI, int rotate, int paperWidth, int paperHeight)
328 {
329   PSOutputDev *psOut = new PSOutputDev(file.latin1(), &(data->doc), data->doc.getXRef(), data->doc.getCatalog(), NULL, 1, data->doc.getNumPages(), psModePS, paperWidth, paperHeight);
330 
331   if (psOut->isOk()) {
332     QValueList<int>::iterator it;
333     for (it = pageList.begin(); it != pageList.end(); ++it )
334       data->doc.displayPage(psOut, *it, hDPI, vDPI, rotate, gFalse, gTrue, gTrue);
335 
336     delete psOut;
337     return true;
338   } else {
339     delete psOut;
340     return false;
341   }
342 }
343 
344 }
345