1 //========================================================================
2 //
3 // FileSpec.cc
4 //
5 // All changes made under the Poppler project to this file are licensed
6 // under GPL version 2 or later
7 //
8 // Copyright (C) 2008-2009 Carlos Garcia Campos <carlosgc@gnome.org>
9 // Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
10 // Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
11 // Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
12 //
13 // To see a description of the changes please see the Changelog file that
14 // came with your tarball or type make ChangeLog if you are building from git
15 //
16 //========================================================================
17 
18 //========================================================================
19 //
20 // Most of the code from Link.cc and PSOutputDev.cc
21 //
22 // Copyright 1996-2003 Glyph & Cog, LLC
23 //
24 //========================================================================
25 
26 #include <config.h>
27 
28 #include "FileSpec.h"
29 
EmbFile(Object * efStream)30 EmbFile::EmbFile(Object *efStream)
31 {
32   m_size = -1;
33   m_createDate = NULL;
34   m_modDate = NULL;
35   m_checksum = NULL;
36   m_mimetype = NULL;
37 
38   efStream->copy(&m_objStr);
39 
40   if (efStream->isStream()) {
41     // dataDict corresponds to Table 3.41 in the PDF1.6 spec.
42     Dict *dataDict = efStream->streamGetDict();
43 
44     // subtype is normally the mimetype
45     Object subtypeName;
46     if (dataDict->lookup("Subtype", &subtypeName)->isName()) {
47       m_mimetype = new GooString(subtypeName.getName());
48     }
49     subtypeName.free();
50 
51     // paramDict corresponds to Table 3.42 in the PDF1.6 spec
52     Object paramDict;
53     if (dataDict->lookup("Params", &paramDict)->isDict()) {
54       Object paramObj;
55       if (paramDict.dictLookup("ModDate", &paramObj)->isString())
56         m_modDate = new GooString(paramObj.getString());
57       paramObj.free();
58 
59       if (paramDict.dictLookup("CreationDate", &paramObj)->isString())
60         m_createDate = new GooString(paramObj.getString());
61       paramObj.free();
62 
63       if (paramDict.dictLookup("Size", &paramObj)->isInt())
64         m_size = paramObj.getInt();
65       paramObj.free();
66 
67       if (paramDict.dictLookup("CheckSum", &paramObj)->isString())
68         m_checksum = new GooString(paramObj.getString());
69       paramObj.free();
70     }
71     paramDict.free();
72   }
73 }
74 
~EmbFile()75 EmbFile::~EmbFile()
76 {
77   delete m_createDate;
78   delete m_modDate;
79   delete m_checksum;
80   delete m_mimetype;
81   m_objStr.free();
82 }
83 
save(const char * path)84 GBool EmbFile::save(const char *path) {
85   FILE *f;
86   GBool ret;
87 
88   if (!(f = fopen(path, "wb"))) {
89     return gFalse;
90   }
91   ret = save2(f);
92   fclose(f);
93   return ret;
94 }
95 
save2(FILE * f)96 GBool EmbFile::save2(FILE *f) {
97   int c;
98 
99   m_objStr.streamReset();
100   while ((c = m_objStr.streamGetChar()) != EOF) {
101     fputc(c, f);
102   }
103   return gTrue;
104 }
105 
FileSpec(Object * fileSpecA)106 FileSpec::FileSpec(Object *fileSpecA)
107 {
108   ok = gTrue;
109   fileName = NULL;
110   platformFileName = NULL;
111   embFile = NULL;
112   desc = NULL;
113   fileSpecA->copy(&fileSpec);
114 
115   Object obj1;
116   if (!getFileSpecName(fileSpecA, &obj1)) {
117     ok = gFalse;
118     obj1.free();
119     error(errSyntaxError, -1, "Invalid FileSpec");
120     return;
121   }
122 
123   fileName = obj1.getString()->copy();
124   obj1.free();
125 
126   if (fileSpec.isDict()) {
127     if (fileSpec.dictLookup("EF", &obj1)->isDict()) {
128       if (!obj1.dictLookupNF("F", &fileStream)->isRef()) {
129         ok = gFalse;
130         fileStream.free();
131         error(errSyntaxError, -1, "Invalid FileSpec: Embedded file stream is not an indirect reference");
132         obj1.free();
133         return;
134       }
135     }
136     obj1.free();
137   }
138 
139   if (fileSpec.dictLookup("Desc", &obj1)->isString())
140     desc = obj1.getString()->copy();
141   obj1.free();
142 }
143 
~FileSpec()144 FileSpec::~FileSpec()
145 {
146   fileSpec.free();
147   fileStream.free();
148   delete fileName;
149   delete platformFileName;
150   delete embFile;
151   delete desc;
152 }
153 
getEmbeddedFile()154 EmbFile *FileSpec::getEmbeddedFile()
155 {
156   if(!ok)
157     return NULL;
158 
159   if (embFile)
160     return embFile;
161 
162   Object obj1;
163   XRef *xref = fileSpec.getDict()->getXRef();
164   embFile = new EmbFile(fileStream.fetch(xref, &obj1));
165   obj1.free();
166 
167   return embFile;
168 }
169 
getFileNameForPlatform()170 GooString *FileSpec::getFileNameForPlatform()
171 {
172   if (platformFileName)
173     return platformFileName;
174 
175   Object obj1;
176   if (getFileSpecNameForPlatform(&fileSpec, &obj1))
177     platformFileName = obj1.getString()->copy();
178   obj1.free();
179 
180   return platformFileName;
181 }
182 
getFileSpecName(Object * fileSpec,Object * fileName)183 GBool getFileSpecName (Object *fileSpec, Object *fileName)
184 {
185   if (fileSpec->isString()) {
186     fileSpec->copy(fileName);
187     return gTrue;
188   }
189 
190   if (fileSpec->isDict()) {
191     fileSpec->dictLookup("UF", fileName);
192     if (fileName->isString()) {
193       return gTrue;
194     }
195     fileName->free();
196     fileSpec->dictLookup("F", fileName);
197     if (fileName->isString()) {
198       return gTrue;
199     }
200     fileName->free();
201     fileSpec->dictLookup("DOS", fileName);
202     if (fileName->isString()) {
203       return gTrue;
204     }
205     fileName->free();
206     fileSpec->dictLookup("Mac", fileName);
207     if (fileName->isString()) {
208       return gTrue;
209     }
210     fileName->free();
211     fileSpec->dictLookup("Unix", fileName);
212     if (fileName->isString()) {
213       return gTrue;
214     }
215     fileName->free();
216   }
217   return gFalse;
218 }
219 
getFileSpecNameForPlatform(Object * fileSpec,Object * fileName)220 GBool getFileSpecNameForPlatform (Object *fileSpec, Object *fileName)
221 {
222   if (fileSpec->isString()) {
223     fileSpec->copy(fileName);
224     return gTrue;
225   }
226 
227   if (fileSpec->isDict()) {
228     if (!fileSpec->dictLookup("UF", fileName)->isString ()) {
229       fileName->free();
230       if (!fileSpec->dictLookup("F", fileName)->isString ()) {
231         fileName->free();
232 #ifdef _WIN32
233 	const char *platform = "DOS";
234 #else
235 	const char *platform = "Unix";
236 #endif
237 	if (!fileSpec->dictLookup(platform, fileName)->isString ()) {
238 	  fileName->free();
239 	  error(errSyntaxError, -1, "Illegal file spec");
240 	  return gFalse;
241 	}
242       }
243     }
244   } else {
245     error(errSyntaxError, -1, "Illegal file spec");
246     return gFalse;
247   }
248 
249   // system-dependent path manipulation
250 #ifdef _WIN32
251   int i, j;
252   GooString *name = fileName->getString();
253   // "//...."             --> "\...."
254   // "/x/...."            --> "x:\...."
255   // "/server/share/...." --> "\\server\share\...."
256   // convert escaped slashes to slashes and unescaped slashes to backslashes
257   i = 0;
258   if (name->getChar(0) == '/') {
259     if (name->getLength() >= 2 && name->getChar(1) == '/') {
260       name->del(0);
261       i = 0;
262     } else if (name->getLength() >= 2 &&
263 	       ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') ||
264 		(name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) &&
265 	       (name->getLength() == 2 || name->getChar(2) == '/')) {
266       name->setChar(0, name->getChar(1));
267       name->setChar(1, ':');
268       i = 2;
269     } else {
270       for (j = 2; j < name->getLength(); ++j) {
271         if (name->getChar(j-1) != '\\' &&
272 	    name->getChar(j) == '/') {
273 	  break;
274 	}
275       }
276       if (j < name->getLength()) {
277         name->setChar(0, '\\');
278 	name->insert(0, '\\');
279 	i = 2;
280       }
281     }
282   }
283   for (; i < name->getLength(); ++i) {
284     if (name->getChar(i) == '/') {
285       name->setChar(i, '\\');
286     } else if (name->getChar(i) == '\\' &&
287 	       i+1 < name->getLength() &&
288 	       name->getChar(i+1) == '/') {
289       name->del(i);
290     }
291   }
292 #endif /* _WIN32 */
293 
294   return gTrue;
295 }
296