/src/perfetto/buildtools/lzma/C/7zFile.c
Line | Count | Source |
1 | | /* 7zFile.c -- File IO |
2 | | 2017-04-03 : Igor Pavlov : Public domain */ |
3 | | |
4 | | #include "Precomp.h" |
5 | | |
6 | | #include "7zFile.h" |
7 | | |
8 | | #ifndef USE_WINDOWS_FILE |
9 | | |
10 | | #ifndef UNDER_CE |
11 | | #include <errno.h> |
12 | | #endif |
13 | | |
14 | | #else |
15 | | |
16 | | /* |
17 | | ReadFile and WriteFile functions in Windows have BUG: |
18 | | If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) |
19 | | from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES |
20 | | (Insufficient system resources exist to complete the requested service). |
21 | | Probably in some version of Windows there are problems with other sizes: |
22 | | for 32 MB (maybe also for 16 MB). |
23 | | And message can be "Network connection was lost" |
24 | | */ |
25 | | |
26 | | #define kChunkSizeMax (1 << 22) |
27 | | |
28 | | #endif |
29 | | |
30 | | void File_Construct(CSzFile *p) |
31 | 0 | { |
32 | | #ifdef USE_WINDOWS_FILE |
33 | | p->handle = INVALID_HANDLE_VALUE; |
34 | | #else |
35 | 0 | p->file = NULL; |
36 | 0 | #endif |
37 | 0 | } |
38 | | |
39 | | #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) |
40 | | static WRes File_Open(CSzFile *p, const char *name, int writeMode) |
41 | 0 | { |
42 | | #ifdef USE_WINDOWS_FILE |
43 | | p->handle = CreateFileA(name, |
44 | | writeMode ? GENERIC_WRITE : GENERIC_READ, |
45 | | FILE_SHARE_READ, NULL, |
46 | | writeMode ? CREATE_ALWAYS : OPEN_EXISTING, |
47 | | FILE_ATTRIBUTE_NORMAL, NULL); |
48 | | return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); |
49 | | #else |
50 | 0 | p->file = fopen(name, writeMode ? "wb+" : "rb"); |
51 | 0 | return (p->file != 0) ? 0 : |
52 | | #ifdef UNDER_CE |
53 | | 2; /* ENOENT */ |
54 | | #else |
55 | 0 | errno; |
56 | 0 | #endif |
57 | 0 | #endif |
58 | 0 | } |
59 | | |
60 | 0 | WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } |
61 | 0 | WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); } |
62 | | #endif |
63 | | |
64 | | #ifdef USE_WINDOWS_FILE |
65 | | static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) |
66 | | { |
67 | | p->handle = CreateFileW(name, |
68 | | writeMode ? GENERIC_WRITE : GENERIC_READ, |
69 | | FILE_SHARE_READ, NULL, |
70 | | writeMode ? CREATE_ALWAYS : OPEN_EXISTING, |
71 | | FILE_ATTRIBUTE_NORMAL, NULL); |
72 | | return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); |
73 | | } |
74 | | WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } |
75 | | WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } |
76 | | #endif |
77 | | |
78 | | WRes File_Close(CSzFile *p) |
79 | 0 | { |
80 | | #ifdef USE_WINDOWS_FILE |
81 | | if (p->handle != INVALID_HANDLE_VALUE) |
82 | | { |
83 | | if (!CloseHandle(p->handle)) |
84 | | return GetLastError(); |
85 | | p->handle = INVALID_HANDLE_VALUE; |
86 | | } |
87 | | #else |
88 | 0 | if (p->file != NULL) |
89 | 0 | { |
90 | 0 | int res = fclose(p->file); |
91 | 0 | if (res != 0) |
92 | 0 | return res; |
93 | 0 | p->file = NULL; |
94 | 0 | } |
95 | 0 | #endif |
96 | 0 | return 0; |
97 | 0 | } |
98 | | |
99 | | WRes File_Read(CSzFile *p, void *data, size_t *size) |
100 | 0 | { |
101 | 0 | size_t originalSize = *size; |
102 | 0 | if (originalSize == 0) |
103 | 0 | return 0; |
104 | | |
105 | | #ifdef USE_WINDOWS_FILE |
106 | | |
107 | | *size = 0; |
108 | | do |
109 | | { |
110 | | DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; |
111 | | DWORD processed = 0; |
112 | | BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); |
113 | | data = (void *)((Byte *)data + processed); |
114 | | originalSize -= processed; |
115 | | *size += processed; |
116 | | if (!res) |
117 | | return GetLastError(); |
118 | | if (processed == 0) |
119 | | break; |
120 | | } |
121 | | while (originalSize > 0); |
122 | | return 0; |
123 | | |
124 | | #else |
125 | | |
126 | 0 | *size = fread(data, 1, originalSize, p->file); |
127 | 0 | if (*size == originalSize) |
128 | 0 | return 0; |
129 | 0 | return ferror(p->file); |
130 | | |
131 | 0 | #endif |
132 | 0 | } |
133 | | |
134 | | WRes File_Write(CSzFile *p, const void *data, size_t *size) |
135 | 0 | { |
136 | 0 | size_t originalSize = *size; |
137 | 0 | if (originalSize == 0) |
138 | 0 | return 0; |
139 | | |
140 | | #ifdef USE_WINDOWS_FILE |
141 | | |
142 | | *size = 0; |
143 | | do |
144 | | { |
145 | | DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; |
146 | | DWORD processed = 0; |
147 | | BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); |
148 | | data = (void *)((Byte *)data + processed); |
149 | | originalSize -= processed; |
150 | | *size += processed; |
151 | | if (!res) |
152 | | return GetLastError(); |
153 | | if (processed == 0) |
154 | | break; |
155 | | } |
156 | | while (originalSize > 0); |
157 | | return 0; |
158 | | |
159 | | #else |
160 | | |
161 | 0 | *size = fwrite(data, 1, originalSize, p->file); |
162 | 0 | if (*size == originalSize) |
163 | 0 | return 0; |
164 | 0 | return ferror(p->file); |
165 | | |
166 | 0 | #endif |
167 | 0 | } |
168 | | |
169 | | WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) |
170 | 0 | { |
171 | | #ifdef USE_WINDOWS_FILE |
172 | | |
173 | | LARGE_INTEGER value; |
174 | | DWORD moveMethod; |
175 | | value.LowPart = (DWORD)*pos; |
176 | | value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ |
177 | | switch (origin) |
178 | | { |
179 | | case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; |
180 | | case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; |
181 | | case SZ_SEEK_END: moveMethod = FILE_END; break; |
182 | | default: return ERROR_INVALID_PARAMETER; |
183 | | } |
184 | | value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); |
185 | | if (value.LowPart == 0xFFFFFFFF) |
186 | | { |
187 | | WRes res = GetLastError(); |
188 | | if (res != NO_ERROR) |
189 | | return res; |
190 | | } |
191 | | *pos = ((Int64)value.HighPart << 32) | value.LowPart; |
192 | | return 0; |
193 | | |
194 | | #else |
195 | | |
196 | 0 | int moveMethod; |
197 | 0 | int res; |
198 | 0 | switch (origin) |
199 | 0 | { |
200 | 0 | case SZ_SEEK_SET: moveMethod = SEEK_SET; break; |
201 | 0 | case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; |
202 | 0 | case SZ_SEEK_END: moveMethod = SEEK_END; break; |
203 | 0 | default: return 1; |
204 | 0 | } |
205 | 0 | res = fseek(p->file, (long)*pos, moveMethod); |
206 | 0 | *pos = ftell(p->file); |
207 | 0 | return res; |
208 | | |
209 | 0 | #endif |
210 | 0 | } |
211 | | |
212 | | WRes File_GetLength(CSzFile *p, UInt64 *length) |
213 | 0 | { |
214 | | #ifdef USE_WINDOWS_FILE |
215 | | |
216 | | DWORD sizeHigh; |
217 | | DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); |
218 | | if (sizeLow == 0xFFFFFFFF) |
219 | | { |
220 | | DWORD res = GetLastError(); |
221 | | if (res != NO_ERROR) |
222 | | return res; |
223 | | } |
224 | | *length = (((UInt64)sizeHigh) << 32) + sizeLow; |
225 | | return 0; |
226 | | |
227 | | #else |
228 | | |
229 | 0 | long pos = ftell(p->file); |
230 | 0 | int res = fseek(p->file, 0, SEEK_END); |
231 | 0 | *length = ftell(p->file); |
232 | 0 | fseek(p->file, pos, SEEK_SET); |
233 | 0 | return res; |
234 | | |
235 | 0 | #endif |
236 | 0 | } |
237 | | |
238 | | |
239 | | /* ---------- FileSeqInStream ---------- */ |
240 | | |
241 | | static SRes FileSeqInStream_Read(const ISeqInStream *pp, void *buf, size_t *size) |
242 | 0 | { |
243 | 0 | CFileSeqInStream *p = CONTAINER_FROM_VTBL(pp, CFileSeqInStream, vt); |
244 | 0 | return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; |
245 | 0 | } |
246 | | |
247 | | void FileSeqInStream_CreateVTable(CFileSeqInStream *p) |
248 | 0 | { |
249 | 0 | p->vt.Read = FileSeqInStream_Read; |
250 | 0 | } |
251 | | |
252 | | |
253 | | /* ---------- FileInStream ---------- */ |
254 | | |
255 | | static SRes FileInStream_Read(const ISeekInStream *pp, void *buf, size_t *size) |
256 | 0 | { |
257 | 0 | CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); |
258 | 0 | return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; |
259 | 0 | } |
260 | | |
261 | | static SRes FileInStream_Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin) |
262 | 0 | { |
263 | 0 | CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); |
264 | 0 | return File_Seek(&p->file, pos, origin); |
265 | 0 | } |
266 | | |
267 | | void FileInStream_CreateVTable(CFileInStream *p) |
268 | 0 | { |
269 | 0 | p->vt.Read = FileInStream_Read; |
270 | 0 | p->vt.Seek = FileInStream_Seek; |
271 | 0 | } |
272 | | |
273 | | |
274 | | /* ---------- FileOutStream ---------- */ |
275 | | |
276 | | static size_t FileOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) |
277 | 0 | { |
278 | 0 | CFileOutStream *p = CONTAINER_FROM_VTBL(pp, CFileOutStream, vt); |
279 | 0 | File_Write(&p->file, data, &size); |
280 | 0 | return size; |
281 | 0 | } |
282 | | |
283 | | void FileOutStream_CreateVTable(CFileOutStream *p) |
284 | 0 | { |
285 | 0 | p->vt.Write = FileOutStream_Write; |
286 | 0 | } |