Пример #1
0
        /// <summary>
        /// Replaces the contents of <paramref name="fileIndex"/> with the specified buffer
        /// </summary>
        /// <param name="fileId">File id of the file to replace</param>
        /// <param name="data">New file contents to write</param>
        /// <returns>True if the data was successfully compressed and written to the archive, false otherwise</returns>
        public bool InjectFile(uint fileId, byte[] data)
        {
            // Make sure we have a file id entry in the dictionary.
            if (this.fileEntryLookupDictionary.ContainsKey(fileId) == false)
            {
                // No dictionary entry for this file id.
                return(false);
            }

            // Get the index of the file from the file id.
            int fileIndex = this.fileEntryLookupDictionary[fileId];

            // Open the archive for writing.
            if (OpenArchive(true) == false)
            {
                // Failed to open the archive.
                return(false);
            }

            // Compress the data.
            byte[] compressedData = ZlibUtilities.CompressData(data);

            // Seek to the end of the this file's data.
            this.reader.BaseStream.Position = this.fileEntries[fileIndex].DataOffset + this.fileEntries[fileIndex].CompressedSize;

            // Read all the remaining data in the file.
            byte[] remainingData = this.reader.ReadBytes((int)(this.reader.BaseStream.Length - this.reader.BaseStream.Position));

            // Seek to the start of the old file's data.
            this.writer.BaseStream.Position = this.fileEntries[fileIndex].DataOffset;

            // Calculate the offset shift amount and write the new compressed data buffer.
            int offsetShift = compressedData.Length - this.fileEntries[fileIndex].CompressedSize;

            this.writer.Write(compressedData);

            // Write the remaining file data.
            this.writer.Write(remainingData);

            // Loop and update any file entries that need to accommodate for the file size change.
            for (int i = 0; i < this.fileEntries.Count; i++)
            {
                // Check if this file's offset needs to be updated or if it is the file we just replaced.
                if (this.fileEntries[i].DataOffset > this.fileEntries[fileIndex].DataOffset)
                {
                    // Update this file entries data offset.
                    this.fileEntries[i].DataOffset += offsetShift;

                    // Write the new offset to file.
                    this.writer.BaseStream.Position = ArchiveHeader.kSizeOf + (ArchiveFileEntry.kSizeOf * i) + 76;
                    this.writer.Write(this.fileEntries[i].DataOffset);
                }
                else if (i == fileIndex)
                {
                    // Update the data sizes for this file entry.
                    this.fileEntries[i].CompressedSize   = compressedData.Length;
                    this.fileEntries[i].DecompressedSize = data.Length;

                    // Write the new data sizes to file.
                    this.writer.BaseStream.Position = ArchiveHeader.kSizeOf + (ArchiveFileEntry.kSizeOf * i) + 64 + 4;
                    this.writer.Write(this.fileEntries[i].CompressedSize);
                    this.writer.Write(this.fileEntries[i].DecompressedSize);
                }
            }

            // Close the archive and return.
            CloseArchive();
            return(true);
        }
Пример #2
0
        public bool AddFiles(string[] newFileNames, string[] filePaths, out DatumIndex[] newDatums)
        {
            // Satisfy the compiler.
            newDatums = new DatumIndex[0];

            // Open the archive for writing.
            if (OpenArchive(true) == false)
            {
                // Failed to open the archive for writing.
                return(false);
            }

            // Create a new memory stream to hold compressed file data.
            List <int>   fileOffsets = new List <int>();
            MemoryStream dataStream  = new MemoryStream((int)this.reader.BaseStream.Length);

            // Loop through all the files in the archive and read each one into the memory stream.
            for (int i = 0; i < this.fileEntries.Count; i++)
            {
                // Seek to the data offset.
                this.reader.BaseStream.Position = this.fileEntries[i].DataOffset;

                // Read the compressed file data.
                byte[] compressedData = this.reader.ReadBytes(this.fileEntries[i].CompressedSize);

                // Save the data offset and write the compressed data to the memory stream.
                fileOffsets.Add((int)dataStream.Position);
                dataStream.Write(compressedData, 0, compressedData.Length);
            }

            // Loop through all of the new files and create file entries for each one.
            newDatums = new DatumIndex[newFileNames.Length];
            for (int i = 0; i < newFileNames.Length; i++)
            {
                // Read the file contents and compress it.
                byte[] decompressedData = File.ReadAllBytes(filePaths[i]);
                byte[] compressedData   = ZlibUtilities.CompressData(decompressedData);

                // Get the resource type from the file extension.
                ResourceType fileType = (ResourceType)Enum.Parse(typeof(ResourceType), filePaths[i].Substring(filePaths[i].LastIndexOf('.') + 1), true);

                // Create a new file entry for this file.
                ArchiveFileEntry newFileEntry = new ArchiveFileEntry();
                newFileEntry.FileName         = newFileNames[i] + "." + fileType.ToString();
                newFileEntry.CompressedSize   = compressedData.Length;
                newFileEntry.DecompressedSize = decompressedData.Length;
                newFileEntry.FileId           = this.nextFileId++;
                newFileEntry.FileType         = fileType;

                // Copy the new datum to the output list.
                newDatums[i] = new DatumIndex(this.ArchiveId, newFileEntry.FileId);

                // Add the file entry to the list and create a reverse lookup entry.
                this.fileEntryLookupDictionary.Add(newFileEntry.FileId, this.fileEntries.Count);
                this.fileEntries.Add(newFileEntry);

                // Add the data offset to the list and write the compressed data to the data stream.
                fileOffsets.Add((int)dataStream.Position);
                dataStream.Write(compressedData, 0, compressedData.Length);
            }

            // Update the header for the new file count.
            this.writer.BaseStream.Position = 0;
            this.writer.Write(ArchiveHeader.kHeaderMagic1);
            this.writer.Write((short)ArchiveHeader.kVersion);
            this.writer.Write((short)this.fileEntries.Count);

            // Calculate the data start offset based on the new number of files.
            int dataStart = ArchiveHeader.kSizeOf + (this.fileEntries.Count * ArchiveFileEntry.kSizeOf);

            if (dataStart % 0x8000 != 0)
            {
                dataStart += 0x8000 - (dataStart % 0x8000);
            }

            // Loop and write all the file entries.
            for (int i = 0; i < this.fileEntries.Count; i++)
            {
                // Write the file entry.
                string fileName = this.fileEntries[i].GetFileNameNoExtension();
                this.writer.Write(fileName.ToCharArray());
                this.writer.Write(new byte[ArchiveFileEntry.kMaxFileNameLength - fileName.Length]);

                // If we know the file type for this file get the file type id.
                if (GameResource.KnownResourceTypesReverse.ContainsKey(this.fileEntries[i].FileType) == true)
                {
                    this.writer.Write(GameResource.KnownResourceTypesReverse[this.fileEntries[i].FileType]);
                }
                else
                {
                    this.writer.Write((int)this.fileEntries[i].FileType);
                }

                this.writer.Write(this.fileEntries[i].CompressedSize);
                this.writer.Write(this.fileEntries[i].DecompressedSize);
                this.writer.Write(dataStart + fileOffsets[i]);

                // Update the file offset.
                this.fileEntries[i].DataOffset = dataStart + fileOffsets[i];
            }

            // Fill the rest with padding.
            this.writer.Write(new byte[dataStart - (int)this.writer.BaseStream.Position]);

            // Write the data stream and calculate the new file size.
            this.writer.Write(dataStream.ToArray(), 0, (int)dataStream.Length);
            this.fileStream.SetLength(this.writer.BaseStream.Position);

            // Close the archive.
            CloseArchive();
            return(true);
        }