1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
25 **************************************************************************/
27 /* 7zFile.c -- File IO
28 2008-11-22 : Igor Pavlov : Public domain */
29 #include "vogl_core.h"
30 #include "lzma_7zFile.h"
32 #ifndef USE_WINDOWS_FILE
38 #ifdef USE_WINDOWS_FILE
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"
50 #define kChunkSizeMax (1 << 22)
57 void File_Construct(CSzFile *p)
59 #ifdef USE_WINDOWS_FILE
60 p->handle = INVALID_HANDLE_VALUE;
66 static WRes File_Open(CSzFile *p, const char *name, int writeMode)
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();
76 p->file = fopen(name, writeMode ? "wb+" : "rb");
77 return (p->file != 0) ? 0 : errno;
81 WRes InFile_Open(CSzFile *p, const char *name)
83 return File_Open(p, name, 0);
85 WRes OutFile_Open(CSzFile *p, const char *name)
87 return File_Open(p, name, 1);
90 WRes File_Close(CSzFile *p)
92 #ifdef USE_WINDOWS_FILE
93 if (p->handle != INVALID_HANDLE_VALUE)
95 if (!CloseHandle(p->handle))
96 return GetLastError();
97 p->handle = INVALID_HANDLE_VALUE;
102 int res = fclose(p->file);
111 WRes File_Read(CSzFile *p, void *data, size_t *size)
113 size_t originalSize = *size;
114 if (originalSize == 0)
117 #ifdef USE_WINDOWS_FILE
122 DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
124 BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
125 data = (void *)((Byte *)data + processed);
126 originalSize -= processed;
129 return GetLastError();
132 } while (originalSize > 0);
137 *size = fread(data, 1, originalSize, p->file);
138 if (*size == originalSize)
140 return ferror(p->file);
145 WRes File_Write(CSzFile *p, const void *data, size_t *size)
147 size_t originalSize = *size;
148 if (originalSize == 0)
151 #ifdef USE_WINDOWS_FILE
156 DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
158 BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
159 data = (void *)((Byte *)data + processed);
160 originalSize -= processed;
163 return GetLastError();
166 } while (originalSize > 0);
171 *size = fwrite(data, 1, originalSize, p->file);
172 if (*size == originalSize)
174 return ferror(p->file);
179 WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
181 #ifdef USE_WINDOWS_FILE
185 value.LowPart = (DWORD) * pos;
186 value.HighPart = (LONG)((UInt64) * pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
190 moveMethod = FILE_BEGIN;
193 moveMethod = FILE_CURRENT;
196 moveMethod = FILE_END;
199 return ERROR_INVALID_PARAMETER;
201 value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);
202 if (value.LowPart == 0xFFFFFFFF)
204 WRes res = GetLastError();
208 *pos = ((Int64)value.HighPart << 32) | value.LowPart;
218 moveMethod = SEEK_SET;
221 moveMethod = SEEK_CUR;
224 moveMethod = SEEK_END;
229 res = fseek(p->file, (long)*pos, moveMethod);
230 *pos = ftell(p->file);
236 WRes File_GetLength(CSzFile *p, UInt64 *length)
238 #ifdef USE_WINDOWS_FILE
241 DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
242 if (sizeLow == 0xFFFFFFFF)
244 DWORD res = GetLastError();
248 *length = (((UInt64)sizeHigh) << 32) + sizeLow;
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);
262 /* ---------- FileSeqInStream ---------- */
264 static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size)
266 CFileSeqInStream *p = (CFileSeqInStream *)pp;
267 return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
270 void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
272 p->s.Read = FileSeqInStream_Read;
275 /* ---------- FileInStream ---------- */
277 static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
279 CFileInStream *p = (CFileInStream *)pp;
280 return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
283 static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
285 CFileInStream *p = (CFileInStream *)pp;
286 return File_Seek(&p->file, pos, origin);
289 void FileInStream_CreateVTable(CFileInStream *p)
291 p->s.Read = FileInStream_Read;
292 p->s.Seek = FileInStream_Seek;
295 /* ---------- FileOutStream ---------- */
297 static size_t FileOutStream_Write(void *pp, const void *data, size_t size)
299 CFileOutStream *p = (CFileOutStream *)pp;
300 File_Write(&p->file, data, &size);
304 void FileOutStream_CreateVTable(CFileOutStream *p)
306 p->s.Write = FileOutStream_Write;