Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 13:07:28

0001 /* 7zFile.c -- File IO

0002 2009-11-24 : Igor Pavlov : Public domain */
0003 
0004 #include "7zFile.h"
0005 
0006 #ifndef USE_WINDOWS_FILE
0007 
0008 #ifndef UNDER_CE
0009 #include <cerrno>
0010 #endif
0011 
0012 #else
0013 
0014 /*

0015    ReadFile and WriteFile functions in Windows have BUG:

0016    If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)

0017    from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES

0018    (Insufficient system resources exist to complete the requested service).

0019    Probably in some version of Windows there are problems with other sizes:

0020    for 32 MB (maybe also for 16 MB).

0021    And message can be "Network connection was lost"

0022 */
0023 
0024 #define kChunkSizeMax (1 << 22)
0025 
0026 #endif
0027 
0028 void File_Construct(CSzFile *p) {
0029 #ifdef USE_WINDOWS_FILE
0030   p->handle = INVALID_HANDLE_VALUE;
0031 #else
0032   p->file = nullptr;
0033 #endif
0034 }
0035 
0036 #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
0037 static WRes File_Open(CSzFile *p, const char *name, int writeMode) {
0038 #ifdef USE_WINDOWS_FILE
0039   p->handle = CreateFileA(name,
0040                           writeMode ? GENERIC_WRITE : GENERIC_READ,
0041                           FILE_SHARE_READ,
0042                           NULL,
0043                           writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
0044                           FILE_ATTRIBUTE_NORMAL,
0045                           NULL);
0046   return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
0047 #else
0048   p->file = fopen(name, writeMode ? "wb+" : "rb");
0049   return (p->file != nullptr) ? 0 :
0050 #ifdef UNDER_CE
0051                               2; /* ENOENT */
0052 #else
0053                               errno;
0054 #endif
0055 #endif
0056 }
0057 
0058 WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
0059 WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); }
0060 #endif
0061 
0062 #ifdef USE_WINDOWS_FILE
0063 static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) {
0064   p->handle = CreateFileW(name,
0065                           writeMode ? GENERIC_WRITE : GENERIC_READ,
0066                           FILE_SHARE_READ,
0067                           NULL,
0068                           writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
0069                           FILE_ATTRIBUTE_NORMAL,
0070                           NULL);
0071   return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
0072 }
0073 WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
0074 WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
0075 #endif
0076 
0077 WRes File_Close(CSzFile *p) {
0078 #ifdef USE_WINDOWS_FILE
0079   if (p->handle != INVALID_HANDLE_VALUE) {
0080     if (!CloseHandle(p->handle))
0081       return GetLastError();
0082     p->handle = INVALID_HANDLE_VALUE;
0083   }
0084 #else
0085   if (p->file != nullptr) {
0086     int res = fclose(p->file);
0087     if (res != 0)
0088       return res;
0089     p->file = nullptr;
0090   }
0091 #endif
0092   return 0;
0093 }
0094 
0095 WRes File_Read(CSzFile *p, void *data, size_t *size) {
0096   size_t originalSize = *size;
0097   if (originalSize == 0)
0098     return 0;
0099 
0100 #ifdef USE_WINDOWS_FILE
0101 
0102   *size = 0;
0103   do {
0104     DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
0105     DWORD processed = 0;
0106     BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
0107     data = (void *)((Byte *)data + processed);
0108     originalSize -= processed;
0109     *size += processed;
0110     if (!res)
0111       return GetLastError();
0112     if (processed == 0)
0113       break;
0114   } while (originalSize > 0);
0115   return 0;
0116 
0117 #else
0118 
0119   *size = fread(data, 1, originalSize, p->file);
0120   if (*size == originalSize)
0121     return 0;
0122   return ferror(p->file);
0123 
0124 #endif
0125 }
0126 
0127 WRes File_Write(CSzFile *p, const void *data, size_t *size) {
0128   size_t originalSize = *size;
0129   if (originalSize == 0)
0130     return 0;
0131 
0132 #ifdef USE_WINDOWS_FILE
0133 
0134   *size = 0;
0135   do {
0136     DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
0137     DWORD processed = 0;
0138     BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
0139     data = (void *)((Byte *)data + processed);
0140     originalSize -= processed;
0141     *size += processed;
0142     if (!res)
0143       return GetLastError();
0144     if (processed == 0)
0145       break;
0146   } while (originalSize > 0);
0147   return 0;
0148 
0149 #else
0150 
0151   *size = fwrite(data, 1, originalSize, p->file);
0152   if (*size == originalSize)
0153     return 0;
0154   return ferror(p->file);
0155 
0156 #endif
0157 }
0158 
0159 WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) {
0160 #ifdef USE_WINDOWS_FILE
0161 
0162   LARGE_INTEGER value;
0163   DWORD moveMethod;
0164   value.LowPart = (DWORD)*pos;
0165   value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
0166   switch (origin) {
0167     case SZ_SEEK_SET:
0168       moveMethod = FILE_BEGIN;
0169       break;
0170     case SZ_SEEK_CUR:
0171       moveMethod = FILE_CURRENT;
0172       break;
0173     case SZ_SEEK_END:
0174       moveMethod = FILE_END;
0175       break;
0176     default:
0177       return ERROR_INVALID_PARAMETER;
0178   }
0179   value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);
0180   if (value.LowPart == 0xFFFFFFFF) {
0181     WRes res = GetLastError();
0182     if (res != NO_ERROR)
0183       return res;
0184   }
0185   *pos = ((Int64)value.HighPart << 32) | value.LowPart;
0186   return 0;
0187 
0188 #else
0189 
0190   int moveMethod;
0191   int res;
0192   switch (origin) {
0193     case SZ_SEEK_SET:
0194       moveMethod = SEEK_SET;
0195       break;
0196     case SZ_SEEK_CUR:
0197       moveMethod = SEEK_CUR;
0198       break;
0199     case SZ_SEEK_END:
0200       moveMethod = SEEK_END;
0201       break;
0202     default:
0203       return 1;
0204   }
0205   res = fseek(p->file, (long)*pos, moveMethod);
0206   *pos = ftell(p->file);
0207   return res;
0208 
0209 #endif
0210 }
0211 
0212 WRes File_GetLength(CSzFile *p, UInt64 *length) {
0213 #ifdef USE_WINDOWS_FILE
0214 
0215   DWORD sizeHigh;
0216   DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
0217   if (sizeLow == 0xFFFFFFFF) {
0218     DWORD res = GetLastError();
0219     if (res != NO_ERROR)
0220       return res;
0221   }
0222   *length = (((UInt64)sizeHigh) << 32) + sizeLow;
0223   return 0;
0224 
0225 #else
0226 
0227   long pos = ftell(p->file);
0228   int res = fseek(p->file, 0, SEEK_END);
0229   *length = ftell(p->file);
0230   fseek(p->file, pos, SEEK_SET);
0231   return res;
0232 
0233 #endif
0234 }
0235 
0236 /* ---------- FileSeqInStream ---------- */
0237 
0238 static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size) {
0239   CFileSeqInStream *p = (CFileSeqInStream *)pp;
0240   return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
0241 }
0242 
0243 void FileSeqInStream_CreateVTable(CFileSeqInStream *p) { p->s.Read = FileSeqInStream_Read; }
0244 
0245 /* ---------- FileInStream ---------- */
0246 
0247 static SRes FileInStream_Read(void *pp, void *buf, size_t *size) {
0248   CFileInStream *p = (CFileInStream *)pp;
0249   return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
0250 }
0251 
0252 static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin) {
0253   CFileInStream *p = (CFileInStream *)pp;
0254   return File_Seek(&p->file, pos, origin);
0255 }
0256 
0257 void FileInStream_CreateVTable(CFileInStream *p) {
0258   p->s.Read = FileInStream_Read;
0259   p->s.Seek = FileInStream_Seek;
0260 }
0261 
0262 /* ---------- FileOutStream ---------- */
0263 
0264 static size_t FileOutStream_Write(void *pp, const void *data, size_t size) {
0265   CFileOutStream *p = (CFileOutStream *)pp;
0266   File_Write(&p->file, data, &size);
0267   return size;
0268 }
0269 
0270 void FileOutStream_CreateVTable(CFileOutStream *p) { p->s.Write = FileOutStream_Write; }