示例#1
0
        public SFOData Build()
        {
            SFOData sfo = new SFOData();

            sfo.Magic   = 0x46535000; // _PSF
            sfo.Version = 0x00000101;
            sfo.Entries = new List <SFODir>();

            var headerSize     = 20;
            var indexTableSize = entries.Count * 16;

            var keyTableSize = entries.Sum(x => x.Key.Length + 1);

            if (keyTableSize % 4 != 0)
            {
                sfo.Padding = (uint)(4 - keyTableSize % 4);
            }

            sfo.KeyTableOffset = (uint)(headerSize + indexTableSize);

            sfo.DataTableOffset = sfo.KeyTableOffset + (uint)keyTableSize + sfo.Padding;

            ushort keyOffset  = 0;
            uint   dataOffset = 0;

            for (var i = 0; i < entries.Count; i++)
            {
                var entry       = entries[i];
                var entryLength = GetEntryLength(entry.Key, entry.Value);
                var maxLength   = GetMaxLength(entry.Key);

                if (entryLength > maxLength)
                {
                    throw new Exception("Value for {entry.Key} exceeds maximum allowed length");
                }

                sfo.Entries.Add(new SFODir()
                {
                    KeyOffset  = keyOffset,
                    Format     = GetEntryType(entry.Key),
                    Length     = entryLength,
                    MaxLength  = maxLength,
                    DataOffset = dataOffset,
                    Key        = entry.Key,
                    Value      = entry.Value,
                });

                dataOffset += maxLength;
                keyOffset  += (ushort)(entries[i].Key.Length + 1);
            }

            sfo.Size = sfo.DataTableOffset + dataOffset;

            return(sfo);
        }
        public static void Write(this Stream stream, SFOData sfo)
        {
            stream.WriteInteger(sfo.Magic, 1);
            stream.WriteInteger(sfo.Version, 1);
            stream.WriteInteger(sfo.KeyTableOffset, 1);
            stream.WriteInteger(sfo.DataTableOffset, 1);
            stream.WriteInteger((ushort)sfo.Entries.Count, 1);

            for (var i = 0; i < sfo.Entries.Count; i++)
            {
                var entry = sfo.Entries[i];
                stream.WriteShort(entry.KeyOffset, 1);
                stream.WriteShort(entry.Format, 1);
                stream.WriteInteger(entry.Length, 1);
                stream.WriteInteger(entry.MaxLength, 1);
                stream.WriteInteger(entry.DataOffset, 1);
            }

            for (var i = 0; i < sfo.Entries.Count; i++)
            {
                var key = sfo.Entries[i].Key;
                stream.Write(key, 0, key.Length);
                stream.WriteByte(0);
            }

            for (var i = 0; i < sfo.Padding; i++)
            {
                stream.WriteByte(0);
            }

            for (var i = 0; i < sfo.Entries.Count; i++)
            {
                var entry = sfo.Entries[i];
                var value = entry.Value;
                switch (entry.Format)
                {
                case 0x0204:
                    stream.Write((string)value, 0, ((string)value).Length);
                    stream.WriteByte(0);
                    for (var j = 0; j < entry.MaxLength - entry.Length; j++)
                    {
                        stream.WriteByte(0);
                    }
                    break;

                case 0x0404:
                    stream.WriteInteger(Convert.ToInt32(value), 1);
                    break;
                }
            }
        }
        public static SFOData ReadSFO(this Stream stream, uint sfoOffset)
        {
            var sfo = new SFOData();

            sfo.Magic           = stream.ReadUInteger();
            sfo.Version         = stream.ReadUInteger();
            sfo.KeyTableOffset  = stream.ReadUInteger();
            sfo.DataTableOffset = stream.ReadUInteger();
            var entries = stream.ReadUInteger();

            sfo.Entries = new List <SFODir>();
            for (var i = 0; i < entries; i++)
            {
                var entry = new SFODir
                {
                    KeyOffset  = stream.ReadUShort(),
                    Format     = stream.ReadUShort(),
                    Length     = stream.ReadUInteger(),
                    MaxLength  = stream.ReadUInteger(),
                    DataOffset = stream.ReadUInteger()
                };
                sfo.Entries.Add(entry);
            }

            for (var i = 0; i < sfo.Entries.Count; i++)
            {
                var entry = sfo.Entries[i];
                stream.Seek(sfoOffset + sfo.KeyTableOffset + entry.KeyOffset, SeekOrigin.Begin);
                var key = stream.ReadString(128);
                entry.Key = key.Substring(0, key.IndexOf('\0'));
            }

            for (var i = 0; i < sfo.Entries.Count; i++)
            {
                var entry = sfo.Entries[i];
                stream.Seek(sfoOffset + sfo.DataTableOffset + entry.DataOffset, SeekOrigin.Begin);
                switch (entry.Format)
                {
                case 0x0204:
                    entry.Value = stream.ReadString((int)entry.Length - 1);
                    break;

                case 0x0404:
                    entry.Value = stream.ReadUInteger();
                    break;
                }
            }

            return(sfo);
        }