|
1 /* 7zExtract.c */ |
|
2 |
|
3 #include "7zExtract.h" |
|
4 #include "7zDecode.h" |
|
5 #include "../../7zCrc.h" |
|
6 |
|
7 SZ_RESULT SzExtract( |
|
8 ISzInStream *inStream, |
|
9 CArchiveDatabaseEx *db, |
|
10 UInt32 fileIndex, |
|
11 UInt32 *blockIndex, |
|
12 Byte **outBuffer, |
|
13 size_t *outBufferSize, |
|
14 size_t *offset, |
|
15 size_t *outSizeProcessed, |
|
16 ISzAlloc *allocMain, |
|
17 ISzAlloc *allocTemp) |
|
18 { |
|
19 UInt32 folderIndex = db->FileIndexToFolderIndexMap[fileIndex]; |
|
20 SZ_RESULT res = SZ_OK; |
|
21 *offset = 0; |
|
22 *outSizeProcessed = 0; |
|
23 if (folderIndex == (UInt32)-1) |
|
24 { |
|
25 allocMain->Free(*outBuffer); |
|
26 *blockIndex = folderIndex; |
|
27 *outBuffer = 0; |
|
28 *outBufferSize = 0; |
|
29 return SZ_OK; |
|
30 } |
|
31 |
|
32 if (*outBuffer == 0 || *blockIndex != folderIndex) |
|
33 { |
|
34 CFolder *folder = db->Database.Folders + folderIndex; |
|
35 CFileSize unPackSizeSpec = SzFolderGetUnPackSize(folder); |
|
36 size_t unPackSize = (size_t)unPackSizeSpec; |
|
37 CFileSize startOffset = SzArDbGetFolderStreamPos(db, folderIndex, 0); |
|
38 #ifndef _LZMA_IN_CB |
|
39 Byte *inBuffer = 0; |
|
40 size_t processedSize; |
|
41 CFileSize packSizeSpec; |
|
42 size_t packSize; |
|
43 RINOK(SzArDbGetFolderFullPackSize(db, folderIndex, &packSizeSpec)); |
|
44 packSize = (size_t)packSizeSpec; |
|
45 if (packSize != packSizeSpec) |
|
46 return SZE_OUTOFMEMORY; |
|
47 #endif |
|
48 if (unPackSize != unPackSizeSpec) |
|
49 return SZE_OUTOFMEMORY; |
|
50 *blockIndex = folderIndex; |
|
51 allocMain->Free(*outBuffer); |
|
52 *outBuffer = 0; |
|
53 |
|
54 RINOK(inStream->Seek(inStream, startOffset)); |
|
55 |
|
56 #ifndef _LZMA_IN_CB |
|
57 if (packSize != 0) |
|
58 { |
|
59 inBuffer = (Byte *)allocTemp->Alloc(packSize); |
|
60 if (inBuffer == 0) |
|
61 return SZE_OUTOFMEMORY; |
|
62 } |
|
63 res = inStream->Read(inStream, inBuffer, packSize, &processedSize); |
|
64 if (res == SZ_OK && processedSize != packSize) |
|
65 res = SZE_FAIL; |
|
66 #endif |
|
67 if (res == SZ_OK) |
|
68 { |
|
69 *outBufferSize = unPackSize; |
|
70 if (unPackSize != 0) |
|
71 { |
|
72 *outBuffer = (Byte *)allocMain->Alloc(unPackSize); |
|
73 if (*outBuffer == 0) |
|
74 res = SZE_OUTOFMEMORY; |
|
75 } |
|
76 if (res == SZ_OK) |
|
77 { |
|
78 res = SzDecode(db->Database.PackSizes + |
|
79 db->FolderStartPackStreamIndex[folderIndex], folder, |
|
80 #ifdef _LZMA_IN_CB |
|
81 inStream, startOffset, |
|
82 #else |
|
83 inBuffer, |
|
84 #endif |
|
85 *outBuffer, unPackSize, allocTemp); |
|
86 if (res == SZ_OK) |
|
87 { |
|
88 if (folder->UnPackCRCDefined) |
|
89 { |
|
90 if (CrcCalc(*outBuffer, unPackSize) != folder->UnPackCRC) |
|
91 res = SZE_CRC_ERROR; |
|
92 } |
|
93 } |
|
94 } |
|
95 } |
|
96 #ifndef _LZMA_IN_CB |
|
97 allocTemp->Free(inBuffer); |
|
98 #endif |
|
99 } |
|
100 if (res == SZ_OK) |
|
101 { |
|
102 UInt32 i; |
|
103 CFileItem *fileItem = db->Database.Files + fileIndex; |
|
104 *offset = 0; |
|
105 for(i = db->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) |
|
106 *offset += (UInt32)db->Database.Files[i].Size; |
|
107 *outSizeProcessed = (size_t)fileItem->Size; |
|
108 if (*offset + *outSizeProcessed > *outBufferSize) |
|
109 return SZE_FAIL; |
|
110 { |
|
111 if (fileItem->IsFileCRCDefined) |
|
112 { |
|
113 if (CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->FileCRC) |
|
114 res = SZE_CRC_ERROR; |
|
115 } |
|
116 } |
|
117 } |
|
118 return res; |
|
119 } |