/src/xpdf-4.04/goo/gfile.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //======================================================================== |
2 | | // |
3 | | // gfile.cc |
4 | | // |
5 | | // Miscellaneous file and directory name manipulation. |
6 | | // |
7 | | // Copyright 1996-2003 Glyph & Cog, LLC |
8 | | // |
9 | | //======================================================================== |
10 | | |
11 | | #include <aconf.h> |
12 | | |
13 | | #ifdef _WIN32 |
14 | | # undef WIN32_LEAN_AND_MEAN |
15 | | # include <windows.h> |
16 | | # include <time.h> |
17 | | # include <direct.h> |
18 | | # include <shobjidl.h> |
19 | | # include <shlguid.h> |
20 | | #else |
21 | | # if !defined(ACORN) |
22 | | # include <sys/types.h> |
23 | | # include <sys/stat.h> |
24 | | # include <fcntl.h> |
25 | | # endif |
26 | | # include <time.h> |
27 | | # include <limits.h> |
28 | | # include <string.h> |
29 | | # if !defined(VMS) && !defined(ACORN) |
30 | | # include <pwd.h> |
31 | | # endif |
32 | | # if defined(VMS) && (__DECCXX_VER < 50200000) |
33 | | # include <unixlib.h> |
34 | | # endif |
35 | | #endif // _WIN32 |
36 | | #include "gmem.h" |
37 | | #include "gmempp.h" |
38 | | #include "GString.h" |
39 | | #include "gfile.h" |
40 | | |
41 | | // Some systems don't define this, so just make it something reasonably |
42 | | // large. |
43 | | #ifndef PATH_MAX |
44 | | #define PATH_MAX 1024 |
45 | | #endif |
46 | | |
47 | | //------------------------------------------------------------------------ |
48 | | |
49 | 7.12k | GString *getHomeDir() { |
50 | | #ifdef VMS |
51 | | //---------- VMS ---------- |
52 | | return new GString("SYS$LOGIN:"); |
53 | | |
54 | | #elif defined(_WIN32) |
55 | | //---------- Win32 ---------- |
56 | | char *s; |
57 | | GString *ret; |
58 | | |
59 | | if ((s = getenv("USERPROFILE"))) |
60 | | ret = new GString(s); |
61 | | else |
62 | | ret = new GString("."); |
63 | | return ret; |
64 | | |
65 | | #elif defined(__EMX__) |
66 | | //---------- OS/2+EMX ---------- |
67 | | char *s; |
68 | | GString *ret; |
69 | | |
70 | | if ((s = getenv("HOME"))) |
71 | | ret = new GString(s); |
72 | | else |
73 | | ret = new GString("."); |
74 | | return ret; |
75 | | |
76 | | #elif defined(ACORN) |
77 | | //---------- RISCOS ---------- |
78 | | return new GString("@"); |
79 | | |
80 | | #else |
81 | | //---------- Unix ---------- |
82 | 7.12k | char *s; |
83 | 7.12k | struct passwd *pw; |
84 | 7.12k | GString *ret; |
85 | | |
86 | 7.12k | if ((s = getenv("HOME"))) { |
87 | 7.12k | ret = new GString(s); |
88 | 7.12k | } else { |
89 | 0 | if ((s = getenv("USER"))) |
90 | 0 | pw = getpwnam(s); |
91 | 0 | else |
92 | 0 | pw = getpwuid(getuid()); |
93 | 0 | if (pw) |
94 | 0 | ret = new GString(pw->pw_dir); |
95 | 0 | else |
96 | 0 | ret = new GString("."); |
97 | 0 | } |
98 | 7.12k | return ret; |
99 | 7.12k | #endif |
100 | 7.12k | } |
101 | | |
102 | 0 | GString *getCurrentDir() { |
103 | 0 | char buf[PATH_MAX+1]; |
104 | |
|
105 | | #if defined(__EMX__) |
106 | | if (_getcwd2(buf, sizeof(buf))) |
107 | | #elif defined(_WIN32) |
108 | | if (GetCurrentDirectoryA(sizeof(buf), buf)) |
109 | | #elif defined(ACORN) |
110 | | if (strcpy(buf, "@")) |
111 | | #else |
112 | 0 | if (getcwd(buf, sizeof(buf))) |
113 | 0 | #endif |
114 | 0 | return new GString(buf); |
115 | 0 | return new GString(); |
116 | 0 | } |
117 | | |
118 | 173k | GString *appendToPath(GString *path, const char *fileName) { |
119 | | #if defined(VMS) |
120 | | //---------- VMS ---------- |
121 | | //~ this should handle everything necessary for file |
122 | | //~ requesters, but it's certainly not complete |
123 | | char *p0, *p1, *p2; |
124 | | char *q1; |
125 | | |
126 | | p0 = path->getCString(); |
127 | | p1 = p0 + path->getLength() - 1; |
128 | | if (!strcmp(fileName, "-")) { |
129 | | if (*p1 == ']') { |
130 | | for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ; |
131 | | if (*p2 == '[') |
132 | | ++p2; |
133 | | path->del(p2 - p0, p1 - p2); |
134 | | } else if (*p1 == ':') { |
135 | | path->append("[-]"); |
136 | | } else { |
137 | | path->clear(); |
138 | | path->append("[-]"); |
139 | | } |
140 | | } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) { |
141 | | if (*p1 == ']') { |
142 | | path->insert(p1 - p0, '.'); |
143 | | path->insert(p1 - p0 + 1, fileName, q1 - fileName); |
144 | | } else if (*p1 == ':') { |
145 | | path->append('['); |
146 | | path->append(']'); |
147 | | path->append(fileName, q1 - fileName); |
148 | | } else { |
149 | | path->clear(); |
150 | | path->append(fileName, q1 - fileName); |
151 | | } |
152 | | } else { |
153 | | if (*p1 != ']' && *p1 != ':') |
154 | | path->clear(); |
155 | | path->append(fileName); |
156 | | } |
157 | | return path; |
158 | | |
159 | | #elif defined(_WIN32) |
160 | | //---------- Win32 ---------- |
161 | | GString *tmp; |
162 | | char buf[256]; |
163 | | char *fp; |
164 | | |
165 | | tmp = new GString(path); |
166 | | tmp->append('/'); |
167 | | tmp->append(fileName); |
168 | | GetFullPathNameA(tmp->getCString(), sizeof(buf), buf, &fp); |
169 | | delete tmp; |
170 | | path->clear(); |
171 | | path->append(buf); |
172 | | return path; |
173 | | |
174 | | #elif defined(ACORN) |
175 | | //---------- RISCOS ---------- |
176 | | char *p; |
177 | | int i; |
178 | | |
179 | | path->append("."); |
180 | | i = path->getLength(); |
181 | | path->append(fileName); |
182 | | for (p = path->getCString() + i; *p; ++p) { |
183 | | if (*p == '/') { |
184 | | *p = '.'; |
185 | | } else if (*p == '.') { |
186 | | *p = '/'; |
187 | | } |
188 | | } |
189 | | return path; |
190 | | |
191 | | #elif defined(__EMX__) |
192 | | //---------- OS/2+EMX ---------- |
193 | | int i; |
194 | | |
195 | | // appending "." does nothing |
196 | | if (!strcmp(fileName, ".")) |
197 | | return path; |
198 | | |
199 | | // appending ".." goes up one directory |
200 | | if (!strcmp(fileName, "..")) { |
201 | | for (i = path->getLength() - 2; i >= 0; --i) { |
202 | | if (path->getChar(i) == '/' || path->getChar(i) == '\\' || |
203 | | path->getChar(i) == ':') |
204 | | break; |
205 | | } |
206 | | if (i <= 0) { |
207 | | if (path->getChar(0) == '/' || path->getChar(0) == '\\') { |
208 | | path->del(1, path->getLength() - 1); |
209 | | } else if (path->getLength() >= 2 && path->getChar(1) == ':') { |
210 | | path->del(2, path->getLength() - 2); |
211 | | } else { |
212 | | path->clear(); |
213 | | path->append(".."); |
214 | | } |
215 | | } else { |
216 | | if (path->getChar(i-1) == ':') |
217 | | ++i; |
218 | | path->del(i, path->getLength() - i); |
219 | | } |
220 | | return path; |
221 | | } |
222 | | |
223 | | // otherwise, append "/" and new path component |
224 | | if (path->getLength() > 0 && |
225 | | path->getChar(path->getLength() - 1) != '/' && |
226 | | path->getChar(path->getLength() - 1) != '\\') |
227 | | path->append('/'); |
228 | | path->append(fileName); |
229 | | return path; |
230 | | |
231 | | #else |
232 | | //---------- Unix ---------- |
233 | 173k | int i; |
234 | | |
235 | | // appending "." does nothing |
236 | 173k | if (!strcmp(fileName, ".")) |
237 | 0 | return path; |
238 | | |
239 | | // appending ".." goes up one directory |
240 | 173k | if (!strcmp(fileName, "..")) { |
241 | 0 | for (i = path->getLength() - 2; i >= 0; --i) { |
242 | 0 | if (path->getChar(i) == '/') |
243 | 0 | break; |
244 | 0 | } |
245 | 0 | if (i <= 0) { |
246 | 0 | if (path->getChar(0) == '/') { |
247 | 0 | path->del(1, path->getLength() - 1); |
248 | 0 | } else { |
249 | 0 | path->clear(); |
250 | 0 | path->append(".."); |
251 | 0 | } |
252 | 0 | } else { |
253 | 0 | path->del(i, path->getLength() - i); |
254 | 0 | } |
255 | 0 | return path; |
256 | 0 | } |
257 | | |
258 | | // otherwise, append "/" and new path component |
259 | 173k | if (path->getLength() > 0 && |
260 | 173k | path->getChar(path->getLength() - 1) != '/') |
261 | 173k | path->append('/'); |
262 | 173k | path->append(fileName); |
263 | 173k | return path; |
264 | 173k | #endif |
265 | 173k | } |
266 | | |
267 | 0 | GString *grabPath(char *fileName) { |
268 | | #ifdef VMS |
269 | | //---------- VMS ---------- |
270 | | char *p; |
271 | | |
272 | | if ((p = strrchr(fileName, ']'))) |
273 | | return new GString(fileName, p + 1 - fileName); |
274 | | if ((p = strrchr(fileName, ':'))) |
275 | | return new GString(fileName, p + 1 - fileName); |
276 | | return new GString(); |
277 | | |
278 | | #elif defined(__EMX__) || defined(_WIN32) |
279 | | //---------- OS/2+EMX and Win32 ---------- |
280 | | char *p; |
281 | | |
282 | | if ((p = strrchr(fileName, '/'))) |
283 | | return new GString(fileName, (int)(p - fileName)); |
284 | | if ((p = strrchr(fileName, '\\'))) |
285 | | return new GString(fileName, (int)(p - fileName)); |
286 | | if ((p = strrchr(fileName, ':'))) |
287 | | return new GString(fileName, (int)(p + 1 - fileName)); |
288 | | return new GString(); |
289 | | |
290 | | #elif defined(ACORN) |
291 | | //---------- RISCOS ---------- |
292 | | char *p; |
293 | | |
294 | | if ((p = strrchr(fileName, '.'))) |
295 | | return new GString(fileName, p - fileName); |
296 | | return new GString(); |
297 | | |
298 | | #else |
299 | | //---------- Unix ---------- |
300 | 0 | char *p; |
301 | |
|
302 | 0 | if ((p = strrchr(fileName, '/'))) |
303 | 0 | return new GString(fileName, (int)(p - fileName)); |
304 | 0 | return new GString(); |
305 | 0 | #endif |
306 | 0 | } |
307 | | |
308 | 0 | GBool isAbsolutePath(char *path) { |
309 | | #ifdef VMS |
310 | | //---------- VMS ---------- |
311 | | return strchr(path, ':') || |
312 | | (path[0] == '[' && path[1] != '.' && path[1] != '-'); |
313 | | |
314 | | #elif defined(__EMX__) || defined(_WIN32) |
315 | | //---------- OS/2+EMX and Win32 ---------- |
316 | | return path[0] == '/' || path[0] == '\\' || path[1] == ':'; |
317 | | |
318 | | #elif defined(ACORN) |
319 | | //---------- RISCOS ---------- |
320 | | return path[0] == '$'; |
321 | | |
322 | | #else |
323 | | //---------- Unix ---------- |
324 | 0 | return path[0] == '/'; |
325 | 0 | #endif |
326 | 0 | } |
327 | | |
328 | 0 | GString *makePathAbsolute(GString *path) { |
329 | | #ifdef VMS |
330 | | //---------- VMS ---------- |
331 | | char buf[PATH_MAX+1]; |
332 | | |
333 | | if (!isAbsolutePath(path->getCString())) { |
334 | | if (getcwd(buf, sizeof(buf))) { |
335 | | path->insert(0, buf); |
336 | | } |
337 | | } |
338 | | return path; |
339 | | |
340 | | #elif defined(_WIN32) |
341 | | //---------- Win32 ---------- |
342 | | char buf[MAX_PATH]; |
343 | | char *fp; |
344 | | |
345 | | buf[0] = '\0'; |
346 | | if (!GetFullPathNameA(path->getCString(), MAX_PATH, buf, &fp)) { |
347 | | path->clear(); |
348 | | return path; |
349 | | } |
350 | | path->clear(); |
351 | | path->append(buf); |
352 | | return path; |
353 | | |
354 | | #elif defined(ACORN) |
355 | | //---------- RISCOS ---------- |
356 | | path->insert(0, '@'); |
357 | | return path; |
358 | | |
359 | | #else |
360 | | //---------- Unix and OS/2+EMX ---------- |
361 | 0 | struct passwd *pw; |
362 | 0 | char buf[PATH_MAX+1]; |
363 | 0 | GString *s; |
364 | 0 | char *p1, *p2; |
365 | 0 | int n; |
366 | |
|
367 | 0 | if (path->getChar(0) == '~') { |
368 | 0 | if (path->getChar(1) == '/' || |
369 | | #ifdef __EMX__ |
370 | | path->getChar(1) == '\\' || |
371 | | #endif |
372 | 0 | path->getLength() == 1) { |
373 | 0 | path->del(0, 1); |
374 | 0 | s = getHomeDir(); |
375 | 0 | path->insert(0, s); |
376 | 0 | delete s; |
377 | 0 | } else { |
378 | 0 | p1 = path->getCString() + 1; |
379 | | #ifdef __EMX__ |
380 | | for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ; |
381 | | #else |
382 | 0 | for (p2 = p1; *p2 && *p2 != '/'; ++p2) ; |
383 | 0 | #endif |
384 | 0 | if ((n = (int)(p2 - p1)) > PATH_MAX) |
385 | 0 | n = PATH_MAX; |
386 | 0 | strncpy(buf, p1, n); |
387 | 0 | buf[n] = '\0'; |
388 | 0 | if ((pw = getpwnam(buf))) { |
389 | 0 | path->del(0, (int)(p2 - p1 + 1)); |
390 | 0 | path->insert(0, pw->pw_dir); |
391 | 0 | } |
392 | 0 | } |
393 | 0 | } else if (!isAbsolutePath(path->getCString())) { |
394 | 0 | if (getcwd(buf, sizeof(buf))) { |
395 | 0 | #ifndef __EMX__ |
396 | 0 | path->insert(0, '/'); |
397 | 0 | #endif |
398 | 0 | path->insert(0, buf); |
399 | 0 | } |
400 | 0 | } |
401 | 0 | return path; |
402 | 0 | #endif |
403 | 0 | } |
404 | | |
405 | 0 | GBool pathIsFile(const char *path) { |
406 | | #ifdef _WIN32 |
407 | | wchar_t wPath[winMaxLongPath + 1]; |
408 | | fileNameToUCS2(path, wPath, winMaxLongPath + 1); |
409 | | DWORD attr = GetFileAttributesW(wPath); |
410 | | return attr != INVALID_FILE_ATTRIBUTES && |
411 | | !(attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); |
412 | | #else |
413 | 0 | struct stat statBuf; |
414 | 0 | return stat(path, &statBuf) == 0 && S_ISREG(statBuf.st_mode); |
415 | 0 | #endif |
416 | 0 | } |
417 | | |
418 | 0 | time_t getModTime(char *fileName) { |
419 | | #ifdef _WIN32 |
420 | | //~ should implement this, but it's (currently) only used in xpdf |
421 | | return 0; |
422 | | #else |
423 | 0 | struct stat statBuf; |
424 | |
|
425 | 0 | if (stat(fileName, &statBuf)) { |
426 | 0 | return 0; |
427 | 0 | } |
428 | 0 | return statBuf.st_mtime; |
429 | 0 | #endif |
430 | 0 | } |
431 | | |
432 | | GBool openTempFile(GString **name, FILE **f, |
433 | 0 | const char *mode, const char *ext) { |
434 | | #if defined(_WIN32) |
435 | | //---------- Win32 ---------- |
436 | | char tempPath[MAX_PATH + 1]; |
437 | | GString *s, *s2; |
438 | | FILE *f2; |
439 | | DWORD n; |
440 | | int t, i; |
441 | | |
442 | | // this has the standard race condition problem, but I haven't found |
443 | | // a better way to generate temp file names with extensions on |
444 | | // Windows |
445 | | n = GetTempPathA(sizeof(tempPath), tempPath); |
446 | | if (n > 0 && n <= sizeof(tempPath)) { |
447 | | s = new GString(tempPath); |
448 | | if (tempPath[n-1] != '\\') { |
449 | | s->append('\\'); |
450 | | } |
451 | | } else { |
452 | | s = new GString(".\\"); |
453 | | } |
454 | | s->appendf("xpdf_{0:d}_{1:d}_", |
455 | | (int)GetCurrentProcessId(), (int)GetCurrentThreadId()); |
456 | | t = (int)time(NULL); |
457 | | for (i = 0; i < 1000; ++i) { |
458 | | s2 = GString::format("{0:t}{1:d}", s, t + i); |
459 | | if (ext) { |
460 | | s2->append(ext); |
461 | | } |
462 | | if (!(f2 = fopen(s2->getCString(), "r"))) { |
463 | | if (!(f2 = fopen(s2->getCString(), mode))) { |
464 | | delete s2; |
465 | | delete s; |
466 | | return gFalse; |
467 | | } |
468 | | *name = s2; |
469 | | *f = f2; |
470 | | delete s; |
471 | | return gTrue; |
472 | | } |
473 | | fclose(f2); |
474 | | delete s2; |
475 | | } |
476 | | delete s; |
477 | | return gFalse; |
478 | | #elif defined(VMS) || defined(__EMX__) || defined(ACORN) |
479 | | //---------- non-Unix ---------- |
480 | | char *s; |
481 | | |
482 | | // There is a security hole here: an attacker can create a symlink |
483 | | // with this file name after the tmpnam call and before the fopen |
484 | | // call. I will happily accept fixes to this function for non-Unix |
485 | | // OSs. |
486 | | if (!(s = tmpnam(NULL))) { |
487 | | return gFalse; |
488 | | } |
489 | | *name = new GString(s); |
490 | | if (ext) { |
491 | | (*name)->append(ext); |
492 | | } |
493 | | if (!(*f = fopen((*name)->getCString(), mode))) { |
494 | | delete (*name); |
495 | | *name = NULL; |
496 | | return gFalse; |
497 | | } |
498 | | return gTrue; |
499 | | #else |
500 | | //---------- Unix ---------- |
501 | 0 | char *s; |
502 | 0 | int fd; |
503 | |
|
504 | 0 | if (ext) { |
505 | 0 | #if HAVE_MKSTEMPS |
506 | 0 | if ((s = getenv("TMPDIR"))) { |
507 | 0 | *name = new GString(s); |
508 | 0 | } else { |
509 | 0 | *name = new GString("/tmp"); |
510 | 0 | } |
511 | 0 | (*name)->append("/XXXXXX")->append(ext); |
512 | 0 | fd = mkstemps((*name)->getCString(), (int)strlen(ext)); |
513 | | #else |
514 | | if (!(s = tmpnam(NULL))) { |
515 | | return gFalse; |
516 | | } |
517 | | *name = new GString(s); |
518 | | (*name)->append(ext); |
519 | | fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); |
520 | | #endif |
521 | 0 | } else { |
522 | 0 | #if HAVE_MKSTEMP |
523 | 0 | if ((s = getenv("TMPDIR"))) { |
524 | 0 | *name = new GString(s); |
525 | 0 | } else { |
526 | 0 | *name = new GString("/tmp"); |
527 | 0 | } |
528 | 0 | (*name)->append("/XXXXXX"); |
529 | 0 | fd = mkstemp((*name)->getCString()); |
530 | | #else // HAVE_MKSTEMP |
531 | | if (!(s = tmpnam(NULL))) { |
532 | | return gFalse; |
533 | | } |
534 | | *name = new GString(s); |
535 | | fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); |
536 | | #endif // HAVE_MKSTEMP |
537 | 0 | } |
538 | 0 | if (fd < 0 || !(*f = fdopen(fd, mode))) { |
539 | 0 | delete *name; |
540 | 0 | *name = NULL; |
541 | 0 | return gFalse; |
542 | 0 | } |
543 | 0 | return gTrue; |
544 | 0 | #endif |
545 | 0 | } |
546 | | |
547 | 0 | GBool createDir(char *path, int mode) { |
548 | | #ifdef _WIN32 |
549 | | return !_mkdir(path); |
550 | | #else |
551 | 0 | return !mkdir(path, mode); |
552 | 0 | #endif |
553 | 0 | } |
554 | | |
555 | 0 | GBool executeCommand(char *cmd) { |
556 | | #ifdef VMS |
557 | | return system(cmd) ? gTrue : gFalse; |
558 | | #else |
559 | 0 | return system(cmd) ? gFalse : gTrue; |
560 | 0 | #endif |
561 | 0 | } |
562 | | |
563 | | #ifdef _WIN32 |
564 | | GString *fileNameToUTF8(char *path) { |
565 | | GString *s; |
566 | | char *p; |
567 | | |
568 | | s = new GString(); |
569 | | for (p = path; *p; ++p) { |
570 | | if (*p & 0x80) { |
571 | | s->append((char)(0xc0 | ((*p >> 6) & 0x03))); |
572 | | s->append((char)(0x80 | (*p & 0x3f))); |
573 | | } else { |
574 | | s->append(*p); |
575 | | } |
576 | | } |
577 | | return s; |
578 | | } |
579 | | |
580 | | GString *fileNameToUTF8(wchar_t *path) { |
581 | | GString *s; |
582 | | wchar_t *p; |
583 | | |
584 | | s = new GString(); |
585 | | for (p = path; *p; ++p) { |
586 | | if (*p < 0x80) { |
587 | | s->append((char)*p); |
588 | | } else if (*p < 0x800) { |
589 | | s->append((char)(0xc0 | ((*p >> 6) & 0x1f))); |
590 | | s->append((char)(0x80 | (*p & 0x3f))); |
591 | | } else { |
592 | | s->append((char)(0xe0 | ((*p >> 12) & 0x0f))); |
593 | | s->append((char)(0x80 | ((*p >> 6) & 0x3f))); |
594 | | s->append((char)(0x80 | (*p & 0x3f))); |
595 | | } |
596 | | } |
597 | | return s; |
598 | | } |
599 | | |
600 | | wchar_t *fileNameToUCS2(const char *path, wchar_t *out, size_t outSize) { |
601 | | const char *p; |
602 | | size_t i; |
603 | | |
604 | | for (p = path, i = 0; *p && i < outSize - 1; ++i) { |
605 | | if ((p[0] & 0xe0) == 0xc0 && |
606 | | p[1] && (p[1] & 0xc0) == 0x80) { |
607 | | out[i] = (wchar_t)(((p[0] & 0x1f) << 6) | |
608 | | (p[1] & 0x3f)); |
609 | | p += 2; |
610 | | } else if ((p[0] & 0xf0) == 0xe0 && |
611 | | (p[1] & 0xc0) == 0x80 && |
612 | | (p[2] & 0xc0) == 0x80) { |
613 | | out[i] = (wchar_t)(((p[0] & 0x0f) << 12) | |
614 | | ((p[1] & 0x3f) << 6) | |
615 | | (p[2] & 0x3f)); |
616 | | p += 3; |
617 | | } else { |
618 | | out[i] = (wchar_t)(p[0] & 0xff); |
619 | | p += 1; |
620 | | } |
621 | | } |
622 | | out[i] = (wchar_t)0; |
623 | | return out; |
624 | | } |
625 | | #endif |
626 | | |
627 | 0 | FILE *openFile(const char *path, const char *mode) { |
628 | | #if defined(_WIN32) |
629 | | wchar_t wPath[winMaxLongPath + 1]; |
630 | | wchar_t wMode[8]; |
631 | | int i; |
632 | | |
633 | | fileNameToUCS2(path, wPath, winMaxLongPath + 1); |
634 | | for (i = 0; mode[i] && i < sizeof(wMode)/sizeof(wchar_t) - 1; ++i) { |
635 | | wMode[i] = (wchar_t)(mode[i] & 0xff); |
636 | | } |
637 | | wMode[i] = (wchar_t)0; |
638 | | readWindowsShortcut(wPath, winMaxLongPath + 1); |
639 | | return _wfopen(wPath, wMode); |
640 | | #elif defined(VMS) |
641 | | return fopen(path, mode, "ctx=stm"); |
642 | | #else |
643 | 0 | return fopen(path, mode); |
644 | 0 | #endif |
645 | 0 | } |
646 | | |
647 | | #ifdef _WIN32 |
648 | | void readWindowsShortcut(wchar_t *wPath, size_t wPathSize) { |
649 | | size_t n = wcslen(wPath); |
650 | | if (n < 4 || wcscmp(wPath + n - 4, L".lnk")) { |
651 | | return; |
652 | | } |
653 | | IShellLinkW *shellLink; |
654 | | HRESULT hres; |
655 | | hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, |
656 | | IID_IShellLinkW, (LPVOID *)&shellLink); |
657 | | bool needCoUninit = false; |
658 | | if (hres == CO_E_NOTINITIALIZED) { |
659 | | CoInitialize(NULL); |
660 | | needCoUninit = true; |
661 | | hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, |
662 | | IID_IShellLinkW, (LPVOID *)&shellLink); |
663 | | } |
664 | | if (FAILED(hres)) { |
665 | | return; |
666 | | } |
667 | | IPersistFile *persistFile; |
668 | | hres = shellLink->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile); |
669 | | if (FAILED(hres)) { |
670 | | return; |
671 | | } |
672 | | hres = persistFile->Load(wPath, STGM_READ); |
673 | | if (FAILED(hres)) { |
674 | | fprintf(stderr, "IPersistFile.Load failed: 0x%08x\n", hres); |
675 | | exit(1); |
676 | | } |
677 | | wchar_t target[winMaxLongPath + 1]; |
678 | | hres = shellLink->GetPath(target, winMaxLongPath + 1, NULL, 0); |
679 | | if (FAILED(hres)) { |
680 | | return; |
681 | | } |
682 | | shellLink->Release(); |
683 | | if (needCoUninit) { |
684 | | CoUninitialize(); |
685 | | } |
686 | | if (wcslen(target) > wPathSize - 1) { |
687 | | return; |
688 | | } |
689 | | wcscpy(wPath, target); |
690 | | } |
691 | | #endif |
692 | | |
693 | 0 | int makeDir(const char *path, int mode) { |
694 | | #ifdef _WIN32 |
695 | | wchar_t wPath[winMaxLongPath + 1]; |
696 | | return _wmkdir(fileNameToUCS2(path, wPath, winMaxLongPath + 1)); |
697 | | #else |
698 | 0 | return mkdir(path, (mode_t)mode); |
699 | 0 | #endif |
700 | 0 | } |
701 | | |
702 | 0 | char *getLine(char *buf, int size, FILE *f) { |
703 | 0 | int c, i; |
704 | |
|
705 | 0 | i = 0; |
706 | 0 | while (i < size - 1) { |
707 | 0 | if ((c = fgetc(f)) == EOF) { |
708 | 0 | break; |
709 | 0 | } |
710 | 0 | buf[i++] = (char)c; |
711 | 0 | if (c == '\x0a') { |
712 | 0 | break; |
713 | 0 | } |
714 | 0 | if (c == '\x0d') { |
715 | 0 | c = fgetc(f); |
716 | 0 | if (c == '\x0a' && i < size - 1) { |
717 | 0 | buf[i++] = (char)c; |
718 | 0 | } else if (c != EOF) { |
719 | 0 | ungetc(c, f); |
720 | 0 | } |
721 | 0 | break; |
722 | 0 | } |
723 | 0 | } |
724 | 0 | buf[i] = '\0'; |
725 | 0 | if (i == 0) { |
726 | 0 | return NULL; |
727 | 0 | } |
728 | 0 | return buf; |
729 | 0 | } |
730 | | |
731 | 0 | int gfseek(FILE *f, GFileOffset offset, int whence) { |
732 | 0 | #if HAVE_FSEEKO |
733 | 0 | return fseeko(f, offset, whence); |
734 | | #elif HAVE_FSEEK64 |
735 | | return fseek64(f, offset, whence); |
736 | | #elif HAVE_FSEEKI64 |
737 | | return _fseeki64(f, offset, whence); |
738 | | #else |
739 | | return fseek(f, offset, whence); |
740 | | #endif |
741 | 0 | } |
742 | | |
743 | 0 | GFileOffset gftell(FILE *f) { |
744 | 0 | #if HAVE_FSEEKO |
745 | 0 | return ftello(f); |
746 | | #elif HAVE_FSEEK64 |
747 | | return ftell64(f); |
748 | | #elif HAVE_FSEEKI64 |
749 | | return _ftelli64(f); |
750 | | #else |
751 | | return ftell(f); |
752 | | #endif |
753 | 0 | } |
754 | | |
755 | 0 | void fixCommandLine(int *argc, char **argv[]) { |
756 | | #ifdef _WIN32 |
757 | | int argcw; |
758 | | wchar_t **argvw; |
759 | | GString *arg; |
760 | | int i; |
761 | | |
762 | | argvw = CommandLineToArgvW(GetCommandLineW(), &argcw); |
763 | | if (!argvw || argcw < 0) { |
764 | | return; |
765 | | } |
766 | | |
767 | | *argc = argcw; |
768 | | |
769 | | *argv = (char **)gmallocn(argcw + 1, sizeof(char *)); |
770 | | for (i = 0; i < argcw; ++i) { |
771 | | arg = fileNameToUTF8(argvw[i]); |
772 | | (*argv)[i] = copyString(arg->getCString()); |
773 | | delete arg; |
774 | | } |
775 | | (*argv)[argcw] = NULL; |
776 | | |
777 | | LocalFree(argvw); |
778 | | #endif |
779 | 0 | } |