Package SevenZip.Archive.SevenZip

Source Code of SevenZip.Archive.SevenZip.ArchiveDB

package SevenZip.Archive.SevenZip;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;

import Common.BoolVector;
import Common.CRC;
import Common.IntVector;
import Common.LongVector;

import SevenZip.IInStream;
import SevenZip.Archive.Common.BindPair;

public class ArchiveDB {

  public static final int kNumNoIndex = 0xFFFFFFFF;
 
    public final LongVector    PackSizes          = new LongVector();
  public final BoolVector    PackCRCsDefined        = new BoolVector();
  public final IntVector    PackCRCs          = new IntVector();
  public final IntVector    NumUnPackStreamsVector    = new IntVector();
  public final Vector      Files            = new Vector();
  public      Vector      Folders            = new Vector();
 
  public final IntVector    FolderStartPackStreamIndex  = new IntVector();
  public final IntVector    FolderStartFileIndex    = new IntVector();
  public final IntVector    FileIndexToFolderIndexMap  = new IntVector();
 
  private final InStream    inStream;
  private final InArchiveInfo  ArchiveInfo          = new InArchiveInfo();
  private final LongVector  PackStreamStartPositions  = new LongVector();
   
    public ArchiveDB(InStream inStream) throws IOException {
        this.inStream = inStream;
    this.ArchiveInfo.StartPosition = this.inStream.archiveBeginStreamPosition;
       
        byte [] btmp = new byte[2];
        int realProcessedSize = this.inStream.ReadDirect(btmp, 2);
        if (realProcessedSize != 2)
            throw new IOException("Unexpected End Of Archive"); // throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
       
        this.ArchiveInfo.ArchiveVersion_Major = btmp[0];
        this.ArchiveInfo.ArchiveVersion_Minor = btmp[1];
       
        if (this.ArchiveInfo.ArchiveVersion_Major != Header.kMajorVersion)
            throw new IOException("Unsupported Version: " +
                this.ArchiveInfo.ArchiveVersion_Major + "." +
                this.ArchiveInfo.ArchiveVersion_Minor);
       
        int crcFromArchive = this.inStream.SafeReadDirectUInt32();
        long nextHeaderOffset = this.inStream.SafeReadDirectUInt64();
        long nextHeaderSize = this.inStream.SafeReadDirectUInt64();
        int nextHeaderCRC = this.inStream.SafeReadDirectUInt32();
       
        this.ArchiveInfo.StartPositionAfterHeader = this.inStream.position;
       
        CRC crc = new CRC();
        crc.UpdateUInt64(nextHeaderOffset);
        crc.UpdateUInt64(nextHeaderSize);
        crc.UpdateUInt32(nextHeaderCRC);
       
        if (crc.GetDigest() != crcFromArchive)
            throw new IOException("Incorrect Header, CRCs don't match: archive: " +
                Integer.toHexString(crcFromArchive) + ", calculated: " + crc); // CInArchiveException(CInArchiveException::kIncorrectHeader);
       
        if (nextHeaderSize == 0)
            return;
       
        if (nextHeaderSize >= 0xFFFFFFFFL)
            throw new IOException("second header too big: " + nextHeaderSize);
       
        this.inStream.position = this.inStream.stream.Seek(nextHeaderOffset,IInStream.STREAM_SEEK_CUR);
       
        this.readNextStreamHeaders((int)nextHeaderSize, nextHeaderCRC);
        this.readHeader();
        this.Fill();
    }
   
    private void readNextStreamHeaders(int nextHeaderSize, int nextHeaderCRC) throws IOException {
        byte[] buffer = new byte[nextHeaderSize];
       
        // SafeReadDirect(buffer2.data(), (int)nextHeaderSize);
        if (!this.inStream.SafeReadDirect(buffer, nextHeaderSize))
            throw new IOException("Unexpected End Of Archive"); // throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
       
        if (!CRC.VerifyDigest(nextHeaderCRC, buffer, nextHeaderSize))
            throw new IOException("Incorrect Header, CRCs don't match"); // CInArchiveException(CInArchiveException::kIncorrectHeader);
       
        // TODO:
        StreamSwitch streamSwitch = new StreamSwitch();
        streamSwitch.Set(this.inStream, buffer);
       
        long type;
        while ((type = this.inStream.ReadID()) != Header.NID.kHeader) {
            if (type != Header.NID.kEncodedHeader)
                throw new IOException("Incorrect Header");
           
            Vector dataVector = this.ReadAndDecodePackedStreams(
                    this.ArchiveInfo.StartPositionAfterHeader, 1);
           
            if (dataVector.size() == 0) {
                return;
            } else if (dataVector.size() > 1) {
                throw new IOException("Incorrect Header");
            }
            streamSwitch.Set(this.inStream, (byte[])dataVector.firstElement()); // dataVector.Front()
        }
       
        streamSwitch.close();
    }
   
    private void ReadArchiveProperties(InArchiveInfo archiveInfo) throws IOException {
      while (this.inStream.ReadID() != Header.NID.kEnd)
        this.inStream.SkeepData();
    }
   
    private void readHeader() throws IOException {
        long type = this.inStream.ReadID();
       
        if (type == Header.NID.kArchiveProperties) {
            this.ReadArchiveProperties(this.ArchiveInfo);
            type = this.inStream.ReadID();
        }
       
        Vector dataVector = new Vector();
       
        if (type == Header.NID.kAdditionalStreamsInfo) {
            dataVector.addAll(ReadAndDecodePackedStreams(
                    this.ArchiveInfo.StartPositionAfterHeader, 1));
            this.ArchiveInfo.DataStartPosition2 += this.ArchiveInfo.StartPositionAfterHeader;
            type = this.inStream.ReadID();
        }
       
        LongVector unPackSizes = new LongVector();
        BoolVector digestsDefined = new BoolVector();
        IntVector digests = new IntVector();
       
        if (type == Header.NID.kMainStreamsInfo) {
            type = this.inStream.ReadID();
            assert (type == Header.NID.kPackInfo);
            this.ReadPackInfo(this.PackSizes, this.PackCRCsDefined, this.PackCRCs, 0);
           
            type = this.inStream.ReadID();
            assert (type == Header.NID.kUnPackInfo);
            this.Folders = ReadUnPackInfo(dataVector);
           
            type = this.inStream.ReadID();
            assert (type == Header.NID.kSubStreamsInfo);
            this.ReadSubStreamsInfo(this.Folders, this.NumUnPackStreamsVector, unPackSizes, digestsDefined, digests);
           
            type = this.inStream.ReadID();
            assert (type == Header.NID.kEnd);
           
            this.ArchiveInfo.DataStartPosition += this.ArchiveInfo.StartPositionAfterHeader;
            type = this.inStream.ReadID();
        } else {
            for(int i = 0; i < this.Folders.size(); i++) {
                this.NumUnPackStreamsVector.add(1);
                Folder folder = (Folder)this.Folders.get(i);
                unPackSizes.add(folder.GetUnPackSize());
                digestsDefined.add(folder.UnPackCRCDefined);
                digests.add(folder.UnPackCRC);
            }
        }
       
        if (type == Header.NID.kEnd)
            return;
        if (type != Header.NID.kFilesInfo)
            throw new IOException("Incorrect Header");
       
        this.readFileDescriptions(dataVector, unPackSizes, digests, digestsDefined);
    }
   
    private void readFileDescriptions(
        Vector dataVector,
        LongVector unPackSizes,
        IntVector digests,
        BoolVector digestsDefined) throws IOException {
       
        int numFiles = this.inStream.ReadNum();
        this.ArchiveInfo.FileInfoPopIDs.add(Header.NID.kSize);
        if (!this.PackSizes.isEmpty())
            this.ArchiveInfo.FileInfoPopIDs.add(Header.NID.kPackInfo);
        if (numFiles > 0 && !digests.isEmpty())
            this.ArchiveInfo.FileInfoPopIDs.add(Header.NID.kCRC);
       
        this.Files.clear();
        this.Files.ensureCapacity(numFiles);
        for (int i=0; i<numFiles; i++)
            this.Files.add(new FileItem());
       
        BoolVector emptyStreamVector = new BoolVector();
        emptyStreamVector.Reserve(numFiles);
        for(int i = 0; i < numFiles; i++)
            emptyStreamVector.add(false);
        BoolVector emptyFileVector = new BoolVector();
        BoolVector antiFileVector = new BoolVector();
        int numEmptyStreams = 0;
       
        long type;
        while ((type = this.inStream.ReadID()) != Header.NID.kEnd) {
            long size = this.inStream.ReadNumber();
            this.ArchiveInfo.FileInfoPopIDs.add(type);
            switch((int)type) {
                case Header.NID.kEmptyStream:
                    emptyStreamVector.setBoolVector(this.inStream.ReadBoolVector(numFiles));
                    for (int i=0; i<emptyStreamVector.size(); i++)
                        if (emptyStreamVector.get(i))
                            numEmptyStreams++;
                    emptyFileVector.Reserve(numEmptyStreams);
                    antiFileVector.Reserve(numEmptyStreams);
                    for (int i = 0; i < numEmptyStreams; i++) {
                        emptyFileVector.add(false);
                        antiFileVector.add(false);
                    }
                    break;
                case Header.NID.kName:         this.ReadFileNames(dataVector); break;
                case Header.NID.kWinAttributes:   this.ReadFileAttributes(dataVector); break;
                case Header.NID.kStartPos:       this.ReadFileStartPositions(dataVector); break;
                case Header.NID.kEmptyFile:     emptyFileVector.setBoolVector(this.inStream.ReadBoolVector(numEmptyStreams)); break;
                case Header.NID.kAnti:         antiFileVector.setBoolVector(this.inStream.ReadBoolVector(numEmptyStreams)); break;
                case Header.NID.kCreationTime:
                case Header.NID.kLastWriteTime:
                case Header.NID.kLastAccessTime:   this.ReadTime(dataVector, type); break;
                default:
                    this.ArchiveInfo.FileInfoPopIDs.DeleteBack();
                    this.inStream.SkeepData(size);
                    break;
            }
        }
       
        int emptyFileIndex = 0;
        int sizeIndex = 0;
        for(int i = 0; i < numFiles; i++) {
            FileItem file = (FileItem)this.Files.get(i);
            file.HasStream = !emptyStreamVector.get(i);
            if(file.HasStream) {
                file.IsDirectory = false;
                file.IsAnti = false;
                file.UnPackSize = unPackSizes.get(sizeIndex);
                file.FileCRC = digests.get(sizeIndex);
                file.IsFileCRCDefined = digestsDefined.get(sizeIndex);
                sizeIndex++;
            } else {
                file.IsDirectory = !emptyFileVector.get(emptyFileIndex);
                file.IsAnti = antiFileVector.get(emptyFileIndex);
                emptyFileIndex++;
                file.UnPackSize = 0;
                file.IsFileCRCDefined = false;
            }
        }
    }
   
    private void ReadSubStreamsInfo(
            Vector folders,
            IntVector numUnPackStreamsInFolders,
            LongVector unPackSizes,
            BoolVector digestsDefined,
            IntVector digeststhrows IOException {
        numUnPackStreamsInFolders.clear();
        numUnPackStreamsInFolders.Reserve(folders.size());
        long type;
       
        while ((type = this.inStream.ReadID()) != Header.NID.kCRC &&
            type != Header.NID.kSize &&
            type != Header.NID.kEnd) {
            if (type == Header.NID.kNumUnPackStream) {
                for(int i = 0; i < folders.size(); i++) {
                    int value = this.inStream.ReadNum();
                    numUnPackStreamsInFolders.add(value);
                }
                continue;
            }
            this.inStream.SkeepData();
        }
       
        if (numUnPackStreamsInFolders.isEmpty())
            for (int i=0; i<folders.size(); i++)
                numUnPackStreamsInFolders.add(1);
       
        final ArrayList sizes = new ArrayList();
        int numSubstreams;
        long sum, size;
        for (int i=0; i<numUnPackStreamsInFolders.size(); i++) {
          numSubstreams = numUnPackStreamsInFolders.get(i);
          if (numSubstreams < 1) continue;
          sum = 0;
          if (type == Header.NID.kSize)
            for (int j=1; j<numSubstreams; j++) {
              sum += size = this.inStream.ReadNumber();
              sizes.add(new Long(size));
            }
          sizes.add(new Long((((Folder)folders.get(i)).GetUnPackSize() - sum)));
        }
        unPackSizes.addAll(sizes);
        sizes.clear();
       
        if (type == Header.NID.kSize)
            type = this.inStream.ReadID();
       
        int numDigests = 0;
        int numDigestsTotal = 0;
        for(int i = 0; i < folders.size(); i++) {
            numSubstreams = numUnPackStreamsInFolders.get(i);
            if (numSubstreams != 1 || !((Folder)folders.get(i)).UnPackCRCDefined)
                numDigests += numSubstreams;
            numDigestsTotal += numSubstreams;
        }
       
        final ArrayList bsizes = new ArrayList();
        do {
            if (type == Header.NID.kCRC) {
                BoolVector digestsDefined2 = new BoolVector();
                IntVector digests2 = new IntVector();
                digests2 = this.inStream.ReadHashDigests(numDigests, digestsDefined2);
                int digestIndex = 0;
               
                for (int i=0; i<folders.size(); i++) {
                  numSubstreams = numUnPackStreamsInFolders.get(i);
                  Folder folder = (Folder)folders.get(i);
                  if (numSubstreams == 1 && folder.UnPackCRCDefined) {
                    bsizes.add(Boolean.TRUE);
                    sizes.add(new Integer(folder.UnPackCRC));
                  } else {
                    for (int j=0; j<numSubstreams; j++, digestIndex++) {
                      bsizes.add(new Boolean(digestsDefined2.get(digestIndex)));
                      sizes.add(new Integer(digests2.get(digestIndex)));
                    }
                  }
                }
                digestsDefined.addAll(bsizes);
                bsizes.clear();
                digests.addAll(sizes);
                sizes.clear();
            } else {
              this.inStream.SkeepData();
            }
        } while ((type = this.inStream.ReadID()) != Header.NID.kEnd);
       
        if (digestsDefined.isEmpty()) {
            digests.clear();
            for (int i=0; i<numDigestsTotal; i++) {
                digestsDefined.add(false);
                digests.add(0);
            }
        }
    }
   
    private Vector ReadAndDecodePackedStreams(long baseOffset, int dataStartPosIndex) throws IOException {
        LongVector packSizes = new LongVector();
       
        BoolVector packCRCsDefined = new BoolVector();
        IntVector packCRCs = new IntVector();
       
        long type = this.inStream.ReadID();
        assert (type == Header.NID.kPackInfo);
        this.ReadPackInfo(packSizes, packCRCsDefined, packCRCs, dataStartPosIndex);
       
        type = this.inStream.ReadID();
        assert (type == Header.NID.kUnPackInfo);
        Vector folders = ReadUnPackInfo(null);
       
        type = this.inStream.ReadID();
        assert (type == Header.NID.kEnd);
       
        int packIndex = 0;
        Decoder decoder = new Decoder(false); // _ST_MODE
       
        Vector dataVector = new Vector();
        long dataStartPos = baseOffset + ((dataStartPosIndex == 0) ?
            this.ArchiveInfo.DataStartPosition : this.ArchiveInfo.DataStartPosition2);
        for(int i=0; i<folders.size(); i++) {
            Folder folder = (Folder)folders.get(i);
            long unPackSize = folder.GetUnPackSize();
            if (unPackSize > InStream.kNumMax || unPackSize > 0xFFFFFFFFL)
                throw new IOException("unPackSize too great: " + unPackSize);
           
            ByteArrayOutputStream baos = new ByteArrayOutputStream((int)unPackSize);
            decoder.Decode(
                this.inStream.stream, dataStartPos,
                    packSizes, packIndex,
                    folder, baos, null);
            byte[] data; // TODO: stream belassen!
            dataVector.add(data = baos.toByteArray());
           
            if (folder.UnPackCRCDefined)
                if (!CRC.VerifyDigest(folder.UnPackCRC, data, (int)unPackSize))
                    throw new IOException("Incorrect Header, CRCs of packed folder don't match: archive: " +
                        Integer.toHexString(folder.UnPackCRC) + ", calculated: " +
                        Integer.toHexString(CRC.CalculateDigest(data, (int)unPackSize)) +
                        ". Either is the archive corrupted or an internal error occured");
           
            for (int j = 0; j < folder.PackStreams.size(); j++)
                dataStartPos += packSizes.get(packIndex++);
        }
       
        return dataVector;
    }
   
    private void ReadPackInfo(
            LongVector packSizes,
            BoolVector packCRCsDefined,
            IntVector packCRCs,
            int dataStartPosIndex)
            throws IOException {
      if (dataStartPosIndex == 0) {
          this.ArchiveInfo.DataStartPosition = this.inStream.ReadNumber();
      } else {
        this.ArchiveInfo.DataStartPosition2 = this.inStream.ReadNumber();
      }
        int numPackStreams = this.inStream.ReadNum();
       
        this.inStream.skipToAttribute(Header.NID.kSize);
       
        packSizes.clear();
        packSizes.Reserve(numPackStreams);
        for(int i = 0; i < numPackStreams; i++) {
            long size = this.inStream.ReadNumber();
            packSizes.add(size);
        }
       
        long type;
        while ((type = this.inStream.ReadID()) != Header.NID.kEnd) {
            if (type == Header.NID.kCRC) {
              packCRCs = this.inStream.ReadHashDigests(numPackStreams, packCRCsDefined);
                continue;
            }
            this.inStream.SkeepData();
        }
        if (packCRCsDefined.isEmpty()) {
            packCRCsDefined.Reserve(numPackStreams);
            packCRCsDefined.clear();
            packCRCs.Reserve(numPackStreams);
            packCRCs.clear();
            for(int i = 0; i < numPackStreams; i++) {
                packCRCsDefined.add(false);
                packCRCs.add(0);
            }
        }
    }
   
    private void ReadFileNames(Vector from) throws IOException {
        StreamSwitch streamSwitch = new StreamSwitch();
        streamSwitch.Set(this.inStream, from);
      StringBuffer name = new StringBuffer(30);
        char c;
        for (int i=0; i<this.Files.size(); i++) {
            while ((c = this.inStream.ReadWideCharLE()) != '\0')
                name.append(c);
            ((FileItem)this.Files.get(i)).name = new String(name);
            name.delete(0, name.length());
        }
        streamSwitch.close();
    }
   
    private void ReadFileAttributes(Vector from) throws IOException {
        BoolVector boolVector = this.inStream.ReadBoolVector2(this.Files.size());
        StreamSwitch streamSwitch = new StreamSwitch();
        streamSwitch.Set(this.inStream, from);
        for (int i=0; i<this.Files.size(); i++) {
            FileItem file = (FileItem)this.Files.get(i);
            file.AreAttributesDefined = boolVector.get(i);
            if (file.AreAttributesDefined)
                file.Attributes = this.inStream.ReadUInt32();
        }
        streamSwitch.close();
    }
   
    private void ReadFileStartPositions(Vector from) throws IOException {
        BoolVector boolVector = this.inStream.ReadBoolVector2(this.Files.size());
        StreamSwitch streamSwitch = new StreamSwitch();
        streamSwitch.Set(this.inStream, from);
        for(int i=0; i<this.Files.size(); i++) {
            FileItem file = (FileItem)this.Files.get(i);
            file.IsStartPosDefined = boolVector.get(i);
            if (file.IsStartPosDefined)
                file.StartPos = this.inStream.ReadUInt64();
        }
        streamSwitch.close();
    }
   
    private void ReadTime(Vector dataVector, long type) throws IOException {
        BoolVector boolVector = this.inStream.ReadBoolVector2(this.Files.size());
       
        StreamSwitch streamSwitch = new StreamSwitch();
        streamSwitch.Set(this.inStream, dataVector);
       
        for (int i=0; i<this.Files.size(); i++) {
            FileItem file = (FileItem)this.Files.get(i);
            int low = 0;
            int high = 0;
            boolean defined = boolVector.get(i);
            if (defined) {
                low = this.inStream.ReadUInt32();
                high = this.inStream.ReadUInt32();
            }
            switch((int)type) {
                case Header.NID.kCreationTime:
                    // file.IsCreationTimeDefined = defined;
                    if (defined)
                        file.CreationTime = InStream.FileTimeToLong(high,low);
                    break;
                case Header.NID.kLastWriteTime:
                    // file.IsLastWriteTimeDefined = defined;
                    if (defined)
                        file.LastWriteTime = InStream.FileTimeToLong(high,low);
                    break;
                case Header.NID.kLastAccessTime:
                    // file.IsLastAccessTimeDefined = defined;
                    if (defined)
                        file.LastAccessTime = InStream.FileTimeToLong(high,low);
                    break;
            }
        }
        streamSwitch.close();
    }
   
    private Vector ReadUnPackInfo(Vector dataVector) throws IOException {
        this.inStream.skipToAttribute(Header.NID.kFolder);
       
        int numFolders = this.inStream.ReadNum();
       
        StreamSwitch streamSwitch = new StreamSwitch();
        streamSwitch.Set(this.inStream, dataVector);
        Vector folders = new Vector(numFolders);
        for (int i=0; i<numFolders; i++)
            folders.add(GetNextFolderItem());
        streamSwitch.close();
       
        this.inStream.skipToAttribute(Header.NID.kCodersUnPackSize);
       
        for (int i=0; i<numFolders; i++) {
            Folder folder = (Folder)folders.get(i);
            int numOutStreams = folder.GetNumOutStreams();
            folder.UnPackSizes.Reserve(numOutStreams);
            for (int j=0; j<numOutStreams; j++) {
                long unPackSize = this.inStream.ReadNumber();
                folder.UnPackSizes.add(unPackSize);
            }
        }
       
        long type;
        while ((type = this.inStream.ReadID()) != Header.NID.kEnd) {
            if (type == Header.NID.kCRC) {
                BoolVector crcsDefined = new BoolVector();
                IntVector crcs = new IntVector();
                crcs = this.inStream.ReadHashDigests(numFolders, crcsDefined);
                for (int i=0; i<numFolders; i++) {
                    Folder folder = (Folder)folders.get(i);
                    folder.UnPackCRCDefined = crcsDefined.get(i);
                    folder.UnPackCRC = crcs.get(i);
                }
                continue;
            }
            this.inStream.SkeepData();
        }
        return folders;
    }
   
    private Folder GetNextFolderItem() throws IOException {
        int numCoders = this.inStream.ReadNum();
       
        Folder folder = new Folder();
        folder.Coders.clear();
        folder.Coders.ensureCapacity(numCoders);
        int numInStreams = 0;
        int numOutStreams = 0;
        for (int i=0; i<numCoders; i++) {
            folder.Coders.add(new CoderInfo());
            CoderInfo coder = (CoderInfo)folder.Coders.lastElement();
            int mainByte;
            do {
                AltCoderInfo altCoder = new AltCoderInfo();
                coder.AltCoders.add(altCoder);
                mainByte = this.inStream.ReadByte();
                altCoder.MethodID.IDSize = (byte)(mainByte & 0xF);
                if (!this.inStream.ReadBytes(altCoder.MethodID.ID, altCoder.MethodID.IDSize))
                  throw new IOException("error reading properties for alternative decoder");
               
                if ((mainByte & 0x10) != 0) {
                    coder.NumInStreams = this.inStream.ReadNum();
                    coder.NumOutStreams = this.inStream.ReadNum();
                } else {
                    coder.NumInStreams = 1;
                    coder.NumOutStreams = 1;
                }
                if ((mainByte & 0x20) != 0) {
                    int propertiesSize = this.inStream.ReadNum();
                    if (!this.inStream.ReadBytes(altCoder.Properties, propertiesSize))
                      throw new IOException("error reading properties for alternative decoder");
                }
            } while ((mainByte & 0x80) != 0);
            numInStreams += coder.NumInStreams;
            numOutStreams += coder.NumOutStreams;
        }
       
        // RINOK(ReadNumber(numBindPairs));
        int numBindPairs = numOutStreams - 1;
        folder.BindPairs.clear();
        folder.BindPairs.ensureCapacity(numBindPairs);
        for (int i=0; i<numBindPairs; i++) {
            BindPair bindPair = new BindPair();
            bindPair.InIndex = this.inStream.ReadNum();
            bindPair.OutIndex = this.inStream.ReadNum();
            folder.BindPairs.add(bindPair);
        }
       
        int numPackedStreams = numInStreams - numBindPairs;
        folder.PackStreams.Reserve(numPackedStreams);
        if (numPackedStreams == 1) {
            for (int j=0; j<numInStreams; j++)
                if (folder.FindBindPairForInStream(j) < 0) {
                folder.PackStreams.add(j);
                break;
                }
        } else {
            for (int i=0; i<numPackedStreams; i++) {
              int packStreamInfo = this.inStream.ReadNum();
              folder.PackStreams.add(packStreamInfo);
            }
        }
       
        return folder;
    }
   
    private void Fill()  throws IOException {
        FillFolderStartPackStream();
        FillStartPos();
        FillFolderStartFileIndex();
    }
   
    private void FillFolderStartPackStream() {
        this.FolderStartPackStreamIndex.clear();
        this.FolderStartPackStreamIndex.Reserve(this.Folders.size());
        int startPos = 0;
        for(int i = 0; i < this.Folders.size(); i++) {
            this.FolderStartPackStreamIndex.add(startPos);
            startPos += ((Folder)this.Folders.get(i)).PackStreams.size();
        }
    }
   
    private void FillStartPos() {
        this.PackStreamStartPositions.clear();
        this.PackStreamStartPositions.Reserve(this.PackSizes.size());
        long startPos = 0;
        for(int i = 0; i < this.PackSizes.size(); i++) {
            this.PackStreamStartPositions.add(startPos);
            startPos += this.PackSizes.get(i);
        }
    }
   
    private void FillFolderStartFileIndex() throws IOException {
        this.FolderStartFileIndex.clear();
        this.FolderStartFileIndex.Reserve(this.Folders.size());
        this.FileIndexToFolderIndexMap.clear();
        this.FileIndexToFolderIndexMap.Reserve(this.Files.size());
       
        int folderIndex = 0;
        int indexInFolder = 0;
        for (int i = 0; i < this.Files.size(); i++) {
            FileItem file = (FileItem)this.Files.get(i);
            boolean emptyStream = !file.HasStream;
            if (emptyStream && indexInFolder == 0) {
                this.FileIndexToFolderIndexMap.add(kNumNoIndex);
                continue;
            }
            if (indexInFolder == 0) {
                // v3.13 incorrectly worked with empty folders
                // v4.07: Loop for skipping empty folders
                for (;;) {
                    if (folderIndex >= this.Folders.size())
                        throw new IOException("Incorrect Header");
                    this.FolderStartFileIndex.add(i); // check it
                    if (this.NumUnPackStreamsVector.get(folderIndex) != 0)
                        break;
                    folderIndex++;
                }
            }
            this.FileIndexToFolderIndexMap.add(folderIndex);
            if (emptyStream)
                continue;
            indexInFolder++;
            if (indexInFolder >= this.NumUnPackStreamsVector.get(folderIndex)) {
                folderIndex++;
                indexInFolder = 0;
            }
        }
    }
   
    /* ---------------------------------------------------------------------------------------------------
     * public methods
     * --------------------------------------------------------------------------------------------------- */
   
    public void clear() {
        this.ArchiveInfo.FileInfoPopIDs.clear();
        this.PackStreamStartPositions.clear();
        this.FolderStartPackStreamIndex.clear();
        this.FolderStartFileIndex.clear();
        this.FileIndexToFolderIndexMap.clear();
       
        this.PackSizes.clear();
        this.PackCRCsDefined.clear();
        this.PackCRCs.clear();
        this.Folders.clear();
        this.NumUnPackStreamsVector.clear();
        this.Files.clear();
    }
   
    public long GetFolderFullPackSize(int folderIndex) {
        int packStreamIndex = this.FolderStartPackStreamIndex.get(folderIndex);
        Folder folder = (Folder)this.Folders.get(folderIndex);
        long size = 0;
        for (int i = 0; i < folder.PackStreams.size(); i++)
            size += this.PackSizes.get(packStreamIndex + i);
        return size;
    }
   
    public long GetFolderStreamPos(int folderIndex, int indexInFolder) {
        return this.ArchiveInfo.DataStartPosition +
                this.PackStreamStartPositions.get(this.FolderStartPackStreamIndex.get(folderIndex) +
                indexInFolder);
    }
}
TOP

Related Classes of SevenZip.Archive.SevenZip.ArchiveDB

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.