1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 /* prevent gp.h from defining fopen */
17 #define fopen fopen
18 
19 #include "windows_.h"
20 #include "stdio_.h"
21 #include "gp.h"
22 #include "memory_.h"
23 #include "stat_.h"
24 
25 #include "gp_mswin.h"
26 
27 /* Open a file with the given name, as a stream of uninterpreted bytes. */
28 FILE *
gp_fopen_impl(gs_memory_t * mem,const char * fname,const char * mode)29 gp_fopen_impl(gs_memory_t *mem, const char *fname, const char *mode)
30 {
31     int len = utf8_to_wchar(NULL, fname);
32     wchar_t *uni;
33     wchar_t wmode[4];
34     FILE *file;
35 
36     if (len <= 0)
37         return NULL;
38 
39     uni = (wchar_t *)gs_alloc_bytes(mem, len*sizeof(wchar_t), "gp_fopen_impl");
40     if (uni == NULL)
41         return NULL;
42     utf8_to_wchar(uni, fname);
43     utf8_to_wchar(wmode, mode);
44     file = _wfopen(uni, wmode);
45     gs_free_object(mem, uni, "gs_fopen_impl");
46 
47     return file;
48 }
49 
50 /* Create a second open FILE on the basis of a given one */
gp_fdup_impl(FILE * f,const char * mode)51 FILE *gp_fdup_impl(FILE *f, const char *mode)
52 {
53     int fd = fileno(f);
54     if (fd < 0)
55         return NULL;
56 
57     fd = dup(fd);
58     if (fd < 0)
59         return NULL;
60 
61     return fdopen(fd, mode);
62 }
63 
64 /* Read from a specified offset within a FILE into a buffer */
gp_pread_impl(char * buf,size_t count,gs_offset_t offset,FILE * f)65 int gp_pread_impl(char *buf, size_t count, gs_offset_t offset, FILE *f)
66 {
67     OVERLAPPED overlapped;
68     DWORD ret;
69     HANDLE hnd = (HANDLE)_get_osfhandle(fileno(f));
70 
71     if (hnd == INVALID_HANDLE_VALUE)
72         return -1;
73 
74     memset(&overlapped, 0, sizeof(OVERLAPPED));
75     overlapped.Offset = (DWORD)offset;
76     overlapped.OffsetHigh = (DWORD)(offset >> 32);
77 
78     if (!ReadFile((HANDLE)hnd, buf, count, &ret, &overlapped))
79         return -1;
80 
81     return ret;
82 }
83 
84 /* Write to a specified offset within a FILE from a buffer */
gp_pwrite_impl(const char * buf,size_t count,gs_offset_t offset,FILE * f)85 int gp_pwrite_impl(const char *buf, size_t count, gs_offset_t offset, FILE *f)
86 {
87     OVERLAPPED overlapped;
88     DWORD ret;
89     HANDLE hnd = (HANDLE)_get_osfhandle(fileno(f));
90 
91     if (hnd == INVALID_HANDLE_VALUE)
92         return -1;
93 
94     memset(&overlapped, 0, sizeof(OVERLAPPED));
95     overlapped.Offset = (DWORD)offset;
96     overlapped.OffsetHigh = (DWORD)(offset >> 32);
97 
98     if (!WriteFile((HANDLE)hnd, buf, count, &ret, &overlapped))
99         return -1;
100 
101     return ret;
102 }
103 
104 /* --------- 64 bit file access ----------- */
105 /* MSVC versions before 8 doen't provide big files.
106    MSVC 8 doesn't distinguish big and small files,
107    but provide special positioning functions
108    to access data behind 4GB.
109    Currently we support 64 bits file access with MSVC only.
110  */
111 
112 #if defined(_MSC_VER) && _MSC_VER < 1400
113     int64_t _ftelli64( FILE *);
114     int _fseeki64( FILE *, int64_t, int);
115 #endif
116 
gp_ftell_impl(FILE * strm)117 gs_offset_t gp_ftell_impl(FILE *strm)
118 {
119 #if !defined(_MSC_VER)
120     return ftell(strm);
121 #elif _MSC_VER < 1200
122     return ftell(strm);
123 #else
124     return (int64_t)_ftelli64(strm);
125 #endif
126 }
127 
gp_fseek_impl(FILE * strm,gs_offset_t offset,int origin)128 int gp_fseek_impl(FILE *strm, gs_offset_t offset, int origin)
129 {
130 #if !defined(_MSC_VER)
131     return fseek(strm, offset, origin);
132 #elif _MSC_VER < 1200
133     long offset1 = (long)offset;
134 
135     if (offset != offset1)
136         return -1;
137     return fseek(strm, offset1, origin);
138 #else
139     return _fseeki64(strm, offset, origin);
140 #endif
141 }
142 
gp_fseekable_impl(FILE * f)143 bool gp_fseekable_impl(FILE *f)
144 {
145     struct __stat64 s;
146     int fno;
147 
148     fno = fileno(f);
149     if (fno < 0)
150         return(false);
151 
152     if (_fstat64(fno, &s) < 0)
153         return(false);
154 
155     return((bool)S_ISREG(s.st_mode));
156 }
157