2 2017-04-03 : Igor Pavlov : Public domain */
8 #ifndef USE_WINDOWS_FILE
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"
26 #define kChunkSizeMax (1 << 22)
30 void File_Construct(CSzFile
*p
)
32 #ifdef USE_WINDOWS_FILE
33 p
->handle
= INVALID_HANDLE_VALUE
;
39 #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
40 static WRes
File_Open(CSzFile
*p
, const char *name
, int writeMode
)
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();
50 p
->file
= fopen(name
, writeMode
? "wb+" : "rb");
51 return (p
->file
!= 0) ? 0 :
60 WRes
InFile_Open(CSzFile
*p
, const char *name
) { return File_Open(p
, name
, 0); }
61 WRes
OutFile_Open(CSzFile
*p
, const char *name
) { return File_Open(p
, name
, 1); }
64 #ifdef USE_WINDOWS_FILE
65 static WRes
File_OpenW(CSzFile
*p
, const WCHAR
*name
, int writeMode
)
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();
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); }
78 WRes
File_Close(CSzFile
*p
)
80 #ifdef USE_WINDOWS_FILE
81 if (p
->handle
!= INVALID_HANDLE_VALUE
)
83 if (!CloseHandle(p
->handle
))
84 return GetLastError();
85 p
->handle
= INVALID_HANDLE_VALUE
;
90 int res
= fclose(p
->file
);
99 WRes
File_Read(CSzFile
*p
, void *data
, size_t *size
)
101 size_t originalSize
= *size
;
102 if (originalSize
== 0)
105 #ifdef USE_WINDOWS_FILE
110 DWORD curSize
= (originalSize
> kChunkSizeMax
) ? kChunkSizeMax
: (DWORD
)originalSize
;
112 BOOL res
= ReadFile(p
->handle
, data
, curSize
, &processed
, NULL
);
113 data
= (void *)((Byte
*)data
+ processed
);
114 originalSize
-= processed
;
117 return GetLastError();
121 while (originalSize
> 0);
126 *size
= fread(data
, 1, originalSize
, p
->file
);
127 if (*size
== originalSize
)
129 return ferror(p
->file
);
134 WRes
File_Write(CSzFile
*p
, const void *data
, size_t *size
)
136 size_t originalSize
= *size
;
137 if (originalSize
== 0)
140 #ifdef USE_WINDOWS_FILE
145 DWORD curSize
= (originalSize
> kChunkSizeMax
) ? kChunkSizeMax
: (DWORD
)originalSize
;
147 BOOL res
= WriteFile(p
->handle
, data
, curSize
, &processed
, NULL
);
148 data
= (void *)((Byte
*)data
+ processed
);
149 originalSize
-= processed
;
152 return GetLastError();
156 while (originalSize
> 0);
161 *size
= fwrite(data
, 1, originalSize
, p
->file
);
162 if (*size
== originalSize
)
164 return ferror(p
->file
);
169 WRes
File_Seek(CSzFile
*p
, Int64
*pos
, ESzSeek origin
)
171 #ifdef USE_WINDOWS_FILE
175 value
.LowPart
= (DWORD
)*pos
;
176 value
.HighPart
= (LONG
)((UInt64
)*pos
>> 16 >> 16); /* for case when UInt64 is 32-bit only */
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
;
184 value
.LowPart
= SetFilePointer(p
->handle
, value
.LowPart
, &value
.HighPart
, moveMethod
);
185 if (value
.LowPart
== 0xFFFFFFFF)
187 WRes res
= GetLastError();
191 *pos
= ((Int64
)value
.HighPart
<< 32) | value
.LowPart
;
200 case SZ_SEEK_SET
: moveMethod
= SEEK_SET
; break;
201 case SZ_SEEK_CUR
: moveMethod
= SEEK_CUR
; break;
202 case SZ_SEEK_END
: moveMethod
= SEEK_END
; break;
205 res
= fseek(p
->file
, (long)*pos
, moveMethod
);
206 *pos
= ftell(p
->file
);
212 WRes
File_GetLength(CSzFile
*p
, UInt64
*length
)
214 #ifdef USE_WINDOWS_FILE
217 DWORD sizeLow
= GetFileSize(p
->handle
, &sizeHigh
);
218 if (sizeLow
== 0xFFFFFFFF)
220 DWORD res
= GetLastError();
224 *length
= (((UInt64
)sizeHigh
) << 32) + sizeLow
;
229 long pos
= ftell(p
->file
);
230 int res
= fseek(p
->file
, 0, SEEK_END
);
231 *length
= ftell(p
->file
);
232 fseek(p
->file
, pos
, SEEK_SET
);
239 /* ---------- FileSeqInStream ---------- */
241 static SRes
FileSeqInStream_Read(const ISeqInStream
*pp
, void *buf
, size_t *size
)
243 CFileSeqInStream
*p
= CONTAINER_FROM_VTBL(pp
, CFileSeqInStream
, vt
);
244 return File_Read(&p
->file
, buf
, size
) == 0 ? SZ_OK
: SZ_ERROR_READ
;
247 void FileSeqInStream_CreateVTable(CFileSeqInStream
*p
)
249 p
->vt
.Read
= FileSeqInStream_Read
;
253 /* ---------- FileInStream ---------- */
255 static SRes
FileInStream_Read(const ISeekInStream
*pp
, void *buf
, size_t *size
)
257 CFileInStream
*p
= CONTAINER_FROM_VTBL(pp
, CFileInStream
, vt
);
258 return (File_Read(&p
->file
, buf
, size
) == 0) ? SZ_OK
: SZ_ERROR_READ
;
261 static SRes
FileInStream_Seek(const ISeekInStream
*pp
, Int64
*pos
, ESzSeek origin
)
263 CFileInStream
*p
= CONTAINER_FROM_VTBL(pp
, CFileInStream
, vt
);
264 return File_Seek(&p
->file
, pos
, origin
);
267 void FileInStream_CreateVTable(CFileInStream
*p
)
269 p
->vt
.Read
= FileInStream_Read
;
270 p
->vt
.Seek
= FileInStream_Seek
;
274 /* ---------- FileOutStream ---------- */
276 static size_t FileOutStream_Write(const ISeqOutStream
*pp
, const void *data
, size_t size
)
278 CFileOutStream
*p
= CONTAINER_FROM_VTBL(pp
, CFileOutStream
, vt
);
279 File_Write(&p
->file
, data
, &size
);
283 void FileOutStream_CreateVTable(CFileOutStream
*p
)
285 p
->vt
.Write
= FileOutStream_Write
;