Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5728 | serge | 1 | /* 7zFile.c -- File IO |
2 | 2009-11-24 : Igor Pavlov : Public domain */ |
||
3 | |||
4 | #include "Precomp.h" |
||
5 | |||
6 | #include "7zFile.h" |
||
7 | |||
8 | #ifndef USE_WINDOWS_FILE |
||
9 | |||
10 | #ifndef UNDER_CE |
||
11 | #include |
||
12 | #endif |
||
13 | |||
14 | #else |
||
15 | |||
16 | /* |
||
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" |
||
24 | */ |
||
25 | |||
26 | #define kChunkSizeMax (1 << 22) |
||
27 | |||
28 | #endif |
||
29 | |||
30 | void File_Construct(CSzFile *p) |
||
31 | { |
||
32 | #ifdef USE_WINDOWS_FILE |
||
33 | p->handle = INVALID_HANDLE_VALUE; |
||
34 | #else |
||
35 | p->file = NULL; |
||
36 | #endif |
||
37 | } |
||
38 | |||
39 | #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) |
||
40 | static WRes File_Open(CSzFile *p, const char *name, int writeMode) |
||
41 | { |
||
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(); |
||
49 | #else |
||
50 | p->file = fopen(name, writeMode ? "wb+" : "rb"); |
||
51 | return (p->file != 0) ? 0 : |
||
52 | #ifdef UNDER_CE |
||
53 | 2; /* ENOENT */ |
||
54 | #else |
||
55 | errno; |
||
56 | #endif |
||
57 | #endif |
||
58 | } |
||
59 | |||
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); } |
||
62 | #endif |
||
63 | |||
64 | #ifdef USE_WINDOWS_FILE |
||
65 | static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) |
||
66 | { |
||
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(); |
||
73 | } |
||
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); } |
||
76 | #endif |
||
77 | |||
78 | WRes File_Close(CSzFile *p) |
||
79 | { |
||
80 | #ifdef USE_WINDOWS_FILE |
||
81 | if (p->handle != INVALID_HANDLE_VALUE) |
||
82 | { |
||
83 | if (!CloseHandle(p->handle)) |
||
84 | return GetLastError(); |
||
85 | p->handle = INVALID_HANDLE_VALUE; |
||
86 | } |
||
87 | #else |
||
88 | if (p->file != NULL) |
||
89 | { |
||
90 | int res = fclose(p->file); |
||
91 | if (res != 0) |
||
92 | return res; |
||
93 | p->file = NULL; |
||
94 | } |
||
95 | #endif |
||
96 | return 0; |
||
97 | } |
||
98 | |||
99 | WRes File_Read(CSzFile *p, void *data, size_t *size) |
||
100 | { |
||
101 | size_t originalSize = *size; |
||
102 | if (originalSize == 0) |
||
103 | return 0; |
||
104 | |||
105 | #ifdef USE_WINDOWS_FILE |
||
106 | |||
107 | *size = 0; |
||
108 | do |
||
109 | { |
||
110 | DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; |
||
111 | DWORD processed = 0; |
||
112 | BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); |
||
113 | data = (void *)((Byte *)data + processed); |
||
114 | originalSize -= processed; |
||
115 | *size += processed; |
||
116 | if (!res) |
||
117 | return GetLastError(); |
||
118 | if (processed == 0) |
||
119 | break; |
||
120 | } |
||
121 | while (originalSize > 0); |
||
122 | return 0; |
||
123 | |||
124 | #else |
||
125 | |||
126 | *size = fread(data, 1, originalSize, p->file); |
||
127 | if (*size == originalSize) |
||
128 | return 0; |
||
129 | return ferror(p->file); |
||
130 | |||
131 | #endif |
||
132 | } |
||
133 | |||
134 | WRes File_Write(CSzFile *p, const void *data, size_t *size) |
||
135 | { |
||
136 | size_t originalSize = *size; |
||
137 | if (originalSize == 0) |
||
138 | return 0; |
||
139 | |||
140 | #ifdef USE_WINDOWS_FILE |
||
141 | |||
142 | *size = 0; |
||
143 | do |
||
144 | { |
||
145 | DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; |
||
146 | DWORD processed = 0; |
||
147 | BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); |
||
148 | data = (void *)((Byte *)data + processed); |
||
149 | originalSize -= processed; |
||
150 | *size += processed; |
||
151 | if (!res) |
||
152 | return GetLastError(); |
||
153 | if (processed == 0) |
||
154 | break; |
||
155 | } |
||
156 | while (originalSize > 0); |
||
157 | return 0; |
||
158 | |||
159 | #else |
||
160 | |||
161 | *size = fwrite(data, 1, originalSize, p->file); |
||
162 | if (*size == originalSize) |
||
163 | return 0; |
||
164 | return ferror(p->file); |
||
165 | |||
166 | #endif |
||
167 | } |
||
168 | |||
169 | WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) |
||
170 | { |
||
171 | #ifdef USE_WINDOWS_FILE |
||
172 | |||
173 | LARGE_INTEGER value; |
||
174 | DWORD moveMethod; |
||
175 | value.LowPart = (DWORD)*pos; |
||
176 | value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ |
||
177 | switch (origin) |
||
178 | { |
||
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; |
||
183 | } |
||
184 | value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); |
||
185 | if (value.LowPart == 0xFFFFFFFF) |
||
186 | { |
||
187 | WRes res = GetLastError(); |
||
188 | if (res != NO_ERROR) |
||
189 | return res; |
||
190 | } |
||
191 | *pos = ((Int64)value.HighPart << 32) | value.LowPart; |
||
192 | return 0; |
||
193 | |||
194 | #else |
||
195 | |||
196 | int moveMethod; |
||
197 | int res; |
||
198 | switch (origin) |
||
199 | { |
||
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; |
||
203 | default: return 1; |
||
204 | } |
||
205 | res = fseek(p->file, (long)*pos, moveMethod); |
||
206 | *pos = ftell(p->file); |
||
207 | return res; |
||
208 | |||
209 | #endif |
||
210 | } |
||
211 | |||
212 | WRes File_GetLength(CSzFile *p, UInt64 *length) |
||
213 | { |
||
214 | #ifdef USE_WINDOWS_FILE |
||
215 | |||
216 | DWORD sizeHigh; |
||
217 | DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); |
||
218 | if (sizeLow == 0xFFFFFFFF) |
||
219 | { |
||
220 | DWORD res = GetLastError(); |
||
221 | if (res != NO_ERROR) |
||
222 | return res; |
||
223 | } |
||
224 | *length = (((UInt64)sizeHigh) << 32) + sizeLow; |
||
225 | return 0; |
||
226 | |||
227 | #else |
||
228 | |||
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); |
||
233 | return res; |
||
234 | |||
235 | #endif |
||
236 | } |
||
237 | |||
238 | |||
239 | /* ---------- FileSeqInStream ---------- */ |
||
240 | |||
241 | static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size) |
||
242 | { |
||
243 | CFileSeqInStream *p = (CFileSeqInStream *)pp; |
||
244 | return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; |
||
245 | } |
||
246 | |||
247 | void FileSeqInStream_CreateVTable(CFileSeqInStream *p) |
||
248 | { |
||
249 | p->s.Read = FileSeqInStream_Read; |
||
250 | } |
||
251 | |||
252 | |||
253 | /* ---------- FileInStream ---------- */ |
||
254 | |||
255 | static SRes FileInStream_Read(void *pp, void *buf, size_t *size) |
||
256 | { |
||
257 | CFileInStream *p = (CFileInStream *)pp; |
||
258 | return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; |
||
259 | } |
||
260 | |||
261 | static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin) |
||
262 | { |
||
263 | CFileInStream *p = (CFileInStream *)pp; |
||
264 | return File_Seek(&p->file, pos, origin); |
||
265 | } |
||
266 | |||
267 | void FileInStream_CreateVTable(CFileInStream *p) |
||
268 | { |
||
269 | p->s.Read = FileInStream_Read; |
||
270 | p->s.Seek = FileInStream_Seek; |
||
271 | } |
||
272 | |||
273 | |||
274 | /* ---------- FileOutStream ---------- */ |
||
275 | |||
276 | static size_t FileOutStream_Write(void *pp, const void *data, size_t size) |
||
277 | { |
||
278 | CFileOutStream *p = (CFileOutStream *)pp; |
||
279 | File_Write(&p->file, data, &size); |
||
280 | return size; |
||
281 | } |
||
282 | |||
283 | void FileOutStream_CreateVTable(CFileOutStream *p) |
||
284 | { |
||
285 | p->s.Write = FileOutStream_Write; |
||
286 | }><>><>><> |