Example #1
0
        public static void ExportFont(Stream stream, string outputFile)
        {
            var reader = new BINAReader(stream);

            reader.ReadHeader();

            var sig = reader.ReadSignature(8);

            if (sig != "KFCS1000")
            {
                throw new InvalidSignatureException("KFCS1000", sig);
            }

            var fontName = reader.GetString();

            reader.JumpAhead(4);
            reader.JumpAhead(0x10);
            var length = reader.ReadInt64();
            var fntSig = reader.ReadSignature();

            outputFile = fntSig == "OTTO" ? Path.ChangeExtension(outputFile, ".otf")
                : Path.ChangeExtension(outputFile, ".ttf");
            var data = reader.ReadBytes((int)length - 4);

            using (var fntStream = File.Create(outputFile))
            {
                fntStream.Write(Encoding.Default.GetBytes(fntSig), 0, 4);
                fntStream.Write(data, 0, data.Length);
            }
        }
        public override void Load(Stream fileStream)
        {
            // PACx Header
            var reader = new BINAReader(fileStream);

            Header.Read(reader);

            // Type Names
            var typeTree = ReadNodeTree(reader);
            var names    = new string[typeTree.Nodes.Count];

            for (int i = 0; i < typeTree.Nodes.Count; ++i)
            {
                var typeNode = typeTree.Nodes[i];
                if (typeNode.ChildCount < 1)
                {
                    continue;
                }

                int nameIndex = -1;
                if (typeNode.ChildIDTableOffset > 0)
                {
                    reader.JumpTo(typeNode.ChildIDTableOffset);
                    nameIndex = reader.ReadInt32();
                }

                if (typeNode.NameOffset > 0)
                {
                    reader.JumpTo(typeNode.NameOffset);
                    names[i] = reader.ReadNullTerminatedString();
                }
            }

            // Types
            foreach (var type in typeTree.Nodes)
            {
                if (!type.HasData)
                {
                    continue;
                }

                string name = string.Empty;
                var    n    = type;

                while (n.ParentIndex >= 0)
                {
                    name = $"{names[n.ParentIndex]}{name}";
                    n    = typeTree.Nodes[n.ParentIndex];
                }

                reader.JumpTo(type.DataOffset);
                var fileTree = ReadNodeTree(reader);

                // File Names
                var fileNames = new string[fileTree.Nodes.Count];
                for (int i = 0; i < fileTree.Nodes.Count; ++i)
                {
                    var fileNode = fileTree.Nodes[i];
                    if (fileNode.ChildCount < 1)
                    {
                        continue;
                    }

                    int nameIndex = -1;
                    if (fileNode.ChildIDTableOffset > 0)
                    {
                        reader.JumpTo(fileNode.ChildIDTableOffset);
                        nameIndex = reader.ReadInt32();
                    }

                    if (fileNode.NameOffset > 0)
                    {
                        reader.JumpTo(fileNode.NameOffset);
                        fileNames[i] = reader.ReadNullTerminatedString();
                    }
                }

                // File Nodes
                foreach (var file in fileTree.Nodes)
                {
                    if (!file.HasData)
                    {
                        continue;
                    }

                    name = string.Empty;
                    n    = file;

                    while (n.ParentIndex >= 0)
                    {
                        name = $"{fileNames[n.ParentIndex]}{name}";
                        n    = fileTree.Nodes[n.ParentIndex];
                    }

                    // File Entries
                    reader.JumpTo(file.DataOffset);
                    uint pacID = reader.ReadUInt32();
                    if (pacID != Header.ID)
                    {
                        Console.WriteLine(
                            $"WARNING: Skipped file {name} as its pac ID was missing");
                        continue;
                    }

                    ulong fileSize        = reader.ReadUInt64();
                    uint  padding1        = reader.ReadUInt32();
                    long  fileDataOffset  = reader.ReadInt64();
                    ulong padding2        = reader.ReadUInt64();
                    long  extensionOffset = reader.ReadInt64();
                    uint  pacType         = reader.ReadUInt32();
                    uint  padding3        = reader.ReadUInt32();

                    if (fileDataOffset <= 0 || pacType == 1)
                    {
                        continue;
                    }

                    // File Extension
                    reader.JumpTo(extensionOffset);
                    name += $".{reader.ReadNullTerminatedString()}";

                    // File Data
                    reader.JumpTo(fileDataOffset);
                    var data = reader.ReadBytes((int)fileSize);

                    // BINA Check
                    // TODO: Remove this check
                    if (data[0] == 0x42 && data[1] == 0x49 && data[2] == 0x4E && data[3] == 0x41)
                    {
                        if (pacType != 2)
                        {
                            Console.WriteLine(
                                $"WARNING: FileType ({pacType}) != 2 when file carries BINA Header!");
                        }
                    }
                    else
                    {
                        if (pacType == 2)
                        {
                            Console.WriteLine(
                                $"WARNING: FileType ({pacType}) == 2 when file has no BINA Header!");
                        }
                    }

                    Data.Add(new ArchiveFile(name, data));
                }
            }
        }
Example #3
0
        // Methods
        public override void Load(Stream fileStream,
                                  Dictionary <string, SetObjectType> objectTemplates)
        {
            // Header
            var reader = new BINAReader(fileStream);

            Header = reader.ReadHeader();

            //Set Name (hardcoded to ASSUME it's four characters long)
            long namePosition = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and parameters

            reader.JumpAhead(0xC);
            Name = reader.ReadNullTerminatedString();
            reader.JumpTo(namePosition, true);
            reader.JumpAhead(0x2C);

            uint objectCount       = reader.ReadUInt32();
            uint objectTableOffset = reader.ReadUInt32();
            uint groupCount        = reader.ReadUInt32();
            uint groupTableOffset  = reader.ReadUInt32();

            //Objects
            reader.JumpTo(objectTableOffset, false);
            for (uint i = 0; i < objectCount; i++)
            {
                var obj = new SetObject();
                obj.ObjectID = i;
                uint objectNameOffset = reader.ReadUInt32();
                uint objectTypeOffset = reader.ReadUInt32();
                obj.UnknownBytes       = reader.ReadBytes(16); //parameter.Unknown 16 bytes (pattern tends to be 40 00 00 00/01 (depending on whether object is activated by a group) 00 00 00 00 00 00 00 00 00 00 00 00)
                obj.Transform.Position = reader.ReadVector3();
                obj.DrawDistance       = reader.ReadSingle();
                obj.Transform.Rotation = reader.ReadQuaternion();
                uint parameterCount  = reader.ReadUInt32();
                uint parameterOffset = reader.ReadUInt32();

                long position = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and parameters

                //Object Name and Type
                reader.JumpTo(objectNameOffset, false);
                obj.ObjectName = reader.ReadNullTerminatedString();
                reader.JumpTo(objectTypeOffset, false);
                obj.ObjectType = reader.ReadNullTerminatedString();

                reader.JumpTo(parameterOffset, false);
                //Object Parameters
                for (uint c = 0; c < parameterCount; c++)
                {
                    var  parameter     = new SetObjectParam();
                    uint parameterType = reader.ReadUInt32();
                    switch (parameterType)
                    {
                    case 0:     //boolean
                        parameter.DataType = typeof(bool);
                        parameter.Data     = reader.ReadUInt32() == 1;
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    case 1:     //int
                        parameter.DataType = typeof(int);
                        parameter.Data     = reader.ReadInt32();
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    case 2:     //single
                        parameter.DataType = typeof(float);
                        parameter.Data     = reader.ReadSingle();
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    case 3:     //string
                        uint offset = reader.ReadUInt32();
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();

                        long stringParameterPosition = reader.BaseStream.Position;     //Save position so we can jump back after reading name, type and parameters
                        reader.JumpTo(offset, false);

                        parameter.DataType = typeof(string);
                        parameter.Data     = reader.ReadNullTerminatedString();

                        reader.JumpTo(stringParameterPosition, true);
                        break;

                    case 4:     //Vector3
                        parameter.DataType = typeof(Vector3);
                        parameter.Data     = reader.ReadVector3();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    case 6:     //uint
                        parameter.DataType = typeof(uint);
                        parameter.Data     = reader.ReadUInt32();
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    default:
                        Console.WriteLine("Unhandled Data Type!");
                        break;
                    }
                    obj.Parameters.Add(parameter);
                }

                //Save Object and jump back for the next one
                Objects.Add(obj);
                reader.JumpTo(position, true);
            }

            //Groups
            reader.JumpTo(groupTableOffset, false);
            for (uint i = 0; i < groupCount; i++)
            {
                var  group           = new SetGroup();
                uint groupNameOffset = reader.ReadUInt32();
                uint groupTypeOffset = reader.ReadUInt32();
                group.GroupObjectCount = reader.ReadUInt32();
                uint groupObjectListOffset = reader.ReadUInt32();

                long position = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and object list

                //Group Name and Type
                reader.JumpTo(groupNameOffset, false);
                group.GroupName = reader.ReadNullTerminatedString();
                reader.JumpTo(groupTypeOffset, false);
                group.GroupType = reader.ReadNullTerminatedString();

                //Group Object List
                reader.JumpTo(groupObjectListOffset, false);
                for (uint c = 0; c < group.GroupObjectCount; c++)
                {
                    reader.JumpAhead(4);
                    group.ObjectIDs.Add(reader.ReadUInt32());
                }

                //Save Group and jump back for the next one
                Groups.Add(group);
                reader.JumpTo(position, true);
            }
        }
        protected SetObject ReadObject(BINAReader reader,
                                       Dictionary <string, SetObjectType> objectTemplates)
        {
            var   obj           = new SetObject();
            ulong padding1      = reader.ReadUInt64();
            long  objTypeOffset = reader.ReadInt64();
            long  objNameOffset = reader.ReadInt64();

            ushort id            = reader.ReadUInt16();
            ushort groupID       = reader.ReadUInt16();
            ushort parentID      = reader.ReadUInt16();
            ushort parentGroupID = reader.ReadUInt16();

            obj.CustomData.Add("ParentID", new SetObjectParam(
                                   typeof(ushort), parentID));
            obj.CustomData.Add("ParentGroupID", new SetObjectParam(
                                   typeof(ushort), parentGroupID));

            obj.ObjectID = id;
            obj.CustomData.Add("GroupID", new SetObjectParam(
                                   typeof(ushort), groupID));

            var pos            = reader.ReadVector3();
            var rot            = reader.ReadVector3();
            var childPosOffset = reader.ReadVector3();
            var childRotOffset = reader.ReadVector3();

            obj.CustomData.Add("ChildPosOffset", new SetObjectParam(
                                   typeof(Vector3), childPosOffset));

            obj.CustomData.Add("ChildRotOffset", new SetObjectParam(
                                   typeof(Vector3), childRotOffset));

            obj.Transform.Position = pos;
            obj.Transform.Rotation = new Quaternion(rot, true);

            long  extraParamsOffset = reader.ReadInt64();
            ulong unknownCount1     = reader.ReadUInt64();
            ulong unknownCount2     = reader.ReadUInt64();
            ulong padding3          = reader.ReadUInt64();

            long objParamsOffset = reader.ReadInt64();

            // Unknown Count Checks
            if (unknownCount1 != unknownCount2)
            {
                Console.WriteLine(
                    "WARNING: UnknownCount1 ({0}) != UnknownCount2 ({1})",
                    unknownCount1, unknownCount2);
            }

            if (unknownCount1 > 1)
            {
                Console.WriteLine(
                    "WARNING: UnknownCount1 > 1 ({0})",
                    unknownCount1);
            }

            // Extra Parameter Offsets
            var extraParamOffsets = new long[unknownCount1];

            reader.JumpTo(extraParamsOffset, false);

            for (uint i = 0; i < unknownCount1; ++i)
            {
                extraParamOffsets[i] = reader.ReadInt64();
                ulong padding5 = reader.ReadUInt64(); // TODO: Make sure this is correct
            }

            // Extra Parameters
            for (uint i = 0; i < unknownCount1; ++i)
            {
                reader.JumpTo(extraParamOffsets[i], false);
                ulong padding6 = reader.ReadUInt64();

                long  extraParamNameOffset = reader.ReadInt64();
                ulong extraParamLength     = reader.ReadUInt64();
                long  extraParamDataOffset = reader.ReadInt64();

                // Extra Parameter Data
                reader.JumpTo(extraParamDataOffset, false);
                var data = reader.ReadBytes((int)extraParamLength);

                // Extra Parameter Name
                reader.JumpTo(extraParamNameOffset, false);
                string name = reader.ReadNullTerminatedString();

                // Parse Data
                switch (name)
                {
                case "RangeSpawning":
                {
                    obj.CustomData.Add("RangeIn", new SetObjectParam(
                                           typeof(float), BitConverter.ToSingle(data, 0)));

                    obj.CustomData.Add("RangeOut", new SetObjectParam(
                                           typeof(float), BitConverter.ToSingle(data, 4)));
                    continue;
                }
                }

                Console.WriteLine($"WARNING: Unknown extra parameter type {name}");
                obj.CustomData.Add(name, new SetObjectParam(
                                       data.GetType(), data));
            }

            // Object Name
            reader.JumpTo(objNameOffset, false);
            string objName = reader.ReadNullTerminatedString();

            obj.CustomData.Add("Name", new SetObjectParam(typeof(string), objName));

            // Object Type
            reader.JumpTo(objTypeOffset, false);
            string objType = reader.ReadNullTerminatedString();

            obj.ObjectType = objType;

            if (!objectTemplates.ContainsKey(objType))
            {
                Console.WriteLine(
                    "WARNING: Skipped {0} because there is no template for type {1}!",
                    objName, objType);
                Console.WriteLine("Params at: {0:X}",
                                  objParamsOffset + reader.Offset);
                return(null);
            }

            //Console.WriteLine("\"{1}\" Params at: {0:X}",
            //    objParamsOffset + reader.Offset, objName);
            var template = objectTemplates[objType];

            // Object Parameters
            reader.JumpTo(objParamsOffset, false);
            foreach (var param in template.Parameters)
            {
                obj.Parameters.Add(ReadParameter(reader, param));
            }

            // Additional Padding
            var rawDataLenExtra = template.GetExtra("RawByteLength");

            if (uint.TryParse(rawDataLenExtra?.Value, out var rawLength))
            {
                uint paramLen = (uint)(reader.BaseStream.Position -
                                       objParamsOffset - reader.Offset);

                if (paramLen != rawLength)
                {
                    obj.CustomData.Add("RawByteLength", new SetObjectParam(
                                           typeof(uint), rawLength));
                }
            }

            // Padding Checks
            if (padding1 != 0)
            {
                Console.WriteLine($"WARNING: Obj Padding1 != 0 ({padding1})");
            }

            if (padding3 != 0)
            {
                Console.WriteLine($"WARNING: Obj Padding3 != 0 ({padding3})");
            }

            return(obj);
        }