xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Iso/IsoIn.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Archive/IsoIn.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../../C/CpuArch.h"
6 
7 #include "../../../Common/MyException.h"
8 
9 #include "../../Common/StreamUtils.h"
10 
11 #include "../HandlerCont.h"
12 
13 #include "IsoIn.h"
14 
15 namespace NArchive {
16 namespace NIso {
17 
18 struct CUnexpectedEndException {};
19 struct CHeaderErrorException {};
20 struct CEndianErrorException {};
21 
22 static const char * const kMediaTypes[] =
23 {
24     "NoEmul"
25   , "1.2M"
26   , "1.44M"
27   , "2.88M"
28   , "HardDisk"
29 };
30 
Parse(const Byte * p)31 bool CBootInitialEntry::Parse(const Byte *p)
32 {
33   Bootable = (p[0] == NBootEntryId::kInitialEntryBootable);
34   BootMediaType = p[1];
35   LoadSegment = GetUi16(p + 2);
36   SystemType = p[4];
37   SectorCount = GetUi16(p + 6);
38   LoadRBA = GetUi32(p + 8);
39   memcpy(VendorSpec, p + 12, 20);
40   if (p[5] != 0)
41     return false;
42   if (p[0] != NBootEntryId::kInitialEntryBootable
43       && p[0] != NBootEntryId::kInitialEntryNotBootable)
44     return false;
45   return true;
46 }
47 
GetName() const48 AString CBootInitialEntry::GetName() const
49 {
50   AString s (Bootable ? "Boot" : "NotBoot");
51   s.Add_Minus();
52 
53   if (BootMediaType < Z7_ARRAY_SIZE(kMediaTypes))
54     s += kMediaTypes[BootMediaType];
55   else
56     s.Add_UInt32(BootMediaType);
57 
58   if (VendorSpec[0] == 1)
59   {
60     // "Language and Version Information (IBM)"
61 
62     unsigned i;
63     for (i = 1; i < sizeof(VendorSpec); i++)
64       if (VendorSpec[i] > 0x7F)
65         break;
66     if (i == sizeof(VendorSpec))
67     {
68       s.Add_Minus();
69       for (i = 1; i < sizeof(VendorSpec); i++)
70       {
71         char c = (char)VendorSpec[i];
72         if (c == 0)
73           break;
74         if (c == '\\' || c == '/')
75           c = '_';
76         s += c;
77       }
78     }
79   }
80 
81   s += ".img";
82   return s;
83 }
84 
ReadByte()85 Byte CInArchive::ReadByte()
86 {
87   if (m_BufferPos >= kBlockSize)
88     m_BufferPos = 0;
89   if (m_BufferPos == 0)
90   {
91     size_t processed = kBlockSize;
92     HRESULT res = ReadStream(_stream, m_Buffer, &processed);
93     if (res != S_OK)
94       throw CSystemException(res);
95     if (processed != kBlockSize)
96       throw CUnexpectedEndException();
97     UInt64 end = _position + processed;
98     if (PhySize < end)
99       PhySize = end;
100   }
101   Byte b = m_Buffer[m_BufferPos++];
102   _position++;
103   return b;
104 }
105 
ReadBytes(Byte * data,UInt32 size)106 void CInArchive::ReadBytes(Byte *data, UInt32 size)
107 {
108   for (UInt32 i = 0; i < size; i++)
109     data[i] = ReadByte();
110 }
111 
Skip(size_t size)112 void CInArchive::Skip(size_t size)
113 {
114   while (size-- != 0)
115     ReadByte();
116 }
117 
SkipZeros(size_t size)118 void CInArchive::SkipZeros(size_t size)
119 {
120   while (size-- != 0)
121   {
122     Byte b = ReadByte();
123     if (b != 0)
124       throw CHeaderErrorException();
125   }
126 }
127 
ReadUInt16()128 UInt16 CInArchive::ReadUInt16()
129 {
130   Byte b[4];
131   ReadBytes(b, 4);
132   UInt32 val = 0;
133   for (int i = 0; i < 2; i++)
134   {
135     if (b[i] != b[3 - i])
136       IncorrectBigEndian = true;
137     val |= ((UInt32)(b[i]) << (8 * i));
138   }
139   return (UInt16)val;
140 }
141 
ReadUInt32Le()142 UInt32 CInArchive::ReadUInt32Le()
143 {
144   UInt32 val = 0;
145   for (int i = 0; i < 4; i++)
146     val |= ((UInt32)(ReadByte()) << (8 * i));
147   return val;
148 }
149 
ReadUInt32Be()150 UInt32 CInArchive::ReadUInt32Be()
151 {
152   UInt32 val = 0;
153   for (int i = 0; i < 4; i++)
154   {
155     val <<= 8;
156     val |= ReadByte();
157   }
158   return val;
159 }
160 
ReadUInt32()161 UInt32 CInArchive::ReadUInt32()
162 {
163   Byte b[8];
164   ReadBytes(b, 8);
165   UInt32 val = 0;
166   for (int i = 0; i < 4; i++)
167   {
168     if (b[i] != b[7 - i])
169       throw CEndianErrorException();
170     val |= ((UInt32)(b[i]) << (8 * i));
171   }
172   return val;
173 }
174 
ReadDigits(int numDigits)175 UInt32 CInArchive::ReadDigits(int numDigits)
176 {
177   UInt32 res = 0;
178   for (int i = 0; i < numDigits; i++)
179   {
180     Byte b = ReadByte();
181     if (b < '0' || b > '9')
182     {
183       if (b == 0 || b == ' ') // it's bug in some CD's
184         b = '0';
185       else
186         throw CHeaderErrorException();
187     }
188     UInt32 d = (UInt32)(b - '0');
189     res *= 10;
190     res += d;
191   }
192   return res;
193 }
194 
ReadDateTime(CDateTime & d)195 void CInArchive::ReadDateTime(CDateTime &d)
196 {
197   d.Year = (UInt16)ReadDigits(4);
198   d.Month = (Byte)ReadDigits(2);
199   d.Day = (Byte)ReadDigits(2);
200   d.Hour = (Byte)ReadDigits(2);
201   d.Minute = (Byte)ReadDigits(2);
202   d.Second = (Byte)ReadDigits(2);
203   d.Hundredths = (Byte)ReadDigits(2);
204   d.GmtOffset = (signed char)ReadByte();
205 }
206 
ReadBootRecordDescriptor(CBootRecordDescriptor & d)207 void CInArchive::ReadBootRecordDescriptor(CBootRecordDescriptor &d)
208 {
209   ReadBytes(d.BootSystemId, sizeof(d.BootSystemId));
210   ReadBytes(d.BootId, sizeof(d.BootId));
211   ReadBytes(d.BootSystemUse, sizeof(d.BootSystemUse));
212 }
213 
ReadRecordingDateTime(CRecordingDateTime & t)214 void CInArchive::ReadRecordingDateTime(CRecordingDateTime &t)
215 {
216   t.Year = ReadByte();
217   t.Month = ReadByte();
218   t.Day = ReadByte();
219   t.Hour = ReadByte();
220   t.Minute = ReadByte();
221   t.Second = ReadByte();
222   t.GmtOffset = (signed char)ReadByte();
223 }
224 
ReadDirRecord2(CDirRecord & r,Byte len)225 void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len)
226 {
227   r.ExtendedAttributeRecordLen = ReadByte();
228   if (r.ExtendedAttributeRecordLen != 0)
229     throw CHeaderErrorException();
230   r.ExtentLocation = ReadUInt32();
231   r.Size = ReadUInt32();
232   ReadRecordingDateTime(r.DateTime);
233   r.FileFlags = ReadByte();
234   r.FileUnitSize = ReadByte();
235   r.InterleaveGapSize = ReadByte();
236   r.VolSequenceNumber = ReadUInt16();
237   Byte idLen = ReadByte();
238   r.FileId.Alloc(idLen);
239   ReadBytes((Byte *)r.FileId, idLen);
240   unsigned padSize = 1 - (idLen & 1);
241 
242   // SkipZeros(padSize);
243   Skip(padSize); // it's bug in some cd's. Must be zeros
244 
245   unsigned curPos = 33 + idLen + padSize;
246   if (curPos > len)
247     throw CHeaderErrorException();
248   unsigned rem = len - curPos;
249   r.SystemUse.Alloc(rem);
250   ReadBytes((Byte *)r.SystemUse, rem);
251 }
252 
ReadDirRecord(CDirRecord & r)253 void CInArchive::ReadDirRecord(CDirRecord &r)
254 {
255   Byte len = ReadByte();
256   // Some CDs can have incorrect value len = 48 ('0') in VolumeDescriptor.
257   // But maybe we must use real "len" for other records.
258   len = 34;
259   ReadDirRecord2(r, len);
260 }
261 
ReadVolumeDescriptor(CVolumeDescriptor & d)262 void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d)
263 {
264   d.VolFlags = ReadByte();
265   ReadBytes(d.SystemId, sizeof(d.SystemId));
266   ReadBytes(d.VolumeId, sizeof(d.VolumeId));
267   SkipZeros(8);
268   d.VolumeSpaceSize = ReadUInt32();
269   ReadBytes(d.EscapeSequence, sizeof(d.EscapeSequence));
270   d.VolumeSetSize = ReadUInt16();
271   d.VolumeSequenceNumber = ReadUInt16();
272   d.LogicalBlockSize = ReadUInt16();
273   d.PathTableSize = ReadUInt32();
274   d.LPathTableLocation = ReadUInt32Le();
275   d.LOptionalPathTableLocation = ReadUInt32Le();
276   d.MPathTableLocation = ReadUInt32Be();
277   d.MOptionalPathTableLocation = ReadUInt32Be();
278   ReadDirRecord(d.RootDirRecord);
279   ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId));
280   ReadBytes(d.PublisherId, sizeof(d.PublisherId));
281   ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId));
282   ReadBytes(d.ApplicationId, sizeof(d.ApplicationId));
283   ReadBytes(d.CopyrightFileId, sizeof(d.CopyrightFileId));
284   ReadBytes(d.AbstractFileId, sizeof(d.AbstractFileId));
285   ReadBytes(d.BibFileId, sizeof(d.BibFileId));
286   ReadDateTime(d.CTime);
287   ReadDateTime(d.MTime);
288   ReadDateTime(d.ExpirationTime);
289   ReadDateTime(d.EffectiveTime);
290   const Byte fileStructureVersion = ReadByte();
291   // d.FileStructureVersion = fileStructureVersion;
292   if (fileStructureVersion != 1 &&  // ECMA-119
293       fileStructureVersion != 2)    // some ISO files have fileStructureVersion == 2.
294   {
295     // v24.05: we ignore that field, because we don't know what exact values are allowed there
296     // throw CHeaderErrorException();
297   }
298   SkipZeros(1); // (Reserved for future standardization)
299   ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse));
300   // Most ISO contain zeros in the following field (reserved for future standardization).
301   // But some ISO programs write some data to that area.
302   // So we disable check for zeros.
303   Skip(653); // SkipZeros(653);
304 }
305 
306 static const Byte kSig_CD001[5] = { 'C', 'D', '0', '0', '1' };
307 
308 /*
309 static const Byte kSig_NSR02[5] = { 'N', 'S', 'R', '0', '2' };
310 static const Byte kSig_NSR03[5] = { 'N', 'S', 'R', '0', '3' };
311 static const Byte kSig_BEA01[5] = { 'B', 'E', 'A', '0', '1' };
312 static const Byte kSig_TEA01[5] = { 'T', 'E', 'A', '0', '1' };
313 */
314 
CheckSignature(const Byte * sig,const Byte * data)315 static inline bool CheckSignature(const Byte *sig, const Byte *data)
316 {
317   for (int i = 0; i < 5; i++)
318     if (sig[i] != data[i])
319       return false;
320   return true;
321 }
322 
SeekToBlock(UInt32 blockIndex)323 void CInArchive::SeekToBlock(UInt32 blockIndex)
324 {
325   const HRESULT res = _stream->Seek(
326       (Int64)((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize),
327       STREAM_SEEK_SET, &_position);
328   if (res != S_OK)
329     throw CSystemException(res);
330   m_BufferPos = 0;
331 }
332 
333 static const int kNumLevelsMax = 256;
334 
ReadDir(CDir & d,int level)335 void CInArchive::ReadDir(CDir &d, int level)
336 {
337   if (!d.IsDir())
338     return;
339   if (level > kNumLevelsMax)
340   {
341     TooDeepDirs = true;
342     return;
343   }
344 
345   {
346     FOR_VECTOR (i, UniqStartLocations)
347       if (UniqStartLocations[i] == d.ExtentLocation)
348       {
349         SelfLinkedDirs = true;
350         return;
351       }
352     UniqStartLocations.Add(d.ExtentLocation);
353   }
354 
355   SeekToBlock(d.ExtentLocation);
356   UInt64 startPos = _position;
357 
358   bool firstItem = true;
359   for (;;)
360   {
361     UInt64 offset = _position - startPos;
362     if (offset >= d.Size)
363       break;
364     Byte len = ReadByte();
365     if (len == 0)
366       continue;
367     CDir subItem;
368     ReadDirRecord2(subItem, len);
369     if (firstItem && level == 0)
370       IsSusp = subItem.CheckSusp(SuspSkipSize);
371 
372     if (!subItem.IsSystemItem())
373       d._subItems.Add(subItem);
374 
375     firstItem = false;
376   }
377   FOR_VECTOR (i, d._subItems)
378     ReadDir(d._subItems[i], level + 1);
379 
380   UniqStartLocations.DeleteBack();
381 }
382 
CreateRefs(CDir & d)383 void CInArchive::CreateRefs(CDir &d)
384 {
385   if (!d.IsDir())
386     return;
387   for (unsigned i = 0; i < d._subItems.Size();)
388   {
389     CRef ref;
390     CDir &subItem = d._subItems[i];
391     subItem.Parent = &d;
392     ref.Dir = &d;
393     ref.Index = i++;
394     ref.NumExtents = 1;
395     ref.TotalSize = subItem.Size;
396     if (subItem.IsNonFinalExtent())
397     {
398       for (;;)
399       {
400         if (i == d._subItems.Size())
401         {
402           HeadersError = true;
403           break;
404         }
405         const CDir &next = d._subItems[i];
406         if (!subItem.AreMultiPartEqualWith(next))
407           break;
408         i++;
409         ref.NumExtents++;
410         ref.TotalSize += next.Size;
411         if (!next.IsNonFinalExtent())
412           break;
413       }
414     }
415     Refs.Add(ref);
416     CreateRefs(subItem);
417   }
418 }
419 
ReadBootInfo()420 void CInArchive::ReadBootInfo()
421 {
422   if (!_bootIsDefined)
423     return;
424   HeadersError = true;
425 
426   if (memcmp(_bootDesc.BootSystemId, kElToritoSpec, sizeof(_bootDesc.BootSystemId)) != 0)
427     return;
428 
429   UInt32 blockIndex = GetUi32(_bootDesc.BootSystemUse);
430   SeekToBlock(blockIndex);
431 
432   Byte buf[32];
433   ReadBytes(buf, 32);
434 
435   if (buf[0] != NBootEntryId::kValidationEntry
436       || buf[2] != 0
437       || buf[3] != 0
438       || buf[30] != 0x55
439       || buf[31] != 0xAA)
440     return;
441 
442   {
443     UInt32 sum = 0;
444     for (unsigned i = 0; i < 32; i += 2)
445       sum += GetUi16(buf + i);
446     if ((sum & 0xFFFF) != 0)
447       return;
448     /*
449     CBootValidationEntry e;
450     e.PlatformId = buf[1];
451     memcpy(e.Id, buf + 4, sizeof(e.Id));
452     // UInt16 checkSum = GetUi16(p + 28);
453     */
454   }
455 
456   ReadBytes(buf, 32);
457   {
458     CBootInitialEntry e;
459     if (!e.Parse(buf))
460       return;
461     BootEntries.Add(e);
462   }
463 
464   bool error = false;
465 
466   for (;;)
467   {
468     ReadBytes(buf, 32);
469     Byte headerIndicator = buf[0];
470     if (headerIndicator != NBootEntryId::kMoreHeaders
471         && headerIndicator != NBootEntryId::kFinalHeader)
472       break;
473 
474     // Section Header
475     // Byte platform = p[1];
476     unsigned numEntries = GetUi16(buf + 2);
477     // id[28]
478 
479     for (unsigned i = 0; i < numEntries; i++)
480     {
481       ReadBytes(buf, 32);
482       CBootInitialEntry e;
483       if (!e.Parse(buf))
484       {
485         error = true;
486         break;
487       }
488       if (e.BootMediaType & (1 << 5))
489       {
490         // Section entry extension
491         for (unsigned j = 0;; j++)
492         {
493           ReadBytes(buf, 32);
494           if (j > 32 || buf[0] != NBootEntryId::kExtensionIndicator)
495           {
496             error = true;
497             break;
498           }
499           if ((buf[1] & (1 << 5)) == 0)
500             break;
501           // info += (buf + 2, 30)
502         }
503       }
504       BootEntries.Add(e);
505     }
506 
507     if (headerIndicator != NBootEntryId::kMoreHeaders)
508       break;
509   }
510 
511   HeadersError = error;
512 }
513 
Open2()514 HRESULT CInArchive::Open2()
515 {
516   _position = 0;
517   RINOK(InStream_GetSize_SeekToEnd(_stream, _fileSize))
518   if (_fileSize < kStartPos)
519     return S_FALSE;
520   RINOK(_stream->Seek(kStartPos, STREAM_SEEK_SET, &_position))
521 
522   PhySize = _position;
523   m_BufferPos = 0;
524   // BlockSize = kBlockSize;
525 
526   for (;;)
527   {
528     Byte sig[7];
529     ReadBytes(sig, 7);
530     Byte ver = sig[6];
531 
532     if (!CheckSignature(kSig_CD001, sig + 1))
533     {
534       return S_FALSE;
535       /*
536       if (sig[0] != 0 || ver != 1)
537         break;
538       if (CheckSignature(kSig_BEA01, sig + 1))
539       {
540       }
541       else if (CheckSignature(kSig_TEA01, sig + 1))
542       {
543         break;
544       }
545       else if (CheckSignature(kSig_NSR02, sig + 1))
546       {
547       }
548       else
549         break;
550       SkipZeros(0x800 - 7);
551       continue;
552       */
553     }
554 
555     // version = 2 for ISO 9660:1999?
556     if (ver > 2)
557       return S_FALSE;
558 
559     if (sig[0] == NVolDescType::kTerminator)
560     {
561       break;
562       // Skip(0x800 - 7);
563       // continue;
564     }
565 
566     switch (sig[0])
567     {
568       case NVolDescType::kBootRecord:
569       {
570         _bootIsDefined = true;
571         ReadBootRecordDescriptor(_bootDesc);
572         break;
573       }
574       case NVolDescType::kPrimaryVol:
575       case NVolDescType::kSupplementaryVol:
576       {
577         // some ISOs have two PrimaryVols.
578         CVolumeDescriptor vd;
579         ReadVolumeDescriptor(vd);
580         if (sig[0] == NVolDescType::kPrimaryVol)
581         {
582           // some burners write "Joliet" Escape Sequence to primary volume
583           memset(vd.EscapeSequence, 0, sizeof(vd.EscapeSequence));
584         }
585         VolDescs.Add(vd);
586         break;
587       }
588       default:
589         break;
590     }
591   }
592 
593   if (VolDescs.IsEmpty())
594     return S_FALSE;
595   for (MainVolDescIndex = (int)VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
596     if (VolDescs[MainVolDescIndex].IsJoliet())
597       break;
598   /* FIXME: some volume can contain Rock Ridge, that is better than
599      Joliet volume. So we need some way to detect such case */
600   // MainVolDescIndex = 0; // to read primary volume
601   const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
602   if (vd.LogicalBlockSize != kBlockSize)
603     return S_FALSE;
604 
605   {
606     FOR_VECTOR (i, VolDescs)
607     {
608       const CVolumeDescriptor &vd2 = VolDescs[i];
609       UpdatePhySize(0, vd2.Get_VolumeSpaceSize_inBytes());
610     }
611   }
612 
613 
614   IsArc = true;
615 
616   (CDirRecord &)_rootDir = vd.RootDirRecord;
617   ReadDir(_rootDir, 0);
618   CreateRefs(_rootDir);
619   ReadBootInfo();
620 
621   {
622     FOR_VECTOR (i, Refs)
623     {
624       const CRef &ref = Refs[i];
625       for (UInt32 j = 0; j < ref.NumExtents; j++)
626       {
627         const CDir &item = ref.Dir->_subItems[ref.Index + j];
628         if (!item.IsDir() && item.Size != 0)
629           UpdatePhySize(item.ExtentLocation, item.Size);
630       }
631     }
632   }
633 
634   {
635     // find boot item for expand:
636     // UEFI Specification : 13.3.2.1. ISO-9660 and El Torito
637     _expand_BootEntries_index = -1;
638     FOR_VECTOR (i, BootEntries)
639     {
640       const CBootInitialEntry &be = BootEntries[i];
641       if (be.SectorCount <= 1 && be.BootMediaType == NBootMediaType::kNoEmulation)
642         if (_expand_BootEntries_index == -1
643           || be.LoadRBA >= BootEntries[_expand_BootEntries_index].LoadRBA)
644         _expand_BootEntries_index = (int)i;
645     }
646   }
647 
648   {
649     FOR_VECTOR (i, BootEntries)
650     {
651       const CBootInitialEntry &be = BootEntries[i];
652       UpdatePhySize(be.LoadRBA, GetBootItemSize(i));
653     }
654   }
655 
656   if (PhySize < _fileSize)
657   {
658     UInt64 rem = _fileSize - PhySize;
659     const UInt64 kRemMax = 1 << 21;
660     if (rem <= kRemMax)
661     {
662       RINOK(InStream_SeekSet(_stream, PhySize))
663       bool areThereNonZeros = false;
664       UInt64 numZeros = 0;
665       RINOK(ReadZeroTail(_stream, areThereNonZeros, numZeros, kRemMax))
666       if (!areThereNonZeros)
667         PhySize += numZeros;
668     }
669   }
670 
671   return S_OK;
672 }
673 
Open(IInStream * inStream)674 HRESULT CInArchive::Open(IInStream *inStream)
675 {
676   Clear();
677   _stream = inStream;
678   try { return Open2(); }
679   catch(const CSystemException &e) { return e.ErrorCode; }
680   catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; }
681   catch(CHeaderErrorException &) { HeadersError = true; return S_FALSE; }
682   catch(CEndianErrorException &) { IncorrectBigEndian = true; return S_FALSE; }
683 }
684 
Clear()685 void CInArchive::Clear()
686 {
687   IsArc = false;
688   UnexpectedEnd = false;
689   HeadersError = false;
690   IncorrectBigEndian = false;
691   TooDeepDirs = false;
692   SelfLinkedDirs = false;
693 
694   UniqStartLocations.Clear();
695 
696   Refs.Clear();
697   _rootDir.Clear();
698   VolDescs.Clear();
699   _bootIsDefined = false;
700   BootEntries.Clear();
701   SuspSkipSize = 0;
702   IsSusp = false;
703 
704   _expand_BootEntries_index = -1;
705 }
706 
707 
GetBootItemSize(unsigned index) const708 UInt64 CInArchive::GetBootItemSize(unsigned index) const
709 {
710   const CBootInitialEntry &be = BootEntries[index];
711   UInt64 size = be.GetSize();
712        if (be.BootMediaType == NBootMediaType::k1d2Floppy)  size = 1200 << 10;
713   else if (be.BootMediaType == NBootMediaType::k1d44Floppy) size = 1440 << 10;
714   else if (be.BootMediaType == NBootMediaType::k2d88Floppy) size = 2880 << 10;
715   const UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize;
716   if (startPos < _fileSize)
717   {
718     const UInt64 rem = _fileSize - startPos;
719     /*
720        UEFI modification to ISO specification:
721        because SectorCount is 16-bit, size is limited by (32 MB).
722        UEFI Specification :
723         13.3.2.1. ISO-9660 and El Torito
724         If the value of Sector Count is set to 0 or 1,
725         EFI will assume the system partition consumes the space
726         from the beginning of the "no emulation" image to the end of the CD-ROM.
727     */
728     //
729     if ((int)index == _expand_BootEntries_index || rem < size)
730       size = rem;
731   }
732   return size;
733 }
734 
735 }}
736