1 // Archive/IsoIn.h
2 
3 #ifndef __ARCHIVE_ISO_IN_H
4 #define __ARCHIVE_ISO_IN_H
5 
6 #include "../../../Common/MyCom.h"
7 
8 #include "../../IStream.h"
9 
10 #include "IsoHeader.h"
11 #include "IsoItem.h"
12 
13 namespace NArchive {
14 namespace NIso {
15 
16 struct CDir: public CDirRecord
17 {
18   CDir *Parent;
19   CObjectVector<CDir> _subItems;
20 
ClearCDir21   void Clear()
22   {
23     Parent = 0;
24     _subItems.Clear();
25   }
26 
GetPathCDir27   AString GetPath(bool checkSusp, unsigned skipSize) const
28   {
29     AString s;
30 
31     unsigned len = 0;
32     const CDir *cur = this;
33 
34     for (;;)
35     {
36       unsigned curLen;
37       cur->GetNameCur(checkSusp, skipSize, curLen);
38       len += curLen;
39       cur = cur->Parent;
40       if (!cur || !cur->Parent)
41         break;
42       len++;
43     }
44 
45     char *p = s.GetBuf_SetEnd(len) + len;
46 
47     cur = this;
48 
49     for (;;)
50     {
51       unsigned curLen;
52       const Byte *name = cur->GetNameCur(checkSusp, skipSize, curLen);
53       p -= curLen;
54       if (curLen != 0)
55         memcpy(p, name, curLen);
56       cur = cur->Parent;
57       if (!cur || !cur->Parent)
58         break;
59       p--;
60       *p = CHAR_PATH_SEPARATOR;
61     }
62 
63     return s;
64   }
65 
GetPathUCDir66   void GetPathU(UString &s) const
67   {
68     s.Empty();
69 
70     unsigned len = 0;
71     const CDir *cur = this;
72 
73     for (;;)
74     {
75       unsigned curLen = (unsigned)(cur->FileId.Size() / 2);
76       const Byte *fid = cur->FileId;
77 
78       unsigned i;
79       for (i = 0; i < curLen; i++)
80         if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0)
81           break;
82       len += i;
83       cur = cur->Parent;
84       if (!cur || !cur->Parent)
85         break;
86       len++;
87     }
88 
89     wchar_t *p = s.GetBuf_SetEnd(len) + len;
90 
91     cur = this;
92 
93     for (;;)
94     {
95       unsigned curLen = (unsigned)(cur->FileId.Size() / 2);
96       const Byte *fid = cur->FileId;
97 
98       unsigned i;
99       for (i = 0; i < curLen; i++)
100         if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0)
101           break;
102       curLen = i;
103 
104       p -= curLen;
105       for (i = 0; i < curLen; i++)
106         p[i] = (wchar_t)(((wchar_t)fid[i * 2] << 8) | fid[i * 2 + 1]);
107       cur = cur->Parent;
108       if (!cur || !cur->Parent)
109         break;
110       p--;
111       *p = WCHAR_PATH_SEPARATOR;
112     }
113   }
114 };
115 
116 struct CDateTime
117 {
118   UInt16 Year;
119   Byte Month;
120   Byte Day;
121   Byte Hour;
122   Byte Minute;
123   Byte Second;
124   Byte Hundredths;
125   signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
126 
NotSpecifiedCDateTime127   bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
128       Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
129 
GetFileTimeCDateTime130   bool GetFileTime(FILETIME &ft) const
131   {
132     UInt64 value;
133     bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value);
134     if (res)
135     {
136       value -= (Int64)((Int32)GmtOffset * 15 * 60);
137       value *= 10000000;
138     }
139     ft.dwLowDateTime = (DWORD)value;
140     ft.dwHighDateTime = (DWORD)(value >> 32);
141     return res;
142   }
143 };
144 
145 struct CBootRecordDescriptor
146 {
147   Byte BootSystemId[32];  // a-characters
148   Byte BootId[32];        // a-characters
149   Byte BootSystemUse[1977];
150 };
151 
152 struct CBootValidationEntry
153 {
154   Byte PlatformId;
155   Byte Id[24]; // to identify the manufacturer/developer of the CD-ROM.
156 };
157 
158 struct CBootInitialEntry
159 {
160   bool Bootable;
161   Byte BootMediaType;
162   UInt16 LoadSegment;
163   /* This is the load segment for the initial boot image. If this
164      value is 0 the system will use the traditional segment of 7C0. If this value
165      is non-zero the system will use the specified segment. This applies to x86
166      architectures only. For "flat" model architectures (such as Motorola) this
167      is the address divided by 10. */
168   Byte SystemType;    // This must be a copy of byte 5 (System Type) from the
169                       // Partition Table found in the boot image.
170   UInt16 SectorCount; // This is the number of virtual/emulated sectors the system
171                       // will store at Load Segment during the initial boot procedure.
172   UInt32 LoadRBA;     // This is the start address of the virtual disk. CDs use
173                       // Relative/Logical block addressing.
174 
175   Byte VendorSpec[20];
176 
GetSizeCBootInitialEntry177   UInt32 GetSize() const
178   {
179     // if (BootMediaType == NBootMediaType::k1d44Floppy) (1440 << 10);
180     return (UInt32)SectorCount * 512;
181   }
182 
183   bool Parse(const Byte *p);
184   AString GetName() const;
185 };
186 
187 struct CVolumeDescriptor
188 {
189   Byte VolFlags;
190   Byte SystemId[32]; // a-characters. An identification of a system
191                      // which can recognize and act upon the content of the Logical
192                      // Sectors with logical Sector Numbers 0 to 15 of the volume.
193   Byte VolumeId[32]; // d-characters. An identification of the volume.
194   UInt32 VolumeSpaceSize; // the number of Logical Blocks in which the Volume Space of the volume is recorded
195   Byte EscapeSequence[32];
196   UInt16 VolumeSetSize;
197   UInt16 VolumeSequenceNumber; // the ordinal number of the volume in the Volume Set of which the volume is a member.
198   UInt16 LogicalBlockSize;
199   UInt32 PathTableSize;
200   UInt32 LPathTableLocation;
201   UInt32 LOptionalPathTableLocation;
202   UInt32 MPathTableLocation;
203   UInt32 MOptionalPathTableLocation;
204   CDirRecord RootDirRecord;
205   Byte VolumeSetId[128];
206   Byte PublisherId[128];
207   Byte DataPreparerId[128];
208   Byte ApplicationId[128];
209   Byte CopyrightFileId[37];
210   Byte AbstractFileId[37];
211   Byte BibFileId[37];
212   CDateTime CTime;
213   CDateTime MTime;
214   CDateTime ExpirationTime;
215   CDateTime EffectiveTime;
216   Byte FileStructureVersion; // = 1;
217   Byte ApplicationUse[512];
218 
IsJolietCVolumeDescriptor219   bool IsJoliet() const
220   {
221     if ((VolFlags & 1) != 0)
222       return false;
223     Byte b = EscapeSequence[2];
224     return (EscapeSequence[0] == 0x25 && EscapeSequence[1] == 0x2F &&
225       (b == 0x40 || b == 0x43 || b == 0x45));
226   }
227 };
228 
229 struct CRef
230 {
231   const CDir *Dir;
232   UInt32 Index;
233   UInt32 NumExtents;
234   UInt64 TotalSize;
235 };
236 
237 const UInt32 kBlockSize = 1 << 11;
238 
239 class CInArchive
240 {
241   IInStream *_stream;
242   UInt64 _position;
243 
244   UInt32 m_BufferPos;
245 
246   CDir _rootDir;
247   bool _bootIsDefined;
248   CBootRecordDescriptor _bootDesc;
249 
250   void Skip(size_t size);
251   void SkipZeros(size_t size);
252   Byte ReadByte();
253   void ReadBytes(Byte *data, UInt32 size);
254   UInt16 ReadUInt16();
255   UInt32 ReadUInt32Le();
256   UInt32 ReadUInt32Be();
257   UInt32 ReadUInt32();
258   UInt64 ReadUInt64();
259   UInt32 ReadDigits(int numDigits);
260   void ReadDateTime(CDateTime &d);
261   void ReadRecordingDateTime(CRecordingDateTime &t);
262   void ReadDirRecord2(CDirRecord &r, Byte len);
263   void ReadDirRecord(CDirRecord &r);
264 
265   void ReadBootRecordDescriptor(CBootRecordDescriptor &d);
266   void ReadVolumeDescriptor(CVolumeDescriptor &d);
267 
268   void SeekToBlock(UInt32 blockIndex);
269   void ReadDir(CDir &d, int level);
270   void CreateRefs(CDir &d);
271 
272   void ReadBootInfo();
273   HRESULT Open2();
274 public:
275   HRESULT Open(IInStream *inStream);
276   void Clear();
277 
278   UInt64 _fileSize;
279   UInt64 PhySize;
280 
281   CRecordVector<CRef> Refs;
282   CObjectVector<CVolumeDescriptor> VolDescs;
283   int MainVolDescIndex;
284   // UInt32 BlockSize;
285   CObjectVector<CBootInitialEntry> BootEntries;
286 
287   bool IsArc;
288   bool UnexpectedEnd;
289   bool HeadersError;
290   bool IncorrectBigEndian;
291   bool TooDeepDirs;
292   bool SelfLinkedDirs;
293   CRecordVector<UInt32> UniqStartLocations;
294 
295   Byte m_Buffer[kBlockSize];
296 
UpdatePhySize(UInt32 blockIndex,UInt64 size)297   void UpdatePhySize(UInt32 blockIndex, UInt64 size)
298   {
299     const UInt64 alignedSize = (size + kBlockSize - 1) & ~((UInt64)kBlockSize - 1);
300     const UInt64 end = (UInt64)blockIndex * kBlockSize + alignedSize;
301     if (PhySize < end)
302       PhySize = end;
303   }
304 
IsJoliet()305   bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); }
306 
GetBootItemSize(int index)307   UInt64 GetBootItemSize(int index) const
308   {
309     const CBootInitialEntry &be = BootEntries[index];
310     UInt64 size = be.GetSize();
311     if (be.BootMediaType == NBootMediaType::k1d2Floppy)
312       size = (1200 << 10);
313     else if (be.BootMediaType == NBootMediaType::k1d44Floppy)
314       size = (1440 << 10);
315     else if (be.BootMediaType == NBootMediaType::k2d88Floppy)
316       size = (2880 << 10);
317     UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize;
318     if (startPos < _fileSize)
319     {
320       if (_fileSize - startPos < size)
321         size = _fileSize - startPos;
322     }
323     return size;
324   }
325 
326   bool IsSusp;
327   unsigned SuspSkipSize;
328 };
329 
330 }}
331 
332 #endif
333