Ejemplo n.º 1
0
 public SdsReader()
 {
     this.FileStream  = null;
     this.DataStream  = null;
     this.BlockStream = null;
     this.hashList    = null;
 }
Ejemplo n.º 2
0
        private void Initialize(Stream input)
        {
            Stream data = input;

            hashList = new Hashes.M3HashList();
            hashList.Initialize();

            // little endian?
            bool littleEndian;

            {
                data.Seek(8, SeekOrigin.Begin);
                var platform = data.ReadString(4, true, Encoding.ASCII);

                littleEndian = platform == "PC";
            }

            // header
            data.Seek(0, SeekOrigin.Begin);
            {
                var memory = data.ReadToMemoryStreamSafe(
                    12, littleEndian);
                var magic    = memory.ReadString(4, true, Encoding.ASCII);
                var version  = memory.ReadValueU32(littleEndian);
                var platform = memory.ReadString(4, true, Encoding.ASCII);

                if (magic != "SDS")
                {
                    throw new FormatException("not an SDS archive");
                }

                if (version != 20 && version != 19)
                {
                    throw new FormatException("unsupported SDS archive version");
                }

                this.Platform = platform;
            }

            data.Seek(0, SeekOrigin.Begin);

            DataStorage.SDSFile file = new DataStorage.SDSFile();
            var mem = data; // data.ReadToMemoryStreamSafe(data.Length, littleEndian);

            file.Deserialize(mem, littleEndian);

            // Read resources count info
            file.resourceInfo.count = (int)data.ReadValueU32(littleEndian);

            // Read resources types
            file.resourceTypes = new DataStorage.SDSResourceType[file.resourceInfo.count];

            // Read resources info
            for (var i = 0; i < file.resourceInfo.count; ++i)
            {
                file.resourceTypes[i]           = new DataStorage.SDSResourceType();
                file.resourceTypes[i].typeIndex = (int)data.ReadValueU32(littleEndian);
                file.resourceTypes[i].strLen    = (int)data.ReadValueU32(littleEndian);
                file.resourceTypes[i].typeName  = new byte[file.resourceTypes[i].strLen];
                data.Read(file.resourceTypes[i].typeName, 0, file.resourceTypes[i].typeName.Length);
                var realTypename = Encoding.ASCII.GetString(file.resourceTypes[i].typeName);
                file.resourceTypes[i].parent = (int)data.ReadValueU32(littleEndian);

                var type = new DataStorage.ResourceTypeReference();
                type.Id   = (uint)file.resourceTypes[i].typeIndex;
                type.Name = realTypename;
                this.ResourceTypes.Add(type);
            }

            // Read chunk info
            file.chunkInfo.magic     = (int)data.ReadValueU32(littleEndian);
            file.chunkInfo.alignment = (int)data.ReadValueU32(littleEndian);

            var tmp = new byte[1];

            data.Read(tmp, 0, tmp.Length);
            file.chunkInfo.flags = (char)tmp[0];

            if (file.chunkInfo.magic != 0x6C7A4555 ||
                file.chunkInfo.alignment != 0x10000 && file.chunkInfo.alignment != 0x00004000 ||
                file.chunkInfo.flags != 4)
            {
                throw new InvalidOperationException();
            }

            // Read chunk data
            var  blockStream   = new BlockStream(data);
            long virtualOffset = 0;
            var  index         = 0;

            file.chunkData = new List <DataStorage.SDSChunk>();
            while (true)
            {
                var i     = index;
                var chunk = new DataStorage.SDSChunk();
                chunk.dataSize = (int)data.ReadValueU32(littleEndian);

                var tmp2 = new byte[1];
                data.Read(tmp2, 0, tmp2.Length);
                chunk.dataType = (char)tmp2[0];

                uint size       = (uint)chunk.dataSize;
                bool compressed = chunk.dataType != 0;
                if (size == 0)
                {
                    break;
                }

                if (compressed == true)
                {
                    var compressionInfo = new DataStorage.CompressedBlockHeader();
                    compressionInfo.Deserialize(data, littleEndian);

                    if (compressionInfo.Unknown04 != 32 ||
                        compressionInfo.Unknown08 != 65536 ||
                        compressionInfo.Unknown0C != 135200769)
                    {
                        throw new InvalidOperationException();
                    }

                    if (size - 32 != compressionInfo.CompressedSize)
                    {
                        throw new InvalidOperationException();
                    }

                    blockStream.AddCompressedBlock(
                        virtualOffset,
                        compressionInfo.UncompressedSize,
                        data.Position,
                        compressionInfo.CompressedSize);

                    data.Seek(compressionInfo.CompressedSize, SeekOrigin.Current);
                }
                else
                {
                    blockStream.AddUncompressedBlock(
                        virtualOffset,
                        size,
                        data.Position);

                    data.Seek(size, SeekOrigin.Current);
                }

                file.chunkData.Add(chunk);
                ++index;
                virtualOffset += file.chunkInfo.alignment;
            }

            // Read files
            blockStream.Seek(0, SeekOrigin.Begin);
            {
                this.Entries.Clear();
                for (uint i = 0; i < file.dataCount; i++)
                {
                    var position = blockStream.Position;
                    var memory   = blockStream.ReadToMemoryStreamSafe(36, littleEndian);

                    var fileHeader = new DataStorage.FileHeader();
                    fileHeader.Deserialize(memory, littleEndian);

                    var    Name        = memory.ReadValueU32(littleEndian);
                    string description = hashList.GetStringByHash(Name);
                    blockStream.Seek(blockStream.Position - 4, SeekOrigin.Begin);

                    if (fileHeader.TypeId == 0) // Flash/XML
                    {
                        var blockPosition = blockStream.Position;
                        var memoryName    = blockStream.ReadToMemoryStreamSafe(255, littleEndian);
                        memoryName.Seek(memoryName.Position + 2, SeekOrigin.Begin);

                        var Name_ = memoryName.ReadStringU16(littleEndian);
                        description = Name_;
                        blockStream.Seek(blockPosition, SeekOrigin.Begin);
                    }

                    if (fileHeader.TypeId == 1) // MemFile
                    {
                        var blockPosition = blockStream.Position;
                        var memoryName    = blockStream.ReadToMemoryStreamSafe(255, littleEndian);
                        memoryName.Seek(memoryName.Position + 6, SeekOrigin.Begin);

                        var Name_ = memoryName.ReadStringU32(littleEndian);
                        description = Name_;
                        blockStream.Seek(blockPosition, SeekOrigin.Begin);
                    }

                    this.Entries.Add(new Entry()
                    {
                        Header      = fileHeader,
                        Description = description,
                        Offset      = blockStream.Position,// Data offset
                        Size        = fileHeader.Size - 36,
                    });

                    blockStream.Seek(position + (fileHeader.Size), SeekOrigin.Begin);
                }
            }

            this.Header      = file;
            this.BlockStream = blockStream;

            this.DataStream = data;
            this.FileStream = input;

            this.BlockStream.FreeLoadedBlocks();
        }