public void ExtractFontFiles(string outputDirectory)
        {
            var fontPatchDescriptor          = manifest.Patches.First(patch => patch.PatchIdentifier == EnglishFontDescriptorId);
            var manifestChunkDescriptorIndex = fontPatchDescriptor.PatchStart;
            var manifestChunk      = manifest.Chunks[(int)manifestChunkDescriptorIndex];
            var chunkDescriptor    = chunkDescriptors.First(desc => desc.Offset == manifestChunk.BasePosition);
            var fileLengthsMapping = new Queue <int>();

            using (StreamWriter descriptorWriter = new StreamWriter(File.Open(outputDirectory + @"\fonts.descriptor", FileMode.Create)))
            {
                using (var completeDecompressedMemoryStream = new MemoryStream())
                {
                    for (int i = 1; i < fontPatchDescriptor.PatchLength; i++)
                    {
                        var patchChunkDescriptor = manifest.Chunks[(int)manifestChunkDescriptorIndex + i];

                        if (patchChunkDescriptor.DirectoryId != (byte)DirectoryNames.InitialExperienceBase && patchChunkDescriptor.DirectoryId != (byte)DirectoryNames.InitialExperiencePatch)
                        {
                            throw new ArgumentException("Not supported");
                        }

                        var dataDir = patchChunkDescriptor.DirectoryId == (byte)DirectoryNames.InitialExperienceBase ? DataDirs[0] : DataDirs[1];

                        string compoundName = BaseDirectory + dataDir + @"\cas_" + (patchChunkDescriptor.Archive + 1).ToString("00") + ".cas";
                        using (BinaryReader reader = new BinaryReader(File.Open(compoundName, FileMode.Open)))
                        {
                            using (BinaryWriter writer = new BinaryWriter(completeDecompressedMemoryStream, ASCIIEncoding.ASCII, true))
                            {
                                reader.BaseStream.Seek(patchChunkDescriptor.BasePosition, SeekOrigin.Begin);
                                var decompressedSize = ChunkHandler.Dechunk(writer, reader, (int)patchChunkDescriptor.BaseLength);
                                fileLengthsMapping.Enqueue(decompressedSize);
                            }
                        }
                    }

                    completeDecompressedMemoryStream.Seek(0, SeekOrigin.Begin);
                    var currentTargetLength = fileLengthsMapping.Dequeue();
                    var subtotalLength      = 0;

                    foreach (var ebx in chunkDescriptor.EbxDescriptors)
                    {
                        var resourceName = BuildResourceName("ebx", ebx);
                        ExtractFileFromIntermediateResourceDescriptor(outputDirectory, completeDecompressedMemoryStream, ebx, resourceName);
                        WriteToLengthsDescriptor(fileLengthsMapping, descriptorWriter, ref currentTargetLength, ref subtotalLength, ebx, resourceName);
                    }

                    foreach (var data in chunkDescriptor.DataDescriptors)
                    {
                        var resourceName = BuildResourceName("data", data);
                        ExtractFileFromIntermediateResourceDescriptor(outputDirectory, completeDecompressedMemoryStream, data, BuildResourceName("data", data));
                        WriteToLengthsDescriptor(fileLengthsMapping, descriptorWriter, ref currentTargetLength, ref subtotalLength, data, resourceName);
                    }
                }
            }
        }
        public void WriteFileFromManifest(Chunk chunk, string directory, string fileName)
        {
            string compoundName = ResolveLanguageCasFile(chunk);

            using (BinaryReader reader = new BinaryReader(File.Open(compoundName, FileMode.Open)))
            {
                reader.BaseStream.Seek(chunk.BasePosition, SeekOrigin.Begin);

                string finalDirectory = directory + @"\manifest\";
                string finalName      = finalDirectory + fileName;
                Directory.CreateDirectory(finalDirectory);

                ChunkHandler.Dechunk(finalName, reader, (int)chunk.BaseLength);
            }
        }
        public void ImportTextFile(string inputDirectory)
        {
            var    chunk        = LocateLanguageFileChunk();
            string compoundName = ResolveLanguageCasFile(chunk);

            using (BinaryWriter writer = new BinaryWriter(File.Open(compoundName, FileMode.Append)))
            {
                var offset   = (int)writer.BaseStream.Position;
                int fileSize = ChunkHandler.Chunk(writer, inputDirectory + @"\manifest\" + EnglishChunkGuid);
                chunk.BasePosition = (uint)offset;
                chunk.BaseLength   = (uint)fileSize;
            }

            UpdateManifest();
        }
        public void WriteFileFromCatalogue(CatalogueEntry entry, string directory)
        {
            string compoundName = Path.GetDirectoryName(entry.Parent.Path) + @"\cas_" + entry.Archive.ToString("00") + ".cas";

            using (BinaryReader reader = new BinaryReader(File.Open(compoundName, FileMode.Open)))
            {
                reader.BaseStream.Seek(entry.Offset, SeekOrigin.Begin);

                string finalDirectory = directory + @"\cat\";
                string finalName      = finalDirectory + entry.ResolvedName;
                Directory.CreateDirectory(finalDirectory);

                ChunkHandler.Dechunk(finalName, reader, entry.Size);
            }
        }
        public void ImportFontFiles(string inputDirectory)
        {
            var fontPatchDescriptor          = manifest.Patches.First(patch => patch.PatchIdentifier == EnglishFontDescriptorId);
            var manifestChunkDescriptorIndex = fontPatchDescriptor.PatchStart;
            var manifestChunk              = manifest.Chunks[(int)manifestChunkDescriptorIndex];
            var chunkDescriptor            = chunkDescriptors.First(desc => desc.Offset == manifestChunk.BasePosition);
            var fileLengthsMapping         = new Queue <int>();
            var relativeChunkIdToFileNames = new Dictionary <int, List <string> >();

            using (StreamReader reader = new StreamReader(File.Open(inputDirectory + @"\fonts_import.descriptor", FileMode.Open)))
            {
                string line       = null;
                int    lineNumber = 1;
                while ((line = reader.ReadLine()) != null)
                {
                    var fileNames = new List <string>();

                    if (line != "-")
                    {
                        fileNames.AddRange(line.Split(','));
                    }

                    relativeChunkIdToFileNames[lineNumber++] = fileNames;
                }
            }

            var resourceDescriptorsToUpdate = new List <ResourceDescriptor>();

            using (BinaryWriter casWriter = new BinaryWriter(File.Open(BaseDirectory + DataDirs[1] + @"\cas_01.cas", FileMode.Append)))
            {
                for (int i = 1; i < fontPatchDescriptor.PatchLength; i++)
                {
                    if (relativeChunkIdToFileNames[i].Count > 0)
                    {
                        uint compressedBlockSize  = 0;
                        var  patchChunkDescriptor = manifest.Chunks[(int)manifestChunkDescriptorIndex + i];
                        patchChunkDescriptor.Archive      = 0;
                        patchChunkDescriptor.DirectoryId  = (byte)DirectoryNames.InitialExperiencePatch;
                        patchChunkDescriptor.BasePosition = (uint)casWriter.BaseStream.Position;

                        foreach (string fileName in relativeChunkIdToFileNames[i])
                        {
                            var compositeResourceDescriptor = chunkDescriptor.ResourceDescriptors.FirstOrDefault(descriptor => fileName.Contains(descriptor.Name));
                            var pathToNewFile = inputDirectory + @"\" + fileName;
                            compressedBlockSize += (uint)ChunkHandler.Chunk(casWriter, pathToNewFile);
                            compositeResourceDescriptor.Resource.Size = (int)new FileInfo(pathToNewFile).Length;
                            resourceDescriptorsToUpdate.Add(compositeResourceDescriptor.Resource);
                        }

                        patchChunkDescriptor.BaseLength = compressedBlockSize;
                    }
                }
            }

            using (BinaryWriter chunkDescriptorWriter = new BinaryWriter(File.Open(ResolveManifestCasFile(), FileMode.Open)))
            {
                foreach (var resourceDescriptor in resourceDescriptorsToUpdate)
                {
                    chunkDescriptorWriter.BaseStream.Seek(resourceDescriptor.Offset + 4, SeekOrigin.Begin);
                    chunkDescriptorWriter.WriteUInt32BE((UInt32)resourceDescriptor.Size);
                }
            }

            UpdateManifest();
        }