7zMain.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /*
  2. 7zMain.c
  3. Test application for 7z Decoder
  4. LZMA SDK 4.43 Copyright (c) 1999-2006 Igor Pavlov (2006-06-04)
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #ifdef _WIN32
  10. #define USE_WINDOWS_FUNCTIONS
  11. #endif
  12. #ifdef USE_WINDOWS_FUNCTIONS
  13. #include <windows.h>
  14. #endif
  15. #include "7zIn.h"
  16. #include "7zExtract.h"
  17. #include "../../7zCrc.h"
  18. #ifdef USE_WINDOWS_FUNCTIONS
  19. typedef HANDLE MY_FILE_HANDLE;
  20. #else
  21. typedef FILE *MY_FILE_HANDLE;
  22. #endif
  23. void ConvertNumberToString(CFileSize value, char *s)
  24. {
  25. char temp[32];
  26. int pos = 0;
  27. do
  28. {
  29. temp[pos++] = (char)('0' + (int)(value % 10));
  30. value /= 10;
  31. }
  32. while (value != 0);
  33. do
  34. *s++ = temp[--pos];
  35. while(pos > 0);
  36. *s = '\0';
  37. }
  38. #define PERIOD_4 (4 * 365 + 1)
  39. #define PERIOD_100 (PERIOD_4 * 25 - 1)
  40. #define PERIOD_400 (PERIOD_100 * 4 + 1)
  41. void ConvertFileTimeToString(CArchiveFileTime *ft, char *s)
  42. {
  43. unsigned year, mon, day, hour, min, sec;
  44. UInt64 v64 = ft->Low | ((UInt64)ft->High << 32);
  45. Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  46. unsigned temp;
  47. UInt32 v;
  48. v64 /= 10000000;
  49. sec = (unsigned)(v64 % 60);
  50. v64 /= 60;
  51. min = (unsigned)(v64 % 60);
  52. v64 /= 60;
  53. hour = (unsigned)(v64 % 24);
  54. v64 /= 24;
  55. v = (UInt32)v64;
  56. year = (unsigned)(1601 + v / PERIOD_400 * 400);
  57. v %= PERIOD_400;
  58. temp = (unsigned)(v / PERIOD_100);
  59. if (temp == 4)
  60. temp = 3;
  61. year += temp * 100;
  62. v -= temp * PERIOD_100;
  63. temp = v / PERIOD_4;
  64. if (temp == 25)
  65. temp = 24;
  66. year += temp * 4;
  67. v -= temp * PERIOD_4;
  68. temp = v / 365;
  69. if (temp == 4)
  70. temp = 3;
  71. year += temp;
  72. v -= temp * 365;
  73. if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
  74. ms[1] = 29;
  75. for (mon = 1; mon <= 12; mon++)
  76. {
  77. unsigned s = ms[mon - 1];
  78. if (v < s)
  79. break;
  80. v -= s;
  81. }
  82. day = (unsigned)v + 1;
  83. sprintf(s, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, day, hour, min, sec);
  84. }
  85. #ifdef USE_WINDOWS_FUNCTIONS
  86. /*
  87. ReadFile and WriteFile functions in Windows have BUG:
  88. If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
  89. from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
  90. (Insufficient system resources exist to complete the requested service).
  91. */
  92. #define kChunkSizeMax (1 << 24)
  93. #endif
  94. size_t MyReadFile(MY_FILE_HANDLE file, void *data, size_t size)
  95. {
  96. if (size == 0)
  97. return 0;
  98. #ifdef USE_WINDOWS_FUNCTIONS
  99. {
  100. size_t processedSize = 0;
  101. do
  102. {
  103. DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
  104. DWORD processedLoc = 0;
  105. BOOL res = ReadFile(file, data, curSize, &processedLoc, NULL);
  106. data = (void *)((unsigned char *)data + processedLoc);
  107. size -= processedLoc;
  108. processedSize += processedLoc;
  109. if (!res || processedLoc == 0)
  110. break;
  111. }
  112. while (size > 0);
  113. return processedSize;
  114. }
  115. #else
  116. return fread(data, 1, size, file);
  117. #endif
  118. }
  119. size_t MyWriteFile(MY_FILE_HANDLE file, void *data, size_t size)
  120. {
  121. if (size == 0)
  122. return 0;
  123. #ifdef USE_WINDOWS_FUNCTIONS
  124. {
  125. size_t processedSize = 0;
  126. do
  127. {
  128. DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
  129. DWORD processedLoc = 0;
  130. BOOL res = WriteFile(file, data, curSize, &processedLoc, NULL);
  131. data = (void *)((unsigned char *)data + processedLoc);
  132. size -= processedLoc;
  133. processedSize += processedLoc;
  134. if (!res)
  135. break;
  136. }
  137. while (size > 0);
  138. return processedSize;
  139. }
  140. #else
  141. return fwrite(data, 1, size, file);
  142. #endif
  143. }
  144. int MyCloseFile(MY_FILE_HANDLE file)
  145. {
  146. #ifdef USE_WINDOWS_FUNCTIONS
  147. return (CloseHandle(file) != FALSE) ? 0 : 1;
  148. #else
  149. return fclose(file);
  150. #endif
  151. }
  152. typedef struct _CFileInStream
  153. {
  154. ISzInStream InStream;
  155. MY_FILE_HANDLE File;
  156. } CFileInStream;
  157. #ifdef _LZMA_IN_CB
  158. #define kBufferSize (1 << 12)
  159. Byte g_Buffer[kBufferSize];
  160. SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize)
  161. {
  162. CFileInStream *s = (CFileInStream *)object;
  163. size_t processedSizeLoc;
  164. if (maxRequiredSize > kBufferSize)
  165. maxRequiredSize = kBufferSize;
  166. processedSizeLoc = MyReadFile(s->File, g_Buffer, maxRequiredSize);
  167. *buffer = g_Buffer;
  168. if (processedSize != 0)
  169. *processedSize = processedSizeLoc;
  170. return SZ_OK;
  171. }
  172. #else
  173. SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size, size_t *processedSize)
  174. {
  175. CFileInStream *s = (CFileInStream *)object;
  176. size_t processedSizeLoc = MyReadFile(s->File, buffer, size);
  177. if (processedSize != 0)
  178. *processedSize = processedSizeLoc;
  179. return SZ_OK;
  180. }
  181. #endif
  182. SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
  183. {
  184. CFileInStream *s = (CFileInStream *)object;
  185. #ifdef USE_WINDOWS_FUNCTIONS
  186. {
  187. LARGE_INTEGER value;
  188. value.LowPart = (DWORD)pos;
  189. value.HighPart = (LONG)((UInt64)pos >> 32);
  190. #ifdef _SZ_FILE_SIZE_32
  191. /* VC 6.0 has bug with >> 32 shifts. */
  192. value.HighPart = 0;
  193. #endif
  194. value.LowPart = SetFilePointer(s->File, value.LowPart, &value.HighPart, FILE_BEGIN);
  195. if (value.LowPart == 0xFFFFFFFF)
  196. if(GetLastError() != NO_ERROR)
  197. return SZE_FAIL;
  198. return SZ_OK;
  199. }
  200. #else
  201. int res = fseek(s->File, (long)pos, SEEK_SET);
  202. if (res == 0)
  203. return SZ_OK;
  204. return SZE_FAIL;
  205. #endif
  206. }
  207. void PrintError(char *sz)
  208. {
  209. printf("\nERROR: %s\n", sz);
  210. }
  211. int main(int numargs, char *args[])
  212. {
  213. CFileInStream archiveStream;
  214. CArchiveDatabaseEx db;
  215. SZ_RESULT res;
  216. ISzAlloc allocImp;
  217. ISzAlloc allocTempImp;
  218. printf("\n7z ANSI-C Decoder 4.48 Copyright (c) 1999-2007 Igor Pavlov 2007-06-21\n");
  219. if (numargs == 1)
  220. {
  221. printf(
  222. "\nUsage: 7zDec <command> <archive_name>\n\n"
  223. "<Commands>\n"
  224. " e: Extract files from archive\n"
  225. " l: List contents of archive\n"
  226. " t: Test integrity of archive\n");
  227. return 0;
  228. }
  229. if (numargs < 3)
  230. {
  231. PrintError("incorrect command");
  232. return 1;
  233. }
  234. archiveStream.File =
  235. #ifdef USE_WINDOWS_FUNCTIONS
  236. CreateFile(args[2], GENERIC_READ, FILE_SHARE_READ,
  237. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  238. if (archiveStream.File == INVALID_HANDLE_VALUE)
  239. #else
  240. archiveStream.File = fopen(args[2], "rb");
  241. if (archiveStream.File == 0)
  242. #endif
  243. {
  244. PrintError("can not open input file");
  245. return 1;
  246. }
  247. archiveStream.InStream.Read = SzFileReadImp;
  248. archiveStream.InStream.Seek = SzFileSeekImp;
  249. allocImp.Alloc = SzAlloc;
  250. allocImp.Free = SzFree;
  251. allocTempImp.Alloc = SzAllocTemp;
  252. allocTempImp.Free = SzFreeTemp;
  253. CrcGenerateTable();
  254. SzArDbExInit(&db);
  255. res = SzArchiveOpen(&archiveStream.InStream, &db, &allocImp, &allocTempImp);
  256. if (res == SZ_OK)
  257. {
  258. char *command = args[1];
  259. int listCommand = 0;
  260. int testCommand = 0;
  261. int extractCommand = 0;
  262. if (strcmp(command, "l") == 0)
  263. listCommand = 1;
  264. if (strcmp(command, "t") == 0)
  265. testCommand = 1;
  266. else if (strcmp(command, "e") == 0)
  267. extractCommand = 1;
  268. if (listCommand)
  269. {
  270. UInt32 i;
  271. for (i = 0; i < db.Database.NumFiles; i++)
  272. {
  273. CFileItem *f = db.Database.Files + i;
  274. char s[32], t[32];
  275. ConvertNumberToString(f->Size, s);
  276. if (f->IsLastWriteTimeDefined)
  277. ConvertFileTimeToString(&f->LastWriteTime, t);
  278. else
  279. strcpy(t, " ");
  280. printf("%10s %s %s\n", s, t, f->Name);
  281. }
  282. }
  283. else if (testCommand || extractCommand)
  284. {
  285. UInt32 i;
  286. /*
  287. if you need cache, use these 3 variables.
  288. if you use external function, you can make these variable as static.
  289. */
  290. UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
  291. Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
  292. size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
  293. printf("\n");
  294. for (i = 0; i < db.Database.NumFiles; i++)
  295. {
  296. size_t offset;
  297. size_t outSizeProcessed;
  298. CFileItem *f = db.Database.Files + i;
  299. if (f->IsDirectory)
  300. printf("Directory ");
  301. else
  302. printf(testCommand ?
  303. "Testing ":
  304. "Extracting");
  305. printf(" %s", f->Name);
  306. if (f->IsDirectory)
  307. {
  308. printf("\n");
  309. continue;
  310. }
  311. res = SzExtract(&archiveStream.InStream, &db, i,
  312. &blockIndex, &outBuffer, &outBufferSize,
  313. &offset, &outSizeProcessed,
  314. &allocImp, &allocTempImp);
  315. if (res != SZ_OK)
  316. break;
  317. if (!testCommand)
  318. {
  319. MY_FILE_HANDLE outputHandle;
  320. size_t processedSize;
  321. char *fileName = f->Name;
  322. size_t nameLen = strlen(f->Name);
  323. for (; nameLen > 0; nameLen--)
  324. if (f->Name[nameLen - 1] == '/')
  325. {
  326. fileName = f->Name + nameLen;
  327. break;
  328. }
  329. outputHandle =
  330. #ifdef USE_WINDOWS_FUNCTIONS
  331. CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_READ,
  332. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  333. if (outputHandle == INVALID_HANDLE_VALUE)
  334. #else
  335. fopen(fileName, "wb+");
  336. if (outputHandle == 0)
  337. #endif
  338. {
  339. PrintError("can not open output file");
  340. res = SZE_FAIL;
  341. break;
  342. }
  343. processedSize = MyWriteFile(outputHandle, outBuffer + offset, outSizeProcessed);
  344. if (processedSize != outSizeProcessed)
  345. {
  346. PrintError("can not write output file");
  347. res = SZE_FAIL;
  348. break;
  349. }
  350. if (MyCloseFile(outputHandle))
  351. {
  352. PrintError("can not close output file");
  353. res = SZE_FAIL;
  354. break;
  355. }
  356. }
  357. printf("\n");
  358. }
  359. allocImp.Free(outBuffer);
  360. }
  361. else
  362. {
  363. PrintError("incorrect command");
  364. res = SZE_FAIL;
  365. }
  366. }
  367. SzArDbExFree(&db, allocImp.Free);
  368. MyCloseFile(archiveStream.File);
  369. if (res == SZ_OK)
  370. {
  371. printf("\nEverything is Ok\n");
  372. return 0;
  373. }
  374. if (res == (SZ_RESULT)SZE_NOTIMPL)
  375. PrintError("decoder doesn't support this archive");
  376. else if (res == (SZ_RESULT)SZE_OUTOFMEMORY)
  377. PrintError("can not allocate memory");
  378. else if (res == (SZ_RESULT)SZE_CRC_ERROR)
  379. PrintError("CRC error");
  380. else
  381. printf("\nERROR #%d\n", res);
  382. return 1;
  383. }