Subversion Repositories spk

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 cycrow 1
/* 7zFile.c -- File IO
2
2008-11-22 : Igor Pavlov : Public domain */
3
 
4
#include "7zFile.h"
5
 
6
#ifndef USE_WINDOWS_FILE
7
 
8
#include <errno.h>
9
 
10
#endif
11
 
12
#ifdef USE_WINDOWS_FILE
13
 
14
/*
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"
22
*/
23
 
24
#define kChunkSizeMax (1 << 22)
25
 
26
#endif
27
 
28
void File_Construct(CSzFile *p)
29
{
30
  #ifdef USE_WINDOWS_FILE
31
  p->handle = INVALID_HANDLE_VALUE;
32
  #else
33
  p->file = NULL;
34
  #endif
35
}
36
 
37
static WRes File_Open(CSzFile *p, const char *name, int writeMode)
38
{
39
  #ifdef USE_WINDOWS_FILE
40
  p->handle = CreateFileA(name,
41
      writeMode ? GENERIC_WRITE : GENERIC_READ,
42
      FILE_SHARE_READ, NULL,
43
      writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
44
      FILE_ATTRIBUTE_NORMAL, NULL);
45
  return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
46
  #else
47
  p->file = fopen(name, writeMode ? "wb+" : "rb");
48
  return (p->file != 0) ? 0 : errno;
49
  #endif
50
}
51
 
52
WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
53
WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); }
54
 
55
WRes File_Close(CSzFile *p)
56
{
57
  #ifdef USE_WINDOWS_FILE
58
  if (p->handle != INVALID_HANDLE_VALUE)
59
  {
60
    if (!CloseHandle(p->handle))
61
      return GetLastError();
62
    p->handle = INVALID_HANDLE_VALUE;
63
  }
64
  #else
65
  if (p->file != NULL)
66
  {
67
    int res = fclose(p->file);
68
    if (res != 0)
69
      return res;
70
    p->file = NULL;
71
  }
72
  #endif
73
  return 0;
74
}
75
 
76
WRes File_Read(CSzFile *p, void *data, size_t *size)
77
{
78
  size_t originalSize = *size;
79
  if (originalSize == 0)
80
    return 0;
81
 
82
  #ifdef USE_WINDOWS_FILE
83
 
84
  *size = 0;
85
  do
86
  {
87
    DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
88
    DWORD processed = 0;
89
    BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
90
    data = (void *)((Byte *)data + processed);
91
    originalSize -= processed;
92
    *size += processed;
93
    if (!res)
94
      return GetLastError();
95
    if (processed == 0)
96
      break;
97
  }
98
  while (originalSize > 0);
99
  return 0;
100
 
101
  #else
102
 
103
  *size = fread(data, 1, originalSize, p->file);
104
  if (*size == originalSize)
105
    return 0;
106
  return ferror(p->file);
107
 
108
  #endif
109
}
110
 
111
WRes File_Write(CSzFile *p, const void *data, size_t *size)
112
{
113
  size_t originalSize = *size;
114
  if (originalSize == 0)
115
    return 0;
116
 
117
  #ifdef USE_WINDOWS_FILE
118
 
119
  *size = 0;
120
  do
121
  {
122
    DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
123
    DWORD processed = 0;
124
    BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
125
    data = (void *)((Byte *)data + processed);
126
    originalSize -= processed;
127
    *size += processed;
128
    if (!res)
129
      return GetLastError();
130
    if (processed == 0)
131
      break;
132
  }
133
  while (originalSize > 0);
134
  return 0;
135
 
136
  #else
137
 
138
  *size = fwrite(data, 1, originalSize, p->file);
139
  if (*size == originalSize)
140
    return 0;
141
  return ferror(p->file);
142
 
143
  #endif
144
}
145
 
146
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
147
{
148
  #ifdef USE_WINDOWS_FILE
149
 
150
  LARGE_INTEGER value;
151
  DWORD moveMethod;
152
  value.LowPart = (DWORD)*pos;
153
  value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
154
  switch (origin)
155
  {
156
    case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
157
    case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
158
    case SZ_SEEK_END: moveMethod = FILE_END; break;
159
    default: return ERROR_INVALID_PARAMETER;
160
  }
161
  value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);
162
  if (value.LowPart == 0xFFFFFFFF)
163
  {
164
    WRes res = GetLastError();
165
    if (res != NO_ERROR)
166
      return res;
167
  }
168
  *pos = ((Int64)value.HighPart << 32) | value.LowPart;
169
  return 0;
170
 
171
  #else
172
 
173
  int moveMethod;
174
  int res;
175
  switch (origin)
176
  {
177
    case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
178
    case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
179
    case SZ_SEEK_END: moveMethod = SEEK_END; break;
180
    default: return 1;
181
  }
182
  res = fseek(p->file, (long)*pos, moveMethod);
183
  *pos = ftell(p->file);
184
  return res;
185
 
186
  #endif
187
}
188
 
189
WRes File_GetLength(CSzFile *p, UInt64 *length)
190
{
191
  #ifdef USE_WINDOWS_FILE
192
 
193
  DWORD sizeHigh;
194
  DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
195
  if (sizeLow == 0xFFFFFFFF)
196
  {
197
    DWORD res = GetLastError();
198
    if (res != NO_ERROR)
199
      return res;
200
  }
201
  *length = (((UInt64)sizeHigh) << 32) + sizeLow;
202
  return 0;
203
 
204
  #else
205
 
206
  long pos = ftell(p->file);
207
  int res = fseek(p->file, 0, SEEK_END);
208
  *length = ftell(p->file);
209
  fseek(p->file, pos, SEEK_SET);
210
  return res;
211
 
212
  #endif
213
}
214
 
215
 
216
/* ---------- FileSeqInStream ---------- */
217
 
218
static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size)
219
{
220
  CFileSeqInStream *p = (CFileSeqInStream *)pp;
221
  return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
222
}
223
 
224
void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
225
{
226
  p->s.Read = FileSeqInStream_Read;
227
}
228
 
229
 
230
/* ---------- FileInStream ---------- */
231
 
232
static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
233
{
234
  CFileInStream *p = (CFileInStream *)pp;
235
  return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
236
}
237
 
238
static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
239
{
240
  CFileInStream *p = (CFileInStream *)pp;
241
  return File_Seek(&p->file, pos, origin);
242
}
243
 
244
void FileInStream_CreateVTable(CFileInStream *p)
245
{
246
  p->s.Read = FileInStream_Read;
247
  p->s.Seek = FileInStream_Seek;
248
}
249
 
250
 
251
/* ---------- FileOutStream ---------- */
252
 
253
static size_t FileOutStream_Write(void *pp, const void *data, size_t size)
254
{
255
  CFileOutStream *p = (CFileOutStream *)pp;
256
  File_Write(&p->file, data, &size);
257
  return size;
258
}
259
 
260
void FileOutStream_CreateVTable(CFileOutStream *p)
261
{
262
  p->s.Write = FileOutStream_Write;
263
}