3 Test application for 7z Decoder
4 LZMA SDK 4.43 Copyright (c) 1999-2006 Igor Pavlov (2006-06-04)
12 #define USE_WINDOWS_FUNCTIONS
15 #ifdef USE_WINDOWS_FUNCTIONS
20 #include "7zExtract.h"
22 #include "../../7zCrc.h"
25 #ifdef USE_WINDOWS_FUNCTIONS
26 typedef HANDLE MY_FILE_HANDLE;
28 typedef FILE *MY_FILE_HANDLE;
31 void ConvertNumberToString(CFileSize value, char *s)
37 temp[pos++] = (char)('0' + (int)(value % 10));
47 #define PERIOD_4 (4 * 365 + 1)
48 #define PERIOD_100 (PERIOD_4 * 25 - 1)
49 #define PERIOD_400 (PERIOD_100 * 4 + 1)
51 void ConvertFileTimeToString(CArchiveFileTime *ft, char *s)
53 unsigned year, mon, day, hour, min, sec;
54 UInt64 v64 = ft->Low | ((UInt64)ft->High << 32);
55 Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
59 sec = (unsigned)(v64 % 60);
61 min = (unsigned)(v64 % 60);
63 hour = (unsigned)(v64 % 24);
68 year = (unsigned)(1601 + v / PERIOD_400 * 400);
71 temp = (unsigned)(v / PERIOD_100);
75 v -= temp * PERIOD_100;
89 if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
91 for (mon = 1; mon <= 12; mon++)
93 unsigned s = ms[mon - 1];
98 day = (unsigned)v + 1;
99 sprintf(s, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, day, hour, min, sec);
103 #ifdef USE_WINDOWS_FUNCTIONS
105 ReadFile and WriteFile functions in Windows have BUG:
106 If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
107 from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
108 (Insufficient system resources exist to complete the requested service).
110 #define kChunkSizeMax (1 << 24)
113 size_t MyReadFile(MY_FILE_HANDLE file, void *data, size_t size)
117 #ifdef USE_WINDOWS_FUNCTIONS
119 size_t processedSize = 0;
122 DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
123 DWORD processedLoc = 0;
124 BOOL res = ReadFile(file, data, curSize, &processedLoc, NULL);
125 data = (void *)((unsigned char *)data + processedLoc);
126 size -= processedLoc;
127 processedSize += processedLoc;
128 if (!res || processedLoc == 0)
132 return processedSize;
135 return fread(data, 1, size, file);
139 size_t MyWriteFile(MY_FILE_HANDLE file, void *data, size_t size)
143 #ifdef USE_WINDOWS_FUNCTIONS
145 size_t processedSize = 0;
148 DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
149 DWORD processedLoc = 0;
150 BOOL res = WriteFile(file, data, curSize, &processedLoc, NULL);
151 data = (void *)((unsigned char *)data + processedLoc);
152 size -= processedLoc;
153 processedSize += processedLoc;
158 return processedSize;
161 return fwrite(data, 1, size, file);
165 int MyCloseFile(MY_FILE_HANDLE file)
167 #ifdef USE_WINDOWS_FUNCTIONS
168 return (CloseHandle(file) != FALSE) ? 0 : 1;
174 typedef struct _CFileInStream
176 ISzInStream InStream;
182 #define kBufferSize (1 << 12)
183 Byte g_Buffer[kBufferSize];
185 SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize)
187 CFileInStream *s = (CFileInStream *)object;
188 size_t processedSizeLoc;
189 if (maxRequiredSize > kBufferSize)
190 maxRequiredSize = kBufferSize;
191 processedSizeLoc = MyReadFile(s->File, g_Buffer, maxRequiredSize);
193 if (processedSize != 0)
194 *processedSize = processedSizeLoc;
200 SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size, size_t *processedSize)
202 CFileInStream *s = (CFileInStream *)object;
203 size_t processedSizeLoc = MyReadFile(s->File, buffer, size);
204 if (processedSize != 0)
205 *processedSize = processedSizeLoc;
211 SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
213 CFileInStream *s = (CFileInStream *)object;
215 #ifdef USE_WINDOWS_FUNCTIONS
218 value.LowPart = (DWORD)pos;
219 value.HighPart = (LONG)((UInt64)pos >> 32);
220 #ifdef _SZ_FILE_SIZE_32
221 /* VC 6.0 has bug with >> 32 shifts. */
224 value.LowPart = SetFilePointer(s->File, value.LowPart, &value.HighPart, FILE_BEGIN);
225 if (value.LowPart == 0xFFFFFFFF)
226 if(GetLastError() != NO_ERROR)
231 int res = fseek(s->File, (long)pos, SEEK_SET);
238 void PrintError(char *sz)
240 printf("\nERROR: %s\n", sz);
243 int main(int numargs, char *args[])
245 CFileInStream archiveStream;
246 CArchiveDatabaseEx db;
249 ISzAlloc allocTempImp;
251 printf("\n7z ANSI-C Decoder 4.48 Copyright (c) 1999-2007 Igor Pavlov 2007-06-21\n");
255 "\nUsage: 7zDec <command> <archive_name>\n\n"
257 " e: Extract files from archive\n"
258 " l: List contents of archive\n"
259 " t: Test integrity of archive\n");
264 PrintError("incorrect command");
269 #ifdef USE_WINDOWS_FUNCTIONS
270 CreateFile(args[2], GENERIC_READ, FILE_SHARE_READ,
271 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
272 if (archiveStream.File == INVALID_HANDLE_VALUE)
274 archiveStream.File = fopen(args[2], "rb");
275 if (archiveStream.File == 0)
278 PrintError("can not open input file");
282 archiveStream.InStream.Read = SzFileReadImp;
283 archiveStream.InStream.Seek = SzFileSeekImp;
285 allocImp.Alloc = SzAlloc;
286 allocImp.Free = SzFree;
288 allocTempImp.Alloc = SzAllocTemp;
289 allocTempImp.Free = SzFreeTemp;
294 res = SzArchiveOpen(&archiveStream.InStream, &db, &allocImp, &allocTempImp);
297 char *command = args[1];
300 int extractCommand = 0;
301 if (strcmp(command, "l") == 0)
303 if (strcmp(command, "t") == 0)
305 else if (strcmp(command, "e") == 0)
311 for (i = 0; i < db.Database.NumFiles; i++)
313 CFileItem *f = db.Database.Files + i;
315 ConvertNumberToString(f->Size, s);
316 if (f->IsLastWriteTimeDefined)
317 ConvertFileTimeToString(&f->LastWriteTime, t);
321 printf("%10s %s %s\n", s, t, f->Name);
324 else if (testCommand || extractCommand)
329 if you need cache, use these 3 variables.
330 if you use external function, you can make these variable as static.
332 UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
333 Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
334 size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
337 for (i = 0; i < db.Database.NumFiles; i++)
340 size_t outSizeProcessed;
341 CFileItem *f = db.Database.Files + i;
343 printf("Directory ");
348 printf(" %s", f->Name);
354 res = SzExtract(&archiveStream.InStream, &db, i,
355 &blockIndex, &outBuffer, &outBufferSize,
356 &offset, &outSizeProcessed,
357 &allocImp, &allocTempImp);
362 MY_FILE_HANDLE outputHandle;
363 size_t processedSize;
364 char *fileName = f->Name;
365 size_t nameLen = strlen(f->Name);
366 for (; nameLen > 0; nameLen--)
367 if (f->Name[nameLen - 1] == '/')
369 fileName = f->Name + nameLen;
374 #ifdef USE_WINDOWS_FUNCTIONS
375 CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_READ,
376 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
377 if (outputHandle == INVALID_HANDLE_VALUE)
379 fopen(fileName, "wb+");
380 if (outputHandle == 0)
383 PrintError("can not open output file");
387 processedSize = MyWriteFile(outputHandle, outBuffer + offset, outSizeProcessed);
388 if (processedSize != outSizeProcessed)
390 PrintError("can not write output file");
394 if (MyCloseFile(outputHandle))
396 PrintError("can not close output file");
403 allocImp.Free(outBuffer);
407 PrintError("incorrect command");
411 SzArDbExFree(&db, allocImp.Free);
413 MyCloseFile(archiveStream.File);
416 printf("\nEverything is Ok\n");
419 if (res == (SZ_RESULT)SZE_NOTIMPL)
420 PrintError("decoder doesn't support this archive");
421 else if (res == (SZ_RESULT)SZE_OUTOFMEMORY)
422 PrintError("can not allocate memory");
423 else if (res == (SZ_RESULT)SZE_CRC_ERROR)
424 PrintError("CRC error");
426 printf("\nERROR #%d\n", res);