7ZItf.cpp 9.7 KB

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