7ZItf.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. #include "7Zitf.h"
  2. #include "Precomp.h"
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include "CpuArch.h"
  6. #include "7z.h"
  7. #include "7zAlloc.h"
  8. #include "7zBuf.h"
  9. #include "7zCrc.h"
  10. #include "7zFile.h"
  11. #include "7zVersion.h"
  12. #ifndef USE_WINDOWS_FILE
  13. /* for mkdir */
  14. #ifdef _WIN32
  15. #include <direct.h>
  16. #else
  17. #include <sys/stat.h>
  18. #include <errno.h>
  19. #endif
  20. #endif
  21. extern "C"
  22. {
  23. #define kInputBufSize ((size_t)1 << 18)
  24. static const ISzAlloc g_Alloc = { SzAlloc, SzFree };
  25. static void Print(const char *s)
  26. {
  27. fputs(s, stdout);
  28. }
  29. static int Buf_EnsureSize(CBuf *dest, size_t size)
  30. {
  31. if (dest->size >= size)
  32. return 1;
  33. Buf_Free(dest, &g_Alloc);
  34. return Buf_Create(dest, size, &g_Alloc);
  35. }
  36. static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s
  37. #ifndef _USE_UTF8
  38. , UINT codePage
  39. #endif
  40. )
  41. {
  42. unsigned len = 0;
  43. for (len = 0; s[len] != 0; len++);
  44. #ifndef _USE_UTF8
  45. {
  46. unsigned size = len * 3 + 100;
  47. if (!Buf_EnsureSize(buf, size))
  48. return SZ_ERROR_MEM;
  49. {
  50. buf->data[0] = 0;
  51. if (len != 0)
  52. {
  53. char defaultChar = '_';
  54. BOOL defUsed;
  55. unsigned numChars = 0;
  56. numChars = WideCharToMultiByte(codePage, 0, (LPCWSTR)s, len, (char *)buf->data, size, &defaultChar, &defUsed);
  57. if (numChars == 0 || numChars >= size)
  58. return SZ_ERROR_FAIL;
  59. buf->data[numChars] = 0;
  60. }
  61. return SZ_OK;
  62. }
  63. }
  64. #else
  65. return Utf16_To_Utf8Buf(buf, s, len);
  66. #endif
  67. }
  68. #ifdef _WIN32
  69. #ifndef USE_WINDOWS_FILE
  70. static UINT g_FileCodePage = CP_ACP;
  71. #endif
  72. #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage
  73. #else
  74. #define MY_FILE_CODE_PAGE_PARAM
  75. #endif
  76. static WRes MyCreateDir(const UInt16 *name)
  77. {
  78. #ifdef USE_WINDOWS_FILE
  79. return CreateDirectoryW((LPCWSTR)name, NULL) ? 0 : GetLastError();
  80. #else
  81. CBuf buf;
  82. WRes res;
  83. Buf_Init(&buf);
  84. RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM));
  85. res =
  86. #ifdef _WIN32
  87. _mkdir((const char *)buf.data)
  88. #else
  89. mkdir((const char *)buf.data, 0777)
  90. #endif
  91. == 0 ? 0 : errno;
  92. Buf_Free(&buf, &g_Alloc);
  93. return res;
  94. #endif
  95. }
  96. static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name)
  97. {
  98. #ifdef USE_WINDOWS_FILE
  99. return OutFile_OpenW(p, (LPCWSTR)name);
  100. #else
  101. CBuf buf;
  102. WRes res;
  103. Buf_Init(&buf);
  104. RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM));
  105. res = OutFile_Open(p, (const char *)buf.data);
  106. Buf_Free(&buf, &g_Alloc);
  107. return res;
  108. #endif
  109. }
  110. static SRes PrintString(const UInt16 *s)
  111. {
  112. CBuf buf;
  113. SRes res;
  114. Buf_Init(&buf);
  115. res = Utf16_To_Char(&buf, s
  116. #ifndef _USE_UTF8
  117. , CP_OEMCP
  118. #endif
  119. );
  120. if (res == SZ_OK)
  121. Print((const char *)buf.data);
  122. Buf_Free(&buf, &g_Alloc);
  123. return res;
  124. }
  125. static void UInt64ToStr(UInt64 value, char *s, int numDigits)
  126. {
  127. char temp[32];
  128. int pos = 0;
  129. do
  130. {
  131. temp[pos++] = (char)('0' + (unsigned)(value % 10));
  132. value /= 10;
  133. } while (value != 0);
  134. for (numDigits -= pos; numDigits > 0; numDigits--)
  135. *s++ = ' ';
  136. do
  137. *s++ = temp[--pos];
  138. while (pos);
  139. *s = '\0';
  140. }
  141. #define PERIOD_4 (4 * 365 + 1)
  142. #define PERIOD_100 (PERIOD_4 * 25 - 1)
  143. #define PERIOD_400 (PERIOD_100 * 4 + 1)
  144. static void PrintLF()
  145. {
  146. Print("\n");
  147. }
  148. static void PrintError(const char *s)
  149. {
  150. Print("\nERROR: ");
  151. Print(s);
  152. PrintLF();
  153. }
  154. bool Decompress(const char * file)
  155. {
  156. ISzAlloc allocImp;
  157. ISzAlloc allocTempImp;
  158. CFileInStream archiveStream;
  159. CLookToRead2 lookStream;
  160. CSzArEx db;
  161. SRes res;
  162. UInt16 *temp = NULL;
  163. size_t tempSize = 0;
  164. allocImp = g_Alloc;
  165. allocTempImp = g_Alloc;
  166. if (InFile_Open(&archiveStream.file, file))
  167. {
  168. PrintError("can not open input file");
  169. return 1;
  170. }
  171. FileInStream_CreateVTable(&archiveStream);
  172. LookToRead2_CreateVTable(&lookStream, False);
  173. lookStream.buf = NULL;
  174. res = SZ_OK;
  175. {
  176. lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
  177. if (!lookStream.buf)
  178. res = SZ_ERROR_MEM;
  179. else
  180. {
  181. lookStream.bufSize = kInputBufSize;
  182. lookStream.realStream = &archiveStream.vt;
  183. LookToRead2_Init(&lookStream);
  184. }
  185. }
  186. CrcGenerateTable();
  187. SzArEx_Init(&db);
  188. if (res == SZ_OK)
  189. {
  190. res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
  191. }
  192. if (res == SZ_OK)
  193. {
  194. int fullPaths = 1;
  195. if (res == SZ_OK)
  196. {
  197. UInt32 i;
  198. /*
  199. if you need cache, use these 3 variables.
  200. if you use external function, you can make these variable as static.
  201. */
  202. UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
  203. Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
  204. size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
  205. for (i = 0; i < db.NumFiles; i++)
  206. {
  207. size_t offset = 0;
  208. size_t outSizeProcessed = 0;
  209. // const CSzFileItem *f = db.Files + i;
  210. size_t len;
  211. unsigned isDir = SzArEx_IsDir(&db, i);
  212. if (isDir && !fullPaths)
  213. continue;
  214. len = SzArEx_GetFileNameUtf16(&db, i, NULL);
  215. // len = SzArEx_GetFullNameLen(&db, i);
  216. if (len > tempSize)
  217. {
  218. SzFree(NULL, temp);
  219. tempSize = len;
  220. temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0]));
  221. if (!temp)
  222. {
  223. res = SZ_ERROR_MEM;
  224. break;
  225. }
  226. }
  227. SzArEx_GetFileNameUtf16(&db, i, temp);
  228. res = PrintString(temp);
  229. if (res != SZ_OK)
  230. break;
  231. if (isDir)
  232. Print("/");
  233. else
  234. {
  235. res = SzArEx_Extract(&db, &lookStream.vt, i,
  236. &blockIndex, &outBuffer, &outBufferSize,
  237. &offset, &outSizeProcessed,
  238. &allocImp, &allocTempImp);
  239. if (res != SZ_OK)
  240. break;
  241. }
  242. {
  243. CSzFile outFile;
  244. size_t processedSize;
  245. size_t j;
  246. UInt16 *name = (UInt16 *)temp;
  247. const UInt16 *destPath = (const UInt16 *)name;
  248. for (j = 0; name[j] != 0; j++)
  249. if (name[j] == '/')
  250. {
  251. if (fullPaths)
  252. {
  253. name[j] = 0;
  254. MyCreateDir(name);
  255. name[j] = CHAR_PATH_SEPARATOR;
  256. }
  257. else
  258. destPath = name + j + 1;
  259. }
  260. if (isDir)
  261. {
  262. MyCreateDir(destPath);
  263. PrintLF();
  264. continue;
  265. }
  266. else if (OutFile_OpenUtf16(&outFile, destPath))
  267. {
  268. PrintError("can not open output file");
  269. res = SZ_ERROR_FAIL;
  270. break;
  271. }
  272. processedSize = outSizeProcessed;
  273. if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed)
  274. {
  275. PrintError("can not write output file");
  276. res = SZ_ERROR_FAIL;
  277. break;
  278. }
  279. #ifdef USE_WINDOWS_FILE
  280. {
  281. FILETIME mtime, ctime;
  282. FILETIME *mtimePtr = NULL;
  283. FILETIME *ctimePtr = NULL;
  284. if (SzBitWithVals_Check(&db.MTime, i))
  285. {
  286. const CNtfsFileTime *t = &db.MTime.Vals[i];
  287. mtime.dwLowDateTime = (DWORD)(t->Low);
  288. mtime.dwHighDateTime = (DWORD)(t->High);
  289. mtimePtr = &mtime;
  290. }
  291. if (SzBitWithVals_Check(&db.CTime, i))
  292. {
  293. const CNtfsFileTime *t = &db.CTime.Vals[i];
  294. ctime.dwLowDateTime = (DWORD)(t->Low);
  295. ctime.dwHighDateTime = (DWORD)(t->High);
  296. ctimePtr = &ctime;
  297. }
  298. if (mtimePtr || ctimePtr)
  299. SetFileTime(outFile.handle, ctimePtr, NULL, mtimePtr);
  300. }
  301. #endif
  302. if (File_Close(&outFile))
  303. {
  304. PrintError("can not close output file");
  305. res = SZ_ERROR_FAIL;
  306. break;
  307. }
  308. #ifdef USE_WINDOWS_FILE
  309. if (SzBitWithVals_Check(&db.Attribs, i))
  310. {
  311. UInt32 attrib = db.Attribs.Vals[i];
  312. /* p7zip stores posix attributes in high 16 bits and adds 0x8000 as marker.
  313. We remove posix bits, if we detect posix mode field */
  314. if ((attrib & 0xF0000000) != 0)
  315. attrib &= 0x7FFF;
  316. SetFileAttributesW((LPCWSTR)destPath, attrib);
  317. }
  318. #endif
  319. }
  320. PrintLF();
  321. }
  322. ISzAlloc_Free(&allocImp, outBuffer);
  323. }
  324. }
  325. SzFree(NULL, temp);
  326. SzArEx_Free(&db, &allocImp);
  327. ISzAlloc_Free(&allocImp, lookStream.buf);
  328. File_Close(&archiveStream.file);
  329. return res == SZ_OK;
  330. }
  331. }