Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  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 <errno.h>
  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. }
  287.