Exemple #1
0
        public static SdsFile FromFile(string sdsPath)
        {
            SdsFile file = new SdsFile();

            file.Path   = System.IO.Path.GetFullPath(sdsPath);
            file.Header = SdsHeader.FromFile(sdsPath);

            using (FileStream fileStream = new FileStream(sdsPath, FileMode.Open, FileAccess.Read))
            {
                fileStream.Seek(file.Header.ResourceTypeTableOffset, SeekOrigin.Begin);
                uint numberOfResources = fileStream.ReadUInt32();
                for (int i = 0; i < numberOfResources; i++)
                {
                    ResourceType resourceType = new ResourceType();
                    resourceType.Id = fileStream.ReadUInt32();
                    uint   resourceLenght = fileStream.ReadUInt32();
                    string typeStr        = fileStream.ReadString((int)resourceLenght).Replace(" ", "");
                    resourceType.Name = (EResourceType)Enum.Parse(typeof(EResourceType), typeStr);
                    uint unknown32 = fileStream.ReadUInt32();
                    if (unknown32 != resourceType.Unknown32)
                    {
                        throw new InvalidDataException(unknown32.ToString());
                    }
                    file.AddResourceType(resourceType);
                }

                fileStream.Seek(file.Header.BlockTableOffset, SeekOrigin.Begin);

                #region Version 19

                if (file.Header.Version == 19U)
                {
                    if (fileStream.ReadUInt32() != UEzl)
                    {
                        throw new Exception("Invalid SDS file!");
                    }

                    fileStream.Seek(5, SeekOrigin.Current);

                    using (MemoryStream decompressedData = new MemoryStream())
                    {
                        while (true)
                        {
                            uint           blockSize = fileStream.ReadUInt32();
                            EDataBlockType blockType = (EDataBlockType)fileStream.ReadUInt8();

                            if (blockSize == 0U)
                            {
                                break;
                            }

                            if (blockType == EDataBlockType.Compressed)
                            {
                                fileStream.Seek(16, SeekOrigin.Current);
                                uint compressedBlockSize = fileStream.ReadUInt32();

                                if (blockSize - 32U != compressedBlockSize)
                                {
                                    throw new Exception("Invalid block!");
                                }

                                fileStream.Seek(12, SeekOrigin.Current);
                                byte[] compressedBlock = new byte[compressedBlockSize];
                                fileStream.Read(compressedBlock, 0, compressedBlock.Length);

                                ZOutputStream decompressStream = new ZOutputStream(decompressedData);
                                decompressStream.Write(compressedBlock, 0, compressedBlock.Length);
                                decompressStream.finish();
                            }

                            else if (blockType == EDataBlockType.Uncompressed)
                            {
                                byte[] decompressedBlock = new byte[blockSize];
                                fileStream.Read(decompressedBlock, 0, decompressedBlock.Length);
                                decompressedData.Write(decompressedBlock, 0, decompressedBlock.Length);
                            }

                            else
                            {
                                throw new Exception("Invalid block type!");
                            }
                        }

                        decompressedData.SeekToStart();

                        fileStream.Seek(file.Header.XmlOffset, SeekOrigin.Begin);
                        byte[] xmlBytes = fileStream.ReadBytes((int)fileStream.Length - (int)fileStream.Position);
                        using (MemoryStream memoryStream = new MemoryStream(xmlBytes))
                            using (XmlReader xmlReader = XmlReader.Create(memoryStream))
                            {
                                ResourceInfo resourceInfo = new ResourceInfo();

                                List <Type> resourceTypes = new List <Type>();
                                foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
                                {
                                    if (type.BaseType == typeof(Resource))
                                    {
                                        resourceTypes.Add(type);
                                    }
                                }

                                while (xmlReader.Read())
                                {
                                    if (xmlReader.NodeType == XmlNodeType.Element)
                                    {
                                        if (xmlReader.Name == "TypeName")
                                        {
                                            resourceInfo = new ResourceInfo();
                                            var resourceType = (EResourceType)Enum.Parse(typeof(EResourceType), xmlReader.ReadElementContentAsString());
                                            resourceInfo.Type = file._resourceTypes.First(x => x.Name == resourceType);
                                        }

                                        else if (xmlReader.Name == "SourceDataDescription")
                                        {
                                            resourceInfo.SourceDataDescription = xmlReader.ReadElementContentAsString();

                                            uint resId = decompressedData.ReadUInt32();
                                            if (resId != resourceInfo.Type.Id)
                                            {
                                                throw new InvalidDataException();
                                            }

                                            uint   size              = decompressedData.ReadUInt32();
                                            ushort version           = decompressedData.ReadUInt16();
                                            uint   slotRamRequired   = decompressedData.ReadUInt32();
                                            uint   slotVRamRequired  = decompressedData.ReadUInt32();
                                            uint   otherRamRequired  = decompressedData.ReadUInt32();
                                            uint   otherVRamRequired = decompressedData.ReadUInt32();
                                            uint   checksum          = decompressedData.ReadUInt32();
                                            byte[] rawData           = decompressedData.ReadBytes((int)size - Resource.StandardHeaderSizeV19);

                                            var targetType        = resourceTypes.First(x => x.Name == resourceInfo.Type.ToString());
                                            var deserializeMethod = targetType.GetMethod(nameof(Resource.Deserialize));
                                            var resourecInstance  = (Resource)deserializeMethod.Invoke(null, new object[] {
                                                resourceInfo, version, slotRamRequired, slotVRamRequired, otherRamRequired, otherVRamRequired, null, rawData, file._mapper
                                            });
                                            file._resources.Add(resourecInstance);
                                        }
                                    }
                                }
                            }
                    }
                }

                #endregion

                #region Version 20

                else if (file.Header.Version == 20U)
                {
                    if (fileStream.ReadUInt32() != UEzl)
                    {
                        throw new Exception("Invalid SDS file!");
                    }

                    fileStream.Seek(5, SeekOrigin.Current);

                    using (MemoryStream decompressedData = new MemoryStream())
                    {
                        while (true)
                        {
                            uint           blockSize = fileStream.ReadUInt32();
                            EDataBlockType blockType = (EDataBlockType)fileStream.ReadUInt8();

                            if (blockSize == 0U)
                            {
                                break;
                            }

                            if (blockType == EDataBlockType.Compressed)
                            {
                                uint uncompressedSize = fileStream.ReadUInt32();
                                fileStream.Seek(12, SeekOrigin.Current);
                                uint compressedBlockSize = fileStream.ReadUInt32();

                                if (blockSize - 128U != compressedBlockSize)
                                {
                                    throw new Exception("Invalid block!");
                                }

                                fileStream.Seek(108, SeekOrigin.Current);
                                byte[] compressedBlock = new byte[compressedBlockSize];
                                fileStream.Read(compressedBlock, 0, compressedBlock.Length);
                                byte[] decompressed = Oodle.Decompress(compressedBlock, compressedBlock.Length, (int)uncompressedSize);
                                decompressedData.Write(decompressed);
                            }

                            else if (blockType == EDataBlockType.Uncompressed)
                            {
                                byte[] decompressedBlock = new byte[blockSize];
                                fileStream.Read(decompressedBlock, 0, decompressedBlock.Length);
                                decompressedData.Write(decompressedBlock, 0, decompressedBlock.Length);
                            }

                            else
                            {
                                throw new Exception("Invalid block type!");
                            }
                        }

                        List <Type> resourceTypes = new List <Type>();
                        foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
                        {
                            if (type.BaseType == typeof(Resource))
                            {
                                resourceTypes.Add(type);
                            }
                        }

                        decompressedData.SeekToStart();
                        while (decompressedData.Position != decompressedData.Length)
                        {
                            uint resId = decompressedData.ReadUInt32();

                            ResourceInfo resourceInfo = new ResourceInfo();
                            resourceInfo.Type = file._resourceTypes.First(x => x.Id == resId);

                            uint   size              = decompressedData.ReadUInt32();
                            ushort version           = decompressedData.ReadUInt16();
                            ulong  nameHash          = decompressedData.ReadUInt64();
                            uint   slotRamRequired   = decompressedData.ReadUInt32();
                            uint   slotVRamRequired  = decompressedData.ReadUInt32();
                            uint   otherRamRequired  = decompressedData.ReadUInt32();
                            uint   otherVRamRequired = decompressedData.ReadUInt32();
                            uint   checksum          = decompressedData.ReadUInt32();
                            byte[] rawData           = decompressedData.ReadBytes((int)size - Resource.StandardHeaderSizeV20);

                            var targetType        = resourceTypes.First(x => x.Name == resourceInfo.Type.ToString());
                            var deserializeMethod = targetType.GetMethod(nameof(Resource.Deserialize));
                            var resourceInstance  = (Resource)deserializeMethod.Invoke(null, new object[] {
                                resourceInfo, version, slotRamRequired, slotVRamRequired, otherRamRequired, otherVRamRequired, nameHash, rawData, file._mapper
                            });
                            file._resources.Add(resourceInstance);
                        }
                    }
                }

                #endregion
            }

            return(file);
        }