コード例 #1
0
ファイル: Sarc.cs プロジェクト: caleb-mabry/Kuriimu2
        public IList <IArchiveFileInfo> Load(Stream input)
        {
            using var br = new BinaryReaderX(input, true, ByteOrder.BigEndian);

            // Determine byte order
            input.Position = 0x6;
            br.ByteOrder   = _byteOrder = br.ReadType <ByteOrder>();

            // Read header
            input.Position = 0;
            _header        = br.ReadType <SarcHeader>();

            // Read entries
            _sfatHeader = br.ReadType <SfatHeader>();
            var entries = br.ReadMultiple <SfatEntry>(_sfatHeader.entryCount);

            // Read names
            BinaryReaderX nameBr = null;

            if (entries.Any(x => (x.Flags & 0x100) > 0))
            {
                _sfntHeader = br.ReadType <SfntHeader>();
                var nameStream = new SubStream(input, input.Position, _header.dataOffset - input.Position);
                nameBr = new BinaryReaderX(nameStream);
            }

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

            foreach (var entry in entries)
            {
                var fileStream = new SubStream(input, _header.dataOffset + entry.startOffset, entry.endOffset - entry.startOffset);
                var magic      = SarcSupport.DetermineMagic(fileStream);

                var name = $"{entry.nameHash:X8}{SarcSupport.DetermineExtension(magic)}";
                if (nameBr != null)
                {
                    nameBr.BaseStream.Position = entry.FntOffset;
                    name = nameBr.ReadCStringASCII();
                }

                result.Add(new SarcArchiveFileInfo(fileStream, name, magic, entry));
            }

            return(result);
        }
コード例 #2
0
ファイル: Sarc.cs プロジェクト: caleb-mabry/Kuriimu2
        public void Save(Stream output, IList <IArchiveFileInfo> files, bool isCompressed)
        {
            var simpleHash = new SimpleHash(_sfatHeader.hashMultiplier);

            using var bw = new BinaryWriterX(output, true, _byteOrder);

            var sortedFiles = files.Cast <SarcArchiveFileInfo>().OrderBy(x => _sfntHeader == null ? x.Entry.nameHash : simpleHash.ComputeValue(x.FilePath.ToRelative().FullName)).ToArray();

            // Calculate offsets
            var sfatOffset = HeaderSize;
            var sfntOffset = sfatOffset + SfatHeaderSize + files.Count * SfatEntrySize;
            var dataOffset = _sfntHeader == null
                ? sfntOffset + SfntHeaderSize
                : sfntOffset + SfntHeaderSize + files.Sum(x => (x.FilePath.ToRelative().FullName.Length + 4) & ~3);

            var alignment         = sortedFiles.Max(x => SarcSupport.DetermineAlignment(x, _byteOrder, isCompressed));
            var alignedDataOffset = (dataOffset + alignment - 1) & ~(alignment - 1);

            // Write files
            var entries = new List <SfatEntry>();
            var strings = new List <string>();

            var stringPosition = 0;
            var dataPosition   = alignedDataOffset;

            foreach (var file in sortedFiles)
            {
                // Write file data
                alignment = SarcSupport.DetermineAlignment(file, _byteOrder, isCompressed);
                var alignedDataPosition = (dataPosition + alignment - 1) & ~(alignment - 1);

                output.Position = alignedDataPosition;
                var writtenSize = file.SaveFileData(output);

                // Add entry
                entries.Add(new SfatEntry
                {
                    startOffset = alignedDataPosition - alignedDataOffset,
                    endOffset   = (int)(alignedDataPosition + writtenSize - alignedDataOffset),
                    Flags       = (short)(_sfntHeader == null ? 0 : 0x100),
                    FntOffset   = (short)(_sfntHeader == null ? 0 : stringPosition),
                    nameHash    = _sfntHeader == null ? file.Entry.nameHash : simpleHash.ComputeValue(file.FilePath.ToRelative().FullName)
                });

                // Add string
                strings.Add(file.FilePath.ToRelative().FullName);

                dataPosition    = (int)(alignedDataPosition + writtenSize);
                stringPosition += (file.FilePath.ToRelative().FullName.Length + 4) & ~3;
            }

            // Write SFNT
            output.Position = sfntOffset;
            bw.WriteType(new SfntHeader());

            if (_sfntHeader != null)
            {
                foreach (var s in strings)
                {
                    bw.WriteString(s, Encoding.ASCII, false);
                    bw.WriteAlignment(4);
                }
            }

            // Write SFAT
            output.Position = sfatOffset;
            bw.WriteType(new SfatHeader {
                entryCount = (short)files.Count, hashMultiplier = _sfatHeader.hashMultiplier
            });
            bw.WriteMultiple(entries);

            // Write header
            output.Position = 0;
            bw.WriteType(new SarcHeader {
                byteOrder = _byteOrder, dataOffset = alignedDataOffset, fileSize = (int)output.Length, unk1 = _header.unk1
            });
        }