1 /* 7zFile.c -- File IO
\r
2 2009-11-24 : Igor Pavlov : Public domain */
\r
8 #ifndef USE_WINDOWS_FILE
\r
17 ReadFile and WriteFile functions in Windows have BUG:
\r
18 If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
\r
19 from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
\r
20 (Insufficient system resources exist to complete the requested service).
\r
21 Probably in some version of Windows there are problems with other sizes:
\r
22 for 32 MB (maybe also for 16 MB).
\r
23 And message can be "Network connection was lost"
\r
26 #define kChunkSizeMax (1 << 22)
\r
30 void File_Construct(CSzFile *p)
\r
32 #ifdef USE_WINDOWS_FILE
\r
33 p->handle = INVALID_HANDLE_VALUE;
\r
39 #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
\r
40 static WRes File_Open(CSzFile *p, const char *name, int writeMode)
\r
42 #ifdef USE_WINDOWS_FILE
\r
43 p->handle = CreateFileA(name,
\r
44 writeMode ? GENERIC_WRITE : GENERIC_READ,
\r
45 FILE_SHARE_READ, NULL,
\r
46 writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
\r
47 FILE_ATTRIBUTE_NORMAL, NULL);
\r
48 return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
\r
50 p->file = fopen(name, writeMode ? "wb+" : "rb");
\r
51 return (p->file != 0) ? 0 :
\r
60 WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
\r
61 WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); }
\r
64 #ifdef USE_WINDOWS_FILE
\r
65 static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
\r
67 p->handle = CreateFileW(name,
\r
68 writeMode ? GENERIC_WRITE : GENERIC_READ,
\r
69 FILE_SHARE_READ, NULL,
\r
70 writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
\r
71 FILE_ATTRIBUTE_NORMAL, NULL);
\r
72 return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
\r
74 WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
\r
75 WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
\r
78 WRes File_Close(CSzFile *p)
\r
80 #ifdef USE_WINDOWS_FILE
\r
81 if (p->handle != INVALID_HANDLE_VALUE)
\r
83 if (!CloseHandle(p->handle))
\r
84 return GetLastError();
\r
85 p->handle = INVALID_HANDLE_VALUE;
\r
88 if (p->file != NULL)
\r
90 int res = fclose(p->file);
\r
99 WRes File_Read(CSzFile *p, void *data, size_t *size)
\r
101 size_t originalSize = *size;
\r
102 if (originalSize == 0)
\r
105 #ifdef USE_WINDOWS_FILE
\r
110 DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
\r
111 DWORD processed = 0;
\r
112 BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
\r
113 data = (void *)((Byte *)data + processed);
\r
114 originalSize -= processed;
\r
115 *size += processed;
\r
117 return GetLastError();
\r
118 if (processed == 0)
\r
121 while (originalSize > 0);
\r
126 *size = fread(data, 1, originalSize, p->file);
\r
127 if (*size == originalSize)
\r
129 return ferror(p->file);
\r
134 WRes File_Write(CSzFile *p, const void *data, size_t *size)
\r
136 size_t originalSize = *size;
\r
137 if (originalSize == 0)
\r
140 #ifdef USE_WINDOWS_FILE
\r
145 DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
\r
146 DWORD processed = 0;
\r
147 BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
\r
148 data = (void *)((Byte *)data + processed);
\r
149 originalSize -= processed;
\r
150 *size += processed;
\r
152 return GetLastError();
\r
153 if (processed == 0)
\r
156 while (originalSize > 0);
\r
161 *size = fwrite(data, 1, originalSize, p->file);
\r
162 if (*size == originalSize)
\r
164 return ferror(p->file);
\r
169 WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
\r
171 #ifdef USE_WINDOWS_FILE
\r
173 LARGE_INTEGER value;
\r
175 value.LowPart = (DWORD)*pos;
\r
176 value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
\r
179 case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
\r
180 case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
\r
181 case SZ_SEEK_END: moveMethod = FILE_END; break;
\r
182 default: return ERROR_INVALID_PARAMETER;
\r
184 value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);
\r
185 if (value.LowPart == 0xFFFFFFFF)
\r
187 WRes res = GetLastError();
\r
188 if (res != NO_ERROR)
\r
191 *pos = ((Int64)value.HighPart << 32) | value.LowPart;
\r
200 case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
\r
201 case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
\r
202 case SZ_SEEK_END: moveMethod = SEEK_END; break;
\r
205 res = fseek(p->file, (long)*pos, moveMethod);
\r
206 *pos = ftell(p->file);
\r
212 WRes File_GetLength(CSzFile *p, UInt64 *length)
\r
214 #ifdef USE_WINDOWS_FILE
\r
217 DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
\r
218 if (sizeLow == 0xFFFFFFFF)
\r
220 DWORD res = GetLastError();
\r
221 if (res != NO_ERROR)
\r
224 *length = (((UInt64)sizeHigh) << 32) + sizeLow;
\r
229 long pos = ftell(p->file);
\r
230 int res = fseek(p->file, 0, SEEK_END);
\r
231 *length = ftell(p->file);
\r
232 fseek(p->file, pos, SEEK_SET);
\r
239 /* ---------- FileSeqInStream ---------- */
\r
241 static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size)
\r
243 CFileSeqInStream *p = (CFileSeqInStream *)pp;
\r
244 return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
\r
247 void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
\r
249 p->s.Read = FileSeqInStream_Read;
\r
253 /* ---------- FileInStream ---------- */
\r
255 static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
\r
257 CFileInStream *p = (CFileInStream *)pp;
\r
258 return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
\r
261 static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
\r
263 CFileInStream *p = (CFileInStream *)pp;
\r
264 return File_Seek(&p->file, pos, origin);
\r
267 void FileInStream_CreateVTable(CFileInStream *p)
\r
269 p->s.Read = FileInStream_Read;
\r
270 p->s.Seek = FileInStream_Seek;
\r
274 /* ---------- FileOutStream ---------- */
\r
276 static size_t FileOutStream_Write(void *pp, const void *data, size_t size)
\r
278 CFileOutStream *p = (CFileOutStream *)pp;
\r
279 File_Write(&p->file, data, &size);
\r
283 void FileOutStream_CreateVTable(CFileOutStream *p)
\r
285 p->s.Write = FileOutStream_Write;
\r