コード例 #1
0
ファイル: CabinetFile.cs プロジェクト: gus33000/Cabinet.NET
        private IReadOnlyCollection <CabinetVolume> ReadVolumes(Stream cabinetStream)
        {
            var cabinetBinaryReader = new BinaryReader(cabinetStream);

            List <CabinetVolume> volumes = new List <CabinetVolume>();

            for (int i = 0; i < cabinetHeader.CabinetFileHeader.cFolders; i++)
            {
                CabinetVolume volume = new CabinetVolume()
                {
                    CabinetFileVolume         = cabinetStream.ReadStruct <CFFOLDER>(),
                    AdditionalApplicationData = cabinetHeader.VolumeAdditionalApplicationDataSize > 0 ? cabinetBinaryReader.ReadBytes(cabinetHeader.VolumeAdditionalApplicationDataSize) : new byte[0]
                };

                volumes.Add(volume);

                if (volume.CabinetFileVolume.typeCompress != CFFOLDER.CFTYPECOMPRESS.TYPE_LZX &&
                    volume.CabinetFileVolume.typeCompress != CFFOLDER.CFTYPECOMPRESS.TYPE_MSZIP &&
                    volume.CabinetFileVolume.typeCompress != CFFOLDER.CFTYPECOMPRESS.TYPE_NONE)
                {
                    throw new Exception("Unsupported Cabinet: Only LZX, MSZip and Store is currently supported");
                }

                if (volume.CabinetFileVolume.typeCompress == CFFOLDER.CFTYPECOMPRESS.TYPE_LZX)
                {
                    if (volume.CabinetFileVolume.typeCompressOption < 15 || volume.CabinetFileVolume.typeCompressOption > 21)
                    {
                        throw new Exception("Unsupported Cabinet: LZX variable does not fall in supported ranges");
                    }
                }
            }

            return(volumes);
        }
コード例 #2
0
ファイル: CabinetFile.cs プロジェクト: gus33000/Cabinet.NET
        public string ExtractFile(string FileName)
        {
            var destination = Path.GetTempFileName();

            // Do the extraction
            for (int volumeIndex = 0; volumeIndex < volumes.Count; volumeIndex++)
            {
                CabinetVolume volume = volumes.ElementAt(volumeIndex);

                LzxDecoder lzx = null;
                Inflater   inf = null;
                if (volume.CabinetFileVolume.typeCompress == CFFOLDER.CFTYPECOMPRESS.TYPE_LZX)
                {
                    lzx = new LzxDecoder(volume.CabinetFileVolume.typeCompressOption);
                }

                if (volume.CabinetFileVolume.typeCompress == CFFOLDER.CFTYPECOMPRESS.TYPE_MSZIP)
                {
                    inf = new Inflater(true);
                }

                List <(CFDATA dataStruct, int dataOffsetCabinet, int beginFolderOffset, int endFolderOffset, int index)>            datas        = new List <(CFDATA dataStruct, int dataOffsetCabinet, int beginFolderOffset, int endFolderOffset, int index)>();
                List <(CabinetVolumeFile file, int startingBlock, int startingBlockOffset, int endingBlock, int endingBlockOffset)> fileBlockMap = new List <(CabinetVolumeFile file, int startingBlock, int startingBlockOffset, int endingBlock, int endingBlockOffset)>();

                // Build Data Map
                using (var cabinetFileStream = File.OpenRead(InputFile))
                {
                    var cabinetBinaryReader = new BinaryReader(cabinetFileStream);
                    cabinetFileStream.Seek(volume.CabinetFileVolume.firstDataBlockOffset, SeekOrigin.Begin);

                    int offset = 0;
                    for (int i = 0; i < volume.CabinetFileVolume.dataBlockCount; i++)
                    {
                        CFDATA CabinetData = cabinetBinaryReader.BaseStream.ReadStruct <CFDATA>();
                        cabinetBinaryReader.BaseStream.Seek(cabinetHeader.DataAdditionalApplicationDataSize, SeekOrigin.Current);
                        datas.Add((CabinetData, (int)cabinetBinaryReader.BaseStream.Position, offset, offset + CabinetData.cbUncomp - 1, i));
                        cabinetBinaryReader.BaseStream.Seek(CabinetData.cbData, SeekOrigin.Current);
                        offset += CabinetData.cbUncomp;
                    }

                    // Build Block Map
                    foreach (CabinetVolumeFile file in files)
                    {
                        if (file.CabinetFileVolumeFile.iFolder != volumeIndex)
                        {
                            continue;
                        }

                        var FirstBlock = datas.First(x => x.beginFolderOffset <= file.CabinetFileVolumeFile.uoffFolderStart &&
                                                     file.CabinetFileVolumeFile.uoffFolderStart <= x.endFolderOffset);
                        var LastBlock = datas.First(x => x.beginFolderOffset <= (file.CabinetFileVolumeFile.uoffFolderStart + file.CabinetFileVolumeFile.cbFile - 1) &&
                                                    (file.CabinetFileVolumeFile.uoffFolderStart + file.CabinetFileVolumeFile.cbFile - 1) <= x.endFolderOffset);

                        int fileBeginFolderOffset = (int)file.CabinetFileVolumeFile.uoffFolderStart;
                        int fileEndFolderOffset   = (int)file.CabinetFileVolumeFile.uoffFolderStart + (int)file.CabinetFileVolumeFile.cbFile - 1;

                        int start = (int)file.CabinetFileVolumeFile.uoffFolderStart - FirstBlock.beginFolderOffset;
                        int end   = fileEndFolderOffset - LastBlock.beginFolderOffset;

                        fileBlockMap.Add((file, FirstBlock.index, start, LastBlock.index, end));
                    }

                    int fcount = 0;

                    for (int i = 0; i < volume.CabinetFileVolume.dataBlockCount; i++)
                    {
                        var CabinetData = datas[i];

                        cabinetBinaryReader.BaseStream.Seek(CabinetData.dataOffsetCabinet, SeekOrigin.Begin);

                        byte[] uncompressedDataBlock = new byte[CabinetData.dataStruct.cbUncomp];
                        byte[] compressedDataBlock   = null;

                        if (volume.CabinetFileVolume.typeCompress == CFFOLDER.CFTYPECOMPRESS.TYPE_MSZIP)
                        {
                            var magic = cabinetBinaryReader.ReadBytes(2);

                            if (StructuralComparisons.StructuralComparer.Compare(magic, new byte[] { (byte)'C', (byte)'K' }) != 0)
                            {
                                throw new Exception("Bad Cabinet: Invalid Signature for MSZIP block");
                            }

                            compressedDataBlock = cabinetBinaryReader.ReadBytes(CabinetData.dataStruct.cbData - 2);
                        }
                        else
                        {
                            compressedDataBlock = cabinetBinaryReader.ReadBytes(CabinetData.dataStruct.cbData);
                        }

                        using (var uncompressedDataBlockStream = new MemoryStream(uncompressedDataBlock))
                            using (var compressedDataBlockStream = new MemoryStream(compressedDataBlock))
                            {
                                ExpandBlock(uncompressedDataBlockStream, compressedDataBlockStream, volume.CabinetFileVolume.typeCompress, lzx, inf);
                            }

                        foreach (CabinetVolumeFile file in files)
                        {
                            if (file.CabinetFileVolumeFile.iFolder != volumeIndex)
                            {
                                continue;
                            }

                            if (file.FileName.ToLower() != FileName.ToLower())
                            {
                                continue;
                            }

                            var mapping = fileBlockMap.First(x => x.file.FileName == file.FileName);

                            // This block contains this file
                            if (mapping.startingBlock <= i && i <= mapping.endingBlock)
                            {
                                int start = 0;
                                int end   = CabinetData.dataStruct.cbUncomp - 1;

                                bool IsFirstBlock = mapping.startingBlock == i;
                                bool IsLastBlock  = mapping.endingBlock == i;

                                if (IsFirstBlock)
                                {
                                    start = mapping.startingBlockOffset;
                                }

                                if (IsLastBlock)
                                {
                                    end = mapping.endingBlockOffset;
                                    fcount++;
                                }

                                int count = end - start + 1;

                                using (var uncompressedDataStream = File.Open(destination, FileMode.OpenOrCreate))
                                {
                                    uncompressedDataStream.Seek(0, SeekOrigin.End);
                                    uncompressedDataStream.Write(uncompressedDataBlock, start, count);
                                }
                            }
                        }
                    }
                }
            }

            return(destination);
        }