public Archive(string fileName)
        {
            FileName = fileName;
            using (System.IO.FileStream stream = System.IO.File.Open(FileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
            {
                CFHEADER header = CFHEADER.FromStream(stream);

                int dataBlocks = 0;

                for (int i = 0; i < header.CFHEADER_FIXED.cFolders; i++)
                {
                    CFFOLDER folder = CFFOLDER.FromStream(stream, header);
                    m_folders.Add(folder);

                    dataBlocks += folder.cCFData;
                }

                stream.Seek(header.CFHEADER_FIXED.coffFiles, System.IO.SeekOrigin.Begin);

                for (int i = 0; i < header.CFHEADER_FIXED.cFiles; i++)
                {
                    CFFILE file = CFFILE.FromStream(stream);
                    m_files.Add(file);
                }
                stream.Close();
            }
        }
        internal static CFFOLDER FromStream(FileStream stream, CFHEADER header)
        {
            CFFOLDER     folder = new CFFOLDER();
            BinaryReader reader = new BinaryReader(stream);

            folder.coffCabStart = reader.ReadUInt32();
            folder.cCFData      = reader.ReadUInt16();
            folder.typeCompress = reader.ReadUInt16();

            if (((header.CFHEADER_FIXED.flags & CFHEADER_FLAGS.RESERVE_PRESENT) == CFHEADER_FLAGS.RESERVE_PRESENT) &&
                header.CFHEADER_OPTIONAL.cbCFFolder != 0)
            {
                folder.abReserve = reader.ReadBytes(header.CFHEADER_OPTIONAL.cbCFFolder);
            }

            return(folder);
        }
        public virtual void ExtractFile(FileInfo fileInfo, string targetFileName, bool overwriteExisting)
        {
            CFFOLDER containingFolder = m_folders[fileInfo.CFFILE.iFolder];

            using (System.IO.Stream input = System.IO.File.Open(FileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
            {
                int toRead = (int)fileInfo.CFFILE.cbFile;

                CabDecompressor decompressor = new CabDecompressor((CompressionType)containingFolder.typeCompress);
                CabFolderStream folderStream = new CabFolderStream(input, containingFolder.coffCabStart, containingFolder.Compressed);

                // skip to the beginning of the file. this is done by decompressing into a null stream
                if (fileInfo.CFFILE.uoffFolderStart > 0)
                {
                    using (NullStream ns = new NullStream())
                    {
                        decompressor.DecompressBlock((int)fileInfo.CFFILE.uoffFolderStart, folderStream.SizeCompressed, folderStream.SizeUncompressed, folderStream, ns);
                    }
                }

                using (SizeLimitedOutputStream output = new SizeLimitedOutputStream(targetFileName, System.IO.FileMode.OpenOrCreate, (int)fileInfo.CFFILE.cbFile))
                {
                    while (toRead > 0)
                    {
                        int nextBlock = Math.Min(toRead, folderStream.SizeUncompressed);
                        if (folderStream.SizeUncompressed == -1)
                        {
                            nextBlock = toRead;
                        }
                        //System.Diagnostics.Debug.WriteLine(string.Format("Reading {0} bytes", nextBlock));
                        decompressor.DecompressBlock(nextBlock, folderStream.SizeCompressed, folderStream.SizeUncompressed, folderStream, output);
                        toRead -= nextBlock;
                        output.Flush();
                    }
                }
            }
        }