/src/xpdf-4.05/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 | 11.5k | 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 | 11.5k | char *s; |
83 | 11.5k | struct passwd *pw; |
84 | 11.5k | GString *ret; |
85 | | |
86 | 11.5k | if ((s = getenv("HOME"))) { |
87 | 11.5k | ret = new GString(s); |
88 | 11.5k | } 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 | 11.5k | return ret; |
99 | 11.5k | #endif |
100 | 11.5k | } |
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 | 172k | 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 | 172k | int i; |
234 | | |
235 | | // appending "." does nothing |
236 | 172k | if (!strcmp(fileName, ".")) |
237 | 0 | return path; |
238 | | |
239 | | // appending ".." goes up one directory |
240 | 172k | 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 | 172k | if (path->getLength() > 0 && |
260 | 172k | path->getChar(path->getLength() - 1) != '/') |
261 | 172k | path->append('/'); |
262 | 172k | path->append(fileName); |
263 | 172k | return path; |
264 | 172k | #endif |
265 | 172k | } |
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 | GBool pathIsDir(const char *path) { |
419 | | #ifdef _WIN32 |
420 | | wchar_t wPath[winMaxLongPath + 1]; |
421 | | fileNameToUCS2(path, wPath, winMaxLongPath + 1); |
422 | | DWORD attr = GetFileAttributesW(wPath); |
423 | | return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); |
424 | | #else |
425 | 0 | struct stat statBuf; |
426 | 0 | return stat(path, &statBuf) == 0 && S_ISDIR(statBuf.st_mode); |
427 | 0 | #endif |
428 | 0 | } |
429 | | |
430 | 0 | time_t getModTime(char *fileName) { |
431 | | #ifdef _WIN32 |
432 | | //~ should implement this, but it's (currently) only used in xpdf |
433 | | return 0; |
434 | | #else |
435 | 0 | struct stat statBuf; |
436 | |
|
437 | 0 | if (stat(fileName, &statBuf)) { |
438 | 0 | return 0; |
439 | 0 | } |
440 | 0 | return statBuf.st_mtime; |
441 | 0 | #endif |
442 | 0 | } |
443 | | |
444 | | GBool openTempFile(GString **name, FILE **f, |
445 | 0 | const char *mode, const char *ext) { |
446 | | #if defined(_WIN32) |
447 | | //---------- Win32 ---------- |
448 | | char tempPath[MAX_PATH + 1]; |
449 | | GString *s, *s2; |
450 | | FILE *f2; |
451 | | DWORD n; |
452 | | int t, i; |
453 | | |
454 | | // this has the standard race condition problem, but I haven't found |
455 | | // a better way to generate temp file names with extensions on |
456 | | // Windows |
457 | | n = GetTempPathA(sizeof(tempPath), tempPath); |
458 | | if (n > 0 && n <= sizeof(tempPath)) { |
459 | | s = new GString(tempPath); |
460 | | if (tempPath[n-1] != '\\') { |
461 | | s->append('\\'); |
462 | | } |
463 | | } else { |
464 | | s = new GString(".\\"); |
465 | | } |
466 | | s->appendf("xpdf_{0:d}_{1:d}_", |
467 | | (int)GetCurrentProcessId(), (int)GetCurrentThreadId()); |
468 | | t = (int)time(NULL); |
469 | | for (i = 0; i < 1000; ++i) { |
470 | | s2 = GString::format("{0:t}{1:d}", s, t + i); |
471 | | if (ext) { |
472 | | s2->append(ext); |
473 | | } |
474 | | if (!(f2 = fopen(s2->getCString(), "r"))) { |
475 | | if (!(f2 = fopen(s2->getCString(), mode))) { |
476 | | delete s2; |
477 | | delete s; |
478 | | return gFalse; |
479 | | } |
480 | | *name = s2; |
481 | | *f = f2; |
482 | | delete s; |
483 | | return gTrue; |
484 | | } |
485 | | fclose(f2); |
486 | | delete s2; |
487 | | } |
488 | | delete s; |
489 | | return gFalse; |
490 | | #elif defined(VMS) || defined(__EMX__) || defined(ACORN) |
491 | | //---------- non-Unix ---------- |
492 | | char *s; |
493 | | |
494 | | // There is a security hole here: an attacker can create a symlink |
495 | | // with this file name after the tmpnam call and before the fopen |
496 | | // call. I will happily accept fixes to this function for non-Unix |
497 | | // OSs. |
498 | | if (!(s = tmpnam(NULL))) { |
499 | | return gFalse; |
500 | | } |
501 | | *name = new GString(s); |
502 | | if (ext) { |
503 | | (*name)->append(ext); |
504 | | } |
505 | | if (!(*f = fopen((*name)->getCString(), mode))) { |
506 | | delete (*name); |
507 | | *name = NULL; |
508 | | return gFalse; |
509 | | } |
510 | | return gTrue; |
511 | | #else |
512 | | //---------- Unix ---------- |
513 | 0 | char *s; |
514 | 0 | int fd; |
515 | |
|
516 | 0 | if (ext) { |
517 | 0 | #if HAVE_MKSTEMPS |
518 | 0 | if ((s = getenv("TMPDIR"))) { |
519 | 0 | *name = new GString(s); |
520 | 0 | } else { |
521 | 0 | *name = new GString("/tmp"); |
522 | 0 | } |
523 | 0 | (*name)->append("/XXXXXX")->append(ext); |
524 | 0 | fd = mkstemps((*name)->getCString(), (int)strlen(ext)); |
525 | | #else |
526 | | if (!(s = tmpnam(NULL))) { |
527 | | return gFalse; |
528 | | } |
529 | | *name = new GString(s); |
530 | | (*name)->append(ext); |
531 | | fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); |
532 | | #endif |
533 | 0 | } else { |
534 | 0 | #if HAVE_MKSTEMP |
535 | 0 | if ((s = getenv("TMPDIR"))) { |
536 | 0 | *name = new GString(s); |
537 | 0 | } else { |
538 | 0 | *name = new GString("/tmp"); |
539 | 0 | } |
540 | 0 | (*name)->append("/XXXXXX"); |
541 | 0 | fd = mkstemp((*name)->getCString()); |
542 | | #else // HAVE_MKSTEMP |
543 | | if (!(s = tmpnam(NULL))) { |
544 | | return gFalse; |
545 | | } |
546 | | *name = new GString(s); |
547 | | fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); |
548 | | #endif // HAVE_MKSTEMP |
549 | 0 | } |
550 | 0 | if (fd < 0 || !(*f = fdopen(fd, mode))) { |
551 | 0 | delete *name; |
552 | 0 | *name = NULL; |
553 | 0 | return gFalse; |
554 | 0 | } |
555 | 0 | return gTrue; |
556 | 0 | #endif |
557 | 0 | } |
558 | | |
559 | 0 | GBool createDir(char *path, int mode) { |
560 | | #ifdef _WIN32 |
561 | | return !_mkdir(path); |
562 | | #else |
563 | 0 | return !mkdir(path, mode); |
564 | 0 | #endif |
565 | 0 | } |
566 | | |
567 | 0 | GBool executeCommand(char *cmd) { |
568 | | #ifdef VMS |
569 | | return system(cmd) ? gTrue : gFalse; |
570 | | #else |
571 | 0 | return system(cmd) ? gFalse : gTrue; |
572 | 0 | #endif |
573 | 0 | } |
574 | | |
575 | | #ifdef _WIN32 |
576 | | GString *fileNameToUTF8(char *path) { |
577 | | GString *s; |
578 | | char *p; |
579 | | |
580 | | s = new GString(); |
581 | | for (p = path; *p; ++p) { |
582 | | if (*p & 0x80) { |
583 | | s->append((char)(0xc0 | ((*p >> 6) & 0x03))); |
584 | | s->append((char)(0x80 | (*p & 0x3f))); |
585 | | } else { |
586 | | s->append(*p); |
587 | | } |
588 | | } |
589 | | return s; |
590 | | } |
591 | | |
592 | | GString *fileNameToUTF8(wchar_t *path) { |
593 | | GString *s; |
594 | | wchar_t *p; |
595 | | |
596 | | s = new GString(); |
597 | | for (p = path; *p; ++p) { |
598 | | if (*p < 0x80) { |
599 | | s->append((char)*p); |
600 | | } else if (*p < 0x800) { |
601 | | s->append((char)(0xc0 | ((*p >> 6) & 0x1f))); |
602 | | s->append((char)(0x80 | (*p & 0x3f))); |
603 | | } else { |
604 | | s->append((char)(0xe0 | ((*p >> 12) & 0x0f))); |
605 | | s->append((char)(0x80 | ((*p >> 6) & 0x3f))); |
606 | | s->append((char)(0x80 | (*p & 0x3f))); |
607 | | } |
608 | | } |
609 | | return s; |
610 | | } |
611 | | |
612 | | GString *fileNameMultiByteToUTF8(char *path) { |
613 | | wchar_t fileNameW[winMaxLongPath + 1]; |
614 | | if (MultiByteToWideChar(CP_OEMCP, 0, path, -1, |
615 | | fileNameW, sizeof(fileNameW) / sizeof(wchar_t))) { |
616 | | return fileNameToUTF8(fileNameW); |
617 | | } else { |
618 | | // shouldn't happen, but just in case... |
619 | | return new GString(path); |
620 | | } |
621 | | } |
622 | | |
623 | | wchar_t *fileNameToUCS2(const char *path, wchar_t *out, size_t outSize) { |
624 | | const char *p; |
625 | | size_t i; |
626 | | |
627 | | for (p = path, i = 0; *p && i < outSize - 1; ++i) { |
628 | | if ((p[0] & 0xe0) == 0xc0 && |
629 | | p[1] && (p[1] & 0xc0) == 0x80) { |
630 | | out[i] = (wchar_t)(((p[0] & 0x1f) << 6) | |
631 | | (p[1] & 0x3f)); |
632 | | p += 2; |
633 | | } else if ((p[0] & 0xf0) == 0xe0 && |
634 | | (p[1] & 0xc0) == 0x80 && |
635 | | (p[2] & 0xc0) == 0x80) { |
636 | | out[i] = (wchar_t)(((p[0] & 0x0f) << 12) | |
637 | | ((p[1] & 0x3f) << 6) | |
638 | | (p[2] & 0x3f)); |
639 | | p += 3; |
640 | | } else { |
641 | | out[i] = (wchar_t)(p[0] & 0xff); |
642 | | p += 1; |
643 | | } |
644 | | } |
645 | | out[i] = (wchar_t)0; |
646 | | return out; |
647 | | } |
648 | | #endif |
649 | | |
650 | 0 | FILE *openFile(const char *path, const char *mode) { |
651 | | #if defined(_WIN32) |
652 | | wchar_t wPath[winMaxLongPath + 1]; |
653 | | wchar_t wMode[8]; |
654 | | int i; |
655 | | |
656 | | fileNameToUCS2(path, wPath, winMaxLongPath + 1); |
657 | | for (i = 0; mode[i] && i < sizeof(wMode)/sizeof(wchar_t) - 1; ++i) { |
658 | | wMode[i] = (wchar_t)(mode[i] & 0xff); |
659 | | } |
660 | | wMode[i] = (wchar_t)0; |
661 | | readWindowsShortcut(wPath, winMaxLongPath + 1); |
662 | | return _wfopen(wPath, wMode); |
663 | | #elif defined(VMS) |
664 | | return fopen(path, mode, "ctx=stm"); |
665 | | #else |
666 | 0 | return fopen(path, mode); |
667 | 0 | #endif |
668 | 0 | } |
669 | | |
670 | | #ifdef _WIN32 |
671 | | void readWindowsShortcut(wchar_t *wPath, size_t wPathSize) { |
672 | | size_t n = wcslen(wPath); |
673 | | if (n < 4 || wcscmp(wPath + n - 4, L".lnk")) { |
674 | | return; |
675 | | } |
676 | | IShellLinkW *shellLink; |
677 | | HRESULT hres; |
678 | | hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, |
679 | | IID_IShellLinkW, (LPVOID *)&shellLink); |
680 | | bool needCoUninit = false; |
681 | | if (hres == CO_E_NOTINITIALIZED) { |
682 | | CoInitialize(NULL); |
683 | | needCoUninit = true; |
684 | | hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, |
685 | | IID_IShellLinkW, (LPVOID *)&shellLink); |
686 | | } |
687 | | if (FAILED(hres)) { |
688 | | return; |
689 | | } |
690 | | IPersistFile *persistFile; |
691 | | hres = shellLink->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile); |
692 | | if (FAILED(hres)) { |
693 | | return; |
694 | | } |
695 | | hres = persistFile->Load(wPath, STGM_READ); |
696 | | if (FAILED(hres)) { |
697 | | fprintf(stderr, "IPersistFile.Load failed: 0x%08lx\n", hres); |
698 | | exit(1); |
699 | | } |
700 | | wchar_t target[winMaxLongPath + 1]; |
701 | | hres = shellLink->GetPath(target, winMaxLongPath + 1, NULL, 0); |
702 | | if (FAILED(hres)) { |
703 | | return; |
704 | | } |
705 | | shellLink->Release(); |
706 | | if (needCoUninit) { |
707 | | CoUninitialize(); |
708 | | } |
709 | | if (wcslen(target) > wPathSize - 1) { |
710 | | return; |
711 | | } |
712 | | wcscpy(wPath, target); |
713 | | } |
714 | | #endif |
715 | | |
716 | 0 | int makeDir(const char *path, int mode) { |
717 | | #ifdef _WIN32 |
718 | | wchar_t wPath[winMaxLongPath + 1]; |
719 | | return _wmkdir(fileNameToUCS2(path, wPath, winMaxLongPath + 1)); |
720 | | #else |
721 | 0 | return mkdir(path, (mode_t)mode); |
722 | 0 | #endif |
723 | 0 | } |
724 | | |
725 | 0 | char *getLine(char *buf, int size, FILE *f) { |
726 | 0 | int c, i; |
727 | |
|
728 | 0 | i = 0; |
729 | 0 | while (i < size - 1) { |
730 | 0 | if ((c = fgetc(f)) == EOF) { |
731 | 0 | break; |
732 | 0 | } |
733 | 0 | buf[i++] = (char)c; |
734 | 0 | if (c == '\x0a') { |
735 | 0 | break; |
736 | 0 | } |
737 | 0 | if (c == '\x0d') { |
738 | 0 | c = fgetc(f); |
739 | 0 | if (c == '\x0a' && i < size - 1) { |
740 | 0 | buf[i++] = (char)c; |
741 | 0 | } else if (c != EOF) { |
742 | 0 | ungetc(c, f); |
743 | 0 | } |
744 | 0 | break; |
745 | 0 | } |
746 | 0 | } |
747 | 0 | buf[i] = '\0'; |
748 | 0 | if (i == 0) { |
749 | 0 | return NULL; |
750 | 0 | } |
751 | 0 | return buf; |
752 | 0 | } |
753 | | |
754 | 0 | int gfseek(FILE *f, GFileOffset offset, int whence) { |
755 | 0 | #if HAVE_FSEEKO |
756 | 0 | return fseeko(f, offset, whence); |
757 | | #elif HAVE_FSEEK64 |
758 | | return fseek64(f, offset, whence); |
759 | | #elif HAVE_FSEEKI64 |
760 | | return _fseeki64(f, offset, whence); |
761 | | #else |
762 | | return fseek(f, offset, whence); |
763 | | #endif |
764 | 0 | } |
765 | | |
766 | 0 | GFileOffset gftell(FILE *f) { |
767 | 0 | #if HAVE_FSEEKO |
768 | 0 | return ftello(f); |
769 | | #elif HAVE_FSEEK64 |
770 | | return ftell64(f); |
771 | | #elif HAVE_FSEEKI64 |
772 | | return _ftelli64(f); |
773 | | #else |
774 | | return ftell(f); |
775 | | #endif |
776 | 0 | } |
777 | | |
778 | 0 | void fixCommandLine(int *argc, char **argv[]) { |
779 | | #ifdef _WIN32 |
780 | | int argcw; |
781 | | wchar_t **argvw; |
782 | | GString *arg; |
783 | | int i; |
784 | | |
785 | | argvw = CommandLineToArgvW(GetCommandLineW(), &argcw); |
786 | | if (!argvw || argcw < 0) { |
787 | | return; |
788 | | } |
789 | | |
790 | | *argc = argcw; |
791 | | |
792 | | *argv = (char **)gmallocn(argcw + 1, sizeof(char *)); |
793 | | for (i = 0; i < argcw; ++i) { |
794 | | arg = fileNameToUTF8(argvw[i]); |
795 | | (*argv)[i] = copyString(arg->getCString()); |
796 | | delete arg; |
797 | | } |
798 | | (*argv)[argcw] = NULL; |
799 | | |
800 | | LocalFree(argvw); |
801 | | #endif |
802 | 0 | } |