xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/LpHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // LpHandler.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 "../../../C/CpuArch.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Sha256.h"
7*f6dc9357SAndroid Build Coastguard Worker 
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariantUtils.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
15*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
18*f6dc9357SAndroid Build Coastguard Worker 
19*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
22*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
23*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetUi64(p)
24*f6dc9357SAndroid Build Coastguard Worker 
25*f6dc9357SAndroid Build Coastguard Worker #define G16(_offs_, dest) dest = Get16(p + (_offs_));
26*f6dc9357SAndroid Build Coastguard Worker #define G32(_offs_, dest) dest = Get32(p + (_offs_));
27*f6dc9357SAndroid Build Coastguard Worker #define G64(_offs_, dest) dest = Get64(p + (_offs_));
28*f6dc9357SAndroid Build Coastguard Worker 
29*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
32*f6dc9357SAndroid Build Coastguard Worker 
33*f6dc9357SAndroid Build Coastguard Worker namespace NExt {
34*f6dc9357SAndroid Build Coastguard Worker API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize);
35*f6dc9357SAndroid Build Coastguard Worker }
36*f6dc9357SAndroid Build Coastguard Worker 
37*f6dc9357SAndroid Build Coastguard Worker namespace NLp {
38*f6dc9357SAndroid Build Coastguard Worker 
39*f6dc9357SAndroid Build Coastguard Worker /*
40*f6dc9357SAndroid Build Coastguard Worker Android 10+ use Android's Dynamic Partitions to allow the
41*f6dc9357SAndroid Build Coastguard Worker different read-only system partitions (e.g. system, vendor, product)
42*f6dc9357SAndroid Build Coastguard Worker to share the same pool of storage space (as LVM in Linux).
43*f6dc9357SAndroid Build Coastguard Worker Name for partition: "super" (for GPT) or "super.img" (for file).
44*f6dc9357SAndroid Build Coastguard Worker Dynamic Partition Tools: lpmake
45*f6dc9357SAndroid Build Coastguard Worker All partitions that are A/B-ed should be named as follows (slots are always named a, b, etc.):
46*f6dc9357SAndroid Build Coastguard Worker boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
47*f6dc9357SAndroid Build Coastguard Worker */
48*f6dc9357SAndroid Build Coastguard Worker 
49*f6dc9357SAndroid Build Coastguard Worker #define LP_METADATA_MAJOR_VERSION 10
50*f6dc9357SAndroid Build Coastguard Worker // #define LP_METADATA_MINOR_VERSION_MIN 0
51*f6dc9357SAndroid Build Coastguard Worker // #define LP_METADATA_MINOR_VERSION_MAX 2
52*f6dc9357SAndroid Build Coastguard Worker 
53*f6dc9357SAndroid Build Coastguard Worker // #define LP_SECTOR_SIZE 512
54*f6dc9357SAndroid Build Coastguard Worker static const unsigned kSectorSizeLog = 9;
55*f6dc9357SAndroid Build Coastguard Worker 
56*f6dc9357SAndroid Build Coastguard Worker /* Amount of space reserved at the start of every super partition to avoid
57*f6dc9357SAndroid Build Coastguard Worker  * creating an accidental boot sector. */
58*f6dc9357SAndroid Build Coastguard Worker #define LP_PARTITION_RESERVED_BYTES 4096
59*f6dc9357SAndroid Build Coastguard Worker #define LP_METADATA_GEOMETRY_SIZE 4096
60*f6dc9357SAndroid Build Coastguard Worker #define LP_METADATA_HEADER_MAGIC 0x414C5030
61*f6dc9357SAndroid Build Coastguard Worker 
62*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_SignatureSize = 8;
63*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[k_SignatureSize] =
64*f6dc9357SAndroid Build Coastguard Worker   { 0x67, 0x44, 0x6c, 0x61, 0x34, 0, 0, 0 };
65*f6dc9357SAndroid Build Coastguard Worker 
66*f6dc9357SAndroid Build Coastguard Worker // The length (36) is the same as the maximum length of a GPT partition name.
67*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNameLen = 36;
68*f6dc9357SAndroid Build Coastguard Worker 
AddName36ToString(AString & s,const char * name,bool strictConvert)69*f6dc9357SAndroid Build Coastguard Worker static void AddName36ToString(AString &s, const char *name, bool strictConvert)
70*f6dc9357SAndroid Build Coastguard Worker {
71*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < kNameLen; i++)
72*f6dc9357SAndroid Build Coastguard Worker   {
73*f6dc9357SAndroid Build Coastguard Worker     char c = name[i];
74*f6dc9357SAndroid Build Coastguard Worker     if (c == 0)
75*f6dc9357SAndroid Build Coastguard Worker       return;
76*f6dc9357SAndroid Build Coastguard Worker     if (strictConvert && c < 32)
77*f6dc9357SAndroid Build Coastguard Worker       c = '_';
78*f6dc9357SAndroid Build Coastguard Worker     s += c;
79*f6dc9357SAndroid Build Coastguard Worker   }
80*f6dc9357SAndroid Build Coastguard Worker }
81*f6dc9357SAndroid Build Coastguard Worker 
82*f6dc9357SAndroid Build Coastguard Worker 
83*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Geometry_Size = 0x34;
84*f6dc9357SAndroid Build Coastguard Worker 
85*f6dc9357SAndroid Build Coastguard Worker // LpMetadataGeometry
86*f6dc9357SAndroid Build Coastguard Worker struct CGeometry
87*f6dc9357SAndroid Build Coastguard Worker {
88*f6dc9357SAndroid Build Coastguard Worker   // UInt32 magic;
89*f6dc9357SAndroid Build Coastguard Worker   // UInt32 struct_size;
90*f6dc9357SAndroid Build Coastguard Worker   // Byte checksum[32];   /*  SHA256 checksum of this struct, with this field set to 0. */
91*f6dc9357SAndroid Build Coastguard Worker 
92*f6dc9357SAndroid Build Coastguard Worker   /* Maximum amount of space a single copy of the metadata can use,
93*f6dc9357SAndroid Build Coastguard Worker      a multiple of LP_SECTOR_SIZE. */
94*f6dc9357SAndroid Build Coastguard Worker   UInt32 metadata_max_size;
95*f6dc9357SAndroid Build Coastguard Worker 
96*f6dc9357SAndroid Build Coastguard Worker   /* Number of copies of the metadata to keep.
97*f6dc9357SAndroid Build Coastguard Worker      For Non-A/B: 1, For A/B: 2, for A/B/C: 3.
98*f6dc9357SAndroid Build Coastguard Worker      A backup copy of each slot is kept */
99*f6dc9357SAndroid Build Coastguard Worker   UInt32 metadata_slot_count;
100*f6dc9357SAndroid Build Coastguard Worker 
101*f6dc9357SAndroid Build Coastguard Worker   /* minimal alignment for partition and extent sizes, a multiple of LP_SECTOR_SIZE. */
102*f6dc9357SAndroid Build Coastguard Worker   UInt32 logical_block_size;
103*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NLp::CGeometry104*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p)
105*f6dc9357SAndroid Build Coastguard Worker   {
106*f6dc9357SAndroid Build Coastguard Worker     G32 (40, metadata_max_size)
107*f6dc9357SAndroid Build Coastguard Worker     G32 (44, metadata_slot_count)
108*f6dc9357SAndroid Build Coastguard Worker     G32 (48, logical_block_size)
109*f6dc9357SAndroid Build Coastguard Worker     if (metadata_slot_count == 0 || metadata_slot_count >= ((UInt32)1 << 20))
110*f6dc9357SAndroid Build Coastguard Worker       return false;
111*f6dc9357SAndroid Build Coastguard Worker     if (metadata_max_size == 0)
112*f6dc9357SAndroid Build Coastguard Worker       return false;
113*f6dc9357SAndroid Build Coastguard Worker     if ((metadata_max_size & (((UInt32)1 << kSectorSizeLog) - 1)) != 0)
114*f6dc9357SAndroid Build Coastguard Worker       return false;
115*f6dc9357SAndroid Build Coastguard Worker     return true;
116*f6dc9357SAndroid Build Coastguard Worker   }
117*f6dc9357SAndroid Build Coastguard Worker 
GetTotalMetadataSizeNArchive::NLp::CGeometry118*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetTotalMetadataSize() const
119*f6dc9357SAndroid Build Coastguard Worker   {
120*f6dc9357SAndroid Build Coastguard Worker     // there are 2 copies of GEOMETRY and METADATA slots
121*f6dc9357SAndroid Build Coastguard Worker     return LP_PARTITION_RESERVED_BYTES +
122*f6dc9357SAndroid Build Coastguard Worker            LP_METADATA_GEOMETRY_SIZE * 2 +
123*f6dc9357SAndroid Build Coastguard Worker            ((UInt64)metadata_max_size * metadata_slot_count) * 2;
124*f6dc9357SAndroid Build Coastguard Worker   }
125*f6dc9357SAndroid Build Coastguard Worker };
126*f6dc9357SAndroid Build Coastguard Worker 
127*f6dc9357SAndroid Build Coastguard Worker 
128*f6dc9357SAndroid Build Coastguard Worker 
129*f6dc9357SAndroid Build Coastguard Worker // LpMetadataTableDescriptor
130*f6dc9357SAndroid Build Coastguard Worker struct CDescriptor
131*f6dc9357SAndroid Build Coastguard Worker {
132*f6dc9357SAndroid Build Coastguard Worker   UInt32 offset;        /*  Location of the table, relative to end of the metadata header. */
133*f6dc9357SAndroid Build Coastguard Worker   UInt32 num_entries;   /*  Number of entries in the table. */
134*f6dc9357SAndroid Build Coastguard Worker   UInt32 entry_size;    /*  Size of each entry in the table, in bytes. */
135*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NLp::CDescriptor136*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
137*f6dc9357SAndroid Build Coastguard Worker   {
138*f6dc9357SAndroid Build Coastguard Worker     G32 (0, offset)
139*f6dc9357SAndroid Build Coastguard Worker     G32 (4, num_entries)
140*f6dc9357SAndroid Build Coastguard Worker     G32 (8, entry_size)
141*f6dc9357SAndroid Build Coastguard Worker   }
142*f6dc9357SAndroid Build Coastguard Worker 
CheckLimitsNArchive::NLp::CDescriptor143*f6dc9357SAndroid Build Coastguard Worker   bool CheckLimits(UInt32 limit) const
144*f6dc9357SAndroid Build Coastguard Worker   {
145*f6dc9357SAndroid Build Coastguard Worker     if (entry_size == 0)
146*f6dc9357SAndroid Build Coastguard Worker       return false;
147*f6dc9357SAndroid Build Coastguard Worker     const UInt32 size = num_entries * entry_size;
148*f6dc9357SAndroid Build Coastguard Worker     if (size / entry_size != num_entries)
149*f6dc9357SAndroid Build Coastguard Worker       return false;
150*f6dc9357SAndroid Build Coastguard Worker     if (offset > limit || limit - offset < size)
151*f6dc9357SAndroid Build Coastguard Worker       return false;
152*f6dc9357SAndroid Build Coastguard Worker     return true;
153*f6dc9357SAndroid Build Coastguard Worker   }
154*f6dc9357SAndroid Build Coastguard Worker };
155*f6dc9357SAndroid Build Coastguard Worker 
156*f6dc9357SAndroid Build Coastguard Worker 
157*f6dc9357SAndroid Build Coastguard Worker // #define LP_PARTITION_ATTR_NONE 0x0
158*f6dc9357SAndroid Build Coastguard Worker // #define LP_PARTITION_ATTR_READONLY (1 << 0)
159*f6dc9357SAndroid Build Coastguard Worker 
160*f6dc9357SAndroid Build Coastguard Worker /* This flag is only intended to be used with super_empty.img and super.img on
161*f6dc9357SAndroid Build Coastguard Worker  * retrofit devices. On these devices there are A and B super partitions, and
162*f6dc9357SAndroid Build Coastguard Worker  * we don't know ahead of time which slot the image will be applied to.
163*f6dc9357SAndroid Build Coastguard Worker  *
164*f6dc9357SAndroid Build Coastguard Worker  * If set, the partition name needs a slot suffix applied. The slot suffix is
165*f6dc9357SAndroid Build Coastguard Worker  * determined by the metadata slot number (0 = _a, 1 = _b).
166*f6dc9357SAndroid Build Coastguard Worker  */
167*f6dc9357SAndroid Build Coastguard Worker // #define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
168*f6dc9357SAndroid Build Coastguard Worker 
169*f6dc9357SAndroid Build Coastguard Worker /* This flag is applied automatically when using MetadataBuilder::NewForUpdate.
170*f6dc9357SAndroid Build Coastguard Worker  * It signals that the partition was created (or modified) for a snapshot-based
171*f6dc9357SAndroid Build Coastguard Worker  * update. If this flag is not present, the partition was likely flashed via
172*f6dc9357SAndroid Build Coastguard Worker  * fastboot.
173*f6dc9357SAndroid Build Coastguard Worker  */
174*f6dc9357SAndroid Build Coastguard Worker // #define LP_PARTITION_ATTR_UPDATED (1 << 2)
175*f6dc9357SAndroid Build Coastguard Worker 
176*f6dc9357SAndroid Build Coastguard Worker /* This flag marks a partition as disabled. It should not be used or mapped. */
177*f6dc9357SAndroid Build Coastguard Worker // #define LP_PARTITION_ATTR_DISABLED (1 << 3)
178*f6dc9357SAndroid Build Coastguard Worker 
179*f6dc9357SAndroid Build Coastguard Worker static const char * const g_PartitionAttr[] =
180*f6dc9357SAndroid Build Coastguard Worker {
181*f6dc9357SAndroid Build Coastguard Worker     "READONLY"
182*f6dc9357SAndroid Build Coastguard Worker   , "SLOT_SUFFIXED"
183*f6dc9357SAndroid Build Coastguard Worker   , "UPDATED"
184*f6dc9357SAndroid Build Coastguard Worker   , "DISABLED"
185*f6dc9357SAndroid Build Coastguard Worker };
186*f6dc9357SAndroid Build Coastguard Worker 
187*f6dc9357SAndroid Build Coastguard Worker static unsigned const k_MetaPartition_Size = 52;
188*f6dc9357SAndroid Build Coastguard Worker 
189*f6dc9357SAndroid Build Coastguard Worker // LpMetadataPartition
190*f6dc9357SAndroid Build Coastguard Worker struct CPartition
191*f6dc9357SAndroid Build Coastguard Worker {
192*f6dc9357SAndroid Build Coastguard Worker   /* ASCII characters: alphanumeric or _. at least one ASCII character,
193*f6dc9357SAndroid Build Coastguard Worker      (name) must be unique across all partition names. */
194*f6dc9357SAndroid Build Coastguard Worker   char name[kNameLen];
195*f6dc9357SAndroid Build Coastguard Worker 
196*f6dc9357SAndroid Build Coastguard Worker   UInt32 attributes;   /* (LP_PARTITION_ATTR_*). */
197*f6dc9357SAndroid Build Coastguard Worker 
198*f6dc9357SAndroid Build Coastguard Worker   /* Index of the first extent owned by this partition. The extent will
199*f6dc9357SAndroid Build Coastguard Worker    * start at logical sector 0. Gaps between extents are not allowed. */
200*f6dc9357SAndroid Build Coastguard Worker   UInt32 first_extent_index;
201*f6dc9357SAndroid Build Coastguard Worker 
202*f6dc9357SAndroid Build Coastguard Worker   /* Number of extents in the partition. Every partition must have at least one extent. */
203*f6dc9357SAndroid Build Coastguard Worker   UInt32 num_extents;
204*f6dc9357SAndroid Build Coastguard Worker 
205*f6dc9357SAndroid Build Coastguard Worker   /* Group this partition belongs to. */
206*f6dc9357SAndroid Build Coastguard Worker   UInt32 group_index;
207*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NLp::CPartition208*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
209*f6dc9357SAndroid Build Coastguard Worker   {
210*f6dc9357SAndroid Build Coastguard Worker     memcpy(name, p, kNameLen);
211*f6dc9357SAndroid Build Coastguard Worker     G32 (36, attributes)
212*f6dc9357SAndroid Build Coastguard Worker     G32 (40, first_extent_index)
213*f6dc9357SAndroid Build Coastguard Worker     G32 (44, num_extents)
214*f6dc9357SAndroid Build Coastguard Worker     G32 (48, group_index)
215*f6dc9357SAndroid Build Coastguard Worker   }
216*f6dc9357SAndroid Build Coastguard Worker 
217*f6dc9357SAndroid Build Coastguard Worker   // calced properties:
218*f6dc9357SAndroid Build Coastguard Worker   UInt32 MethodsMask;
219*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumSectors;
220*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumSectors_Pack;
221*f6dc9357SAndroid Build Coastguard Worker   const char *Ext;
222*f6dc9357SAndroid Build Coastguard Worker 
GetSizeNArchive::NLp::CPartition223*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetSize() const { return NumSectors << kSectorSizeLog; }
GetPackSizeNArchive::NLp::CPartition224*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetPackSize() const { return NumSectors_Pack << kSectorSizeLog; }
225*f6dc9357SAndroid Build Coastguard Worker 
CPartitionNArchive::NLp::CPartition226*f6dc9357SAndroid Build Coastguard Worker   CPartition():
227*f6dc9357SAndroid Build Coastguard Worker       MethodsMask(0),
228*f6dc9357SAndroid Build Coastguard Worker       NumSectors(0),
229*f6dc9357SAndroid Build Coastguard Worker       NumSectors_Pack(0),
230*f6dc9357SAndroid Build Coastguard Worker       Ext(NULL)
231*f6dc9357SAndroid Build Coastguard Worker       {}
232*f6dc9357SAndroid Build Coastguard Worker };
233*f6dc9357SAndroid Build Coastguard Worker 
234*f6dc9357SAndroid Build Coastguard Worker 
235*f6dc9357SAndroid Build Coastguard Worker 
236*f6dc9357SAndroid Build Coastguard Worker 
237*f6dc9357SAndroid Build Coastguard Worker #define LP_TARGET_TYPE_LINEAR 0
238*f6dc9357SAndroid Build Coastguard Worker /* This extent is a dm-zero target. The index is ignored and must be 0. */
239*f6dc9357SAndroid Build Coastguard Worker #define LP_TARGET_TYPE_ZERO 1
240*f6dc9357SAndroid Build Coastguard Worker 
241*f6dc9357SAndroid Build Coastguard Worker static const char * const g_Methods[] =
242*f6dc9357SAndroid Build Coastguard Worker {
243*f6dc9357SAndroid Build Coastguard Worker     "RAW" // "LINEAR"
244*f6dc9357SAndroid Build Coastguard Worker   , "ZERO"
245*f6dc9357SAndroid Build Coastguard Worker };
246*f6dc9357SAndroid Build Coastguard Worker 
247*f6dc9357SAndroid Build Coastguard Worker static unsigned const k_MetaExtent_Size = 24;
248*f6dc9357SAndroid Build Coastguard Worker 
249*f6dc9357SAndroid Build Coastguard Worker // LpMetadataExtent
250*f6dc9357SAndroid Build Coastguard Worker struct CExtent
251*f6dc9357SAndroid Build Coastguard Worker {
252*f6dc9357SAndroid Build Coastguard Worker   UInt64 num_sectors;  /*  Length in 512-byte sectors. */
253*f6dc9357SAndroid Build Coastguard Worker   UInt32 target_type;  /*  Target type for device-mapper (LP_TARGET_TYPE_*). */
254*f6dc9357SAndroid Build Coastguard Worker 
255*f6dc9357SAndroid Build Coastguard Worker   /* for LINEAR: The sector on the physical partition that this extent maps onto.
256*f6dc9357SAndroid Build Coastguard Worker      for ZERO:   must be 0. */
257*f6dc9357SAndroid Build Coastguard Worker   UInt64 target_data;
258*f6dc9357SAndroid Build Coastguard Worker 
259*f6dc9357SAndroid Build Coastguard Worker   /* for LINEAR: index into the block devices table.
260*f6dc9357SAndroid Build Coastguard Worker      for ZERO:   must be 0. */
261*f6dc9357SAndroid Build Coastguard Worker   UInt32 target_source;
262*f6dc9357SAndroid Build Coastguard Worker 
IsRAWNArchive::NLp::CExtent263*f6dc9357SAndroid Build Coastguard Worker   bool IsRAW() const { return target_type == LP_TARGET_TYPE_LINEAR; }
264*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NLp::CExtent265*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
266*f6dc9357SAndroid Build Coastguard Worker   {
267*f6dc9357SAndroid Build Coastguard Worker     G64 (0, num_sectors)
268*f6dc9357SAndroid Build Coastguard Worker     G32 (8, target_type)
269*f6dc9357SAndroid Build Coastguard Worker     G64 (12, target_data)
270*f6dc9357SAndroid Build Coastguard Worker     G32 (20, target_source)
271*f6dc9357SAndroid Build Coastguard Worker   }
272*f6dc9357SAndroid Build Coastguard Worker };
273*f6dc9357SAndroid Build Coastguard Worker 
274*f6dc9357SAndroid Build Coastguard Worker 
275*f6dc9357SAndroid Build Coastguard Worker /* This flag is only intended to be used with super_empty.img and super.img on
276*f6dc9357SAndroid Build Coastguard Worker  * retrofit devices. If set, the group needs a slot suffix to be interpreted
277*f6dc9357SAndroid Build Coastguard Worker  * correctly. The suffix is automatically applied by ReadMetadata().
278*f6dc9357SAndroid Build Coastguard Worker  */
279*f6dc9357SAndroid Build Coastguard Worker // #define LP_GROUP_SLOT_SUFFIXED (1 << 0)
280*f6dc9357SAndroid Build Coastguard Worker static unsigned const k_Group_Size = 48;
281*f6dc9357SAndroid Build Coastguard Worker 
282*f6dc9357SAndroid Build Coastguard Worker // LpMetadataPartitionGroup
283*f6dc9357SAndroid Build Coastguard Worker struct CGroup
284*f6dc9357SAndroid Build Coastguard Worker {
285*f6dc9357SAndroid Build Coastguard Worker   char name[kNameLen];
286*f6dc9357SAndroid Build Coastguard Worker   UInt32 flags;  /* (LP_GROUP_*). */
287*f6dc9357SAndroid Build Coastguard Worker   UInt64 maximum_size; /* Maximum size in bytes. If 0, the group has no maximum size. */
288*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NLp::CGroup289*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
290*f6dc9357SAndroid Build Coastguard Worker   {
291*f6dc9357SAndroid Build Coastguard Worker     memcpy(name, p, kNameLen);
292*f6dc9357SAndroid Build Coastguard Worker     G32 (36, flags)
293*f6dc9357SAndroid Build Coastguard Worker     G64 (40, maximum_size)
294*f6dc9357SAndroid Build Coastguard Worker   }
295*f6dc9357SAndroid Build Coastguard Worker };
296*f6dc9357SAndroid Build Coastguard Worker 
297*f6dc9357SAndroid Build Coastguard Worker 
298*f6dc9357SAndroid Build Coastguard Worker 
299*f6dc9357SAndroid Build Coastguard Worker 
300*f6dc9357SAndroid Build Coastguard Worker /* This flag is only intended to be used with super_empty.img and super.img on
301*f6dc9357SAndroid Build Coastguard Worker  * retrofit devices. On these devices there are A and B super partitions, and
302*f6dc9357SAndroid Build Coastguard Worker  * we don't know ahead of time which slot the image will be applied to.
303*f6dc9357SAndroid Build Coastguard Worker  *
304*f6dc9357SAndroid Build Coastguard Worker  * If set, the block device needs a slot suffix applied before being used with
305*f6dc9357SAndroid Build Coastguard Worker  * IPartitionOpener. The slot suffix is determined by the metadata slot number
306*f6dc9357SAndroid Build Coastguard Worker  * (0 = _a, 1 = _b).
307*f6dc9357SAndroid Build Coastguard Worker  */
308*f6dc9357SAndroid Build Coastguard Worker // #define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)
309*f6dc9357SAndroid Build Coastguard Worker 
310*f6dc9357SAndroid Build Coastguard Worker static unsigned const k_Device_Size = 64;
311*f6dc9357SAndroid Build Coastguard Worker 
312*f6dc9357SAndroid Build Coastguard Worker /* This struct defines an entry in the block_devices table. There must be at
313*f6dc9357SAndroid Build Coastguard Worker  * least one device, and the first device must represent the partition holding
314*f6dc9357SAndroid Build Coastguard Worker  * the super metadata.
315*f6dc9357SAndroid Build Coastguard Worker  */
316*f6dc9357SAndroid Build Coastguard Worker // LpMetadataBlockDevice
317*f6dc9357SAndroid Build Coastguard Worker struct CDevice
318*f6dc9357SAndroid Build Coastguard Worker {
319*f6dc9357SAndroid Build Coastguard Worker     /* 0: First usable sector for allocating logical partitions. this will be
320*f6dc9357SAndroid Build Coastguard Worker      * the first sector after the initial geometry blocks, followed by the
321*f6dc9357SAndroid Build Coastguard Worker      * space consumed by metadata_max_size*metadata_slot_count*2.
322*f6dc9357SAndroid Build Coastguard Worker      */
323*f6dc9357SAndroid Build Coastguard Worker   UInt64 first_logical_sector;
324*f6dc9357SAndroid Build Coastguard Worker 
325*f6dc9357SAndroid Build Coastguard Worker     /* 8: Alignment for defining partitions or partition extents. For example,
326*f6dc9357SAndroid Build Coastguard Worker      * an alignment of 1MiB will require that all partitions have a size evenly
327*f6dc9357SAndroid Build Coastguard Worker      * divisible by 1MiB, and that the smallest unit the partition can grow by
328*f6dc9357SAndroid Build Coastguard Worker      * is 1MiB.
329*f6dc9357SAndroid Build Coastguard Worker      *
330*f6dc9357SAndroid Build Coastguard Worker      * Alignment is normally determined at runtime when growing or adding
331*f6dc9357SAndroid Build Coastguard Worker      * partitions. If for some reason the alignment cannot be determined, then
332*f6dc9357SAndroid Build Coastguard Worker      * this predefined alignment in the geometry is used instead. By default
333*f6dc9357SAndroid Build Coastguard Worker      * it is set to 1MiB.
334*f6dc9357SAndroid Build Coastguard Worker      */
335*f6dc9357SAndroid Build Coastguard Worker   UInt32 alignment;
336*f6dc9357SAndroid Build Coastguard Worker 
337*f6dc9357SAndroid Build Coastguard Worker     /* 12: Alignment offset for "stacked" devices. For example, if the "super"
338*f6dc9357SAndroid Build Coastguard Worker      * partition itself is not aligned within the parent block device's
339*f6dc9357SAndroid Build Coastguard Worker      * partition table, then we adjust for this in deciding where to place
340*f6dc9357SAndroid Build Coastguard Worker      * |first_logical_sector|.
341*f6dc9357SAndroid Build Coastguard Worker      *
342*f6dc9357SAndroid Build Coastguard Worker      * Similar to |alignment|, this will be derived from the operating system.
343*f6dc9357SAndroid Build Coastguard Worker      * If it cannot be determined, it is assumed to be 0.
344*f6dc9357SAndroid Build Coastguard Worker      */
345*f6dc9357SAndroid Build Coastguard Worker   UInt32 alignment_offset;
346*f6dc9357SAndroid Build Coastguard Worker 
347*f6dc9357SAndroid Build Coastguard Worker     /* 16: Block device size, as specified when the metadata was created. This
348*f6dc9357SAndroid Build Coastguard Worker      * can be used to verify the geometry against a target device.
349*f6dc9357SAndroid Build Coastguard Worker      */
350*f6dc9357SAndroid Build Coastguard Worker   UInt64 size;
351*f6dc9357SAndroid Build Coastguard Worker 
352*f6dc9357SAndroid Build Coastguard Worker     /* 24: Partition name in the GPT*/
353*f6dc9357SAndroid Build Coastguard Worker   char partition_name[kNameLen];
354*f6dc9357SAndroid Build Coastguard Worker 
355*f6dc9357SAndroid Build Coastguard Worker     /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
356*f6dc9357SAndroid Build Coastguard Worker   UInt32 flags;
357*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NLp::CDevice358*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
359*f6dc9357SAndroid Build Coastguard Worker   {
360*f6dc9357SAndroid Build Coastguard Worker     memcpy(partition_name, p + 24, kNameLen);
361*f6dc9357SAndroid Build Coastguard Worker     G64 (0, first_logical_sector)
362*f6dc9357SAndroid Build Coastguard Worker     G32 (8, alignment)
363*f6dc9357SAndroid Build Coastguard Worker     G32 (12, alignment_offset)
364*f6dc9357SAndroid Build Coastguard Worker     G64 (16, size)
365*f6dc9357SAndroid Build Coastguard Worker     G32 (60, flags)
366*f6dc9357SAndroid Build Coastguard Worker   }
367*f6dc9357SAndroid Build Coastguard Worker };
368*f6dc9357SAndroid Build Coastguard Worker 
369*f6dc9357SAndroid Build Coastguard Worker 
370*f6dc9357SAndroid Build Coastguard Worker /* This device uses Virtual A/B. Note that on retrofit devices, the expanded
371*f6dc9357SAndroid Build Coastguard Worker  * header may not be present.
372*f6dc9357SAndroid Build Coastguard Worker  */
373*f6dc9357SAndroid Build Coastguard Worker // #define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1
374*f6dc9357SAndroid Build Coastguard Worker 
375*f6dc9357SAndroid Build Coastguard Worker static const char * const g_Header_Flags[] =
376*f6dc9357SAndroid Build Coastguard Worker {
377*f6dc9357SAndroid Build Coastguard Worker   "VIRTUAL_AB"
378*f6dc9357SAndroid Build Coastguard Worker };
379*f6dc9357SAndroid Build Coastguard Worker 
380*f6dc9357SAndroid Build Coastguard Worker 
381*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_LpMetadataHeader10_size = 128;
382*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_LpMetadataHeader12_size = 256;
383*f6dc9357SAndroid Build Coastguard Worker 
384*f6dc9357SAndroid Build Coastguard Worker struct LpMetadataHeader
385*f6dc9357SAndroid Build Coastguard Worker {
386*f6dc9357SAndroid Build Coastguard Worker   /*  0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */
387*f6dc9357SAndroid Build Coastguard Worker   UInt32 magic;
388*f6dc9357SAndroid Build Coastguard Worker 
389*f6dc9357SAndroid Build Coastguard Worker   /*  4: Version number required to read this metadata. If the version is not
390*f6dc9357SAndroid Build Coastguard Worker    * equal to the library version, the metadata should be considered
391*f6dc9357SAndroid Build Coastguard Worker    * incompatible.
392*f6dc9357SAndroid Build Coastguard Worker    */
393*f6dc9357SAndroid Build Coastguard Worker   UInt16 major_version;
394*f6dc9357SAndroid Build Coastguard Worker 
395*f6dc9357SAndroid Build Coastguard Worker   /*  6: Minor version. A library supporting newer features should be able to
396*f6dc9357SAndroid Build Coastguard Worker    * read metadata with an older minor version. However, an older library
397*f6dc9357SAndroid Build Coastguard Worker    * should not support reading metadata if its minor version is higher.
398*f6dc9357SAndroid Build Coastguard Worker    */
399*f6dc9357SAndroid Build Coastguard Worker   UInt16 minor_version;
400*f6dc9357SAndroid Build Coastguard Worker 
401*f6dc9357SAndroid Build Coastguard Worker   /*  8: The size of this header struct. */
402*f6dc9357SAndroid Build Coastguard Worker   UInt32 header_size;
403*f6dc9357SAndroid Build Coastguard Worker 
404*f6dc9357SAndroid Build Coastguard Worker   /* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as
405*f6dc9357SAndroid Build Coastguard Worker    * if this field were set to 0.
406*f6dc9357SAndroid Build Coastguard Worker    */
407*f6dc9357SAndroid Build Coastguard Worker   // Byte header_checksum[32];
408*f6dc9357SAndroid Build Coastguard Worker 
409*f6dc9357SAndroid Build Coastguard Worker   /* 44: The total size of all tables. This size is contiguous; tables may not
410*f6dc9357SAndroid Build Coastguard Worker    * have gaps in between, and they immediately follow the header.
411*f6dc9357SAndroid Build Coastguard Worker    */
412*f6dc9357SAndroid Build Coastguard Worker   UInt32 tables_size;
413*f6dc9357SAndroid Build Coastguard Worker 
414*f6dc9357SAndroid Build Coastguard Worker   /* 48: SHA256 checksum of all table contents. */
415*f6dc9357SAndroid Build Coastguard Worker   Byte tables_checksum[32];
416*f6dc9357SAndroid Build Coastguard Worker 
417*f6dc9357SAndroid Build Coastguard Worker   /* 80: Partition table descriptor. */
418*f6dc9357SAndroid Build Coastguard Worker   CDescriptor partitions;
419*f6dc9357SAndroid Build Coastguard Worker   /* 92: Extent table descriptor. */
420*f6dc9357SAndroid Build Coastguard Worker   CDescriptor extents;
421*f6dc9357SAndroid Build Coastguard Worker   /* 104: Updateable group descriptor. */
422*f6dc9357SAndroid Build Coastguard Worker   CDescriptor groups;
423*f6dc9357SAndroid Build Coastguard Worker   /* 116: Block device table. */
424*f6dc9357SAndroid Build Coastguard Worker   CDescriptor block_devices;
425*f6dc9357SAndroid Build Coastguard Worker 
426*f6dc9357SAndroid Build Coastguard Worker   /* Everything past here is header version 1.2+, and is only included if
427*f6dc9357SAndroid Build Coastguard Worker    * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must
428*f6dc9357SAndroid Build Coastguard Worker    * zero these additional fields.
429*f6dc9357SAndroid Build Coastguard Worker    */
430*f6dc9357SAndroid Build Coastguard Worker 
431*f6dc9357SAndroid Build Coastguard Worker   /* 128: See LP_HEADER_FLAG_ constants for possible values. Header flags are
432*f6dc9357SAndroid Build Coastguard Worker    * independent of the version number and intended to be informational only.
433*f6dc9357SAndroid Build Coastguard Worker    * New flags can be added without bumping the version.
434*f6dc9357SAndroid Build Coastguard Worker    */
435*f6dc9357SAndroid Build Coastguard Worker   // UInt32 flags;
436*f6dc9357SAndroid Build Coastguard Worker 
437*f6dc9357SAndroid Build Coastguard Worker   /* 132: Reserved (zero), pad to 256 bytes. */
438*f6dc9357SAndroid Build Coastguard Worker   // Byte reserved[124];
439*f6dc9357SAndroid Build Coastguard Worker 
Parse128NArchive::NLp::LpMetadataHeader440*f6dc9357SAndroid Build Coastguard Worker   void Parse128(const Byte *p)
441*f6dc9357SAndroid Build Coastguard Worker   {
442*f6dc9357SAndroid Build Coastguard Worker     G32 (0, magic)
443*f6dc9357SAndroid Build Coastguard Worker     G16 (4, major_version)
444*f6dc9357SAndroid Build Coastguard Worker     G16 (6, minor_version)
445*f6dc9357SAndroid Build Coastguard Worker     G32 (8, header_size)
446*f6dc9357SAndroid Build Coastguard Worker     // Byte header_checksum[32];
447*f6dc9357SAndroid Build Coastguard Worker     G32 (44, tables_size)
448*f6dc9357SAndroid Build Coastguard Worker     memcpy (tables_checksum, p + 48, 32);
449*f6dc9357SAndroid Build Coastguard Worker     partitions.Parse(p + 80);
450*f6dc9357SAndroid Build Coastguard Worker     extents.Parse(p + 92);
451*f6dc9357SAndroid Build Coastguard Worker     groups.Parse(p + 104);
452*f6dc9357SAndroid Build Coastguard Worker     block_devices.Parse(p + 116);
453*f6dc9357SAndroid Build Coastguard Worker     /* Everything past here is header version 1.2+, and is only included if
454*f6dc9357SAndroid Build Coastguard Worker      * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must
455*f6dc9357SAndroid Build Coastguard Worker      * zero these additional fields.
456*f6dc9357SAndroid Build Coastguard Worker      */
457*f6dc9357SAndroid Build Coastguard Worker   }
458*f6dc9357SAndroid Build Coastguard Worker };
459*f6dc9357SAndroid Build Coastguard Worker 
460*f6dc9357SAndroid Build Coastguard Worker 
CheckSha256(const Byte * data,size_t size,const Byte * checksum)461*f6dc9357SAndroid Build Coastguard Worker static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum)
462*f6dc9357SAndroid Build Coastguard Worker {
463*f6dc9357SAndroid Build Coastguard Worker   MY_ALIGN (16)
464*f6dc9357SAndroid Build Coastguard Worker   CSha256 sha;
465*f6dc9357SAndroid Build Coastguard Worker   Sha256_Init(&sha);
466*f6dc9357SAndroid Build Coastguard Worker   Sha256_Update(&sha, data, size);
467*f6dc9357SAndroid Build Coastguard Worker   MY_ALIGN (16)
468*f6dc9357SAndroid Build Coastguard Worker   Byte calced[32];
469*f6dc9357SAndroid Build Coastguard Worker   Sha256_Final(&sha, calced);
470*f6dc9357SAndroid Build Coastguard Worker   return memcmp(checksum, calced, 32) == 0;
471*f6dc9357SAndroid Build Coastguard Worker }
472*f6dc9357SAndroid Build Coastguard Worker 
CheckSha256_csOffset(Byte * data,size_t size,unsigned hashOffset)473*f6dc9357SAndroid Build Coastguard Worker static bool CheckSha256_csOffset(Byte *data, size_t size, unsigned hashOffset)
474*f6dc9357SAndroid Build Coastguard Worker {
475*f6dc9357SAndroid Build Coastguard Worker   MY_ALIGN (4)
476*f6dc9357SAndroid Build Coastguard Worker   Byte checksum[32];
477*f6dc9357SAndroid Build Coastguard Worker   Byte *shaData = &data[hashOffset];
478*f6dc9357SAndroid Build Coastguard Worker   memcpy(checksum, shaData, 32);
479*f6dc9357SAndroid Build Coastguard Worker   memset(shaData, 0, 32);
480*f6dc9357SAndroid Build Coastguard Worker   return CheckSha256(data, size, checksum);
481*f6dc9357SAndroid Build Coastguard Worker }
482*f6dc9357SAndroid Build Coastguard Worker 
483*f6dc9357SAndroid Build Coastguard Worker 
484*f6dc9357SAndroid Build Coastguard Worker 
485*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_1(
486*f6dc9357SAndroid Build Coastguard Worker   IInArchiveGetStream
487*f6dc9357SAndroid Build Coastguard Worker )
488*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CPartition> _items;
489*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CExtent> Extents;
490*f6dc9357SAndroid Build Coastguard Worker 
491*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _stream;
492*f6dc9357SAndroid Build Coastguard Worker   UInt64 _totalSize;
493*f6dc9357SAndroid Build Coastguard Worker   // UInt64 _usedSize;
494*f6dc9357SAndroid Build Coastguard Worker   // UInt64 _headersSize;
495*f6dc9357SAndroid Build Coastguard Worker 
496*f6dc9357SAndroid Build Coastguard Worker   CGeometry geom;
497*f6dc9357SAndroid Build Coastguard Worker   UInt16 Major_version;
498*f6dc9357SAndroid Build Coastguard Worker   UInt16 Minor_version;
499*f6dc9357SAndroid Build Coastguard Worker   UInt32 Flags;
500*f6dc9357SAndroid Build Coastguard Worker 
501*f6dc9357SAndroid Build Coastguard Worker   Int32 _mainFileIndex;
502*f6dc9357SAndroid Build Coastguard Worker   UInt32 MethodsMask;
503*f6dc9357SAndroid Build Coastguard Worker   bool _headerWarning;
504*f6dc9357SAndroid Build Coastguard Worker   AString GroupsString;
505*f6dc9357SAndroid Build Coastguard Worker   AString DevicesString;
506*f6dc9357SAndroid Build Coastguard Worker   AString DeviceArcName;
507*f6dc9357SAndroid Build Coastguard Worker 
508*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open2(IInStream *stream);
509*f6dc9357SAndroid Build Coastguard Worker };
510*f6dc9357SAndroid Build Coastguard Worker 
511*f6dc9357SAndroid Build Coastguard Worker 
AddComment_UInt64(AString & s,const char * name,UInt64 val)512*f6dc9357SAndroid Build Coastguard Worker static void AddComment_UInt64(AString &s, const char *name, UInt64 val)
513*f6dc9357SAndroid Build Coastguard Worker {
514*f6dc9357SAndroid Build Coastguard Worker   s.Add_Space();
515*f6dc9357SAndroid Build Coastguard Worker   s += name;
516*f6dc9357SAndroid Build Coastguard Worker   s += '=';
517*f6dc9357SAndroid Build Coastguard Worker   s.Add_UInt64(val);
518*f6dc9357SAndroid Build Coastguard Worker }
519*f6dc9357SAndroid Build Coastguard Worker 
520*f6dc9357SAndroid Build Coastguard Worker 
IsBufZero(const Byte * data,size_t size)521*f6dc9357SAndroid Build Coastguard Worker static bool IsBufZero(const Byte *data, size_t size)
522*f6dc9357SAndroid Build Coastguard Worker {
523*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < size; i += 4)
524*f6dc9357SAndroid Build Coastguard Worker     if (*(const UInt32 *)(const void *)(data + i) != 0)
525*f6dc9357SAndroid Build Coastguard Worker       return false;
526*f6dc9357SAndroid Build Coastguard Worker   return true;
527*f6dc9357SAndroid Build Coastguard Worker }
528*f6dc9357SAndroid Build Coastguard Worker 
529*f6dc9357SAndroid Build Coastguard Worker 
Open2(IInStream * stream)530*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream)
531*f6dc9357SAndroid Build Coastguard Worker {
532*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekSet(stream, LP_PARTITION_RESERVED_BYTES))
533*f6dc9357SAndroid Build Coastguard Worker   {
534*f6dc9357SAndroid Build Coastguard Worker     MY_ALIGN (4)
535*f6dc9357SAndroid Build Coastguard Worker     Byte buf[k_Geometry_Size];
536*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(stream, buf, k_Geometry_Size))
537*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
538*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
539*f6dc9357SAndroid Build Coastguard Worker     if (!geom.Parse(buf))
540*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
541*f6dc9357SAndroid Build Coastguard Worker     if (!CheckSha256_csOffset(buf, k_Geometry_Size, 8))
542*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
543*f6dc9357SAndroid Build Coastguard Worker   }
544*f6dc9357SAndroid Build Coastguard Worker 
545*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer buffer;
546*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekToBegin(stream))
547*f6dc9357SAndroid Build Coastguard Worker   buffer.Alloc(LP_METADATA_GEOMETRY_SIZE * 2);
548*f6dc9357SAndroid Build Coastguard Worker   {
549*f6dc9357SAndroid Build Coastguard Worker     // buffer.Size() >= LP_PARTITION_RESERVED_BYTES
550*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(stream, buffer, LP_PARTITION_RESERVED_BYTES))
551*f6dc9357SAndroid Build Coastguard Worker     if (!IsBufZero(buffer, LP_PARTITION_RESERVED_BYTES))
552*f6dc9357SAndroid Build Coastguard Worker     {
553*f6dc9357SAndroid Build Coastguard Worker       _headerWarning = true;
554*f6dc9357SAndroid Build Coastguard Worker       // return S_FALSE;
555*f6dc9357SAndroid Build Coastguard Worker     }
556*f6dc9357SAndroid Build Coastguard Worker   }
557*f6dc9357SAndroid Build Coastguard Worker 
558*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, buffer, LP_METADATA_GEOMETRY_SIZE * 2))
559*f6dc9357SAndroid Build Coastguard Worker   // we check that 2 copies of GEOMETRY are identical:
560*f6dc9357SAndroid Build Coastguard Worker   if (memcmp(buffer, buffer + LP_METADATA_GEOMETRY_SIZE, LP_METADATA_GEOMETRY_SIZE) != 0
561*f6dc9357SAndroid Build Coastguard Worker       || !IsBufZero(buffer + k_Geometry_Size, LP_METADATA_GEOMETRY_SIZE - k_Geometry_Size))
562*f6dc9357SAndroid Build Coastguard Worker   {
563*f6dc9357SAndroid Build Coastguard Worker     _headerWarning = true;
564*f6dc9357SAndroid Build Coastguard Worker     // return S_FALSE;
565*f6dc9357SAndroid Build Coastguard Worker   }
566*f6dc9357SAndroid Build Coastguard Worker 
567*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, buffer, k_LpMetadataHeader10_size))
568*f6dc9357SAndroid Build Coastguard Worker   LpMetadataHeader header;
569*f6dc9357SAndroid Build Coastguard Worker   header.Parse128(buffer);
570*f6dc9357SAndroid Build Coastguard Worker   if (header.magic != LP_METADATA_HEADER_MAGIC ||
571*f6dc9357SAndroid Build Coastguard Worker       header.major_version != LP_METADATA_MAJOR_VERSION ||
572*f6dc9357SAndroid Build Coastguard Worker       header.header_size < k_LpMetadataHeader10_size)
573*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
574*f6dc9357SAndroid Build Coastguard Worker   Flags = 0;
575*f6dc9357SAndroid Build Coastguard Worker   if (header.header_size > k_LpMetadataHeader10_size)
576*f6dc9357SAndroid Build Coastguard Worker   {
577*f6dc9357SAndroid Build Coastguard Worker     if (header.header_size != k_LpMetadataHeader12_size)
578*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
579*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(stream, buffer + k_LpMetadataHeader10_size,
580*f6dc9357SAndroid Build Coastguard Worker         header.header_size - k_LpMetadataHeader10_size))
581*f6dc9357SAndroid Build Coastguard Worker     Flags = Get32(buffer + k_LpMetadataHeader10_size);
582*f6dc9357SAndroid Build Coastguard Worker   }
583*f6dc9357SAndroid Build Coastguard Worker   Major_version = header.major_version;
584*f6dc9357SAndroid Build Coastguard Worker   Minor_version = header.minor_version;
585*f6dc9357SAndroid Build Coastguard Worker 
586*f6dc9357SAndroid Build Coastguard Worker   if (!CheckSha256_csOffset(buffer, header.header_size, 12))
587*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
588*f6dc9357SAndroid Build Coastguard Worker 
589*f6dc9357SAndroid Build Coastguard Worker   if (geom.metadata_max_size < header.tables_size ||
590*f6dc9357SAndroid Build Coastguard Worker       geom.metadata_max_size - header.tables_size < header.header_size)
591*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
592*f6dc9357SAndroid Build Coastguard Worker 
593*f6dc9357SAndroid Build Coastguard Worker   buffer.AllocAtLeast(header.tables_size);
594*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, buffer, header.tables_size))
595*f6dc9357SAndroid Build Coastguard Worker 
596*f6dc9357SAndroid Build Coastguard Worker   const UInt64 totalMetaSize = geom.GetTotalMetadataSize();
597*f6dc9357SAndroid Build Coastguard Worker   // _headersSize = _totalSize;
598*f6dc9357SAndroid Build Coastguard Worker   _totalSize = totalMetaSize;
599*f6dc9357SAndroid Build Coastguard Worker 
600*f6dc9357SAndroid Build Coastguard Worker   if (!CheckSha256(buffer, header.tables_size, header.tables_checksum))
601*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
602*f6dc9357SAndroid Build Coastguard Worker 
603*f6dc9357SAndroid Build Coastguard Worker   {
604*f6dc9357SAndroid Build Coastguard Worker     const CDescriptor &d = header.partitions;
605*f6dc9357SAndroid Build Coastguard Worker     if (!d.CheckLimits(header.tables_size))
606*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
607*f6dc9357SAndroid Build Coastguard Worker     if (d.entry_size != k_MetaPartition_Size)
608*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
609*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < d.num_entries; i++)
610*f6dc9357SAndroid Build Coastguard Worker     {
611*f6dc9357SAndroid Build Coastguard Worker       CPartition part;
612*f6dc9357SAndroid Build Coastguard Worker       part.Parse(buffer + d.offset + i * d.entry_size);
613*f6dc9357SAndroid Build Coastguard Worker       const UInt32 extLimit = part.first_extent_index + part.num_extents;
614*f6dc9357SAndroid Build Coastguard Worker       if (extLimit < part.first_extent_index ||
615*f6dc9357SAndroid Build Coastguard Worker           extLimit > header.extents.num_entries ||
616*f6dc9357SAndroid Build Coastguard Worker           part.group_index >= header.groups.num_entries)
617*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
618*f6dc9357SAndroid Build Coastguard Worker       _items.Add(part);
619*f6dc9357SAndroid Build Coastguard Worker     }
620*f6dc9357SAndroid Build Coastguard Worker   }
621*f6dc9357SAndroid Build Coastguard Worker   {
622*f6dc9357SAndroid Build Coastguard Worker     const CDescriptor &d = header.extents;
623*f6dc9357SAndroid Build Coastguard Worker     if (!d.CheckLimits(header.tables_size))
624*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
625*f6dc9357SAndroid Build Coastguard Worker     if (d.entry_size != k_MetaExtent_Size)
626*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
627*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < d.num_entries; i++)
628*f6dc9357SAndroid Build Coastguard Worker     {
629*f6dc9357SAndroid Build Coastguard Worker       CExtent e;
630*f6dc9357SAndroid Build Coastguard Worker       e.Parse(buffer + d.offset + i * d.entry_size);
631*f6dc9357SAndroid Build Coastguard Worker       // if (e.target_type > LP_TARGET_TYPE_ZERO) return S_FALSE;
632*f6dc9357SAndroid Build Coastguard Worker       if (e.IsRAW())
633*f6dc9357SAndroid Build Coastguard Worker       {
634*f6dc9357SAndroid Build Coastguard Worker         if (e.target_source >= header.block_devices.num_entries)
635*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
636*f6dc9357SAndroid Build Coastguard Worker         const UInt64 endSector = e.target_data + e.num_sectors;
637*f6dc9357SAndroid Build Coastguard Worker         const UInt64 endOffset = endSector << kSectorSizeLog;
638*f6dc9357SAndroid Build Coastguard Worker         if (_totalSize < endOffset)
639*f6dc9357SAndroid Build Coastguard Worker           _totalSize = endOffset;
640*f6dc9357SAndroid Build Coastguard Worker       }
641*f6dc9357SAndroid Build Coastguard Worker       MethodsMask |= (UInt32)1 << e.target_type;
642*f6dc9357SAndroid Build Coastguard Worker       Extents.Add(e);
643*f6dc9357SAndroid Build Coastguard Worker     }
644*f6dc9357SAndroid Build Coastguard Worker   }
645*f6dc9357SAndroid Build Coastguard Worker 
646*f6dc9357SAndroid Build Coastguard Worker   // _usedSize = _totalSize;
647*f6dc9357SAndroid Build Coastguard Worker   {
648*f6dc9357SAndroid Build Coastguard Worker     const CDescriptor &d = header.groups;
649*f6dc9357SAndroid Build Coastguard Worker     if (!d.CheckLimits(header.tables_size))
650*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
651*f6dc9357SAndroid Build Coastguard Worker     if (d.entry_size != k_Group_Size)
652*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
653*f6dc9357SAndroid Build Coastguard Worker     AString s;
654*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < d.num_entries; i++)
655*f6dc9357SAndroid Build Coastguard Worker     {
656*f6dc9357SAndroid Build Coastguard Worker       CGroup g;
657*f6dc9357SAndroid Build Coastguard Worker       g.Parse(buffer + d.offset + i * d.entry_size);
658*f6dc9357SAndroid Build Coastguard Worker       if (_totalSize < g.maximum_size)
659*f6dc9357SAndroid Build Coastguard Worker         _totalSize = g.maximum_size;
660*f6dc9357SAndroid Build Coastguard Worker       s += "  ";
661*f6dc9357SAndroid Build Coastguard Worker       AddName36ToString(s, g.name, true);
662*f6dc9357SAndroid Build Coastguard Worker       AddComment_UInt64(s, "maximum_size", g.maximum_size);
663*f6dc9357SAndroid Build Coastguard Worker       AddComment_UInt64(s, "flags", g.flags);
664*f6dc9357SAndroid Build Coastguard Worker       s.Add_LF();
665*f6dc9357SAndroid Build Coastguard Worker     }
666*f6dc9357SAndroid Build Coastguard Worker     GroupsString = s;
667*f6dc9357SAndroid Build Coastguard Worker   }
668*f6dc9357SAndroid Build Coastguard Worker 
669*f6dc9357SAndroid Build Coastguard Worker   {
670*f6dc9357SAndroid Build Coastguard Worker     const CDescriptor &d = header.block_devices;
671*f6dc9357SAndroid Build Coastguard Worker     if (!d.CheckLimits(header.tables_size))
672*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
673*f6dc9357SAndroid Build Coastguard Worker     if (d.entry_size != k_Device_Size)
674*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
675*f6dc9357SAndroid Build Coastguard Worker     AString s;
676*f6dc9357SAndroid Build Coastguard Worker     // CRecordVector<CDevice> devices;
677*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < d.num_entries; i++)
678*f6dc9357SAndroid Build Coastguard Worker     {
679*f6dc9357SAndroid Build Coastguard Worker       CDevice v;
680*f6dc9357SAndroid Build Coastguard Worker       v.Parse(buffer + d.offset + i * d.entry_size);
681*f6dc9357SAndroid Build Coastguard Worker       // if (i == 0)
682*f6dc9357SAndroid Build Coastguard Worker       {
683*f6dc9357SAndroid Build Coastguard Worker         // it's super_device is first device;
684*f6dc9357SAndroid Build Coastguard Worker         if (totalMetaSize > (v.first_logical_sector << kSectorSizeLog))
685*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
686*f6dc9357SAndroid Build Coastguard Worker       }
687*f6dc9357SAndroid Build Coastguard Worker       if (_totalSize < v.size)
688*f6dc9357SAndroid Build Coastguard Worker         _totalSize = v.size;
689*f6dc9357SAndroid Build Coastguard Worker       s += "  ";
690*f6dc9357SAndroid Build Coastguard Worker       if (i == 0)
691*f6dc9357SAndroid Build Coastguard Worker         AddName36ToString(DeviceArcName, v.partition_name, true);
692*f6dc9357SAndroid Build Coastguard Worker       // devices.Add(v);
693*f6dc9357SAndroid Build Coastguard Worker       AddName36ToString(s, v.partition_name, true);
694*f6dc9357SAndroid Build Coastguard Worker       AddComment_UInt64(s, "size", v.size);
695*f6dc9357SAndroid Build Coastguard Worker       AddComment_UInt64(s, "first_logical_sector", v.first_logical_sector);
696*f6dc9357SAndroid Build Coastguard Worker       AddComment_UInt64(s, "alignment", v.alignment);
697*f6dc9357SAndroid Build Coastguard Worker       AddComment_UInt64(s, "alignment_offset", v.alignment_offset);
698*f6dc9357SAndroid Build Coastguard Worker       AddComment_UInt64(s, "flags", v.flags);
699*f6dc9357SAndroid Build Coastguard Worker       s.Add_LF();
700*f6dc9357SAndroid Build Coastguard Worker     }
701*f6dc9357SAndroid Build Coastguard Worker     DevicesString = s;
702*f6dc9357SAndroid Build Coastguard Worker   }
703*f6dc9357SAndroid Build Coastguard Worker 
704*f6dc9357SAndroid Build Coastguard Worker   {
705*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, _items)
706*f6dc9357SAndroid Build Coastguard Worker     {
707*f6dc9357SAndroid Build Coastguard Worker       CPartition &part = _items[i];
708*f6dc9357SAndroid Build Coastguard Worker       if (part.first_extent_index > Extents.Size() ||
709*f6dc9357SAndroid Build Coastguard Worker           part.num_extents > Extents.Size() - part.first_extent_index)
710*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
711*f6dc9357SAndroid Build Coastguard Worker 
712*f6dc9357SAndroid Build Coastguard Worker       UInt64 numSectors = 0;
713*f6dc9357SAndroid Build Coastguard Worker       UInt64 numSectors_Pack = 0;
714*f6dc9357SAndroid Build Coastguard Worker       UInt32 methods = 0;
715*f6dc9357SAndroid Build Coastguard Worker       for (UInt32 k = 0; k < part.num_extents; k++)
716*f6dc9357SAndroid Build Coastguard Worker       {
717*f6dc9357SAndroid Build Coastguard Worker         const CExtent &e = Extents[part.first_extent_index + k];
718*f6dc9357SAndroid Build Coastguard Worker         numSectors += e.num_sectors;
719*f6dc9357SAndroid Build Coastguard Worker         if (e.IsRAW())
720*f6dc9357SAndroid Build Coastguard Worker           numSectors_Pack += e.num_sectors;
721*f6dc9357SAndroid Build Coastguard Worker         methods |= (UInt32)1 << e.target_type;
722*f6dc9357SAndroid Build Coastguard Worker       }
723*f6dc9357SAndroid Build Coastguard Worker       part.NumSectors = numSectors;
724*f6dc9357SAndroid Build Coastguard Worker       part.NumSectors_Pack = numSectors_Pack;
725*f6dc9357SAndroid Build Coastguard Worker       part.MethodsMask = methods;
726*f6dc9357SAndroid Build Coastguard Worker     }
727*f6dc9357SAndroid Build Coastguard Worker   }
728*f6dc9357SAndroid Build Coastguard Worker 
729*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
730*f6dc9357SAndroid Build Coastguard Worker }
731*f6dc9357SAndroid Build Coastguard Worker 
732*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback *))733*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
734*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * /* maxCheckStartPosition */,
735*f6dc9357SAndroid Build Coastguard Worker     IArchiveOpenCallback * /* openArchiveCallback */))
736*f6dc9357SAndroid Build Coastguard Worker {
737*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
738*f6dc9357SAndroid Build Coastguard Worker   Close();
739*f6dc9357SAndroid Build Coastguard Worker   RINOK(Open2(stream))
740*f6dc9357SAndroid Build Coastguard Worker   _stream = stream;
741*f6dc9357SAndroid Build Coastguard Worker 
742*f6dc9357SAndroid Build Coastguard Worker   int mainFileIndex = -1;
743*f6dc9357SAndroid Build Coastguard Worker   unsigned numNonEmptyParts = 0;
744*f6dc9357SAndroid Build Coastguard Worker 
745*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (fileIndex, _items)
746*f6dc9357SAndroid Build Coastguard Worker   {
747*f6dc9357SAndroid Build Coastguard Worker     CPartition &item = _items[fileIndex];
748*f6dc9357SAndroid Build Coastguard Worker     if (item.NumSectors != 0)
749*f6dc9357SAndroid Build Coastguard Worker     {
750*f6dc9357SAndroid Build Coastguard Worker       mainFileIndex = (int)fileIndex;
751*f6dc9357SAndroid Build Coastguard Worker       numNonEmptyParts++;
752*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialInStream> parseStream;
753*f6dc9357SAndroid Build Coastguard Worker       if (GetStream(fileIndex, &parseStream) == S_OK && parseStream)
754*f6dc9357SAndroid Build Coastguard Worker       {
755*f6dc9357SAndroid Build Coastguard Worker         const size_t kParseSize = 1 << 11;
756*f6dc9357SAndroid Build Coastguard Worker         Byte buf[kParseSize];
757*f6dc9357SAndroid Build Coastguard Worker         if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK)
758*f6dc9357SAndroid Build Coastguard Worker         {
759*f6dc9357SAndroid Build Coastguard Worker           UInt64 extSize;
760*f6dc9357SAndroid Build Coastguard Worker           if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES)
761*f6dc9357SAndroid Build Coastguard Worker             if (extSize == item.GetSize())
762*f6dc9357SAndroid Build Coastguard Worker               item.Ext = "ext";
763*f6dc9357SAndroid Build Coastguard Worker         }
764*f6dc9357SAndroid Build Coastguard Worker       }
765*f6dc9357SAndroid Build Coastguard Worker     }
766*f6dc9357SAndroid Build Coastguard Worker   }
767*f6dc9357SAndroid Build Coastguard Worker   if (numNonEmptyParts == 1)
768*f6dc9357SAndroid Build Coastguard Worker     _mainFileIndex = mainFileIndex;
769*f6dc9357SAndroid Build Coastguard Worker 
770*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
771*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
772*f6dc9357SAndroid Build Coastguard Worker }
773*f6dc9357SAndroid Build Coastguard Worker 
774*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Close ())775*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
776*f6dc9357SAndroid Build Coastguard Worker {
777*f6dc9357SAndroid Build Coastguard Worker   _totalSize = 0;
778*f6dc9357SAndroid Build Coastguard Worker   // _usedSize = 0;
779*f6dc9357SAndroid Build Coastguard Worker   // _headersSize = 0;
780*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
781*f6dc9357SAndroid Build Coastguard Worker   Extents.Clear();
782*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
783*f6dc9357SAndroid Build Coastguard Worker   _mainFileIndex = -1;
784*f6dc9357SAndroid Build Coastguard Worker   _headerWarning = false;
785*f6dc9357SAndroid Build Coastguard Worker   MethodsMask = 0;
786*f6dc9357SAndroid Build Coastguard Worker   GroupsString.Empty();
787*f6dc9357SAndroid Build Coastguard Worker   DevicesString.Empty();
788*f6dc9357SAndroid Build Coastguard Worker   DeviceArcName.Empty();
789*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
790*f6dc9357SAndroid Build Coastguard Worker }
791*f6dc9357SAndroid Build Coastguard Worker 
792*f6dc9357SAndroid Build Coastguard Worker 
793*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
794*f6dc9357SAndroid Build Coastguard Worker {
795*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
796*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
797*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
798*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts,
799*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
800*f6dc9357SAndroid Build Coastguard Worker   kpidNumBlocks,
801*f6dc9357SAndroid Build Coastguard Worker   kpidOffset
802*f6dc9357SAndroid Build Coastguard Worker };
803*f6dc9357SAndroid Build Coastguard Worker 
804*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
805*f6dc9357SAndroid Build Coastguard Worker {
806*f6dc9357SAndroid Build Coastguard Worker   kpidUnpackVer,
807*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
808*f6dc9357SAndroid Build Coastguard Worker   kpidClusterSize,
809*f6dc9357SAndroid Build Coastguard Worker   // kpidHeadersSize,
810*f6dc9357SAndroid Build Coastguard Worker   // kpidFreeSpace,
811*f6dc9357SAndroid Build Coastguard Worker   kpidName,
812*f6dc9357SAndroid Build Coastguard Worker   kpidComment
813*f6dc9357SAndroid Build Coastguard Worker };
814*f6dc9357SAndroid Build Coastguard Worker 
815*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
816*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
817*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))818*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
819*f6dc9357SAndroid Build Coastguard Worker {
820*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
821*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
822*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
823*f6dc9357SAndroid Build Coastguard Worker   {
824*f6dc9357SAndroid Build Coastguard Worker     case kpidMainSubfile:
825*f6dc9357SAndroid Build Coastguard Worker     {
826*f6dc9357SAndroid Build Coastguard Worker       if (_mainFileIndex >= 0)
827*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)_mainFileIndex;
828*f6dc9357SAndroid Build Coastguard Worker       break;
829*f6dc9357SAndroid Build Coastguard Worker     }
830*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _totalSize; break;
831*f6dc9357SAndroid Build Coastguard Worker 
832*f6dc9357SAndroid Build Coastguard Worker     // case kpidFreeSpace: if (_usedSize != 0) prop = _totalSize - _usedSize; break;
833*f6dc9357SAndroid Build Coastguard Worker     // case kpidHeadersSize: prop = _headersSize; break;
834*f6dc9357SAndroid Build Coastguard Worker 
835*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
836*f6dc9357SAndroid Build Coastguard Worker     {
837*f6dc9357SAndroid Build Coastguard Worker       const UInt32 m = MethodsMask;
838*f6dc9357SAndroid Build Coastguard Worker       if (m != 0)
839*f6dc9357SAndroid Build Coastguard Worker       {
840*f6dc9357SAndroid Build Coastguard Worker         FLAGS_TO_PROP(g_Methods, m, prop);
841*f6dc9357SAndroid Build Coastguard Worker       }
842*f6dc9357SAndroid Build Coastguard Worker       break;
843*f6dc9357SAndroid Build Coastguard Worker     }
844*f6dc9357SAndroid Build Coastguard Worker 
845*f6dc9357SAndroid Build Coastguard Worker     case kpidUnpackVer:
846*f6dc9357SAndroid Build Coastguard Worker     {
847*f6dc9357SAndroid Build Coastguard Worker       AString s;
848*f6dc9357SAndroid Build Coastguard Worker       s.Add_UInt32(Major_version);
849*f6dc9357SAndroid Build Coastguard Worker       s.Add_Dot();
850*f6dc9357SAndroid Build Coastguard Worker       s.Add_UInt32(Minor_version);
851*f6dc9357SAndroid Build Coastguard Worker       prop = s;
852*f6dc9357SAndroid Build Coastguard Worker       break;
853*f6dc9357SAndroid Build Coastguard Worker     }
854*f6dc9357SAndroid Build Coastguard Worker 
855*f6dc9357SAndroid Build Coastguard Worker     case kpidClusterSize:
856*f6dc9357SAndroid Build Coastguard Worker       prop = geom.logical_block_size;
857*f6dc9357SAndroid Build Coastguard Worker       break;
858*f6dc9357SAndroid Build Coastguard Worker 
859*f6dc9357SAndroid Build Coastguard Worker     case kpidComment:
860*f6dc9357SAndroid Build Coastguard Worker     {
861*f6dc9357SAndroid Build Coastguard Worker       AString s;
862*f6dc9357SAndroid Build Coastguard Worker 
863*f6dc9357SAndroid Build Coastguard Worker       s += "metadata_slot_count: ";
864*f6dc9357SAndroid Build Coastguard Worker       s.Add_UInt32(geom.metadata_slot_count);
865*f6dc9357SAndroid Build Coastguard Worker       s.Add_LF();
866*f6dc9357SAndroid Build Coastguard Worker 
867*f6dc9357SAndroid Build Coastguard Worker       s += "metadata_max_size: ";
868*f6dc9357SAndroid Build Coastguard Worker       s.Add_UInt32(geom.metadata_max_size);
869*f6dc9357SAndroid Build Coastguard Worker       s.Add_LF();
870*f6dc9357SAndroid Build Coastguard Worker 
871*f6dc9357SAndroid Build Coastguard Worker       if (Flags != 0)
872*f6dc9357SAndroid Build Coastguard Worker       {
873*f6dc9357SAndroid Build Coastguard Worker         s += "flags: ";
874*f6dc9357SAndroid Build Coastguard Worker         s += FlagsToString(g_Header_Flags, Z7_ARRAY_SIZE(g_Header_Flags), Flags);
875*f6dc9357SAndroid Build Coastguard Worker         s.Add_LF();
876*f6dc9357SAndroid Build Coastguard Worker       }
877*f6dc9357SAndroid Build Coastguard Worker 
878*f6dc9357SAndroid Build Coastguard Worker       if (!GroupsString.IsEmpty())
879*f6dc9357SAndroid Build Coastguard Worker       {
880*f6dc9357SAndroid Build Coastguard Worker         s += "Groups:";
881*f6dc9357SAndroid Build Coastguard Worker         s.Add_LF();
882*f6dc9357SAndroid Build Coastguard Worker         s += GroupsString;
883*f6dc9357SAndroid Build Coastguard Worker       }
884*f6dc9357SAndroid Build Coastguard Worker 
885*f6dc9357SAndroid Build Coastguard Worker       if (!DevicesString.IsEmpty())
886*f6dc9357SAndroid Build Coastguard Worker       {
887*f6dc9357SAndroid Build Coastguard Worker         s += "BlockDevices:";
888*f6dc9357SAndroid Build Coastguard Worker         s.Add_LF();
889*f6dc9357SAndroid Build Coastguard Worker         s += DevicesString;
890*f6dc9357SAndroid Build Coastguard Worker       }
891*f6dc9357SAndroid Build Coastguard Worker 
892*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
893*f6dc9357SAndroid Build Coastguard Worker         prop = s;
894*f6dc9357SAndroid Build Coastguard Worker       break;
895*f6dc9357SAndroid Build Coastguard Worker     }
896*f6dc9357SAndroid Build Coastguard Worker 
897*f6dc9357SAndroid Build Coastguard Worker     case kpidName:
898*f6dc9357SAndroid Build Coastguard Worker       if (!DeviceArcName.IsEmpty())
899*f6dc9357SAndroid Build Coastguard Worker         prop = DeviceArcName + ".lpimg";
900*f6dc9357SAndroid Build Coastguard Worker       break;
901*f6dc9357SAndroid Build Coastguard Worker 
902*f6dc9357SAndroid Build Coastguard Worker     case kpidWarningFlags:
903*f6dc9357SAndroid Build Coastguard Worker       if (_headerWarning)
904*f6dc9357SAndroid Build Coastguard Worker       {
905*f6dc9357SAndroid Build Coastguard Worker         UInt32 v = kpv_ErrorFlags_HeadersError;
906*f6dc9357SAndroid Build Coastguard Worker         prop = v;
907*f6dc9357SAndroid Build Coastguard Worker       }
908*f6dc9357SAndroid Build Coastguard Worker       break;
909*f6dc9357SAndroid Build Coastguard Worker   }
910*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
911*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
912*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
913*f6dc9357SAndroid Build Coastguard Worker }
914*f6dc9357SAndroid Build Coastguard Worker 
915*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))916*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
917*f6dc9357SAndroid Build Coastguard Worker {
918*f6dc9357SAndroid Build Coastguard Worker   *numItems = _items.Size();
919*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
920*f6dc9357SAndroid Build Coastguard Worker }
921*f6dc9357SAndroid Build Coastguard Worker 
922*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))923*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
924*f6dc9357SAndroid Build Coastguard Worker {
925*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
926*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
927*f6dc9357SAndroid Build Coastguard Worker 
928*f6dc9357SAndroid Build Coastguard Worker   const CPartition &item = _items[index];
929*f6dc9357SAndroid Build Coastguard Worker 
930*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
931*f6dc9357SAndroid Build Coastguard Worker   {
932*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
933*f6dc9357SAndroid Build Coastguard Worker     {
934*f6dc9357SAndroid Build Coastguard Worker       AString s;
935*f6dc9357SAndroid Build Coastguard Worker       AddName36ToString(s, item.name, false);
936*f6dc9357SAndroid Build Coastguard Worker       if (s.IsEmpty())
937*f6dc9357SAndroid Build Coastguard Worker         s.Add_UInt32(index);
938*f6dc9357SAndroid Build Coastguard Worker       if (item.num_extents != 0)
939*f6dc9357SAndroid Build Coastguard Worker       {
940*f6dc9357SAndroid Build Coastguard Worker         s.Add_Dot();
941*f6dc9357SAndroid Build Coastguard Worker         s += (item.Ext ? item.Ext : "img");
942*f6dc9357SAndroid Build Coastguard Worker       }
943*f6dc9357SAndroid Build Coastguard Worker       prop = s;
944*f6dc9357SAndroid Build Coastguard Worker       break;
945*f6dc9357SAndroid Build Coastguard Worker     }
946*f6dc9357SAndroid Build Coastguard Worker 
947*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: prop = item.GetSize(); break;
948*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize: prop = item.GetPackSize(); break;
949*f6dc9357SAndroid Build Coastguard Worker     case kpidNumBlocks: prop = item.num_extents; break;
950*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
951*f6dc9357SAndroid Build Coastguard Worker     {
952*f6dc9357SAndroid Build Coastguard Worker       const UInt32 m = item.MethodsMask;
953*f6dc9357SAndroid Build Coastguard Worker       if (m != 0)
954*f6dc9357SAndroid Build Coastguard Worker       {
955*f6dc9357SAndroid Build Coastguard Worker         FLAGS_TO_PROP(g_Methods, m, prop);
956*f6dc9357SAndroid Build Coastguard Worker       }
957*f6dc9357SAndroid Build Coastguard Worker       break;
958*f6dc9357SAndroid Build Coastguard Worker     }
959*f6dc9357SAndroid Build Coastguard Worker     case kpidOffset:
960*f6dc9357SAndroid Build Coastguard Worker       if (item.num_extents != 0)
961*f6dc9357SAndroid Build Coastguard Worker         if (item.first_extent_index < Extents.Size())
962*f6dc9357SAndroid Build Coastguard Worker           prop = Extents[item.first_extent_index].target_data << kSectorSizeLog;
963*f6dc9357SAndroid Build Coastguard Worker       break;
964*f6dc9357SAndroid Build Coastguard Worker 
965*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts:
966*f6dc9357SAndroid Build Coastguard Worker     {
967*f6dc9357SAndroid Build Coastguard Worker       AString s;
968*f6dc9357SAndroid Build Coastguard Worker       s += "group:";
969*f6dc9357SAndroid Build Coastguard Worker       s.Add_UInt32(item.group_index);
970*f6dc9357SAndroid Build Coastguard Worker       s.Add_Space();
971*f6dc9357SAndroid Build Coastguard Worker       s += FlagsToString(g_PartitionAttr, Z7_ARRAY_SIZE(g_PartitionAttr), item.attributes);
972*f6dc9357SAndroid Build Coastguard Worker       prop = s;
973*f6dc9357SAndroid Build Coastguard Worker       break;
974*f6dc9357SAndroid Build Coastguard Worker     }
975*f6dc9357SAndroid Build Coastguard Worker   }
976*f6dc9357SAndroid Build Coastguard Worker 
977*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
978*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
979*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
980*f6dc9357SAndroid Build Coastguard Worker }
981*f6dc9357SAndroid Build Coastguard Worker 
982*f6dc9357SAndroid Build Coastguard Worker 
983*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetStream (UInt32 index,ISequentialInStream ** stream))984*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
985*f6dc9357SAndroid Build Coastguard Worker {
986*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
987*f6dc9357SAndroid Build Coastguard Worker   *stream = NULL;
988*f6dc9357SAndroid Build Coastguard Worker 
989*f6dc9357SAndroid Build Coastguard Worker   const CPartition &item = _items[index];
990*f6dc9357SAndroid Build Coastguard Worker 
991*f6dc9357SAndroid Build Coastguard Worker   if (item.first_extent_index > Extents.Size()
992*f6dc9357SAndroid Build Coastguard Worker       || item.num_extents > Extents.Size() - item.first_extent_index)
993*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
994*f6dc9357SAndroid Build Coastguard Worker 
995*f6dc9357SAndroid Build Coastguard Worker   if (item.num_extents == 0)
996*f6dc9357SAndroid Build Coastguard Worker     return CreateLimitedInStream(_stream, 0, 0, stream);
997*f6dc9357SAndroid Build Coastguard Worker 
998*f6dc9357SAndroid Build Coastguard Worker   if (item.num_extents == 1)
999*f6dc9357SAndroid Build Coastguard Worker   {
1000*f6dc9357SAndroid Build Coastguard Worker     const CExtent &e = Extents[item.first_extent_index];
1001*f6dc9357SAndroid Build Coastguard Worker     if (e.IsRAW())
1002*f6dc9357SAndroid Build Coastguard Worker     {
1003*f6dc9357SAndroid Build Coastguard Worker       const UInt64 pos = e.target_data << kSectorSizeLog;
1004*f6dc9357SAndroid Build Coastguard Worker       if ((pos >> kSectorSizeLog) != e.target_data)
1005*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1006*f6dc9357SAndroid Build Coastguard Worker       const UInt64 size = item.GetSize();
1007*f6dc9357SAndroid Build Coastguard Worker       if (pos + size < pos)
1008*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1009*f6dc9357SAndroid Build Coastguard Worker       return CreateLimitedInStream(_stream, pos, size, stream);
1010*f6dc9357SAndroid Build Coastguard Worker     }
1011*f6dc9357SAndroid Build Coastguard Worker   }
1012*f6dc9357SAndroid Build Coastguard Worker 
1013*f6dc9357SAndroid Build Coastguard Worker   CExtentsStream *extentStreamSpec = new CExtentsStream();
1014*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
1015*f6dc9357SAndroid Build Coastguard Worker 
1016*f6dc9357SAndroid Build Coastguard Worker   // const unsigned kNumDebugExtents = 10;
1017*f6dc9357SAndroid Build Coastguard Worker   extentStreamSpec->Extents.Reserve(item.num_extents + 1
1018*f6dc9357SAndroid Build Coastguard Worker       // + kNumDebugExtents
1019*f6dc9357SAndroid Build Coastguard Worker       );
1020*f6dc9357SAndroid Build Coastguard Worker 
1021*f6dc9357SAndroid Build Coastguard Worker   UInt64 virt = 0;
1022*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 k = 0; k < item.num_extents; k++)
1023*f6dc9357SAndroid Build Coastguard Worker   {
1024*f6dc9357SAndroid Build Coastguard Worker     const CExtent &e = Extents[item.first_extent_index + k];
1025*f6dc9357SAndroid Build Coastguard Worker 
1026*f6dc9357SAndroid Build Coastguard Worker     CSeekExtent se;
1027*f6dc9357SAndroid Build Coastguard Worker     {
1028*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numSectors = e.num_sectors;
1029*f6dc9357SAndroid Build Coastguard Worker       if (numSectors == 0)
1030*f6dc9357SAndroid Build Coastguard Worker       {
1031*f6dc9357SAndroid Build Coastguard Worker         continue;
1032*f6dc9357SAndroid Build Coastguard Worker         // return S_FALSE;
1033*f6dc9357SAndroid Build Coastguard Worker       }
1034*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numBytes = numSectors << kSectorSizeLog;
1035*f6dc9357SAndroid Build Coastguard Worker       if ((numBytes >> kSectorSizeLog) != numSectors)
1036*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1037*f6dc9357SAndroid Build Coastguard Worker       if (numBytes >= ((UInt64)1 << 63) - virt)
1038*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1039*f6dc9357SAndroid Build Coastguard Worker 
1040*f6dc9357SAndroid Build Coastguard Worker       se.Virt = virt;
1041*f6dc9357SAndroid Build Coastguard Worker       virt += numBytes;
1042*f6dc9357SAndroid Build Coastguard Worker     }
1043*f6dc9357SAndroid Build Coastguard Worker 
1044*f6dc9357SAndroid Build Coastguard Worker     const UInt64 phySector = e.target_data;
1045*f6dc9357SAndroid Build Coastguard Worker     if (e.target_type == LP_TARGET_TYPE_ZERO)
1046*f6dc9357SAndroid Build Coastguard Worker     {
1047*f6dc9357SAndroid Build Coastguard Worker       if (phySector != 0)
1048*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1049*f6dc9357SAndroid Build Coastguard Worker       se.SetAs_ZeroFill();
1050*f6dc9357SAndroid Build Coastguard Worker     }
1051*f6dc9357SAndroid Build Coastguard Worker     else if (e.target_type == LP_TARGET_TYPE_LINEAR)
1052*f6dc9357SAndroid Build Coastguard Worker     {
1053*f6dc9357SAndroid Build Coastguard Worker       se.Phy = phySector << kSectorSizeLog;
1054*f6dc9357SAndroid Build Coastguard Worker       if ((se.Phy >> kSectorSizeLog) != phySector)
1055*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1056*f6dc9357SAndroid Build Coastguard Worker       if (se.Phy >= ((UInt64)1 << 63))
1057*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1058*f6dc9357SAndroid Build Coastguard Worker     }
1059*f6dc9357SAndroid Build Coastguard Worker     else
1060*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1061*f6dc9357SAndroid Build Coastguard Worker 
1062*f6dc9357SAndroid Build Coastguard Worker     extentStreamSpec->Extents.AddInReserved(se);
1063*f6dc9357SAndroid Build Coastguard Worker 
1064*f6dc9357SAndroid Build Coastguard Worker     /*
1065*f6dc9357SAndroid Build Coastguard Worker     {
1066*f6dc9357SAndroid Build Coastguard Worker       // for debug
1067*f6dc9357SAndroid Build Coastguard Worker       const UInt64 kAdd = (e.num_sectors << kSectorSizeLog) / kNumDebugExtents;
1068*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < kNumDebugExtents; i++)
1069*f6dc9357SAndroid Build Coastguard Worker       {
1070*f6dc9357SAndroid Build Coastguard Worker         se.Phy += kAdd;
1071*f6dc9357SAndroid Build Coastguard Worker         // se.Phy += (UInt64)1 << 63; // for debug
1072*f6dc9357SAndroid Build Coastguard Worker         // se.Phy += 1; // for debug
1073*f6dc9357SAndroid Build Coastguard Worker         se.Virt += kAdd;
1074*f6dc9357SAndroid Build Coastguard Worker         extentStreamSpec->Extents.AddInReserved(se);
1075*f6dc9357SAndroid Build Coastguard Worker       }
1076*f6dc9357SAndroid Build Coastguard Worker     }
1077*f6dc9357SAndroid Build Coastguard Worker     */
1078*f6dc9357SAndroid Build Coastguard Worker   }
1079*f6dc9357SAndroid Build Coastguard Worker 
1080*f6dc9357SAndroid Build Coastguard Worker   CSeekExtent se;
1081*f6dc9357SAndroid Build Coastguard Worker   se.Phy = 0;
1082*f6dc9357SAndroid Build Coastguard Worker   se.Virt = virt;
1083*f6dc9357SAndroid Build Coastguard Worker   extentStreamSpec->Extents.Add(se);
1084*f6dc9357SAndroid Build Coastguard Worker   extentStreamSpec->Stream = _stream;
1085*f6dc9357SAndroid Build Coastguard Worker   extentStreamSpec->Init();
1086*f6dc9357SAndroid Build Coastguard Worker   *stream = extentStream.Detach();
1087*f6dc9357SAndroid Build Coastguard Worker 
1088*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1089*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1090*f6dc9357SAndroid Build Coastguard Worker }
1091*f6dc9357SAndroid Build Coastguard Worker 
1092*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))1093*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1094*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
1095*f6dc9357SAndroid Build Coastguard Worker {
1096*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1097*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
1098*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
1099*f6dc9357SAndroid Build Coastguard Worker     numItems = _items.Size();
1100*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
1101*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1102*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
1103*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
1104*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
1105*f6dc9357SAndroid Build Coastguard Worker   {
1106*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
1107*f6dc9357SAndroid Build Coastguard Worker     totalSize += _items[index].GetSize();
1108*f6dc9357SAndroid Build Coastguard Worker   }
1109*f6dc9357SAndroid Build Coastguard Worker   extractCallback->SetTotal(totalSize);
1110*f6dc9357SAndroid Build Coastguard Worker 
1111*f6dc9357SAndroid Build Coastguard Worker   totalSize = 0;
1112*f6dc9357SAndroid Build Coastguard Worker 
1113*f6dc9357SAndroid Build Coastguard Worker   NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
1114*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
1115*f6dc9357SAndroid Build Coastguard Worker 
1116*f6dc9357SAndroid Build Coastguard Worker   CLocalProgress *lps = new CLocalProgress;
1117*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressProgressInfo> progress = lps;
1118*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
1119*f6dc9357SAndroid Build Coastguard Worker 
1120*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
1121*f6dc9357SAndroid Build Coastguard Worker   {
1122*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = totalSize;
1123*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = totalSize;
1124*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
1125*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialOutStream> outStream;
1126*f6dc9357SAndroid Build Coastguard Worker     const Int32 askMode = testMode ?
1127*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
1128*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
1129*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
1130*f6dc9357SAndroid Build Coastguard Worker 
1131*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->GetStream(index, &outStream, askMode))
1132*f6dc9357SAndroid Build Coastguard Worker 
1133*f6dc9357SAndroid Build Coastguard Worker     const UInt64 size = _items[index].GetSize();
1134*f6dc9357SAndroid Build Coastguard Worker     totalSize += size;
1135*f6dc9357SAndroid Build Coastguard Worker     if (!testMode && !outStream)
1136*f6dc9357SAndroid Build Coastguard Worker       continue;
1137*f6dc9357SAndroid Build Coastguard Worker 
1138*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->PrepareOperation(askMode))
1139*f6dc9357SAndroid Build Coastguard Worker 
1140*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialInStream> inStream;
1141*f6dc9357SAndroid Build Coastguard Worker     const HRESULT hres = GetStream(index, &inStream);
1142*f6dc9357SAndroid Build Coastguard Worker     int opRes = NExtract::NOperationResult::kUnsupportedMethod;
1143*f6dc9357SAndroid Build Coastguard Worker     if (hres != S_FALSE)
1144*f6dc9357SAndroid Build Coastguard Worker     {
1145*f6dc9357SAndroid Build Coastguard Worker       if (hres != S_OK)
1146*f6dc9357SAndroid Build Coastguard Worker         return hres;
1147*f6dc9357SAndroid Build Coastguard Worker       RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
1148*f6dc9357SAndroid Build Coastguard Worker       opRes = NExtract::NOperationResult::kDataError;
1149*f6dc9357SAndroid Build Coastguard Worker       if (copyCoderSpec->TotalSize == size)
1150*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kOK;
1151*f6dc9357SAndroid Build Coastguard Worker       else if (copyCoderSpec->TotalSize < size)
1152*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kUnexpectedEnd;
1153*f6dc9357SAndroid Build Coastguard Worker     }
1154*f6dc9357SAndroid Build Coastguard Worker     outStream.Release();
1155*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
1156*f6dc9357SAndroid Build Coastguard Worker   }
1157*f6dc9357SAndroid Build Coastguard Worker 
1158*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1159*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1160*f6dc9357SAndroid Build Coastguard Worker }
1161*f6dc9357SAndroid Build Coastguard Worker 
1162*f6dc9357SAndroid Build Coastguard Worker 
1163*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
1164*f6dc9357SAndroid Build Coastguard Worker   "LP", "lpimg img", NULL, 0xc1,
1165*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
1166*f6dc9357SAndroid Build Coastguard Worker   LP_PARTITION_RESERVED_BYTES,
1167*f6dc9357SAndroid Build Coastguard Worker   0,
1168*f6dc9357SAndroid Build Coastguard Worker   NULL)
1169*f6dc9357SAndroid Build Coastguard Worker 
1170*f6dc9357SAndroid Build Coastguard Worker }}
1171