1*f6dc9357SAndroid Build Coastguard Worker // FatHandler.cpp
2*f6dc9357SAndroid Build Coastguard Worker
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker
5*f6dc9357SAndroid Build Coastguard Worker // #include <stdio.h>
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyCom.h"
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringConvert.h"
14*f6dc9357SAndroid Build Coastguard Worker
15*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/TimeUtils.h"
17*f6dc9357SAndroid Build Coastguard Worker
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
20*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
21*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
22*f6dc9357SAndroid Build Coastguard Worker
23*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
24*f6dc9357SAndroid Build Coastguard Worker
25*f6dc9357SAndroid Build Coastguard Worker #include "Common/DummyOutStream.h"
26*f6dc9357SAndroid Build Coastguard Worker
27*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
28*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
29*f6dc9357SAndroid Build Coastguard Worker #define Get16a(p) GetUi16a(p)
30*f6dc9357SAndroid Build Coastguard Worker #define Get32a(p) GetUi32a(p)
31*f6dc9357SAndroid Build Coastguard Worker
32*f6dc9357SAndroid Build Coastguard Worker #define PRF(x) /* x */
33*f6dc9357SAndroid Build Coastguard Worker
34*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
35*f6dc9357SAndroid Build Coastguard Worker namespace NFat {
36*f6dc9357SAndroid Build Coastguard Worker
37*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31;
38*f6dc9357SAndroid Build Coastguard Worker
39*f6dc9357SAndroid Build Coastguard Worker struct CHeader
40*f6dc9357SAndroid Build Coastguard Worker {
41*f6dc9357SAndroid Build Coastguard Worker UInt32 NumSectors;
42*f6dc9357SAndroid Build Coastguard Worker UInt16 NumReservedSectors;
43*f6dc9357SAndroid Build Coastguard Worker Byte NumFats;
44*f6dc9357SAndroid Build Coastguard Worker UInt32 NumFatSectors;
45*f6dc9357SAndroid Build Coastguard Worker UInt32 RootDirSector;
46*f6dc9357SAndroid Build Coastguard Worker UInt32 NumRootDirSectors;
47*f6dc9357SAndroid Build Coastguard Worker UInt32 DataSector;
48*f6dc9357SAndroid Build Coastguard Worker
49*f6dc9357SAndroid Build Coastguard Worker UInt32 FatSize;
50*f6dc9357SAndroid Build Coastguard Worker UInt32 BadCluster;
51*f6dc9357SAndroid Build Coastguard Worker
52*f6dc9357SAndroid Build Coastguard Worker Byte NumFatBits;
53*f6dc9357SAndroid Build Coastguard Worker Byte SectorSizeLog;
54*f6dc9357SAndroid Build Coastguard Worker Byte SectorsPerClusterLog;
55*f6dc9357SAndroid Build Coastguard Worker Byte ClusterSizeLog;
56*f6dc9357SAndroid Build Coastguard Worker
57*f6dc9357SAndroid Build Coastguard Worker UInt16 SectorsPerTrack;
58*f6dc9357SAndroid Build Coastguard Worker UInt16 NumHeads;
59*f6dc9357SAndroid Build Coastguard Worker UInt32 NumHiddenSectors;
60*f6dc9357SAndroid Build Coastguard Worker
61*f6dc9357SAndroid Build Coastguard Worker bool VolFieldsDefined;
62*f6dc9357SAndroid Build Coastguard Worker bool HeadersWarning;
63*f6dc9357SAndroid Build Coastguard Worker
64*f6dc9357SAndroid Build Coastguard Worker UInt32 VolId;
65*f6dc9357SAndroid Build Coastguard Worker // Byte VolName[11];
66*f6dc9357SAndroid Build Coastguard Worker // Byte FileSys[8];
67*f6dc9357SAndroid Build Coastguard Worker
68*f6dc9357SAndroid Build Coastguard Worker // Byte OemName[5];
69*f6dc9357SAndroid Build Coastguard Worker Byte MediaType;
70*f6dc9357SAndroid Build Coastguard Worker
71*f6dc9357SAndroid Build Coastguard Worker // 32-bit FAT
72*f6dc9357SAndroid Build Coastguard Worker UInt16 Flags;
73*f6dc9357SAndroid Build Coastguard Worker UInt16 FsInfoSector;
74*f6dc9357SAndroid Build Coastguard Worker UInt32 RootCluster;
75*f6dc9357SAndroid Build Coastguard Worker
IsFat32NArchive::NFat::CHeader76*f6dc9357SAndroid Build Coastguard Worker bool IsFat32() const { return NumFatBits == 32; }
GetPhySizeNArchive::NFat::CHeader77*f6dc9357SAndroid Build Coastguard Worker UInt64 GetPhySize() const { return (UInt64)NumSectors << SectorSizeLog; }
SectorSizeNArchive::NFat::CHeader78*f6dc9357SAndroid Build Coastguard Worker UInt32 SectorSize() const { return (UInt32)1 << SectorSizeLog; }
ClusterSizeNArchive::NFat::CHeader79*f6dc9357SAndroid Build Coastguard Worker UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; }
ClusterToSectorNArchive::NFat::CHeader80*f6dc9357SAndroid Build Coastguard Worker UInt32 ClusterToSector(UInt32 c) const { return DataSector + ((c - 2) << SectorsPerClusterLog); }
IsEocNArchive::NFat::CHeader81*f6dc9357SAndroid Build Coastguard Worker UInt32 IsEoc(UInt32 c) const { return c > BadCluster; }
IsEocAndUnusedNArchive::NFat::CHeader82*f6dc9357SAndroid Build Coastguard Worker UInt32 IsEocAndUnused(UInt32 c) const { return c > BadCluster && (c & kFatItemUsedByDirMask) == 0; }
IsValidClusterNArchive::NFat::CHeader83*f6dc9357SAndroid Build Coastguard Worker UInt32 IsValidCluster(UInt32 c) const { return c >= 2 && c < FatSize; }
SizeToSectorsNArchive::NFat::CHeader84*f6dc9357SAndroid Build Coastguard Worker UInt32 SizeToSectors(UInt32 size) const { return (size + SectorSize() - 1) >> SectorSizeLog; }
CalcFatSizeInSectorsNArchive::NFat::CHeader85*f6dc9357SAndroid Build Coastguard Worker UInt32 CalcFatSizeInSectors() const { return SizeToSectors((FatSize * (NumFatBits / 4) + 1) / 2); }
86*f6dc9357SAndroid Build Coastguard Worker
GetFatSectorNArchive::NFat::CHeader87*f6dc9357SAndroid Build Coastguard Worker UInt32 GetFatSector() const
88*f6dc9357SAndroid Build Coastguard Worker {
89*f6dc9357SAndroid Build Coastguard Worker UInt32 index = (IsFat32() && (Flags & 0x80) != 0) ? (Flags & 0xF) : 0;
90*f6dc9357SAndroid Build Coastguard Worker if (index > NumFats)
91*f6dc9357SAndroid Build Coastguard Worker index = 0;
92*f6dc9357SAndroid Build Coastguard Worker return NumReservedSectors + index * NumFatSectors;
93*f6dc9357SAndroid Build Coastguard Worker }
94*f6dc9357SAndroid Build Coastguard Worker
GetFilePackSizeNArchive::NFat::CHeader95*f6dc9357SAndroid Build Coastguard Worker UInt64 GetFilePackSize(UInt32 unpackSize) const
96*f6dc9357SAndroid Build Coastguard Worker {
97*f6dc9357SAndroid Build Coastguard Worker UInt64 mask = ClusterSize() - 1;
98*f6dc9357SAndroid Build Coastguard Worker return (unpackSize + mask) & ~mask;
99*f6dc9357SAndroid Build Coastguard Worker }
100*f6dc9357SAndroid Build Coastguard Worker
GetNumClustersNArchive::NFat::CHeader101*f6dc9357SAndroid Build Coastguard Worker UInt32 GetNumClusters(UInt32 size) const
102*f6dc9357SAndroid Build Coastguard Worker { return (UInt32)(((UInt64)size + ClusterSize() - 1) >> ClusterSizeLog); }
103*f6dc9357SAndroid Build Coastguard Worker
104*f6dc9357SAndroid Build Coastguard Worker bool Parse(const Byte *p);
105*f6dc9357SAndroid Build Coastguard Worker };
106*f6dc9357SAndroid Build Coastguard Worker
GetLog(UInt32 num)107*f6dc9357SAndroid Build Coastguard Worker static int GetLog(UInt32 num)
108*f6dc9357SAndroid Build Coastguard Worker {
109*f6dc9357SAndroid Build Coastguard Worker for (int i = 0; i < 31; i++)
110*f6dc9357SAndroid Build Coastguard Worker if (((UInt32)1 << i) == num)
111*f6dc9357SAndroid Build Coastguard Worker return i;
112*f6dc9357SAndroid Build Coastguard Worker return -1;
113*f6dc9357SAndroid Build Coastguard Worker }
114*f6dc9357SAndroid Build Coastguard Worker
115*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kHeaderSize = 512;
116*f6dc9357SAndroid Build Coastguard Worker
117*f6dc9357SAndroid Build Coastguard Worker API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
IsArc_Fat(const Byte * p,size_t size)118*f6dc9357SAndroid Build Coastguard Worker API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size)
119*f6dc9357SAndroid Build Coastguard Worker {
120*f6dc9357SAndroid Build Coastguard Worker if (size < kHeaderSize)
121*f6dc9357SAndroid Build Coastguard Worker return k_IsArc_Res_NEED_MORE;
122*f6dc9357SAndroid Build Coastguard Worker CHeader h;
123*f6dc9357SAndroid Build Coastguard Worker return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO;
124*f6dc9357SAndroid Build Coastguard Worker }
125*f6dc9357SAndroid Build Coastguard Worker
Parse(const Byte * p)126*f6dc9357SAndroid Build Coastguard Worker bool CHeader::Parse(const Byte *p)
127*f6dc9357SAndroid Build Coastguard Worker {
128*f6dc9357SAndroid Build Coastguard Worker if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
129*f6dc9357SAndroid Build Coastguard Worker return false;
130*f6dc9357SAndroid Build Coastguard Worker
131*f6dc9357SAndroid Build Coastguard Worker HeadersWarning = false;
132*f6dc9357SAndroid Build Coastguard Worker
133*f6dc9357SAndroid Build Coastguard Worker int codeOffset = 0;
134*f6dc9357SAndroid Build Coastguard Worker switch (p[0])
135*f6dc9357SAndroid Build Coastguard Worker {
136*f6dc9357SAndroid Build Coastguard Worker case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break;
137*f6dc9357SAndroid Build Coastguard Worker case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break;
138*f6dc9357SAndroid Build Coastguard Worker default: return false;
139*f6dc9357SAndroid Build Coastguard Worker }
140*f6dc9357SAndroid Build Coastguard Worker {
141*f6dc9357SAndroid Build Coastguard Worker {
142*f6dc9357SAndroid Build Coastguard Worker const UInt32 val32 = Get16(p + 11);
143*f6dc9357SAndroid Build Coastguard Worker const int s = GetLog(val32);
144*f6dc9357SAndroid Build Coastguard Worker if (s < 9 || s > 12)
145*f6dc9357SAndroid Build Coastguard Worker return false;
146*f6dc9357SAndroid Build Coastguard Worker SectorSizeLog = (Byte)s;
147*f6dc9357SAndroid Build Coastguard Worker }
148*f6dc9357SAndroid Build Coastguard Worker {
149*f6dc9357SAndroid Build Coastguard Worker const UInt32 val32 = p[13];
150*f6dc9357SAndroid Build Coastguard Worker const int s = GetLog(val32);
151*f6dc9357SAndroid Build Coastguard Worker if (s < 0)
152*f6dc9357SAndroid Build Coastguard Worker return false;
153*f6dc9357SAndroid Build Coastguard Worker SectorsPerClusterLog = (Byte)s;
154*f6dc9357SAndroid Build Coastguard Worker }
155*f6dc9357SAndroid Build Coastguard Worker ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog);
156*f6dc9357SAndroid Build Coastguard Worker if (ClusterSizeLog > 24)
157*f6dc9357SAndroid Build Coastguard Worker return false;
158*f6dc9357SAndroid Build Coastguard Worker }
159*f6dc9357SAndroid Build Coastguard Worker
160*f6dc9357SAndroid Build Coastguard Worker NumReservedSectors = Get16(p + 14);
161*f6dc9357SAndroid Build Coastguard Worker if (NumReservedSectors == 0)
162*f6dc9357SAndroid Build Coastguard Worker return false;
163*f6dc9357SAndroid Build Coastguard Worker
164*f6dc9357SAndroid Build Coastguard Worker NumFats = p[16];
165*f6dc9357SAndroid Build Coastguard Worker if (NumFats < 1 || NumFats > 4)
166*f6dc9357SAndroid Build Coastguard Worker return false;
167*f6dc9357SAndroid Build Coastguard Worker
168*f6dc9357SAndroid Build Coastguard Worker // we also support images that contain 0 in offset field.
169*f6dc9357SAndroid Build Coastguard Worker const bool isOkOffset = (codeOffset == 0)
170*f6dc9357SAndroid Build Coastguard Worker || (codeOffset == (p[0] == 0xEB ? 2 : 3));
171*f6dc9357SAndroid Build Coastguard Worker
172*f6dc9357SAndroid Build Coastguard Worker const UInt16 numRootDirEntries = Get16(p + 17);
173*f6dc9357SAndroid Build Coastguard Worker if (numRootDirEntries == 0)
174*f6dc9357SAndroid Build Coastguard Worker {
175*f6dc9357SAndroid Build Coastguard Worker if (codeOffset < 90 && !isOkOffset)
176*f6dc9357SAndroid Build Coastguard Worker return false;
177*f6dc9357SAndroid Build Coastguard Worker NumFatBits = 32;
178*f6dc9357SAndroid Build Coastguard Worker NumRootDirSectors = 0;
179*f6dc9357SAndroid Build Coastguard Worker }
180*f6dc9357SAndroid Build Coastguard Worker else
181*f6dc9357SAndroid Build Coastguard Worker {
182*f6dc9357SAndroid Build Coastguard Worker // Some FAT12s don't contain VolFields
183*f6dc9357SAndroid Build Coastguard Worker if (codeOffset < 62 - 24 && !isOkOffset)
184*f6dc9357SAndroid Build Coastguard Worker return false;
185*f6dc9357SAndroid Build Coastguard Worker NumFatBits = 0;
186*f6dc9357SAndroid Build Coastguard Worker const UInt32 mask = (1 << (SectorSizeLog - 5)) - 1;
187*f6dc9357SAndroid Build Coastguard Worker if ((numRootDirEntries & mask) != 0)
188*f6dc9357SAndroid Build Coastguard Worker return false;
189*f6dc9357SAndroid Build Coastguard Worker NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5);
190*f6dc9357SAndroid Build Coastguard Worker }
191*f6dc9357SAndroid Build Coastguard Worker
192*f6dc9357SAndroid Build Coastguard Worker NumSectors = Get16(p + 19);
193*f6dc9357SAndroid Build Coastguard Worker if (NumSectors == 0)
194*f6dc9357SAndroid Build Coastguard Worker NumSectors = Get32(p + 32);
195*f6dc9357SAndroid Build Coastguard Worker /*
196*f6dc9357SAndroid Build Coastguard Worker // mkfs.fat could create fat32 image with 16-bit number of sectors.
197*f6dc9357SAndroid Build Coastguard Worker // v23: we allow 16-bit value for number of sectors in fat32.
198*f6dc9357SAndroid Build Coastguard Worker else if (IsFat32())
199*f6dc9357SAndroid Build Coastguard Worker return false;
200*f6dc9357SAndroid Build Coastguard Worker */
201*f6dc9357SAndroid Build Coastguard Worker
202*f6dc9357SAndroid Build Coastguard Worker MediaType = p[21];
203*f6dc9357SAndroid Build Coastguard Worker NumFatSectors = Get16(p + 22);
204*f6dc9357SAndroid Build Coastguard Worker SectorsPerTrack = Get16(p + 24);
205*f6dc9357SAndroid Build Coastguard Worker NumHeads = Get16(p + 26);
206*f6dc9357SAndroid Build Coastguard Worker NumHiddenSectors = Get32(p + 28);
207*f6dc9357SAndroid Build Coastguard Worker
208*f6dc9357SAndroid Build Coastguard Worker // memcpy(OemName, p + 3, 5);
209*f6dc9357SAndroid Build Coastguard Worker
210*f6dc9357SAndroid Build Coastguard Worker int curOffset = 36;
211*f6dc9357SAndroid Build Coastguard Worker p += 36;
212*f6dc9357SAndroid Build Coastguard Worker if (IsFat32())
213*f6dc9357SAndroid Build Coastguard Worker {
214*f6dc9357SAndroid Build Coastguard Worker if (NumFatSectors != 0)
215*f6dc9357SAndroid Build Coastguard Worker return false;
216*f6dc9357SAndroid Build Coastguard Worker NumFatSectors = Get32(p);
217*f6dc9357SAndroid Build Coastguard Worker if (NumFatSectors >= (1 << 24))
218*f6dc9357SAndroid Build Coastguard Worker return false;
219*f6dc9357SAndroid Build Coastguard Worker
220*f6dc9357SAndroid Build Coastguard Worker Flags = Get16(p + 4);
221*f6dc9357SAndroid Build Coastguard Worker if (Get16(p + 6) != 0)
222*f6dc9357SAndroid Build Coastguard Worker return false;
223*f6dc9357SAndroid Build Coastguard Worker RootCluster = Get32(p + 8);
224*f6dc9357SAndroid Build Coastguard Worker FsInfoSector = Get16(p + 12);
225*f6dc9357SAndroid Build Coastguard Worker for (int i = 16; i < 28; i++)
226*f6dc9357SAndroid Build Coastguard Worker if (p[i] != 0)
227*f6dc9357SAndroid Build Coastguard Worker return false;
228*f6dc9357SAndroid Build Coastguard Worker p += 28;
229*f6dc9357SAndroid Build Coastguard Worker curOffset += 28;
230*f6dc9357SAndroid Build Coastguard Worker }
231*f6dc9357SAndroid Build Coastguard Worker
232*f6dc9357SAndroid Build Coastguard Worker // DriveNumber = p[0];
233*f6dc9357SAndroid Build Coastguard Worker VolFieldsDefined = false;
234*f6dc9357SAndroid Build Coastguard Worker if (codeOffset >= curOffset + 3)
235*f6dc9357SAndroid Build Coastguard Worker {
236*f6dc9357SAndroid Build Coastguard Worker VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig
237*f6dc9357SAndroid Build Coastguard Worker if (VolFieldsDefined)
238*f6dc9357SAndroid Build Coastguard Worker {
239*f6dc9357SAndroid Build Coastguard Worker if (codeOffset < curOffset + 26)
240*f6dc9357SAndroid Build Coastguard Worker return false;
241*f6dc9357SAndroid Build Coastguard Worker VolId = Get32(p + 3);
242*f6dc9357SAndroid Build Coastguard Worker // memcpy(VolName, p + 7, 11);
243*f6dc9357SAndroid Build Coastguard Worker // memcpy(FileSys, p + 18, 8);
244*f6dc9357SAndroid Build Coastguard Worker }
245*f6dc9357SAndroid Build Coastguard Worker }
246*f6dc9357SAndroid Build Coastguard Worker
247*f6dc9357SAndroid Build Coastguard Worker if (NumFatSectors == 0)
248*f6dc9357SAndroid Build Coastguard Worker return false;
249*f6dc9357SAndroid Build Coastguard Worker RootDirSector = NumReservedSectors + NumFatSectors * NumFats;
250*f6dc9357SAndroid Build Coastguard Worker DataSector = RootDirSector + NumRootDirSectors;
251*f6dc9357SAndroid Build Coastguard Worker if (NumSectors < DataSector)
252*f6dc9357SAndroid Build Coastguard Worker return false;
253*f6dc9357SAndroid Build Coastguard Worker const UInt32 numDataSectors = NumSectors - DataSector;
254*f6dc9357SAndroid Build Coastguard Worker const UInt32 numClusters = numDataSectors >> SectorsPerClusterLog;
255*f6dc9357SAndroid Build Coastguard Worker
256*f6dc9357SAndroid Build Coastguard Worker BadCluster = 0x0FFFFFF7;
257*f6dc9357SAndroid Build Coastguard Worker // v23: we support unusual (< 0xFFF5) numClusters values in fat32 systems
258*f6dc9357SAndroid Build Coastguard Worker if (NumFatBits != 32)
259*f6dc9357SAndroid Build Coastguard Worker {
260*f6dc9357SAndroid Build Coastguard Worker if (numClusters >= 0xFFF5)
261*f6dc9357SAndroid Build Coastguard Worker return false;
262*f6dc9357SAndroid Build Coastguard Worker NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16);
263*f6dc9357SAndroid Build Coastguard Worker BadCluster &= ((1 << NumFatBits) - 1);
264*f6dc9357SAndroid Build Coastguard Worker }
265*f6dc9357SAndroid Build Coastguard Worker
266*f6dc9357SAndroid Build Coastguard Worker FatSize = numClusters + 2;
267*f6dc9357SAndroid Build Coastguard Worker if (FatSize > BadCluster)
268*f6dc9357SAndroid Build Coastguard Worker return false;
269*f6dc9357SAndroid Build Coastguard Worker if (CalcFatSizeInSectors() > NumFatSectors)
270*f6dc9357SAndroid Build Coastguard Worker {
271*f6dc9357SAndroid Build Coastguard Worker /* some third-party program can create such FAT image, where
272*f6dc9357SAndroid Build Coastguard Worker size of FAT table (NumFatSectors from headers) is smaller than
273*f6dc9357SAndroid Build Coastguard Worker required value that is calculated from calculated (FatSize) value.
274*f6dc9357SAndroid Build Coastguard Worker Another FAT unpackers probably ignore that error.
275*f6dc9357SAndroid Build Coastguard Worker v23.02: we also ignore that error, and
276*f6dc9357SAndroid Build Coastguard Worker we recalculate (FatSize) value from (NumFatSectors).
277*f6dc9357SAndroid Build Coastguard Worker New (FatSize) will be smaller than original "full" (FatSize) value.
278*f6dc9357SAndroid Build Coastguard Worker So we will have some unused clusters at the end of archive.
279*f6dc9357SAndroid Build Coastguard Worker */
280*f6dc9357SAndroid Build Coastguard Worker FatSize = (UInt32)(((UInt64)NumFatSectors << (3 + SectorSizeLog)) / NumFatBits);
281*f6dc9357SAndroid Build Coastguard Worker HeadersWarning = true;
282*f6dc9357SAndroid Build Coastguard Worker }
283*f6dc9357SAndroid Build Coastguard Worker return true;
284*f6dc9357SAndroid Build Coastguard Worker }
285*f6dc9357SAndroid Build Coastguard Worker
286*f6dc9357SAndroid Build Coastguard Worker struct CItem
287*f6dc9357SAndroid Build Coastguard Worker {
288*f6dc9357SAndroid Build Coastguard Worker UString UName;
289*f6dc9357SAndroid Build Coastguard Worker char DosName[11];
290*f6dc9357SAndroid Build Coastguard Worker Byte CTime2;
291*f6dc9357SAndroid Build Coastguard Worker UInt32 CTime;
292*f6dc9357SAndroid Build Coastguard Worker UInt32 MTime;
293*f6dc9357SAndroid Build Coastguard Worker UInt16 ADate;
294*f6dc9357SAndroid Build Coastguard Worker Byte Attrib;
295*f6dc9357SAndroid Build Coastguard Worker Byte Flags;
296*f6dc9357SAndroid Build Coastguard Worker UInt32 Size;
297*f6dc9357SAndroid Build Coastguard Worker UInt32 Cluster;
298*f6dc9357SAndroid Build Coastguard Worker Int32 Parent;
299*f6dc9357SAndroid Build Coastguard Worker
300*f6dc9357SAndroid Build Coastguard Worker // NT uses Flags to store Low Case status
NameIsLowNArchive::NFat::CItem301*f6dc9357SAndroid Build Coastguard Worker bool NameIsLow() const { return (Flags & 0x8) != 0; }
ExtIsLowNArchive::NFat::CItem302*f6dc9357SAndroid Build Coastguard Worker bool ExtIsLow() const { return (Flags & 0x10) != 0; }
IsDirNArchive::NFat::CItem303*f6dc9357SAndroid Build Coastguard Worker bool IsDir() const { return (Attrib & 0x10) != 0; }
304*f6dc9357SAndroid Build Coastguard Worker UString GetShortName() const;
305*f6dc9357SAndroid Build Coastguard Worker UString GetName() const;
306*f6dc9357SAndroid Build Coastguard Worker UString GetVolName() const;
307*f6dc9357SAndroid Build Coastguard Worker };
308*f6dc9357SAndroid Build Coastguard Worker
CopyAndTrim(char * dest,const char * src,unsigned size,bool toLower)309*f6dc9357SAndroid Build Coastguard Worker static unsigned CopyAndTrim(char *dest, const char *src, unsigned size, bool toLower)
310*f6dc9357SAndroid Build Coastguard Worker {
311*f6dc9357SAndroid Build Coastguard Worker memcpy(dest, src, size);
312*f6dc9357SAndroid Build Coastguard Worker if (toLower)
313*f6dc9357SAndroid Build Coastguard Worker {
314*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < size; i++)
315*f6dc9357SAndroid Build Coastguard Worker {
316*f6dc9357SAndroid Build Coastguard Worker char c = dest[i];
317*f6dc9357SAndroid Build Coastguard Worker if (c >= 'A' && c <= 'Z')
318*f6dc9357SAndroid Build Coastguard Worker dest[i] = (char)(c + 0x20);
319*f6dc9357SAndroid Build Coastguard Worker }
320*f6dc9357SAndroid Build Coastguard Worker }
321*f6dc9357SAndroid Build Coastguard Worker
322*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = size;;)
323*f6dc9357SAndroid Build Coastguard Worker {
324*f6dc9357SAndroid Build Coastguard Worker if (i == 0)
325*f6dc9357SAndroid Build Coastguard Worker return 0;
326*f6dc9357SAndroid Build Coastguard Worker if (dest[i - 1] != ' ')
327*f6dc9357SAndroid Build Coastguard Worker return i;
328*f6dc9357SAndroid Build Coastguard Worker i--;
329*f6dc9357SAndroid Build Coastguard Worker }
330*f6dc9357SAndroid Build Coastguard Worker }
331*f6dc9357SAndroid Build Coastguard Worker
FatStringToUnicode(const char * s)332*f6dc9357SAndroid Build Coastguard Worker static UString FatStringToUnicode(const char *s)
333*f6dc9357SAndroid Build Coastguard Worker {
334*f6dc9357SAndroid Build Coastguard Worker return MultiByteToUnicodeString(s, CP_OEMCP);
335*f6dc9357SAndroid Build Coastguard Worker }
336*f6dc9357SAndroid Build Coastguard Worker
GetShortName() const337*f6dc9357SAndroid Build Coastguard Worker UString CItem::GetShortName() const
338*f6dc9357SAndroid Build Coastguard Worker {
339*f6dc9357SAndroid Build Coastguard Worker char s[16];
340*f6dc9357SAndroid Build Coastguard Worker unsigned i = CopyAndTrim(s, DosName, 8, NameIsLow());
341*f6dc9357SAndroid Build Coastguard Worker s[i++] = '.';
342*f6dc9357SAndroid Build Coastguard Worker unsigned j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow());
343*f6dc9357SAndroid Build Coastguard Worker if (j == 0)
344*f6dc9357SAndroid Build Coastguard Worker i--;
345*f6dc9357SAndroid Build Coastguard Worker s[i + j] = 0;
346*f6dc9357SAndroid Build Coastguard Worker return FatStringToUnicode(s);
347*f6dc9357SAndroid Build Coastguard Worker }
348*f6dc9357SAndroid Build Coastguard Worker
GetName() const349*f6dc9357SAndroid Build Coastguard Worker UString CItem::GetName() const
350*f6dc9357SAndroid Build Coastguard Worker {
351*f6dc9357SAndroid Build Coastguard Worker if (!UName.IsEmpty())
352*f6dc9357SAndroid Build Coastguard Worker return UName;
353*f6dc9357SAndroid Build Coastguard Worker return GetShortName();
354*f6dc9357SAndroid Build Coastguard Worker }
355*f6dc9357SAndroid Build Coastguard Worker
GetVolName() const356*f6dc9357SAndroid Build Coastguard Worker UString CItem::GetVolName() const
357*f6dc9357SAndroid Build Coastguard Worker {
358*f6dc9357SAndroid Build Coastguard Worker if (!UName.IsEmpty())
359*f6dc9357SAndroid Build Coastguard Worker return UName;
360*f6dc9357SAndroid Build Coastguard Worker char s[12];
361*f6dc9357SAndroid Build Coastguard Worker unsigned i = CopyAndTrim(s, DosName, 11, false);
362*f6dc9357SAndroid Build Coastguard Worker s[i] = 0;
363*f6dc9357SAndroid Build Coastguard Worker return FatStringToUnicode(s);
364*f6dc9357SAndroid Build Coastguard Worker }
365*f6dc9357SAndroid Build Coastguard Worker
366*f6dc9357SAndroid Build Coastguard Worker struct CDatabase
367*f6dc9357SAndroid Build Coastguard Worker {
368*f6dc9357SAndroid Build Coastguard Worker CHeader Header;
369*f6dc9357SAndroid Build Coastguard Worker CObjectVector<CItem> Items;
370*f6dc9357SAndroid Build Coastguard Worker UInt32 *Fat;
371*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<IInStream> InStream;
372*f6dc9357SAndroid Build Coastguard Worker IArchiveOpenCallback *OpenCallback;
373*f6dc9357SAndroid Build Coastguard Worker
374*f6dc9357SAndroid Build Coastguard Worker UInt32 NumFreeClusters;
375*f6dc9357SAndroid Build Coastguard Worker bool VolItemDefined;
376*f6dc9357SAndroid Build Coastguard Worker CItem VolItem;
377*f6dc9357SAndroid Build Coastguard Worker UInt32 NumDirClusters;
378*f6dc9357SAndroid Build Coastguard Worker CByteBuffer ByteBuf;
379*f6dc9357SAndroid Build Coastguard Worker UInt64 NumCurUsedBytes;
380*f6dc9357SAndroid Build Coastguard Worker
381*f6dc9357SAndroid Build Coastguard Worker UInt64 PhySize;
382*f6dc9357SAndroid Build Coastguard Worker
CDatabaseNArchive::NFat::CDatabase383*f6dc9357SAndroid Build Coastguard Worker CDatabase(): Fat(NULL) {}
~CDatabaseNArchive::NFat::CDatabase384*f6dc9357SAndroid Build Coastguard Worker ~CDatabase() { ClearAndClose(); }
385*f6dc9357SAndroid Build Coastguard Worker
386*f6dc9357SAndroid Build Coastguard Worker void Clear();
387*f6dc9357SAndroid Build Coastguard Worker void ClearAndClose();
388*f6dc9357SAndroid Build Coastguard Worker HRESULT OpenProgressFat(bool changeTotal = true);
389*f6dc9357SAndroid Build Coastguard Worker HRESULT OpenProgress();
390*f6dc9357SAndroid Build Coastguard Worker
391*f6dc9357SAndroid Build Coastguard Worker UString GetItemPath(UInt32 index) const;
392*f6dc9357SAndroid Build Coastguard Worker HRESULT Open();
393*f6dc9357SAndroid Build Coastguard Worker HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level);
394*f6dc9357SAndroid Build Coastguard Worker
GetHeadersSizeNArchive::NFat::CDatabase395*f6dc9357SAndroid Build Coastguard Worker UInt64 GetHeadersSize() const
396*f6dc9357SAndroid Build Coastguard Worker {
397*f6dc9357SAndroid Build Coastguard Worker return (UInt64)(Header.DataSector + (NumDirClusters << Header.SectorsPerClusterLog)) << Header.SectorSizeLog;
398*f6dc9357SAndroid Build Coastguard Worker }
399*f6dc9357SAndroid Build Coastguard Worker HRESULT SeekToSector(UInt32 sector);
SeekToClusterNArchive::NFat::CDatabase400*f6dc9357SAndroid Build Coastguard Worker HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); }
401*f6dc9357SAndroid Build Coastguard Worker };
402*f6dc9357SAndroid Build Coastguard Worker
SeekToSector(UInt32 sector)403*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::SeekToSector(UInt32 sector)
404*f6dc9357SAndroid Build Coastguard Worker {
405*f6dc9357SAndroid Build Coastguard Worker return InStream_SeekSet(InStream, (UInt64)sector << Header.SectorSizeLog);
406*f6dc9357SAndroid Build Coastguard Worker }
407*f6dc9357SAndroid Build Coastguard Worker
Clear()408*f6dc9357SAndroid Build Coastguard Worker void CDatabase::Clear()
409*f6dc9357SAndroid Build Coastguard Worker {
410*f6dc9357SAndroid Build Coastguard Worker PhySize = 0;
411*f6dc9357SAndroid Build Coastguard Worker VolItemDefined = false;
412*f6dc9357SAndroid Build Coastguard Worker NumDirClusters = 0;
413*f6dc9357SAndroid Build Coastguard Worker NumCurUsedBytes = 0;
414*f6dc9357SAndroid Build Coastguard Worker
415*f6dc9357SAndroid Build Coastguard Worker Items.Clear();
416*f6dc9357SAndroid Build Coastguard Worker delete []Fat;
417*f6dc9357SAndroid Build Coastguard Worker Fat = NULL;
418*f6dc9357SAndroid Build Coastguard Worker }
419*f6dc9357SAndroid Build Coastguard Worker
ClearAndClose()420*f6dc9357SAndroid Build Coastguard Worker void CDatabase::ClearAndClose()
421*f6dc9357SAndroid Build Coastguard Worker {
422*f6dc9357SAndroid Build Coastguard Worker Clear();
423*f6dc9357SAndroid Build Coastguard Worker InStream.Release();
424*f6dc9357SAndroid Build Coastguard Worker }
425*f6dc9357SAndroid Build Coastguard Worker
OpenProgressFat(bool changeTotal)426*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::OpenProgressFat(bool changeTotal)
427*f6dc9357SAndroid Build Coastguard Worker {
428*f6dc9357SAndroid Build Coastguard Worker if (!OpenCallback)
429*f6dc9357SAndroid Build Coastguard Worker return S_OK;
430*f6dc9357SAndroid Build Coastguard Worker if (changeTotal)
431*f6dc9357SAndroid Build Coastguard Worker {
432*f6dc9357SAndroid Build Coastguard Worker const UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) +
433*f6dc9357SAndroid Build Coastguard Worker ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog);
434*f6dc9357SAndroid Build Coastguard Worker RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes))
435*f6dc9357SAndroid Build Coastguard Worker }
436*f6dc9357SAndroid Build Coastguard Worker return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes);
437*f6dc9357SAndroid Build Coastguard Worker }
438*f6dc9357SAndroid Build Coastguard Worker
OpenProgress()439*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::OpenProgress()
440*f6dc9357SAndroid Build Coastguard Worker {
441*f6dc9357SAndroid Build Coastguard Worker if (!OpenCallback)
442*f6dc9357SAndroid Build Coastguard Worker return S_OK;
443*f6dc9357SAndroid Build Coastguard Worker UInt64 numItems = Items.Size();
444*f6dc9357SAndroid Build Coastguard Worker return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes);
445*f6dc9357SAndroid Build Coastguard Worker }
446*f6dc9357SAndroid Build Coastguard Worker
GetItemPath(UInt32 index) const447*f6dc9357SAndroid Build Coastguard Worker UString CDatabase::GetItemPath(UInt32 index) const
448*f6dc9357SAndroid Build Coastguard Worker {
449*f6dc9357SAndroid Build Coastguard Worker const CItem *item = &Items[index];
450*f6dc9357SAndroid Build Coastguard Worker UString name = item->GetName();
451*f6dc9357SAndroid Build Coastguard Worker for (;;)
452*f6dc9357SAndroid Build Coastguard Worker {
453*f6dc9357SAndroid Build Coastguard Worker index = (UInt32)item->Parent;
454*f6dc9357SAndroid Build Coastguard Worker if (item->Parent < 0)
455*f6dc9357SAndroid Build Coastguard Worker return name;
456*f6dc9357SAndroid Build Coastguard Worker item = &Items[index];
457*f6dc9357SAndroid Build Coastguard Worker name.InsertAtFront(WCHAR_PATH_SEPARATOR);
458*f6dc9357SAndroid Build Coastguard Worker if (item->UName.IsEmpty())
459*f6dc9357SAndroid Build Coastguard Worker name.Insert(0, item->GetShortName());
460*f6dc9357SAndroid Build Coastguard Worker else
461*f6dc9357SAndroid Build Coastguard Worker name.Insert(0, item->UName);
462*f6dc9357SAndroid Build Coastguard Worker }
463*f6dc9357SAndroid Build Coastguard Worker }
464*f6dc9357SAndroid Build Coastguard Worker
AddSubStringToName(wchar_t * dest,const Byte * p,unsigned numChars)465*f6dc9357SAndroid Build Coastguard Worker static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, unsigned numChars)
466*f6dc9357SAndroid Build Coastguard Worker {
467*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < numChars; i++)
468*f6dc9357SAndroid Build Coastguard Worker {
469*f6dc9357SAndroid Build Coastguard Worker wchar_t c = Get16(p + i * 2);
470*f6dc9357SAndroid Build Coastguard Worker if (c != 0 && c != 0xFFFF)
471*f6dc9357SAndroid Build Coastguard Worker *dest++ = c;
472*f6dc9357SAndroid Build Coastguard Worker }
473*f6dc9357SAndroid Build Coastguard Worker *dest = 0;
474*f6dc9357SAndroid Build Coastguard Worker return dest;
475*f6dc9357SAndroid Build Coastguard Worker }
476*f6dc9357SAndroid Build Coastguard Worker
ReadDir(Int32 parent,UInt32 cluster,unsigned level)477*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level)
478*f6dc9357SAndroid Build Coastguard Worker {
479*f6dc9357SAndroid Build Coastguard Worker unsigned startIndex = Items.Size();
480*f6dc9357SAndroid Build Coastguard Worker if (startIndex >= (1 << 30) || level > 256)
481*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
482*f6dc9357SAndroid Build Coastguard Worker
483*f6dc9357SAndroid Build Coastguard Worker UInt32 sectorIndex = 0;
484*f6dc9357SAndroid Build Coastguard Worker UInt32 blockSize = Header.ClusterSize();
485*f6dc9357SAndroid Build Coastguard Worker bool clusterMode = (Header.IsFat32() || parent >= 0);
486*f6dc9357SAndroid Build Coastguard Worker if (!clusterMode)
487*f6dc9357SAndroid Build Coastguard Worker {
488*f6dc9357SAndroid Build Coastguard Worker blockSize = Header.SectorSize();
489*f6dc9357SAndroid Build Coastguard Worker RINOK(SeekToSector(Header.RootDirSector))
490*f6dc9357SAndroid Build Coastguard Worker }
491*f6dc9357SAndroid Build Coastguard Worker
492*f6dc9357SAndroid Build Coastguard Worker ByteBuf.Alloc(blockSize);
493*f6dc9357SAndroid Build Coastguard Worker UString curName;
494*f6dc9357SAndroid Build Coastguard Worker int checkSum = -1;
495*f6dc9357SAndroid Build Coastguard Worker int numLongRecords = -1;
496*f6dc9357SAndroid Build Coastguard Worker
497*f6dc9357SAndroid Build Coastguard Worker for (UInt32 pos = blockSize;; pos += 32)
498*f6dc9357SAndroid Build Coastguard Worker {
499*f6dc9357SAndroid Build Coastguard Worker if (pos == blockSize)
500*f6dc9357SAndroid Build Coastguard Worker {
501*f6dc9357SAndroid Build Coastguard Worker pos = 0;
502*f6dc9357SAndroid Build Coastguard Worker
503*f6dc9357SAndroid Build Coastguard Worker if ((NumDirClusters & 0xFF) == 0)
504*f6dc9357SAndroid Build Coastguard Worker {
505*f6dc9357SAndroid Build Coastguard Worker RINOK(OpenProgress())
506*f6dc9357SAndroid Build Coastguard Worker }
507*f6dc9357SAndroid Build Coastguard Worker
508*f6dc9357SAndroid Build Coastguard Worker if (clusterMode)
509*f6dc9357SAndroid Build Coastguard Worker {
510*f6dc9357SAndroid Build Coastguard Worker if (Header.IsEoc(cluster))
511*f6dc9357SAndroid Build Coastguard Worker break;
512*f6dc9357SAndroid Build Coastguard Worker if (!Header.IsValidCluster(cluster))
513*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
514*f6dc9357SAndroid Build Coastguard Worker PRF(printf("\nCluster = %4X", cluster));
515*f6dc9357SAndroid Build Coastguard Worker RINOK(SeekToCluster(cluster))
516*f6dc9357SAndroid Build Coastguard Worker const UInt32 newCluster = Fat[cluster];
517*f6dc9357SAndroid Build Coastguard Worker if ((newCluster & kFatItemUsedByDirMask) != 0)
518*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
519*f6dc9357SAndroid Build Coastguard Worker Fat[cluster] |= kFatItemUsedByDirMask;
520*f6dc9357SAndroid Build Coastguard Worker cluster = newCluster;
521*f6dc9357SAndroid Build Coastguard Worker NumDirClusters++;
522*f6dc9357SAndroid Build Coastguard Worker NumCurUsedBytes += Header.ClusterSize();
523*f6dc9357SAndroid Build Coastguard Worker }
524*f6dc9357SAndroid Build Coastguard Worker else if (sectorIndex++ >= Header.NumRootDirSectors)
525*f6dc9357SAndroid Build Coastguard Worker break;
526*f6dc9357SAndroid Build Coastguard Worker
527*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize))
528*f6dc9357SAndroid Build Coastguard Worker }
529*f6dc9357SAndroid Build Coastguard Worker
530*f6dc9357SAndroid Build Coastguard Worker const Byte *p = ByteBuf + pos;
531*f6dc9357SAndroid Build Coastguard Worker
532*f6dc9357SAndroid Build Coastguard Worker if (p[0] == 0)
533*f6dc9357SAndroid Build Coastguard Worker {
534*f6dc9357SAndroid Build Coastguard Worker /*
535*f6dc9357SAndroid Build Coastguard Worker // FreeDOS formats FAT partition with cluster chain longer than required.
536*f6dc9357SAndroid Build Coastguard Worker if (clusterMode && !Header.IsEoc(cluster))
537*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
538*f6dc9357SAndroid Build Coastguard Worker */
539*f6dc9357SAndroid Build Coastguard Worker break;
540*f6dc9357SAndroid Build Coastguard Worker }
541*f6dc9357SAndroid Build Coastguard Worker
542*f6dc9357SAndroid Build Coastguard Worker if (p[0] == 0xE5)
543*f6dc9357SAndroid Build Coastguard Worker {
544*f6dc9357SAndroid Build Coastguard Worker if (numLongRecords > 0)
545*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
546*f6dc9357SAndroid Build Coastguard Worker continue;
547*f6dc9357SAndroid Build Coastguard Worker }
548*f6dc9357SAndroid Build Coastguard Worker
549*f6dc9357SAndroid Build Coastguard Worker Byte attrib = p[11];
550*f6dc9357SAndroid Build Coastguard Worker if ((attrib & 0x3F) == 0xF)
551*f6dc9357SAndroid Build Coastguard Worker {
552*f6dc9357SAndroid Build Coastguard Worker if (p[0] > 0x7F || Get16(p + 26) != 0)
553*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
554*f6dc9357SAndroid Build Coastguard Worker int longIndex = p[0] & 0x3F;
555*f6dc9357SAndroid Build Coastguard Worker if (longIndex == 0)
556*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
557*f6dc9357SAndroid Build Coastguard Worker bool isLast = (p[0] & 0x40) != 0;
558*f6dc9357SAndroid Build Coastguard Worker if (numLongRecords < 0)
559*f6dc9357SAndroid Build Coastguard Worker {
560*f6dc9357SAndroid Build Coastguard Worker if (!isLast)
561*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
562*f6dc9357SAndroid Build Coastguard Worker numLongRecords = longIndex;
563*f6dc9357SAndroid Build Coastguard Worker }
564*f6dc9357SAndroid Build Coastguard Worker else if (isLast || numLongRecords != longIndex)
565*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
566*f6dc9357SAndroid Build Coastguard Worker
567*f6dc9357SAndroid Build Coastguard Worker numLongRecords--;
568*f6dc9357SAndroid Build Coastguard Worker
569*f6dc9357SAndroid Build Coastguard Worker if (p[12] == 0)
570*f6dc9357SAndroid Build Coastguard Worker {
571*f6dc9357SAndroid Build Coastguard Worker wchar_t nameBuf[14];
572*f6dc9357SAndroid Build Coastguard Worker wchar_t *dest;
573*f6dc9357SAndroid Build Coastguard Worker
574*f6dc9357SAndroid Build Coastguard Worker dest = AddSubStringToName(nameBuf, p + 1, 5);
575*f6dc9357SAndroid Build Coastguard Worker dest = AddSubStringToName(dest, p + 14, 6);
576*f6dc9357SAndroid Build Coastguard Worker AddSubStringToName(dest, p + 28, 2);
577*f6dc9357SAndroid Build Coastguard Worker curName = nameBuf + curName;
578*f6dc9357SAndroid Build Coastguard Worker if (isLast)
579*f6dc9357SAndroid Build Coastguard Worker checkSum = p[13];
580*f6dc9357SAndroid Build Coastguard Worker if (checkSum != p[13])
581*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
582*f6dc9357SAndroid Build Coastguard Worker }
583*f6dc9357SAndroid Build Coastguard Worker }
584*f6dc9357SAndroid Build Coastguard Worker else
585*f6dc9357SAndroid Build Coastguard Worker {
586*f6dc9357SAndroid Build Coastguard Worker if (numLongRecords > 0)
587*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
588*f6dc9357SAndroid Build Coastguard Worker CItem item;
589*f6dc9357SAndroid Build Coastguard Worker memcpy(item.DosName, p, 11);
590*f6dc9357SAndroid Build Coastguard Worker
591*f6dc9357SAndroid Build Coastguard Worker if (checkSum >= 0)
592*f6dc9357SAndroid Build Coastguard Worker {
593*f6dc9357SAndroid Build Coastguard Worker Byte sum = 0;
594*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < 11; i++)
595*f6dc9357SAndroid Build Coastguard Worker sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]);
596*f6dc9357SAndroid Build Coastguard Worker if (sum == checkSum)
597*f6dc9357SAndroid Build Coastguard Worker item.UName = curName;
598*f6dc9357SAndroid Build Coastguard Worker }
599*f6dc9357SAndroid Build Coastguard Worker
600*f6dc9357SAndroid Build Coastguard Worker if (item.DosName[0] == 5)
601*f6dc9357SAndroid Build Coastguard Worker item.DosName[0] = (char)(Byte)0xE5;
602*f6dc9357SAndroid Build Coastguard Worker item.Attrib = attrib;
603*f6dc9357SAndroid Build Coastguard Worker item.Flags = p[12];
604*f6dc9357SAndroid Build Coastguard Worker item.Size = Get32(p + 28);
605*f6dc9357SAndroid Build Coastguard Worker item.Cluster = Get16(p + 26);
606*f6dc9357SAndroid Build Coastguard Worker if (Header.NumFatBits > 16)
607*f6dc9357SAndroid Build Coastguard Worker item.Cluster |= ((UInt32)Get16(p + 20) << 16);
608*f6dc9357SAndroid Build Coastguard Worker else
609*f6dc9357SAndroid Build Coastguard Worker {
610*f6dc9357SAndroid Build Coastguard Worker // OS/2 and WinNT probably can store EA (extended atributes) in that field.
611*f6dc9357SAndroid Build Coastguard Worker }
612*f6dc9357SAndroid Build Coastguard Worker
613*f6dc9357SAndroid Build Coastguard Worker item.CTime = Get32(p + 14);
614*f6dc9357SAndroid Build Coastguard Worker item.CTime2 = p[13];
615*f6dc9357SAndroid Build Coastguard Worker item.ADate = Get16(p + 18);
616*f6dc9357SAndroid Build Coastguard Worker item.MTime = Get32(p + 22);
617*f6dc9357SAndroid Build Coastguard Worker item.Parent = parent;
618*f6dc9357SAndroid Build Coastguard Worker
619*f6dc9357SAndroid Build Coastguard Worker if (attrib == 8)
620*f6dc9357SAndroid Build Coastguard Worker {
621*f6dc9357SAndroid Build Coastguard Worker VolItem = item;
622*f6dc9357SAndroid Build Coastguard Worker VolItemDefined = true;
623*f6dc9357SAndroid Build Coastguard Worker }
624*f6dc9357SAndroid Build Coastguard Worker else
625*f6dc9357SAndroid Build Coastguard Worker if (memcmp(item.DosName, ". ", 11) != 0 &&
626*f6dc9357SAndroid Build Coastguard Worker memcmp(item.DosName, ".. ", 11) != 0)
627*f6dc9357SAndroid Build Coastguard Worker {
628*f6dc9357SAndroid Build Coastguard Worker if (!item.IsDir())
629*f6dc9357SAndroid Build Coastguard Worker NumCurUsedBytes += Header.GetFilePackSize(item.Size);
630*f6dc9357SAndroid Build Coastguard Worker Items.Add(item);
631*f6dc9357SAndroid Build Coastguard Worker PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1)));
632*f6dc9357SAndroid Build Coastguard Worker }
633*f6dc9357SAndroid Build Coastguard Worker numLongRecords = -1;
634*f6dc9357SAndroid Build Coastguard Worker curName.Empty();
635*f6dc9357SAndroid Build Coastguard Worker checkSum = -1;
636*f6dc9357SAndroid Build Coastguard Worker }
637*f6dc9357SAndroid Build Coastguard Worker }
638*f6dc9357SAndroid Build Coastguard Worker
639*f6dc9357SAndroid Build Coastguard Worker unsigned finishIndex = Items.Size();
640*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = startIndex; i < finishIndex; i++)
641*f6dc9357SAndroid Build Coastguard Worker {
642*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[i];
643*f6dc9357SAndroid Build Coastguard Worker if (item.IsDir())
644*f6dc9357SAndroid Build Coastguard Worker {
645*f6dc9357SAndroid Build Coastguard Worker PRF(printf("\n%S", GetItemPath(i)));
646*f6dc9357SAndroid Build Coastguard Worker RINOK(CDatabase::ReadDir((int)i, item.Cluster, level + 1))
647*f6dc9357SAndroid Build Coastguard Worker }
648*f6dc9357SAndroid Build Coastguard Worker }
649*f6dc9357SAndroid Build Coastguard Worker return S_OK;
650*f6dc9357SAndroid Build Coastguard Worker }
651*f6dc9357SAndroid Build Coastguard Worker
Open()652*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::Open()
653*f6dc9357SAndroid Build Coastguard Worker {
654*f6dc9357SAndroid Build Coastguard Worker Clear();
655*f6dc9357SAndroid Build Coastguard Worker bool numFreeClustersDefined = false;
656*f6dc9357SAndroid Build Coastguard Worker {
657*f6dc9357SAndroid Build Coastguard Worker Byte buf[kHeaderSize];
658*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize))
659*f6dc9357SAndroid Build Coastguard Worker if (!Header.Parse(buf))
660*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
661*f6dc9357SAndroid Build Coastguard Worker UInt64 fileSize;
662*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize))
663*f6dc9357SAndroid Build Coastguard Worker
664*f6dc9357SAndroid Build Coastguard Worker /* we comment that check to support truncated images */
665*f6dc9357SAndroid Build Coastguard Worker /*
666*f6dc9357SAndroid Build Coastguard Worker if (fileSize < Header.GetPhySize())
667*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
668*f6dc9357SAndroid Build Coastguard Worker */
669*f6dc9357SAndroid Build Coastguard Worker
670*f6dc9357SAndroid Build Coastguard Worker if (Header.IsFat32())
671*f6dc9357SAndroid Build Coastguard Worker {
672*f6dc9357SAndroid Build Coastguard Worker if (((UInt32)Header.FsInfoSector << Header.SectorSizeLog) + kHeaderSize <= fileSize
673*f6dc9357SAndroid Build Coastguard Worker && SeekToSector(Header.FsInfoSector) == S_OK
674*f6dc9357SAndroid Build Coastguard Worker && ReadStream_FALSE(InStream, buf, kHeaderSize) == S_OK
675*f6dc9357SAndroid Build Coastguard Worker && 0xaa550000 == Get32(buf + 508)
676*f6dc9357SAndroid Build Coastguard Worker && 0x41615252 == Get32(buf)
677*f6dc9357SAndroid Build Coastguard Worker && 0x61417272 == Get32(buf + 484))
678*f6dc9357SAndroid Build Coastguard Worker {
679*f6dc9357SAndroid Build Coastguard Worker NumFreeClusters = Get32(buf + 488);
680*f6dc9357SAndroid Build Coastguard Worker numFreeClustersDefined = (NumFreeClusters <= Header.FatSize);
681*f6dc9357SAndroid Build Coastguard Worker }
682*f6dc9357SAndroid Build Coastguard Worker else
683*f6dc9357SAndroid Build Coastguard Worker Header.HeadersWarning = true;
684*f6dc9357SAndroid Build Coastguard Worker }
685*f6dc9357SAndroid Build Coastguard Worker }
686*f6dc9357SAndroid Build Coastguard Worker
687*f6dc9357SAndroid Build Coastguard Worker // numFreeClustersDefined = false; // to recalculate NumFreeClusters
688*f6dc9357SAndroid Build Coastguard Worker if (!numFreeClustersDefined)
689*f6dc9357SAndroid Build Coastguard Worker NumFreeClusters = 0;
690*f6dc9357SAndroid Build Coastguard Worker
691*f6dc9357SAndroid Build Coastguard Worker CByteBuffer byteBuf;
692*f6dc9357SAndroid Build Coastguard Worker Fat = new UInt32[Header.FatSize];
693*f6dc9357SAndroid Build Coastguard Worker
694*f6dc9357SAndroid Build Coastguard Worker RINOK(OpenProgressFat())
695*f6dc9357SAndroid Build Coastguard Worker RINOK(SeekToSector(Header.GetFatSector()))
696*f6dc9357SAndroid Build Coastguard Worker if (Header.NumFatBits == 32)
697*f6dc9357SAndroid Build Coastguard Worker {
698*f6dc9357SAndroid Build Coastguard Worker const UInt32 kBufSize = (1 << 15);
699*f6dc9357SAndroid Build Coastguard Worker byteBuf.Alloc(kBufSize);
700*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 0;;)
701*f6dc9357SAndroid Build Coastguard Worker {
702*f6dc9357SAndroid Build Coastguard Worker UInt32 size = Header.FatSize - i;
703*f6dc9357SAndroid Build Coastguard Worker if (size == 0)
704*f6dc9357SAndroid Build Coastguard Worker break;
705*f6dc9357SAndroid Build Coastguard Worker const UInt32 kBufSize32 = kBufSize / 4;
706*f6dc9357SAndroid Build Coastguard Worker if (size > kBufSize32)
707*f6dc9357SAndroid Build Coastguard Worker size = kBufSize32;
708*f6dc9357SAndroid Build Coastguard Worker const UInt32 readSize = Header.SizeToSectors(size * 4) << Header.SectorSizeLog;
709*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(InStream, byteBuf, readSize))
710*f6dc9357SAndroid Build Coastguard Worker NumCurUsedBytes += readSize;
711*f6dc9357SAndroid Build Coastguard Worker
712*f6dc9357SAndroid Build Coastguard Worker const UInt32 *src = (const UInt32 *)(const void *)(const Byte *)byteBuf;
713*f6dc9357SAndroid Build Coastguard Worker UInt32 *dest = Fat + i;
714*f6dc9357SAndroid Build Coastguard Worker const UInt32 *srcLim = src + size;
715*f6dc9357SAndroid Build Coastguard Worker if (numFreeClustersDefined)
716*f6dc9357SAndroid Build Coastguard Worker do
717*f6dc9357SAndroid Build Coastguard Worker *dest++ = Get32a(src) & 0x0FFFFFFF;
718*f6dc9357SAndroid Build Coastguard Worker while (++src != srcLim);
719*f6dc9357SAndroid Build Coastguard Worker else
720*f6dc9357SAndroid Build Coastguard Worker {
721*f6dc9357SAndroid Build Coastguard Worker UInt32 numFreeClusters = 0;
722*f6dc9357SAndroid Build Coastguard Worker do
723*f6dc9357SAndroid Build Coastguard Worker {
724*f6dc9357SAndroid Build Coastguard Worker const UInt32 v = Get32a(src) & 0x0FFFFFFF;
725*f6dc9357SAndroid Build Coastguard Worker *dest++ = v;
726*f6dc9357SAndroid Build Coastguard Worker numFreeClusters += (UInt32)(v - 1) >> 31;
727*f6dc9357SAndroid Build Coastguard Worker }
728*f6dc9357SAndroid Build Coastguard Worker while (++src != srcLim);
729*f6dc9357SAndroid Build Coastguard Worker NumFreeClusters += numFreeClusters;
730*f6dc9357SAndroid Build Coastguard Worker }
731*f6dc9357SAndroid Build Coastguard Worker i += size;
732*f6dc9357SAndroid Build Coastguard Worker if ((i & 0xFFFFF) == 0)
733*f6dc9357SAndroid Build Coastguard Worker {
734*f6dc9357SAndroid Build Coastguard Worker RINOK(OpenProgressFat(!numFreeClustersDefined))
735*f6dc9357SAndroid Build Coastguard Worker }
736*f6dc9357SAndroid Build Coastguard Worker }
737*f6dc9357SAndroid Build Coastguard Worker }
738*f6dc9357SAndroid Build Coastguard Worker else
739*f6dc9357SAndroid Build Coastguard Worker {
740*f6dc9357SAndroid Build Coastguard Worker const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog;
741*f6dc9357SAndroid Build Coastguard Worker NumCurUsedBytes += kBufSize;
742*f6dc9357SAndroid Build Coastguard Worker byteBuf.Alloc(kBufSize);
743*f6dc9357SAndroid Build Coastguard Worker Byte *p = byteBuf;
744*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(InStream, p, kBufSize))
745*f6dc9357SAndroid Build Coastguard Worker const UInt32 fatSize = Header.FatSize;
746*f6dc9357SAndroid Build Coastguard Worker UInt32 *fat = &Fat[0];
747*f6dc9357SAndroid Build Coastguard Worker if (Header.NumFatBits == 16)
748*f6dc9357SAndroid Build Coastguard Worker for (UInt32 j = 0; j < fatSize; j++)
749*f6dc9357SAndroid Build Coastguard Worker fat[j] = Get16a(p + j * 2);
750*f6dc9357SAndroid Build Coastguard Worker else
751*f6dc9357SAndroid Build Coastguard Worker for (UInt32 j = 0; j < fatSize; j++)
752*f6dc9357SAndroid Build Coastguard Worker fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF;
753*f6dc9357SAndroid Build Coastguard Worker
754*f6dc9357SAndroid Build Coastguard Worker if (!numFreeClustersDefined)
755*f6dc9357SAndroid Build Coastguard Worker {
756*f6dc9357SAndroid Build Coastguard Worker UInt32 numFreeClusters = 0;
757*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 0; i < fatSize; i++)
758*f6dc9357SAndroid Build Coastguard Worker numFreeClusters += (UInt32)(fat[i] - 1) >> 31;
759*f6dc9357SAndroid Build Coastguard Worker NumFreeClusters = numFreeClusters;
760*f6dc9357SAndroid Build Coastguard Worker }
761*f6dc9357SAndroid Build Coastguard Worker }
762*f6dc9357SAndroid Build Coastguard Worker
763*f6dc9357SAndroid Build Coastguard Worker RINOK(OpenProgressFat())
764*f6dc9357SAndroid Build Coastguard Worker
765*f6dc9357SAndroid Build Coastguard Worker if ((Fat[0] & 0xFF) != Header.MediaType)
766*f6dc9357SAndroid Build Coastguard Worker {
767*f6dc9357SAndroid Build Coastguard Worker // that case can mean error in FAT,
768*f6dc9357SAndroid Build Coastguard Worker // but xdf file: (MediaType == 0xF0 && Fat[0] == 0xFF9)
769*f6dc9357SAndroid Build Coastguard Worker // 19.00: so we use non-strict check
770*f6dc9357SAndroid Build Coastguard Worker if ((Fat[0] & 0xFF) < 0xF0)
771*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
772*f6dc9357SAndroid Build Coastguard Worker }
773*f6dc9357SAndroid Build Coastguard Worker
774*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadDir(-1, Header.RootCluster, 0))
775*f6dc9357SAndroid Build Coastguard Worker
776*f6dc9357SAndroid Build Coastguard Worker PhySize = Header.GetPhySize();
777*f6dc9357SAndroid Build Coastguard Worker return S_OK;
778*f6dc9357SAndroid Build Coastguard Worker }
779*f6dc9357SAndroid Build Coastguard Worker
780*f6dc9357SAndroid Build Coastguard Worker
781*f6dc9357SAndroid Build Coastguard Worker
782*f6dc9357SAndroid Build Coastguard Worker Z7_class_CHandler_final:
783*f6dc9357SAndroid Build Coastguard Worker public IInArchive,
784*f6dc9357SAndroid Build Coastguard Worker public IInArchiveGetStream,
785*f6dc9357SAndroid Build Coastguard Worker public CMyUnknownImp,
786*f6dc9357SAndroid Build Coastguard Worker CDatabase
787*f6dc9357SAndroid Build Coastguard Worker {
788*f6dc9357SAndroid Build Coastguard Worker Z7_IFACES_IMP_UNK_2(IInArchive, IInArchiveGetStream)
789*f6dc9357SAndroid Build Coastguard Worker };
790*f6dc9357SAndroid Build Coastguard Worker
791*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
792*f6dc9357SAndroid Build Coastguard Worker {
793*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
794*f6dc9357SAndroid Build Coastguard Worker *stream = NULL;
795*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[index];
796*f6dc9357SAndroid Build Coastguard Worker CClusterInStream *streamSpec = new CClusterInStream;
797*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
798*f6dc9357SAndroid Build Coastguard Worker streamSpec->Stream = InStream;
799*f6dc9357SAndroid Build Coastguard Worker streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog;
800*f6dc9357SAndroid Build Coastguard Worker streamSpec->BlockSizeLog = Header.ClusterSizeLog;
801*f6dc9357SAndroid Build Coastguard Worker streamSpec->Size = item.Size;
802*f6dc9357SAndroid Build Coastguard Worker
803*f6dc9357SAndroid Build Coastguard Worker const UInt32 numClusters = Header.GetNumClusters(item.Size);
804*f6dc9357SAndroid Build Coastguard Worker streamSpec->Vector.ClearAndReserve(numClusters);
805*f6dc9357SAndroid Build Coastguard Worker UInt32 cluster = item.Cluster;
806*f6dc9357SAndroid Build Coastguard Worker UInt32 size = item.Size;
807*f6dc9357SAndroid Build Coastguard Worker
808*f6dc9357SAndroid Build Coastguard Worker if (size == 0)
809*f6dc9357SAndroid Build Coastguard Worker {
810*f6dc9357SAndroid Build Coastguard Worker if (cluster != 0)
811*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
812*f6dc9357SAndroid Build Coastguard Worker }
813*f6dc9357SAndroid Build Coastguard Worker else
814*f6dc9357SAndroid Build Coastguard Worker {
815*f6dc9357SAndroid Build Coastguard Worker const UInt32 clusterSize = Header.ClusterSize();
816*f6dc9357SAndroid Build Coastguard Worker for (;; size -= clusterSize)
817*f6dc9357SAndroid Build Coastguard Worker {
818*f6dc9357SAndroid Build Coastguard Worker if (!Header.IsValidCluster(cluster))
819*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
820*f6dc9357SAndroid Build Coastguard Worker streamSpec->Vector.AddInReserved(cluster - 2);
821*f6dc9357SAndroid Build Coastguard Worker cluster = Fat[cluster];
822*f6dc9357SAndroid Build Coastguard Worker if (size <= clusterSize)
823*f6dc9357SAndroid Build Coastguard Worker break;
824*f6dc9357SAndroid Build Coastguard Worker }
825*f6dc9357SAndroid Build Coastguard Worker if (!Header.IsEocAndUnused(cluster))
826*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
827*f6dc9357SAndroid Build Coastguard Worker }
828*f6dc9357SAndroid Build Coastguard Worker RINOK(streamSpec->InitAndSeek())
829*f6dc9357SAndroid Build Coastguard Worker *stream = streamTemp.Detach();
830*f6dc9357SAndroid Build Coastguard Worker return S_OK;
831*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
832*f6dc9357SAndroid Build Coastguard Worker }
833*f6dc9357SAndroid Build Coastguard Worker
834*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
835*f6dc9357SAndroid Build Coastguard Worker {
836*f6dc9357SAndroid Build Coastguard Worker kpidPath,
837*f6dc9357SAndroid Build Coastguard Worker kpidIsDir,
838*f6dc9357SAndroid Build Coastguard Worker kpidSize,
839*f6dc9357SAndroid Build Coastguard Worker kpidPackSize,
840*f6dc9357SAndroid Build Coastguard Worker kpidMTime,
841*f6dc9357SAndroid Build Coastguard Worker kpidCTime,
842*f6dc9357SAndroid Build Coastguard Worker kpidATime,
843*f6dc9357SAndroid Build Coastguard Worker kpidAttrib,
844*f6dc9357SAndroid Build Coastguard Worker kpidShortName
845*f6dc9357SAndroid Build Coastguard Worker };
846*f6dc9357SAndroid Build Coastguard Worker
847*f6dc9357SAndroid Build Coastguard Worker enum
848*f6dc9357SAndroid Build Coastguard Worker {
849*f6dc9357SAndroid Build Coastguard Worker kpidNumFats = kpidUserDefined
850*f6dc9357SAndroid Build Coastguard Worker // kpidOemName,
851*f6dc9357SAndroid Build Coastguard Worker // kpidVolName,
852*f6dc9357SAndroid Build Coastguard Worker // kpidFileSysType
853*f6dc9357SAndroid Build Coastguard Worker };
854*f6dc9357SAndroid Build Coastguard Worker
855*f6dc9357SAndroid Build Coastguard Worker static const CStatProp kArcProps[] =
856*f6dc9357SAndroid Build Coastguard Worker {
857*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidFileSystem, VT_BSTR},
858*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidClusterSize, VT_UI4},
859*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidFreeSpace, VT_UI8},
860*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidHeadersSize, VT_UI8},
861*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidMTime, VT_FILETIME},
862*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidVolumeName, VT_BSTR},
863*f6dc9357SAndroid Build Coastguard Worker
864*f6dc9357SAndroid Build Coastguard Worker { "FATs", kpidNumFats, VT_UI4},
865*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidSectorSize, VT_UI4},
866*f6dc9357SAndroid Build Coastguard Worker { NULL, kpidId, VT_UI4},
867*f6dc9357SAndroid Build Coastguard Worker // { "OEM Name", kpidOemName, VT_BSTR},
868*f6dc9357SAndroid Build Coastguard Worker // { "Volume Name", kpidVolName, VT_BSTR},
869*f6dc9357SAndroid Build Coastguard Worker // { "File System Type", kpidFileSysType, VT_BSTR}
870*f6dc9357SAndroid Build Coastguard Worker // { NULL, kpidSectorsPerTrack, VT_UI4},
871*f6dc9357SAndroid Build Coastguard Worker // { NULL, kpidNumHeads, VT_UI4},
872*f6dc9357SAndroid Build Coastguard Worker // { NULL, kpidHiddenSectors, VT_UI4}
873*f6dc9357SAndroid Build Coastguard Worker };
874*f6dc9357SAndroid Build Coastguard Worker
875*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
876*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps_WITH_NAME
877*f6dc9357SAndroid Build Coastguard Worker
878*f6dc9357SAndroid Build Coastguard Worker
879*f6dc9357SAndroid Build Coastguard Worker static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop)
880*f6dc9357SAndroid Build Coastguard Worker {
881*f6dc9357SAndroid Build Coastguard Worker FILETIME localFileTime, utc;
882*f6dc9357SAndroid Build Coastguard Worker if (NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime))
883*f6dc9357SAndroid Build Coastguard Worker if (LocalFileTimeToFileTime(&localFileTime, &utc))
884*f6dc9357SAndroid Build Coastguard Worker {
885*f6dc9357SAndroid Build Coastguard Worker UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
886*f6dc9357SAndroid Build Coastguard Worker t64 += ms10 * 100000;
887*f6dc9357SAndroid Build Coastguard Worker utc.dwLowDateTime = (DWORD)t64;
888*f6dc9357SAndroid Build Coastguard Worker utc.dwHighDateTime = (DWORD)(t64 >> 32);
889*f6dc9357SAndroid Build Coastguard Worker prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_Base + 2);
890*f6dc9357SAndroid Build Coastguard Worker }
891*f6dc9357SAndroid Build Coastguard Worker }
892*f6dc9357SAndroid Build Coastguard Worker
893*f6dc9357SAndroid Build Coastguard Worker /*
894*f6dc9357SAndroid Build Coastguard Worker static void StringToProp(const Byte *src, unsigned size, NWindows::NCOM::CPropVariant &prop)
895*f6dc9357SAndroid Build Coastguard Worker {
896*f6dc9357SAndroid Build Coastguard Worker char dest[32];
897*f6dc9357SAndroid Build Coastguard Worker memcpy(dest, src, size);
898*f6dc9357SAndroid Build Coastguard Worker dest[size] = 0;
899*f6dc9357SAndroid Build Coastguard Worker prop = FatStringToUnicode(dest);
900*f6dc9357SAndroid Build Coastguard Worker }
901*f6dc9357SAndroid Build Coastguard Worker
902*f6dc9357SAndroid Build Coastguard Worker #define STRING_TO_PROP(s, p) StringToProp(s, sizeof(s), prop)
903*f6dc9357SAndroid Build Coastguard Worker */
904*f6dc9357SAndroid Build Coastguard Worker
905*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
906*f6dc9357SAndroid Build Coastguard Worker {
907*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
908*f6dc9357SAndroid Build Coastguard Worker NWindows::NCOM::CPropVariant prop;
909*f6dc9357SAndroid Build Coastguard Worker switch (propID)
910*f6dc9357SAndroid Build Coastguard Worker {
911*f6dc9357SAndroid Build Coastguard Worker case kpidFileSystem:
912*f6dc9357SAndroid Build Coastguard Worker {
913*f6dc9357SAndroid Build Coastguard Worker char s[16];
914*f6dc9357SAndroid Build Coastguard Worker s[0] = 'F';
915*f6dc9357SAndroid Build Coastguard Worker s[1] = 'A';
916*f6dc9357SAndroid Build Coastguard Worker s[2] = 'T';
917*f6dc9357SAndroid Build Coastguard Worker ConvertUInt32ToString(Header.NumFatBits, s + 3);
918*f6dc9357SAndroid Build Coastguard Worker prop = s;
919*f6dc9357SAndroid Build Coastguard Worker break;
920*f6dc9357SAndroid Build Coastguard Worker }
921*f6dc9357SAndroid Build Coastguard Worker case kpidClusterSize: prop = Header.ClusterSize(); break;
922*f6dc9357SAndroid Build Coastguard Worker case kpidPhySize: prop = PhySize; break;
923*f6dc9357SAndroid Build Coastguard Worker case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
924*f6dc9357SAndroid Build Coastguard Worker case kpidHeadersSize: prop = GetHeadersSize(); break;
925*f6dc9357SAndroid Build Coastguard Worker case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break;
926*f6dc9357SAndroid Build Coastguard Worker case kpidShortComment:
927*f6dc9357SAndroid Build Coastguard Worker case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
928*f6dc9357SAndroid Build Coastguard Worker case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
929*f6dc9357SAndroid Build Coastguard Worker case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
930*f6dc9357SAndroid Build Coastguard Worker // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
931*f6dc9357SAndroid Build Coastguard Worker // case kpidNumHeads: prop = Header.NumHeads; break;
932*f6dc9357SAndroid Build Coastguard Worker // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break;
933*f6dc9357SAndroid Build Coastguard Worker case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break;
934*f6dc9357SAndroid Build Coastguard Worker // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break;
935*f6dc9357SAndroid Build Coastguard Worker // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break;
936*f6dc9357SAndroid Build Coastguard Worker // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
937*f6dc9357SAndroid Build Coastguard Worker case kpidWarningFlags:
938*f6dc9357SAndroid Build Coastguard Worker {
939*f6dc9357SAndroid Build Coastguard Worker UInt32 v = 0;
940*f6dc9357SAndroid Build Coastguard Worker if (Header.HeadersWarning) v |= kpv_ErrorFlags_HeadersError;
941*f6dc9357SAndroid Build Coastguard Worker if (v != 0)
942*f6dc9357SAndroid Build Coastguard Worker prop = v;
943*f6dc9357SAndroid Build Coastguard Worker break;
944*f6dc9357SAndroid Build Coastguard Worker }
945*f6dc9357SAndroid Build Coastguard Worker }
946*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
947*f6dc9357SAndroid Build Coastguard Worker return S_OK;
948*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
949*f6dc9357SAndroid Build Coastguard Worker }
950*f6dc9357SAndroid Build Coastguard Worker
951*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
952*f6dc9357SAndroid Build Coastguard Worker {
953*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
954*f6dc9357SAndroid Build Coastguard Worker NWindows::NCOM::CPropVariant prop;
955*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[index];
956*f6dc9357SAndroid Build Coastguard Worker switch (propID)
957*f6dc9357SAndroid Build Coastguard Worker {
958*f6dc9357SAndroid Build Coastguard Worker case kpidPath: prop = GetItemPath(index); break;
959*f6dc9357SAndroid Build Coastguard Worker case kpidShortName: prop = item.GetShortName(); break;
960*f6dc9357SAndroid Build Coastguard Worker case kpidIsDir: prop = item.IsDir(); break;
961*f6dc9357SAndroid Build Coastguard Worker case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break;
962*f6dc9357SAndroid Build Coastguard Worker case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
963*f6dc9357SAndroid Build Coastguard Worker case kpidATime: PropVariant_SetFrom_DosTime(prop, ((UInt32)item.ADate << 16)); break;
964*f6dc9357SAndroid Build Coastguard Worker case kpidAttrib: prop = (UInt32)item.Attrib; break;
965*f6dc9357SAndroid Build Coastguard Worker case kpidSize: if (!item.IsDir()) prop = item.Size; break;
966*f6dc9357SAndroid Build Coastguard Worker case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break;
967*f6dc9357SAndroid Build Coastguard Worker }
968*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
969*f6dc9357SAndroid Build Coastguard Worker return S_OK;
970*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
971*f6dc9357SAndroid Build Coastguard Worker }
972*f6dc9357SAndroid Build Coastguard Worker
973*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
974*f6dc9357SAndroid Build Coastguard Worker {
975*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
976*f6dc9357SAndroid Build Coastguard Worker {
977*f6dc9357SAndroid Build Coastguard Worker OpenCallback = callback;
978*f6dc9357SAndroid Build Coastguard Worker InStream = stream;
979*f6dc9357SAndroid Build Coastguard Worker HRESULT res;
980*f6dc9357SAndroid Build Coastguard Worker try
981*f6dc9357SAndroid Build Coastguard Worker {
982*f6dc9357SAndroid Build Coastguard Worker res = CDatabase::Open();
983*f6dc9357SAndroid Build Coastguard Worker if (res == S_OK)
984*f6dc9357SAndroid Build Coastguard Worker return S_OK;
985*f6dc9357SAndroid Build Coastguard Worker }
986*f6dc9357SAndroid Build Coastguard Worker catch(...)
987*f6dc9357SAndroid Build Coastguard Worker {
988*f6dc9357SAndroid Build Coastguard Worker Close();
989*f6dc9357SAndroid Build Coastguard Worker throw;
990*f6dc9357SAndroid Build Coastguard Worker }
991*f6dc9357SAndroid Build Coastguard Worker Close();
992*f6dc9357SAndroid Build Coastguard Worker return res;
993*f6dc9357SAndroid Build Coastguard Worker }
994*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
995*f6dc9357SAndroid Build Coastguard Worker }
996*f6dc9357SAndroid Build Coastguard Worker
997*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
998*f6dc9357SAndroid Build Coastguard Worker {
999*f6dc9357SAndroid Build Coastguard Worker ClearAndClose();
1000*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1001*f6dc9357SAndroid Build Coastguard Worker }
1002*f6dc9357SAndroid Build Coastguard Worker
1003*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1004*f6dc9357SAndroid Build Coastguard Worker Int32 testMode, IArchiveExtractCallback *extractCallback))
1005*f6dc9357SAndroid Build Coastguard Worker {
1006*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
1007*f6dc9357SAndroid Build Coastguard Worker const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
1008*f6dc9357SAndroid Build Coastguard Worker if (allFilesMode)
1009*f6dc9357SAndroid Build Coastguard Worker numItems = Items.Size();
1010*f6dc9357SAndroid Build Coastguard Worker if (numItems == 0)
1011*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1012*f6dc9357SAndroid Build Coastguard Worker UInt32 i;
1013*f6dc9357SAndroid Build Coastguard Worker UInt64 totalSize = 0;
1014*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numItems; i++)
1015*f6dc9357SAndroid Build Coastguard Worker {
1016*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[allFilesMode ? i : indices[i]];
1017*f6dc9357SAndroid Build Coastguard Worker if (!item.IsDir())
1018*f6dc9357SAndroid Build Coastguard Worker totalSize += item.Size;
1019*f6dc9357SAndroid Build Coastguard Worker }
1020*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetTotal(totalSize))
1021*f6dc9357SAndroid Build Coastguard Worker
1022*f6dc9357SAndroid Build Coastguard Worker UInt64 totalPackSize;
1023*f6dc9357SAndroid Build Coastguard Worker totalSize = totalPackSize = 0;
1024*f6dc9357SAndroid Build Coastguard Worker
1025*f6dc9357SAndroid Build Coastguard Worker NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
1026*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
1027*f6dc9357SAndroid Build Coastguard Worker
1028*f6dc9357SAndroid Build Coastguard Worker CLocalProgress *lps = new CLocalProgress;
1029*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ICompressProgressInfo> progress = lps;
1030*f6dc9357SAndroid Build Coastguard Worker lps->Init(extractCallback, false);
1031*f6dc9357SAndroid Build Coastguard Worker
1032*f6dc9357SAndroid Build Coastguard Worker CDummyOutStream *outStreamSpec = new CDummyOutStream;
1033*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
1034*f6dc9357SAndroid Build Coastguard Worker
1035*f6dc9357SAndroid Build Coastguard Worker for (i = 0;; i++)
1036*f6dc9357SAndroid Build Coastguard Worker {
1037*f6dc9357SAndroid Build Coastguard Worker lps->InSize = totalPackSize;
1038*f6dc9357SAndroid Build Coastguard Worker lps->OutSize = totalSize;
1039*f6dc9357SAndroid Build Coastguard Worker RINOK(lps->SetCur())
1040*f6dc9357SAndroid Build Coastguard Worker if (i == numItems)
1041*f6dc9357SAndroid Build Coastguard Worker break;
1042*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialOutStream> realOutStream;
1043*f6dc9357SAndroid Build Coastguard Worker const Int32 askMode = testMode ?
1044*f6dc9357SAndroid Build Coastguard Worker NExtract::NAskMode::kTest :
1045*f6dc9357SAndroid Build Coastguard Worker NExtract::NAskMode::kExtract;
1046*f6dc9357SAndroid Build Coastguard Worker const UInt32 index = allFilesMode ? i : indices[i];
1047*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[index];
1048*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
1049*f6dc9357SAndroid Build Coastguard Worker
1050*f6dc9357SAndroid Build Coastguard Worker if (item.IsDir())
1051*f6dc9357SAndroid Build Coastguard Worker {
1052*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->PrepareOperation(askMode))
1053*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
1054*f6dc9357SAndroid Build Coastguard Worker continue;
1055*f6dc9357SAndroid Build Coastguard Worker }
1056*f6dc9357SAndroid Build Coastguard Worker
1057*f6dc9357SAndroid Build Coastguard Worker totalPackSize += Header.GetFilePackSize(item.Size);
1058*f6dc9357SAndroid Build Coastguard Worker totalSize += item.Size;
1059*f6dc9357SAndroid Build Coastguard Worker
1060*f6dc9357SAndroid Build Coastguard Worker if (!testMode && !realOutStream)
1061*f6dc9357SAndroid Build Coastguard Worker continue;
1062*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->PrepareOperation(askMode))
1063*f6dc9357SAndroid Build Coastguard Worker
1064*f6dc9357SAndroid Build Coastguard Worker outStreamSpec->SetStream(realOutStream);
1065*f6dc9357SAndroid Build Coastguard Worker realOutStream.Release();
1066*f6dc9357SAndroid Build Coastguard Worker outStreamSpec->Init();
1067*f6dc9357SAndroid Build Coastguard Worker
1068*f6dc9357SAndroid Build Coastguard Worker int res = NExtract::NOperationResult::kDataError;
1069*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> inStream;
1070*f6dc9357SAndroid Build Coastguard Worker HRESULT hres = GetStream(index, &inStream);
1071*f6dc9357SAndroid Build Coastguard Worker if (hres != S_FALSE)
1072*f6dc9357SAndroid Build Coastguard Worker {
1073*f6dc9357SAndroid Build Coastguard Worker RINOK(hres)
1074*f6dc9357SAndroid Build Coastguard Worker if (inStream)
1075*f6dc9357SAndroid Build Coastguard Worker {
1076*f6dc9357SAndroid Build Coastguard Worker RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
1077*f6dc9357SAndroid Build Coastguard Worker if (copyCoderSpec->TotalSize == item.Size)
1078*f6dc9357SAndroid Build Coastguard Worker res = NExtract::NOperationResult::kOK;
1079*f6dc9357SAndroid Build Coastguard Worker }
1080*f6dc9357SAndroid Build Coastguard Worker }
1081*f6dc9357SAndroid Build Coastguard Worker outStreamSpec->ReleaseStream();
1082*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetOperationResult(res))
1083*f6dc9357SAndroid Build Coastguard Worker }
1084*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1085*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
1086*f6dc9357SAndroid Build Coastguard Worker }
1087*f6dc9357SAndroid Build Coastguard Worker
1088*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
1089*f6dc9357SAndroid Build Coastguard Worker {
1090*f6dc9357SAndroid Build Coastguard Worker *numItems = Items.Size();
1091*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1092*f6dc9357SAndroid Build Coastguard Worker }
1093*f6dc9357SAndroid Build Coastguard Worker
1094*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { 0x55, 0xAA };
1095*f6dc9357SAndroid Build Coastguard Worker
1096*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
1097*f6dc9357SAndroid Build Coastguard Worker "FAT", "fat img", NULL, 0xDA,
1098*f6dc9357SAndroid Build Coastguard Worker k_Signature,
1099*f6dc9357SAndroid Build Coastguard Worker 0x1FE,
1100*f6dc9357SAndroid Build Coastguard Worker 0,
1101*f6dc9357SAndroid Build Coastguard Worker IsArc_Fat)
1102*f6dc9357SAndroid Build Coastguard Worker
1103*f6dc9357SAndroid Build Coastguard Worker }}
1104