Coverage Report

Created: 2023-09-25 06:35

/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
}