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", ¶mDict)->isDict()) {
54 Object paramObj;
55 if (paramDict.dictLookup("ModDate", ¶mObj)->isString())
56 m_modDate = new GooString(paramObj.getString());
57 paramObj.free();
58
59 if (paramDict.dictLookup("CreationDate", ¶mObj)->isString())
60 m_createDate = new GooString(paramObj.getString());
61 paramObj.free();
62
63 if (paramDict.dictLookup("Size", ¶mObj)->isInt())
64 m_size = paramObj.getInt();
65 paramObj.free();
66
67 if (paramDict.dictLookup("CheckSum", ¶mObj)->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