2 2009-11-24 : Igor Pavlov : Public domain */
6 #ifndef USE_WINDOWS_FILE
15 ReadFile and WriteFile functions in Windows have BUG:
16 If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
17 from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
18 (Insufficient system resources exist to complete the requested service).
19 Probably in some version of Windows there are problems with other sizes:
20 for 32 MB (maybe also for 16 MB).
21 And message can be "Network connection was lost"
24 #define kChunkSizeMax (1 << 22)
28 void File_Construct(CSzFile
*p
)
30 #ifdef USE_WINDOWS_FILE
31 p
->handle
= INVALID_HANDLE_VALUE
;
37 #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
38 static WRes
File_Open(CSzFile
*p
, const char *name
, int writeMode
)
40 #ifdef USE_WINDOWS_FILE
41 p
->handle
= CreateFileA(name
,
42 writeMode
? GENERIC_WRITE
: GENERIC_READ
,
43 FILE_SHARE_READ
, NULL
,
44 writeMode
? CREATE_ALWAYS
: OPEN_EXISTING
,
45 FILE_ATTRIBUTE_NORMAL
, NULL
);
46 return (p
->handle
!= INVALID_HANDLE_VALUE
) ? 0 : GetLastError();
48 p
->file
= fopen(name
, writeMode
? "wb+" : "rb");
49 return (p
->file
!= 0) ? 0 :
58 WRes
InFile_Open(CSzFile
*p
, const char *name
) { return File_Open(p
, name
, 0); }
59 WRes
OutFile_Open(CSzFile
*p
, const char *name
) { return File_Open(p
, name
, 1); }
62 #ifdef USE_WINDOWS_FILE
63 static WRes
File_OpenW(CSzFile
*p
, const WCHAR
*name
, int writeMode
)
65 p
->handle
= CreateFileW(name
,
66 writeMode
? GENERIC_WRITE
: GENERIC_READ
,
67 FILE_SHARE_READ
, NULL
,
68 writeMode
? CREATE_ALWAYS
: OPEN_EXISTING
,
69 FILE_ATTRIBUTE_NORMAL
, NULL
);
70 return (p
->handle
!= INVALID_HANDLE_VALUE
) ? 0 : GetLastError();
72 WRes
InFile_OpenW(CSzFile
*p
, const WCHAR
*name
) { return File_OpenW(p
, name
, 0); }
73 WRes
OutFile_OpenW(CSzFile
*p
, const WCHAR
*name
) { return File_OpenW(p
, name
, 1); }
76 WRes
File_Close(CSzFile
*p
)
78 #ifdef USE_WINDOWS_FILE
79 if (p
->handle
!= INVALID_HANDLE_VALUE
)
81 if (!CloseHandle(p
->handle
))
82 return GetLastError();
83 p
->handle
= INVALID_HANDLE_VALUE
;
88 int res
= fclose(p
->file
);
97 WRes
File_Read(CSzFile
*p
, void *data
, size_t *size
)
99 size_t originalSize
= *size
;
100 if (originalSize
== 0)
103 #ifdef USE_WINDOWS_FILE
108 DWORD curSize
= (originalSize
> kChunkSizeMax
) ? kChunkSizeMax
: (DWORD
)originalSize
;
110 BOOL res
= ReadFile(p
->handle
, data
, curSize
, &processed
, NULL
);
111 data
= (void *)((Byte
*)data
+ processed
);
112 originalSize
-= processed
;
115 return GetLastError();
119 while (originalSize
> 0);
124 *size
= fread(data
, 1, originalSize
, p
->file
);
125 if (*size
== originalSize
)
127 return ferror(p
->file
);
132 WRes
File_Write(CSzFile
*p
, const void *data
, size_t *size
)
134 size_t originalSize
= *size
;
135 if (originalSize
== 0)
138 #ifdef USE_WINDOWS_FILE
143 DWORD curSize
= (originalSize
> kChunkSizeMax
) ? kChunkSizeMax
: (DWORD
)originalSize
;
145 BOOL res
= WriteFile(p
->handle
, data
, curSize
, &processed
, NULL
);
146 data
= (void *)((Byte
*)data
+ processed
);
147 originalSize
-= processed
;
150 return GetLastError();
154 while (originalSize
> 0);
159 *size
= fwrite(data
, 1, originalSize
, p
->file
);
160 if (*size
== originalSize
)
162 return ferror(p
->file
);
167 WRes
File_Seek(CSzFile
*p
, Int64
*pos
, ESzSeek origin
)
169 #ifdef USE_WINDOWS_FILE
173 value
.LowPart
= (DWORD
)*pos
;
174 value
.HighPart
= (LONG
)((UInt64
)*pos
>> 16 >> 16); /* for case when UInt64 is 32-bit only */
177 case SZ_SEEK_SET
: moveMethod
= FILE_BEGIN
; break;
178 case SZ_SEEK_CUR
: moveMethod
= FILE_CURRENT
; break;
179 case SZ_SEEK_END
: moveMethod
= FILE_END
; break;
180 default: return ERROR_INVALID_PARAMETER
;
182 value
.LowPart
= SetFilePointer(p
->handle
, value
.LowPart
, &value
.HighPart
, moveMethod
);
183 if (value
.LowPart
== 0xFFFFFFFF)
185 WRes res
= GetLastError();
189 *pos
= ((Int64
)value
.HighPart
<< 32) | value
.LowPart
;
198 case SZ_SEEK_SET
: moveMethod
= SEEK_SET
; break;
199 case SZ_SEEK_CUR
: moveMethod
= SEEK_CUR
; break;
200 case SZ_SEEK_END
: moveMethod
= SEEK_END
; break;
203 res
= fseek(p
->file
, (long)*pos
, moveMethod
);
204 *pos
= ftell(p
->file
);
210 WRes
File_GetLength(CSzFile
*p
, UInt64
*length
)
212 #ifdef USE_WINDOWS_FILE
215 DWORD sizeLow
= GetFileSize(p
->handle
, &sizeHigh
);
216 if (sizeLow
== 0xFFFFFFFF)
218 DWORD res
= GetLastError();
222 *length
= (((UInt64
)sizeHigh
) << 32) + sizeLow
;
227 long pos
= ftell(p
->file
);
228 int res
= fseek(p
->file
, 0, SEEK_END
);
229 *length
= ftell(p
->file
);
230 fseek(p
->file
, pos
, SEEK_SET
);
237 /* ---------- FileSeqInStream ---------- */
239 static SRes
FileSeqInStream_Read(void *pp
, void *buf
, size_t *size
)
241 CFileSeqInStream
*p
= (CFileSeqInStream
*)pp
;
242 return File_Read(&p
->file
, buf
, size
) == 0 ? SZ_OK
: SZ_ERROR_READ
;
245 void FileSeqInStream_CreateVTable(CFileSeqInStream
*p
)
247 p
->s
.Read
= FileSeqInStream_Read
;
251 /* ---------- FileInStream ---------- */
253 static SRes
FileInStream_Read(void *pp
, void *buf
, size_t *size
)
255 CFileInStream
*p
= (CFileInStream
*)pp
;
256 return (File_Read(&p
->file
, buf
, size
) == 0) ? SZ_OK
: SZ_ERROR_READ
;
259 static SRes
FileInStream_Seek(void *pp
, Int64
*pos
, ESzSeek origin
)
261 CFileInStream
*p
= (CFileInStream
*)pp
;
262 return File_Seek(&p
->file
, pos
, origin
);
265 void FileInStream_CreateVTable(CFileInStream
*p
)
267 p
->s
.Read
= FileInStream_Read
;
268 p
->s
.Seek
= FileInStream_Seek
;
272 /* ---------- FileOutStream ---------- */
274 static size_t FileOutStream_Write(void *pp
, const void *data
, size_t size
)
276 CFileOutStream
*p
= (CFileOutStream
*)pp
;
277 File_Write(&p
->file
, data
, &size
);
281 void FileOutStream_CreateVTable(CFileOutStream
*p
)
283 p
->s
.Write
= FileOutStream_Write
;