public void WriteFile(Stream outstream, FileInArchive file, byte[] data)
        {
            MemoryStream inputMS  = new MemoryStream(data);
            MemoryStream outputMS = new MemoryStream();

            byte[] output_buffer = new byte[0];

            if (file.Descriptor.CompressionMethod == 1) //ZLib compression
            {
                ICSharpCode.SharpZipLib.Zip.Compression.Deflater def = new ICSharpCode.SharpZipLib.Zip.Compression.Deflater();
                ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream defstream = new ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream(outputMS, def);
                defstream.Write(data, 0, data.Length);
                defstream.Flush();
                defstream.Finish();
                output_buffer = outputMS.GetBuffer();
                file.Descriptor.UncompressedSize = (uint)inputMS.Length;

                Write(outstream, file, outputMS);
            }
            else if (file.Descriptor.CompressionMethod == 0)  //No compression
            {
                file.Descriptor.CompressionMethod = 0;
                inputMS.CopyTo(outputMS);
                file.Descriptor.UncompressedSize = (uint)inputMS.Length;

                Write(outstream, file, outputMS);
            }
        }
        private void Write(Stream stream, FileInArchive file, MemoryStream ms)
        {
            stream.Seek((long)file.Descriptor.FileTableEntryPosition + 12, SeekOrigin.Begin);
            int lowMSLength = (int)(ms.Length & 0xFFFFFFFF);

            stream.Write(BitConverter.GetBytes(lowMSLength), 0, 4);

            stream.Seek((long)file.Descriptor.FileTableEntryPosition + 16, SeekOrigin.Begin);
            lowMSLength = (int)(file.Descriptor.UncompressedSize & 0xFFFFFFFF);
            stream.Write(BitConverter.GetBytes(lowMSLength), 0, 4);

            stream.Seek((long)file.Descriptor.FileTableEntryPosition + 32, SeekOrigin.Begin);
            byte[] bArray = new byte[1];
            bArray[0] = (byte)file.CompressionMethod;
            stream.Write(bArray, 0, 1);


            byte[] tmp_bytearray = ms.GetBuffer();
            if (ms.Length <= file.Descriptor.CompressedSize)
            {
                stream.Seek((long)(file.Descriptor.StartingPosition + file.Descriptor.FileHeaderSize), SeekOrigin.Begin);
                stream.Write(tmp_bytearray, 0, (int)ms.Length);
            }
            else
            {
                long fileSize = stream.Length;

                stream.Seek(0, SeekOrigin.End);
                if (file.Descriptor.metadata != null)
                {
                    stream.Write(file.Descriptor.metadata, 0, file.Descriptor.metadata.Length);
                }
                else
                {
                    byte[] fakeMetadata = new byte[file.Descriptor.FileHeaderSize];
                    stream.Write(fakeMetadata, 0, fakeMetadata.Length);
                    //Should throw an exception, but not all files have meta data so...
                }
                stream.Seek(0, SeekOrigin.End);
                stream.Write(tmp_bytearray, 0, (int)ms.Length);

                stream.Seek((long)file.Descriptor.FileTableEntryPosition, SeekOrigin.Begin);
                stream.Write(BitConverter.GetBytes((int)(fileSize & 0xFFFFFFFF)), 0, 4);

                stream.Seek((long)file.Descriptor.FileTableEntryPosition + 4, SeekOrigin.Begin);
                stream.Write(BitConverter.GetBytes((int)((fileSize >> 32) & 0xFFFFFFFF)), 0, 4);

                file.Descriptor.StartingPosition = (int)(fileSize & 0xFFFFFFFF);
            }

            file.Descriptor.CompressedSize = (uint)ms.Length;
            tmp_bytearray = null;
        }
        public byte[] ReadFile(Stream outstream, FileInArchive file)
        {
            if (file.Descriptor.CompressionMethod == 1) //ZLib compression
            {
                outstream.Position = file.Descriptor.StartingPosition + file.Descriptor.FileHeaderSize;
                byte[] compressedData = new byte[file.Descriptor.CompressedSize];
                outstream.Read(compressedData, 0, (int)file.Descriptor.CompressedSize);

                byte[] output_buffer = new byte[file.Descriptor.UncompressedSize];

                ICSharpCode.SharpZipLib.Zip.Compression.Inflater inf = new ICSharpCode.SharpZipLib.Zip.Compression.Inflater();
                inf.SetInput(compressedData);
                inf.Inflate(output_buffer);
                return(output_buffer);
            }
            else
            {
                outstream.Position = file.Descriptor.StartingPosition + file.Descriptor.FileHeaderSize;
                byte[] compressedData = new byte[file.Descriptor.CompressedSize];
                outstream.Read(compressedData, 0, (int)file.Descriptor.CompressedSize);

                return(compressedData);
            }
        }
        public void Load(Stream stream)
        {
            //read the position of the starting file table
            stream.Seek(0x0C, SeekOrigin.Begin);
            byte[] buffer = new byte[8];
            stream.Read(buffer, 0, buffer.Length);
            long tableStart = FileInArchiveDescriptor.convertLittleEndianBufferToInt(buffer, 0);

            tableStart += ((long)FileInArchiveDescriptor.convertLittleEndianBufferToInt(buffer, 4)) << 32;

            //get file count
            stream.Seek(24, SeekOrigin.Begin);
            buffer = new byte[4];
            stream.Read(buffer, 0, buffer.Length);

            _fileCount = FileInArchiveDescriptor.convertLittleEndianBufferToInt(buffer, 0);

            //Init
            long currentReadingPosition;
            uint numberOfFileInTable = 0;
            long endOfTableAddress;

            byte[]        bufferTableHeader = new byte[12];
            byte[]        bufferFileDesc    = new byte[FileInArchiveDescriptor.fileDescriptorSize];
            FileInArchive myArchFile;

            while (tableStart != 0)
            {
                stream.Seek(tableStart, SeekOrigin.Begin);
                stream.Read(bufferTableHeader, 0, bufferTableHeader.Length);

                numberOfFileInTable = FileInArchiveDescriptor.convertLittleEndianBufferToInt(bufferTableHeader, 0); //get number of files

                currentReadingPosition = tableStart + 12;
                endOfTableAddress      = tableStart + 12 + (long)FileInArchiveDescriptor.fileDescriptorSize * (long)numberOfFileInTable; // calculates the end address

                tableStart  = FileInArchiveDescriptor.convertLittleEndianBufferToInt(bufferTableHeader, 4);                              //find the next filetable
                tableStart += (long)FileInArchiveDescriptor.convertLittleEndianBufferToInt(bufferTableHeader, 8) << 32;                  //mostly 0

                while (currentReadingPosition < endOfTableAddress)
                {
                    stream.Seek(currentReadingPosition, SeekOrigin.Begin);
                    stream.Read(bufferFileDesc, 0, bufferFileDesc.Length);

                    myArchFile            = new FileInArchive();
                    myArchFile.Descriptor = new FileInArchiveDescriptor(bufferFileDesc);

                    myArchFile.Descriptor.FileTableEntryPosition = currentReadingPosition;

                    if (myArchFile.Descriptor.StartingPosition > 0 &&
                        myArchFile.Descriptor.CompressedSize > 0 &&
                        myArchFile.Descriptor.UncompressedSize > 0    //If the compressed size is 0, then there is no file
                        )
                    {
                        _files[((long)myArchFile.Descriptor.ph << 32) + myArchFile.Descriptor.sh] = myArchFile;

                        //Retrieve header
                        myArchFile.Descriptor.metadata = new byte[myArchFile.Descriptor.FileHeaderSize];


                        stream.Seek(myArchFile.Descriptor.StartingPosition, SeekOrigin.Begin);
                        stream.Read(myArchFile.Descriptor.metadata, 0, myArchFile.Descriptor.metadata.Length);
                    }
                    currentReadingPosition += FileInArchiveDescriptor.fileDescriptorSize;
                }
            }
        }