Exemple #1
0
        public SARC(Stream input)
        {
            _stream = input;
            using (var br = new BinaryReaderX(input, true))
            {
                //Get ByteOrder
                br.BaseStream.Position = 0x6;
                byteOrder = (ByteOrder)br.ReadUInt16();
                br.BaseStream.Position = 0;
                br.ByteOrder           = byteOrder;

                //Header
                Header = br.ReadStruct <SARCHeader>();

                //FAT
                var sfatHeader  = br.ReadStruct <SFATHeader>();
                var sfatEntries = br.ReadMultiple <SFATEntry>(sfatHeader.nodeCount).ToList();
                hashMultiplier = (uint)sfatHeader.hashMultiplier;

                //FNT
                SFNTHeader = br.ReadStruct <SFNTHeader>();
                var sfntOffset = br.BaseStream.Position;

                //is FNT used?
                usesSFNT = sfatEntries.Any(entry => (entry.SFNTOffsetFlag >> 16) == 0x100);

                Files = sfatEntries.Select(entry =>
                {
                    Support.extensions.TryGetValue(br.PeekString((uint)(Header.dataOffset + entry.dataStart), 4), out var getExt);
                    if (getExt == null)
                    {
                        Support.extensions.TryGetValue(br.PeekString((uint)(Header.dataOffset + entry.dataEnd - 0x28), 4), out getExt);
                    }

                    br.BaseStream.Position = ((entry.SFNTOffsetFlag & 0xffff) << 2) + sfntOffset;
                    var filename           = usesSFNT ? br.ReadCStringA() : $"0x{entry.nameHash:X8}" + ((getExt == null) ? ".bin" : getExt);
                    return(new SarcArchiveFileInfo
                    {
                        Entry = entry,
                        FileName = filename,
                        FileData = new SubStream(input, Header.dataOffset + entry.dataStart, entry.dataEnd - entry.dataStart),
                        State = ArchiveFileState.Archived,
                        Hash = entry.nameHash
                    });
                }).ToList();
            }
        }
Exemple #2
0
        public void Save(Stream output, bool leaveOpen = false)
        {
            using (var bw = new BinaryWriterX(output, leaveOpen, byteOrder))
            {
                //Create SARCHeader
                var header = new SARCHeader
                {
                    byteOrder  = byteOrder,
                    dataOffset = Files.Aggregate(
                        0x14 + 0xc + 0x8 + Files.Sum(afi => usesSFNT ? ((afi.FileName.Length + 4) & ~3) + 0x10 : 0x10),
                        (n, file) => Support.Pad(n, file.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU))
                };

                //SFATHeader
                bw.BaseStream.Position = 0x14;
                bw.WriteStruct(new SFATHeader
                {
                    hashMultiplier = (int)hashMultiplier,
                    nodeCount      = (short)Files.Count
                });

                //SFAT List + nameList
                int nameOffset = 0;
                int dataOffset = 0;
                foreach (var afi in Files)
                {
                    dataOffset = Support.Pad(dataOffset, afi.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU);
                    var fileLen = (int)afi.FileData.Length;

                    var sfatEntry = new SFATEntry
                    {
                        nameHash       = usesSFNT ? SimpleHash.Create(afi.FileName, hashMultiplier) : Convert.ToUInt32(afi.FileName.Substring(2, 8), 16),
                        SFNTOffsetFlag = (uint)(((usesSFNT ? 0x100 : 0) << 16) | (usesSFNT ? nameOffset / 4 : 0)),
                        dataStart      = dataOffset,
                        dataEnd        = dataOffset + fileLen
                    };
                    bw.WriteStruct(sfatEntry);
                    nameOffset = (nameOffset + afi.FileName.Length + 4) & ~3;
                    dataOffset = sfatEntry.dataEnd;
                }

                //SFNT
                bw.WriteStruct(new SFNTHeader());
                if (usesSFNT)
                {
                    foreach (var afi in Files)
                    {
                        bw.WriteASCII(afi.FileName + "\0");
                        bw.BaseStream.Position = (bw.BaseStream.Position + 3) & ~3;
                    }
                }

                //FileData
                bw.WriteAlignment(header.dataOffset);
                foreach (var afi in Files)
                {
                    bw.WriteAlignment(Support.Pad((int)bw.BaseStream.Length, afi.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU));    //(unusual) padding scheme through filenames
                    afi.FileData.CopyTo(bw.BaseStream);
                }

                bw.BaseStream.Position = 0;
                header.fileSize        = (int)bw.BaseStream.Length;
                bw.WriteStruct(header);
            }
        }