Exemple #1
0
        public IList <IArchiveFileInfo> Load(Stream input)
        {
            using var br = new BinaryReaderX(input, true);

            // Read header
            _header = br.ReadType <X3Header>();

            // Read file entries
            var entries = br.ReadMultiple <X3FileEntry>(_header.fileCount);

            // Add files
            var result = new List <IArchiveFileInfo>();

            foreach (var entry in entries)
            {
                var rawFileStream = new SubStream(input, entry.offset * _header.alignment, entry.fileSize);

                // Prepare (de-)compressed file stream for extension detection
                Stream fileStream = rawFileStream;
                if (entry.IsCompressed)
                {
                    fileStream = new X3CompressedStream(fileStream);
                }

                var extension = X3Support.DetermineExtension(fileStream);
                var fileName  = $"{result.Count:00000000}{extension}";

                // Pass unmodified SubStream, so X3Afi can take care of compression wrapping again
                // Necessary for access to original compressed file data in saving
                result.Add(new X3ArchiveFileInfo(rawFileStream, fileName, entry));
            }

            return(result);
        }
Exemple #2
0
        public IList <ArchiveFileInfo> Load(Stream input)
        {
            using var br = new BinaryReaderX(input, true);

            // Read header
            _header = br.ReadType <X3Header>();
            br.BaseStream.Position += 4;

            // Read file entries
            var entries = br.ReadMultiple <X3FileEntry>(_header.fileCount);

            // Add files
            var result = new List <ArchiveFileInfo>();

            foreach (var entry in entries)
            {
                var fileOffset = entry.offset * _header.offsetMultiplier;
                br.BaseStream.Position = fileOffset;

                var    firstBlockLength = -1;
                Stream firstBlock;
                if (entry.IsCompressed)
                {
                    // Compressed files have decompressed size and size of the first "block" prefixed
                    br.BaseStream.Position += 4;
                    firstBlockLength        = br.ReadInt32();
                    firstBlock              = PeekFirstCompressedBlock(input, input.Position, firstBlockLength);
                }
                else
                {
                    // Uncompressed files have only uncompressed size prefixed
                    firstBlock = new SubStream(input, br.BaseStream.Position, 4);
                }

                var extension = DetermineExtension(firstBlock);

                var fileStream = new SubStream(br.BaseStream, fileOffset + (entry.IsCompressed ? 8 : 0), entry.fileSize);
                var fileName   = result.Count.ToString("00000000") + extension;

                if (entry.IsCompressed)
                {
                    result.Add(new X3ArchiveFileInfo(fileStream, fileName,
                                                     Kompression.Implementations.Compressions.ZLib, entry.decompressedFileSize,
                                                     entry, firstBlockLength));
                }
                else
                {
                    result.Add(new X3ArchiveFileInfo(fileStream, fileName,
                                                     entry, firstBlockLength));
                }
            }

            return(result);
        }
Exemple #3
0
        // TODO: Set firstBlockLength again (need to understand enough ZLib for that)
        public void Save(Stream output, IList <IArchiveFileInfo> files)
        {
            using var bw = new BinaryWriterX(output);
            var castedFiles = files.Cast <X3ArchiveFileInfo>().ToArray();

            var header = new X3Header
            {
                fileCount = files.Count
            };

            // Write files
            bw.BaseStream.Position = (HeaderSize + 4 + files.Count * EntrySize + header.offsetMultiplier - 1) & ~(header.offsetMultiplier - 1);

            foreach (var file in castedFiles)
            {
                var fileOffset = bw.BaseStream.Position;

                if (file.Entry.IsCompressed)
                {
                    // Write prefix information when compressed
                    bw.Write((uint)file.FileSize);
                    bw.Write(file.FirstBlockSize);
                }

                var writtenSize = file.SaveFileData(bw.BaseStream);
                bw.WriteAlignment(header.offsetMultiplier);

                file.Entry.offset   = fileOffset / header.offsetMultiplier;
                file.Entry.fileSize = (int)writtenSize;
                if (file.Entry.IsCompressed)
                {
                    file.Entry.decompressedFileSize = (int)file.FileSize;
                }
            }

            // Write file entries
            bw.BaseStream.Position = HeaderSize + 4;
            foreach (var file in castedFiles)
            {
                bw.WriteType(file.Entry);
            }

            // Write header
            bw.BaseStream.Position = 0;
            bw.WriteType(header);
        }
Exemple #4
0
        public IList <IArchiveFileInfo> Load(Stream input)
        {
            using var br = new BinaryReaderX(input, true);

            // Read header
            _header = br.ReadType <X3Header>();
            br.BaseStream.Position += 4;

            // Read file entries
            var entries = br.ReadMultiple <X3FileEntry>(_header.fileCount);

            var firstBlocksList = new List <(int, int, string)>();

            // Add files
            var result = new List <IArchiveFileInfo>();

            foreach (var entry in entries)
            {
                var fileOffset = entry.offset * _header.offsetMultiplier;
                br.BaseStream.Position = fileOffset;

                var    firstBlockLength = -1;
                Stream firstBlock;
                if (entry.IsCompressed)
                {
                    // Compressed files have decompressed size and size of the first "block" prefixed
                    br.BaseStream.Position += 4;
                    firstBlockLength        = br.ReadInt32();
                    firstBlock              = PeekFirstCompressedBlock(input, input.Position, firstBlockLength);
                }
                else
                {
                    // Uncompressed files have only uncompressed size prefixed
                    firstBlock = new SubStream(input, br.BaseStream.Position, 4);
                }

                var extension = DetermineExtension(firstBlock);

                var fileStream = new SubStream(br.BaseStream, fileOffset + (entry.IsCompressed ? 8 : 0), entry.fileSize);
                var fileName   = result.Count.ToString("00000000") + extension;

                if (firstBlockLength >= 0)
                {
                    firstBlocksList.Add((firstBlockLength, entry.fileSize, fileName));
                }

                //if (fileName == "00000001.3ds.gt1")
                //{
                //    var newFs = File.Create(@"D:\Users\Kirito\Desktop\comp_x3.bin");
                //    fileStream.CopyTo(newFs);
                //    fileStream.Position = 0;
                //    newFs.Close();
                //}

                if (entry.IsCompressed)
                {
                    result.Add(new X3ArchiveFileInfo(fileStream, fileName,
                                                     Kompression.Implementations.Compressions.ZLib, entry.decompressedFileSize,
                                                     entry, firstBlockLength));
                }
                else
                {
                    result.Add(new X3ArchiveFileInfo(fileStream, fileName,
                                                     entry, firstBlockLength));
                }
            }

            return(result);
        }