]> git.notmuchmail.org Git - vogl/blob - src/voglcore/lzma_7zFile.cpp
Initial vogl checkin
[vogl] / src / voglcore / lzma_7zFile.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 /* 7zFile.c -- File IO
28 2008-11-22 : Igor Pavlov : Public domain */
29 #include "vogl_core.h"
30 #include "lzma_7zFile.h"
31
32 #ifndef USE_WINDOWS_FILE
33
34 #include <errno.h>
35
36 #endif
37
38 #ifdef USE_WINDOWS_FILE
39
40 /*
41    ReadFile and WriteFile functions in Windows have BUG:
42    If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
43    from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
44    (Insufficient system resources exist to complete the requested service).
45    Probably in some version of Windows there are problems with other sizes:
46    for 32 MB (maybe also for 16 MB).
47    And message can be "Network connection was lost"
48 */
49
50 #define kChunkSizeMax (1 << 22)
51
52 #endif
53
54 namespace vogl
55 {
56
57     void File_Construct(CSzFile *p)
58     {
59 #ifdef USE_WINDOWS_FILE
60         p->handle = INVALID_HANDLE_VALUE;
61 #else
62         p->file = NULL;
63 #endif
64     }
65
66     static WRes File_Open(CSzFile *p, const char *name, int writeMode)
67     {
68 #ifdef USE_WINDOWS_FILE
69         p->handle = CreateFileA(name,
70                                 writeMode ? GENERIC_WRITE : GENERIC_READ,
71                                 FILE_SHARE_READ, NULL,
72                                 writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
73                                 FILE_ATTRIBUTE_NORMAL, NULL);
74         return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
75 #else
76         p->file = fopen(name, writeMode ? "wb+" : "rb");
77         return (p->file != 0) ? 0 : errno;
78 #endif
79     }
80
81     WRes InFile_Open(CSzFile *p, const char *name)
82     {
83         return File_Open(p, name, 0);
84     }
85     WRes OutFile_Open(CSzFile *p, const char *name)
86     {
87         return File_Open(p, name, 1);
88     }
89
90     WRes File_Close(CSzFile *p)
91     {
92 #ifdef USE_WINDOWS_FILE
93         if (p->handle != INVALID_HANDLE_VALUE)
94         {
95             if (!CloseHandle(p->handle))
96                 return GetLastError();
97             p->handle = INVALID_HANDLE_VALUE;
98         }
99 #else
100         if (p->file != NULL)
101         {
102             int res = fclose(p->file);
103             if (res != 0)
104                 return res;
105             p->file = NULL;
106         }
107 #endif
108         return 0;
109     }
110
111     WRes File_Read(CSzFile *p, void *data, size_t *size)
112     {
113         size_t originalSize = *size;
114         if (originalSize == 0)
115             return 0;
116
117 #ifdef USE_WINDOWS_FILE
118
119         *size = 0;
120         do
121         {
122             DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
123             DWORD processed = 0;
124             BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
125             data = (void *)((Byte *)data + processed);
126             originalSize -= processed;
127             *size += processed;
128             if (!res)
129                 return GetLastError();
130             if (processed == 0)
131                 break;
132         } while (originalSize > 0);
133         return 0;
134
135 #else
136
137         *size = fread(data, 1, originalSize, p->file);
138         if (*size == originalSize)
139             return 0;
140         return ferror(p->file);
141
142 #endif
143     }
144
145     WRes File_Write(CSzFile *p, const void *data, size_t *size)
146     {
147         size_t originalSize = *size;
148         if (originalSize == 0)
149             return 0;
150
151 #ifdef USE_WINDOWS_FILE
152
153         *size = 0;
154         do
155         {
156             DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
157             DWORD processed = 0;
158             BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
159             data = (void *)((Byte *)data + processed);
160             originalSize -= processed;
161             *size += processed;
162             if (!res)
163                 return GetLastError();
164             if (processed == 0)
165                 break;
166         } while (originalSize > 0);
167         return 0;
168
169 #else
170
171         *size = fwrite(data, 1, originalSize, p->file);
172         if (*size == originalSize)
173             return 0;
174         return ferror(p->file);
175
176 #endif
177     }
178
179     WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
180     {
181 #ifdef USE_WINDOWS_FILE
182
183         LARGE_INTEGER value;
184         DWORD moveMethod;
185         value.LowPart = (DWORD) * pos;
186         value.HighPart = (LONG)((UInt64) * pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
187         switch (origin)
188         {
189             case SZ_SEEK_SET:
190                 moveMethod = FILE_BEGIN;
191                 break;
192             case SZ_SEEK_CUR:
193                 moveMethod = FILE_CURRENT;
194                 break;
195             case SZ_SEEK_END:
196                 moveMethod = FILE_END;
197                 break;
198             default:
199                 return ERROR_INVALID_PARAMETER;
200         }
201         value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);
202         if (value.LowPart == 0xFFFFFFFF)
203         {
204             WRes res = GetLastError();
205             if (res != NO_ERROR)
206                 return res;
207         }
208         *pos = ((Int64)value.HighPart << 32) | value.LowPart;
209         return 0;
210
211 #else
212
213         int moveMethod;
214         int res;
215         switch (origin)
216         {
217             case SZ_SEEK_SET:
218                 moveMethod = SEEK_SET;
219                 break;
220             case SZ_SEEK_CUR:
221                 moveMethod = SEEK_CUR;
222                 break;
223             case SZ_SEEK_END:
224                 moveMethod = SEEK_END;
225                 break;
226             default:
227                 return 1;
228         }
229         res = fseek(p->file, (long)*pos, moveMethod);
230         *pos = ftell(p->file);
231         return res;
232
233 #endif
234     }
235
236     WRes File_GetLength(CSzFile *p, UInt64 *length)
237     {
238 #ifdef USE_WINDOWS_FILE
239
240         DWORD sizeHigh;
241         DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
242         if (sizeLow == 0xFFFFFFFF)
243         {
244             DWORD res = GetLastError();
245             if (res != NO_ERROR)
246                 return res;
247         }
248         *length = (((UInt64)sizeHigh) << 32) + sizeLow;
249         return 0;
250
251 #else
252
253         long pos = ftell(p->file);
254         int res = fseek(p->file, 0, SEEK_END);
255         *length = ftell(p->file);
256         fseek(p->file, pos, SEEK_SET);
257         return res;
258
259 #endif
260     }
261
262     /* ---------- FileSeqInStream ---------- */
263
264     static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size)
265     {
266         CFileSeqInStream *p = (CFileSeqInStream *)pp;
267         return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
268     }
269
270     void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
271     {
272         p->s.Read = FileSeqInStream_Read;
273     }
274
275     /* ---------- FileInStream ---------- */
276
277     static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
278     {
279         CFileInStream *p = (CFileInStream *)pp;
280         return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
281     }
282
283     static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
284     {
285         CFileInStream *p = (CFileInStream *)pp;
286         return File_Seek(&p->file, pos, origin);
287     }
288
289     void FileInStream_CreateVTable(CFileInStream *p)
290     {
291         p->s.Read = FileInStream_Read;
292         p->s.Seek = FileInStream_Seek;
293     }
294
295     /* ---------- FileOutStream ---------- */
296
297     static size_t FileOutStream_Write(void *pp, const void *data, size_t size)
298     {
299         CFileOutStream *p = (CFileOutStream *)pp;
300         File_Write(&p->file, data, &size);
301         return size;
302     }
303
304     void FileOutStream_CreateVTable(CFileOutStream *p)
305     {
306         p->s.Write = FileOutStream_Write;
307     }
308 }