void ExtractFile(FileDescriptor file, Stream output, Action <int> onProgress = null)
        {
            if (file.Flags.HasFlag(CABFlags.FileInvalid))
            {
                throw new InvalidDataException("File Invalid");
            }

            if (file.LinkFlags.HasFlag(LinkFlags.Prev))
            {
                var prev = index.Values.First(f => f.Index == file.LinkToPrevious);
                ExtractFile(prev, output, onProgress);
                return;
            }

            if (file.Flags.HasFlag(CABFlags.FileObfuscated))
            {
                throw new NotImplementedException("Obfuscated files are not supported");
            }

            var extracter = new CabExtracter(file, volumes);

            extracter.CopyTo(output, onProgress);

            if (output.Length != file.ExpandedSize)
            {
                throw new InvalidDataException("File expanded to wrong length. Expected = {0}, Got = {1}".F(file.ExpandedSize, output.Length));
            }
        }
        void ExtractFile(FileDescriptor file, Stream output, Action<int> onProgress = null)
        {
            if (file.Flags.HasFlag(CABFlags.FileInvalid))
                throw new Exception("File Invalid");

            if (file.LinkFlags.HasFlag(LinkFlags.Prev))
            {
                var prev = index.Values.First(f => f.Index == file.LinkToPrevious);
                ExtractFile(prev, output, onProgress);
                return;
            }

            if (file.Flags.HasFlag(CABFlags.FileObfuscated))
                throw new NotImplementedException("Obfuscated files are not supported");

            var extracter = new CabExtracter(file, volumes);
            extracter.CopyTo(output, onProgress);

            if (output.Length != file.ExpandedSize)
                throw new InvalidDataException("File expanded to wrong length. Expected = {0}, Got = {1}".F(file.ExpandedSize, output.Length));
        }