Пример #1
0
        public static byte[] pack(Dictionary <string, byte[]> files)
        {
            MemoryStream     o  = new MemoryStream();
            BinaryDataWriter bw = new BinaryDataWriter(o, false);

            bw.ByteOrder = ByteOrder.BigEndian;
            bw.Write("SARC", BinaryStringFormat.NoPrefixOrTermination);
            bw.Write((UInt16)0x14);   // Chunk length
            bw.Write((UInt16)0xFEFF); // BOM
            bw.Write((UInt32)0x00);   //filesize update later
            bw.Write((UInt32)0x00);   //Beginning of data
            bw.Write((UInt32)0x01000000);
            bw.Write("SFAT", BinaryStringFormat.NoPrefixOrTermination);
            bw.Write((UInt16)0xc);
            bw.Write((UInt16)files.Keys.Count);
            bw.Write((UInt32)0x00000065);
            List <uint> offsetToUpdate = new List <uint>();

            foreach (string k in files.Keys)
            {
                bw.Write(NameHash(k));
                bw.Write((byte)0x1);
                bw.Write((byte)0); //this should be part of the name index, but u16 will work too
                offsetToUpdate.Add((uint)bw.BaseStream.Position);
                bw.Write((UInt16)0);
                bw.Write((UInt32)0);
                bw.Write((UInt32)0);
            }
            bw.Write("SFNT", BinaryStringFormat.NoPrefixOrTermination);
            bw.Write((UInt16)0x8);
            bw.Write((UInt16)0);
            List <uint> StringOffsets = new List <uint>();

            foreach (string k in files.Keys)
            {
                StringOffsets.Add((uint)bw.BaseStream.Position);
                bw.Write(k, BinaryStringFormat.ZeroTerminated);
                bw.Align(4);
            }
            List <uint> FileOffsets = new List <uint>();

            foreach (string k in files.Keys)
            {
                FileOffsets.Add((uint)bw.BaseStream.Position);
                bw.Write(files[k]);
                bw.Align(4);
            }
            for (int i = 0; i < offsetToUpdate.Count; i++)
            {
                bw.BaseStream.Position = offsetToUpdate[i];
                bw.Write((UInt16)((StringOffsets[i] - StringOffsets[0]) / 4));
                bw.Write((UInt32)(FileOffsets[i] - FileOffsets[0]));
                bw.Write((UInt32)(FileOffsets[i] + files.Values.ToArray()[i].Length - FileOffsets[0]));
            }
            bw.BaseStream.Position = 0x08;
            bw.Write((uint)bw.BaseStream.Length);
            bw.Write((uint)FileOffsets[0]);
            return(o.ToArray());
        }
Пример #2
0
        private void WriteValueContents(BinaryDataWriter writer, Offset offset, ByamlNodeType type, dynamic value)
        {
            if (alreadyWrittenNodes.ContainsKey(value))
            {
                offset.Satisfy((int)alreadyWrittenNodes[value]);
                return;
            }
            // Satisfy the offset to the complex node value which must be 4-byte aligned.
            writer.Align(4);
            offset.Satisfy();

            // Write the value contents.
            switch (type)
            {
                case ByamlNodeType.Dictionary:
                    alreadyWrittenNodes.Add(value, (uint)writer.Position);
                    WriteDictionaryNode(writer, value);
                    break;
                case ByamlNodeType.StringArray:
                    WriteStringArrayNode(writer, value);
                    break;
                case ByamlNodeType.PathArray:
                    alreadyWrittenNodes.Add(value, (uint)writer.Position);
                    WritePathArrayNode(writer, value);
                    break;
                case ByamlNodeType.Array:
                    alreadyWrittenNodes.Add(value, (uint)writer.Position);
                    WriteArrayNode(writer, value);
                    break;
                default:
                    throw new ByamlException($"{type} not supported as complex node.");
            }
        }
Пример #3
0
        private void WritePathArray(BinaryDataWriter writer, Offset offset, IList <List <ByamlPathPoint> > pathArray)
        {
            // Satisfy the offset to the value in the BYAML file which must be 4-byte aligned.
            writer.Align(4);
            offset.Satisfy();

            WriteTypeAndElementCount(writer, ByamlNodeType.PathArray, pathArray.Count);

            // Write the offsets to the paths.
            int pathOffset = 4 + 4 * (pathArray.Count + 1); // Relative to node start + all uint32 offsets.

            foreach (List <ByamlPathPoint> path in pathArray)
            {
                writer.Write(pathOffset);
                pathOffset += path.Count * ByamlPathPoint.SizeInBytes;
            }
            writer.Write(pathOffset); // The last one points to the end of the last path.

            // Write the paths.
            foreach (List <ByamlPathPoint> path in pathArray)
            {
                foreach (ByamlPathPoint point in path)
                {
                    writer.Write(point.Position);
                    writer.Write(point.Normal);
                    writer.Write(point.Unknown);
                }
            }
        }
Пример #4
0
        private void WriteValueContents(BinaryDataWriter writer, Offset offset, ByamlNodeType type, dynamic value)
        {
            // Satisfy the offset to the complex node value which must be 4-byte aligned.
            writer.Align(4);
            offset.Satisfy();

            // Write the value contents.
            switch (type)
            {
            case ByamlNodeType.Dictionary:
                WriteDictionaryNode(writer, value);
                break;

            case ByamlNodeType.StringArray:
                WriteStringArrayNode(writer, value);
                break;

            case ByamlNodeType.PathArray:
                WritePathArrayNode(writer, value);
                break;

            case ByamlNodeType.Array:
                WriteArrayNode(writer, value);
                break;

            default:
                throw new ByamlException($"{type} not supported as complex node.");
            }
        }
Пример #5
0
        private void WriteStringArrayNode(BinaryDataWriter writer, IEnumerable <string> node)
        {
            uint NodeStartPos = (uint)writer.BaseStream.Position;

            WriteTypeAndLength(writer, ByamlNodeType.StringArray, node);

            for (int i = 0; i <= node.Count(); i++)
            {
                writer.Write(new byte[4]);                                     //Space for offsets
            }
            List <uint> offsets = new List <uint>();

            foreach (string str in node)
            {
                offsets.Add((uint)writer.BaseStream.Position - NodeStartPos);
                writer.Write(str, BinaryStringFormat.ZeroTerminated);
            }
            offsets.Add((uint)writer.BaseStream.Position - NodeStartPos);
            writer.Align(4);
            uint backHere = (uint)writer.BaseStream.Position;

            writer.BaseStream.Position = NodeStartPos + 4;
            foreach (uint off in offsets)
            {
                writer.Write(off);
            }
            writer.BaseStream.Position = backHere;
        }
Пример #6
0
        private void WriteArrayNode(BinaryDataWriter writer, IEnumerable node)
        {
            WriteTypeAndLength(writer, ByamlNodeType.Array, node);

            // Write the element types.
            foreach (dynamic element in node)
            {
                writer.Write((byte)GetNodeType(element));
            }

            // Write the elements, which begin after a padding to the next 4 bytes.
            writer.Align(4);
            Dictionary <Offset, dynamic> offsets = new Dictionary <Offset, dynamic>();

            foreach (dynamic element in node)
            {
                var off = WriteValue(writer, element);
                if (off != null)
                {
                    offsets.Add(off, element);
                }
            }

            // Write the contents of complex nodes and satisfy the offsets.
            foreach (var element in offsets)
            {
                WriteValueContents(writer, element.Key, GetNodeType(element.Value), element.Value);
            }
        }
Пример #7
0
        private void WriteArrayOrDictionary(BinaryDataWriter writer, Offset offset, object obj)
        {
            // Satisfy the offset to the value in the BYAML file which must be 4-byte aligned.
            writer.Align(4);
            offset.Satisfy();

            // Serialize the value as an array.
            IList objArray = obj as IList;

            if (objArray != null)
            {
                WriteArray(writer, objArray);
                return;
            }

            // Serialize the value as a custom type.
            Type objType = obj.GetType();

            if (IsTypeByamlObject(objType))
            {
                WriteDictionary(writer, obj);
                return;
            }

            throw new ByamlException($"Type {objType.Name} is not supported as BYAML array or dictionary data.");
        }
Пример #8
0
        private void WriteArrayNode(BinaryDataWriter writer, IEnumerable node)
        {
            WriteTypeAndLength(writer, ByamlNodeType.Array, node);

            // Write the element types.
            foreach (dynamic element in node)
            {
                writer.Write((byte)GetNodeType(element));
            }

            // Write the elements, which begin after a padding to the next 4 bytes.
            writer.Align(4);
            List <Offset> offsets = new List <Offset>();

            foreach (dynamic element in node)
            {
                offsets.Add(WriteValue(writer, element));
            }

            // Write the contents of complex nodes and satisfy the offsets.
            int index = 0;

            foreach (dynamic element in node)
            {
                Offset offset = offsets[index];
                if (offset != null)
                {
                    WriteValueContents(writer, offset, GetNodeType(element), element);
                }
                index++;
            }
        }
Пример #9
0
        public byte[] Write()
        {
            var mem = new MemoryStream();
            BinaryDataWriter bin = new BinaryDataWriter(mem);

            bin.ByteOrder = ByteOrder.LittleEndian;
            bin.Write(Head);
            List <long> TexPositions = new List <long>();

            foreach (var t in Textures)
            {
                TexPositions.Add(bin.BaseStream.Position);
                bin.Write(t.Write());
            }
            var         DataStart        = bin.BaseStream.Position;
            List <long> TexDataPositions = new List <long>();

            bin.Align(0x10);
            bin.Write("BRTD", BinaryStringFormat.NoPrefixOrTermination);
            bin.Write((int)0);
            bin.Write((int)0);
            bin.Write((int)0);
            foreach (var t in Textures)
            {
                TexDataPositions.Add(bin.BaseStream.Position);
                bin.Write(t.Data);
                bin.Align(0x10);
            }
            bin.Align(0x1000);
            UInt32 rltPos = (UInt32)bin.BaseStream.Position;

            bin.Write(Rlt);
            //Update offsets
            bin.BaseStream.Position = 0x18;
            bin.Write((UInt32)rltPos);
            bin.Write((UInt32)bin.BaseStream.Length);
            bin.BaseStream.Position = TexDataPositions[0] - 8;
            bin.Write(rltPos - (TexDataPositions[0] - 0x10));
            for (int i = 0; i < TexPositions.Count; i++)
            {
                bin.BaseStream.Position = TexPositions[i] + 0x2A0;
                bin.Write(TexDataPositions[i]);
            }
            bin.BaseStream.Position = rltPos + 4;
            bin.Write(rltPos);
            return(mem.ToArray());
        }
Пример #10
0
        void ApplyChanges()
        {
            MemoryStream     mem = new MemoryStream();
            BinaryDataWriter bin = new BinaryDataWriter(mem);

            bin.Write((ushort)(Properties.Count + AddedProperties.Count));
            bin.Write((ushort)0);
            bin.Write(new byte[0xC * AddedProperties.Count]);
            bin.Write(data, 4, data.Length - 4);           //write rest of entries, adding new elements first doesn't break relative offets in the struct
            foreach (var m in Properties)
            {
                if ((byte)m.type != 1 && (byte)m.type != 2)
                {
                    continue;
                }
                bin.Position = m.ValueOffset + 0xC * AddedProperties.Count;
                for (int i = 0; i < m.ValueCount; i++)
                {
                    if (m.type == EditableProperty.ValueType.int32)
                    {
                        bin.Write(int.Parse(m.value[i]));
                    }
                    else
                    {
                        bin.Write(float.Parse(m.value[i]));
                    }
                }
            }
            for (int i = 0; i < AddedProperties.Count; i++)
            {
                bin.Position = bin.BaseStream.Length;
                uint DataOffset = (uint)bin.BaseStream.Position;
                for (int j = 0; j < AddedProperties[i].ValueCount; j++)
                {
                    if (AddedProperties[i].type == EditableProperty.ValueType.int32)
                    {
                        bin.Write(int.Parse(AddedProperties[i].value[j]));
                    }
                    else
                    {
                        bin.Write(float.Parse(AddedProperties[i].value[j]));
                    }
                }
                uint NameOffest = (uint)bin.BaseStream.Position;
                bin.Write(AddedProperties[i].Name, BinaryStringFormat.ZeroTerminated);
                bin.Align(4);
                uint entryStart = (uint)(4 + i * 0xC);
                bin.BaseStream.Position = entryStart;
                bin.Write(NameOffest - entryStart);
                bin.Write(DataOffset - entryStart);
                bin.Write(AddedProperties[i].ValueCount);
                bin.Write((byte)AddedProperties[i].type);
                bin.Write((byte)0);
            }
            data = mem.ToArray();
        }
Пример #11
0
        static void WriteModel(BinaryDataWriter er, KCLModel mod)
        {
            long HeaderPos = er.BaseStream.Position;

            mod.Header.Write(er);
            long curpos = er.BaseStream.Position;

            //Write vertices array position
            er.BaseStream.Position = HeaderPos;
            er.Write((uint)(curpos - HeaderPos));
            er.BaseStream.Position = curpos;
            foreach (Vector3D v in mod.Vertices)
            {
                er.Write(v);
            }
            er.Align(4);
            curpos = er.BaseStream.Position;
            //Write normal array position
            er.BaseStream.Position = HeaderPos + 4;
            er.Write((uint)(curpos - HeaderPos));
            er.BaseStream.Position = curpos;
            foreach (Vector3D v in mod.Normals)
            {
                er.Write(v);
            }
            er.Align(4);
            curpos = er.BaseStream.Position;
            //Write Triangles offset
            er.BaseStream.Position = HeaderPos + 8;
            er.Write((uint)(curpos - HeaderPos));
            er.BaseStream.Position = curpos;

            foreach (KCLModel.KCLPlane p in mod.Planes)
            {
                p.Write(er);
            }
            curpos = er.BaseStream.Position;
            //Write Spatial index offset
            er.BaseStream.Position = HeaderPos + 12;
            er.Write((uint)(curpos - HeaderPos));
            er.BaseStream.Position = curpos;
            mod.Octree.Write(er);
        }
Пример #12
0
        private void WriteValueContents(BinaryDataWriter writer, Offset offset, ByamlNodeType type, dynamic value)
        {
            if (alreadyWrittenNodes.ContainsKey(value))
            {
                offset.Satisfy((int)alreadyWrittenNodes[value]);
                return;
            }
            else if (value is IEnumerable)
            {
                foreach (var d in alreadyWrittenNodes.Keys.Where(x => x is IEnumerable && x.Count == value.Count))
                {
                    if (IEnumerableCompare.IsEqual(d, value))
                    {
                        offset.Satisfy((int)alreadyWrittenNodes[d]);
                        return;
                    }
                }
            }

            // Satisfy the offset to the complex node value which must be 4-byte aligned.
            writer.Align(4);
            offset.Satisfy();

            // Write the value contents.
            switch (type)
            {
            case ByamlNodeType.Dictionary:
                alreadyWrittenNodes.Add(value, (uint)writer.Position);
                WriteDictionaryNode(writer, value);
                break;

            case ByamlNodeType.StringArray:
                WriteStringArrayNode(writer, value);
                break;

            case ByamlNodeType.PathArray:
                alreadyWrittenNodes.Add(value, (uint)writer.Position);
                WritePathArrayNode(writer, value);
                break;

            case ByamlNodeType.Array:
                alreadyWrittenNodes.Add(value, (uint)writer.Position);
                WriteArrayNode(writer, value);
                break;

            case ByamlNodeType.Double:
            case ByamlNodeType.ULong:
            case ByamlNodeType.Long:
                writer.Write(value);
                break;

            default:
                throw new ByamlException($"{type} not supported as complex node.");
            }
        }
Пример #13
0
            public static void WriteArray(ByamlContext ctx, ByamlEntry entry, BinaryDataWriter bw)
            {
                var list = (List <ByamlEntry>)entry.Value;

                bw.Write((byte)entry.NodeType);
                bw.WriteInt24(list.Count);

                List <long> tempOffs = new List <long>();

                //node types
                foreach (var item in list)
                {
                    bw.Write((byte)item.NodeType);
                }

                bw.Align(4);

                //values
                foreach (var item in list)
                {
                    if (NodeIsValue(item.NodeType))
                    {
                        WriteValue(ctx, item, bw);
                    }
                    else
                    {
                        tempOffs.Add(bw.Position);
                        bw.Write(0); //temp
                    }
                }

                //array/dictionary
                int index = 0;

                foreach (var item in list)
                {
                    if (!NodeIsValue(item.NodeType))
                    {
                        long curPos = bw.Position;
                        using (bw.TemporarySeek(tempOffs[index++], SeekOrigin.Begin))
                            bw.Write((int)curPos);

                        if (item.NodeType == ByamlNodeType.Array)
                        {
                            WriteArray(ctx, item, bw);
                        }
                        else if (item.NodeType == ByamlNodeType.Dictionary)
                        {
                            WriteDictionary(ctx, item, bw);
                        }
                    }
                }
            }
Пример #14
0
        private void WritePathArrayNode(BinaryDataWriter writer, IEnumerable<List<ByamlPathPoint>> node)
        {
            writer.Align(4);
            WriteTypeAndLength(writer, ByamlNodeType.PathArray, node);

            // Write the offsets to the paths, where the last one points to the end of the last path.
            long offset = 4 + 4 * (node.Count() + 1); // Relative to node start + all uint32 offsets.
            foreach (List<ByamlPathPoint> path in node)
            {
                writer.Write((uint)offset);
                offset += path.Count * 28; // 28 bytes are required for a single point.
            }
            writer.Write((uint)offset);

            // Write the paths.
            foreach (List<ByamlPathPoint> path in node)
            {
                WritePathNode(writer, path);
            }
        }
        /// <summary>
        /// Saves the data into the given <paramref name="stream"/>.
        /// </summary>
        /// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
        public void Save(Stream stream)
        {
            using (BinaryDataWriter writer = new BinaryDataWriter(stream, Encoding.ASCII, true))
            {
                writer.ByteOrder = ByteOrder;

                // Write the file header.
                writer.Write(Identifier, BinaryStringFormat.NoPrefixOrTermination);
                Offset fileSizeOffset = writer.ReserveOffset();
                writer.Write((short)Count);
                writer.Write(Unknown);
                writer.Write(Version);
                Offset[] sectionOffsets = writer.ReserveOffset(Count);
                int      headerLength   = (int)writer.Position;

                // Write all the sections.
                int sectionIndex = 0;
                foreach (SectionBase section in this)
                {
                    // Fill in the offset to this section.
                    sectionOffsets[sectionIndex].Satisfy((int)writer.Position - headerLength);

                    // Write the section header.
                    writer.Write(section.Name, BinaryStringFormat.NoPrefixOrTermination);
                    writer.Write(section.ElementCount);
                    writer.Write((short)section.Count);
                    writer.Write(section.SectionType, false);

                    // Write the section groups, each of them is 4-byte aligned.
                    foreach (GroupBase group in section)
                    {
                        group.Save(writer);
                        writer.Align(4);
                    }

                    sectionIndex++;
                }

                fileSizeOffset.Satisfy();
            }
        }
Пример #16
0
        private void WriteV2(BinaryDataWriter writer)
        {
            writer.ByteOrder = ByteOrder.BigEndian;
            writer.Write((uint)Version);
            writer.ByteOrder = this.ByteOrder;

            Offset octreeOffset           = writer.ReserveOffset();
            Offset modelOffsetArrayOffset = writer.ReserveOffset();

            writer.Write(Models.Count);
            writer.Write(MinCoordinate);
            writer.Write(MaxCoordinate);
            writer.Write(CoordinateShift);
            writer.Write(PrismCount);

            // Write the model octree.
            octreeOffset.Satisfy();
            foreach (ModelOctreeNode rootChild in ModelOctreeRoot)
            {
                rootChild.Write(writer);
            }

            int branchKey = 8;

            foreach (ModelOctreeNode rootChild in ModelOctreeRoot)
            {
                rootChild.WriteChildren(writer, ref branchKey);
            }

            // Write the model offsets.
            modelOffsetArrayOffset.Satisfy();
            Offset[] modelOffsets = writer.ReserveOffset(Models.Count);

            // Write the models.
            for (int i = 0; i < Models.Count; i++)
            {
                modelOffsets[i].Satisfy();
                Models[i].Write(writer, Version);
                writer.Align(4);
            }
        }
Пример #17
0
        private void WriteStringArrayNode(BinaryDataWriter writer, IEnumerable <string> node)
        {
            writer.Align(4);
            WriteTypeAndLength(writer, ByamlNodeType.StringArray, node);

            // Write the offsets to the strings, where the last one points to the end of the last string.
            long offset = 4 + 4 * (node.Count() + 1); // Relative to node start + all uint32 offsets.

            foreach (string str in node)
            {
                writer.Write((uint)offset);
                offset += str.Length + 1;
            }
            writer.Write((uint)offset);

            // Write the 0-terminated strings.
            foreach (string str in node)
            {
                writer.Write(str, BinaryStringFormat.ZeroTerminated);
            }
        }
        /// <summary>
        /// Saves the data into the given <paramref name="stream"/>.
        /// </summary>
        /// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
        public void Save(Stream stream)
        {
            using (BinaryDataWriter writer = new BinaryDataWriter(stream, true)
            {
                ByteOrder = ByteOrder.BigEndian
            })
            {
                // Write the header.
                writer.Write(_signature);
                Offset octreeOffset           = writer.ReserveOffset();
                Offset modelOffsetArrayOffset = writer.ReserveOffset();
                writer.Write(Models.Count);
                writer.Write(MinCoordinate);
                writer.Write(MaxCoordinate);
                writer.Write(CoordinateShift);
                writer.Write(Unknown);

                // Write the model octree.
                octreeOffset.Satisfy();
                foreach (CourseOctreeNode rootChild in CourseOctreeRoot)
                {
                    rootChild.Save(writer);
                }

                // Write the model offsets.
                modelOffsetArrayOffset.Satisfy();
                Offset[] modelOffsets = writer.ReserveOffset(Models.Count);

                // Write the models.
                int i = 0;
                foreach (KclModel model in Models)
                {
                    modelOffsets[i++].Satisfy();
                    model.Save(stream);
                    writer.Align(4);
                }
            }
        }
Пример #19
0
        private void WriteArray(BinaryDataWriter writer, IList array)
        {
            WriteTypeAndElementCount(writer, ByamlNodeType.Array, array.Count);

            // Write the element types (which must be the same for each to be supported for serialization).
            ByamlNodeType nodeType = GetNodeType(array.GetType().GetTypeInfo().GetElementType());

            for (int i = 0; i < array.Count; i++)
            {
                writer.Write((byte)nodeType);
            }

            // Write the elements, which begin after a padding to the next 4 bytes.
            writer.Align(4);
            if (nodeType == ByamlNodeType.Array || nodeType == ByamlNodeType.Dictionary)
            {
                // Arrays or dictionaries are referenced by offsets pointing behind the array.
                Offset[] offsets = new Offset[array.Count];
                for (int i = 0; i < array.Count; i++)
                {
                    offsets[i] = writer.ReserveOffset();
                }
                // Behind the offsets, write the array or dictionary contents and satisfy the 4-byte aligned offsets.
                for (int i = 0; i < array.Count; i++)
                {
                    WriteArrayOrDictionary(writer, offsets[i], array[i]);
                }
            }
            else
            {
                // Primitive values are stored directly rather than being referenced by offsets.
                foreach (object element in array)
                {
                    WritePrimitiveType(writer, nodeType, element);
                }
            }
        }
Пример #20
0
            //write byaml
            public static void WriteStringList(List <string> list, BinaryDataWriter bw)
            {
                long startPos = bw.Position;

                bw.Write((byte)ByamlNodeType.StringTable);
                bw.WriteInt24(list.Count);
                bw.Write(new byte[4 * (list.Count + 1)]); //temp

                long tempPos;

                for (int i = 0; i < list.Count; i++)
                {
                    tempPos = bw.Position;
                    using (bw.TemporarySeek(startPos + 4 + i * 4, SeekOrigin.Begin))
                        bw.Write((int)(tempPos - startPos));

                    bw.Write(Encoding.UTF8.GetBytes(list[i] + "\0"));
                }
                tempPos = bw.Position;
                using (bw.TemporarySeek(startPos + 4 + list.Count * 4, SeekOrigin.Begin))
                    bw.Write((int)(tempPos - startPos));

                bw.Align(4);
            }
Пример #21
0
        private void WriteStringArray(BinaryDataWriter writer, Offset offset, IList <string> stringArray)
        {
            // Satisfy the offset to the value in the BYAML file which must be 4-byte aligned.
            writer.Align(4);
            offset.Satisfy();

            WriteTypeAndElementCount(writer, ByamlNodeType.StringArray, stringArray.Count);

            // Write the offsets to the strings.
            int stringOffset = 4 + 4 * (stringArray.Count + 1); // Relative to node start + all uint32 offsets.

            foreach (string str in stringArray)
            {
                writer.Write(stringOffset);
                stringOffset += str.Length + 1;
            }
            writer.Write(stringOffset); // The last one points to the end of the last string.

            // Write the 0-terminated strings.
            foreach (string str in stringArray)
            {
                writer.Write(str, BinaryStringFormat.ZeroTerminated);
            }
        }
Пример #22
0
        protected void WriteContent(object rootReferenceKey)
        {
            using (_writer)
            {
                // Write the header, specifying magic bytes, version and main node offsets.
                _writer.Write(BYAML_MAGIC);
                _writer.Write(_version);
                Offset nameArrayOffset   = _writer.ReserveOffset();
                Offset stringArrayOffset = _writer.ReserveOffset();
                Offset pathArrayOffset   = _supportPaths ? _writer.ReserveOffset() : null;
                Offset rootOffset        = _writer.ReserveOffset();

                // Write the main nodes.
                _writer.Align(4);
                nameArrayOffset.Satisfy();
                WriteStringArrayNode(_writer, _nameArray);
                if (_stringArray.Length == 0)
                {
                    stringArrayOffset.Satisfy(0);
                }
                else
                {
                    _writer.Align(4);
                    stringArrayOffset.Satisfy();
                    WriteStringArrayNode(_writer, _stringArray);
                }

                // Include a path array offset if requested.
                if (_supportPaths)
                {
                    if (_pathArray.Count == 0)
                    {
                        pathArrayOffset.Satisfy(0);
                    }
                    else
                    {
                        _writer.Align(4);
                        pathArrayOffset.Satisfy();
                        WritePathArrayNode(_writer, _pathArray);
                    }
                }

                _writer.Align(4);

                //write value stack (Dictionary, Array, long, uint, double)
                int valStackPos = (int)_writer.BaseStream.Position;

                //write all dictionaries
                foreach (KeyValuePair <object, ByamlDict> keyValuePair in _dictionaries)
                {
                    _writer.Seek(valStackPos + keyValuePair.Value.offset, SeekOrigin.Begin);

                    if (keyValuePair.Key == rootReferenceKey)
                    {
                        rootOffset.Satisfy();
                    }

                    if (_byteOrder == ByteOrder.BigEndian)
                    {
                        _writer.Write((uint)ByamlNodeType.Dictionary << 24 | (uint)keyValuePair.Value.entries.Length);
                    }
                    else
                    {
                        _writer.Write((uint)ByamlNodeType.Dictionary | (uint)keyValuePair.Value.entries.Length << 8);
                    }

                    foreach ((string key, Entry entry) in keyValuePair.Value.entries)
                    {
                        if (_byteOrder == ByteOrder.BigEndian)
                        {
                            _writer.Write(Array.IndexOf(_nameArray, key) << 8 | (byte)entry.type);
                        }
                        else
                        {
                            _writer.Write(Array.IndexOf(_nameArray, key) | (byte)entry.type << 24);
                        }

                        WriteValue(entry);
                    }
                }

                //write all arrays
                foreach (KeyValuePair <object, ByamlArr> keyValuePair in _arrays)
                {
                    _writer.Seek(valStackPos + keyValuePair.Value.offset, SeekOrigin.Begin);

                    if (keyValuePair.Key == rootReferenceKey)
                    {
                        rootOffset.Satisfy();
                    }

                    if (_byteOrder == ByteOrder.BigEndian)
                    {
                        _writer.Write((uint)ByamlNodeType.Array << 24 | (uint)keyValuePair.Value.entries.Length);
                    }
                    else
                    {
                        _writer.Write((uint)ByamlNodeType.Array | (uint)keyValuePair.Value.entries.Length << 8);
                    }


                    foreach (Entry entry in keyValuePair.Value.entries)
                    {
                        _writer.Write((byte)entry.type);
                    }

                    _writer.Align(4);

                    foreach (Entry entry in keyValuePair.Value.entries)
                    {
                        WriteValue(entry);
                    }
                }

                //write all 8 byte values
                foreach (var keyValuePair in _eightByteValues)
                {
                    _writer.Seek(valStackPos + keyValuePair.Value, SeekOrigin.Begin);
                    _writer.Write(keyValuePair.Key);
                }

                void WriteValue(Entry entry)
                {
                    // Only write the offset for the complex value contents, write simple values directly.
                    switch (entry.type)
                    {
                    case ByamlNodeType.StringIndex:
                        _writer.Write((uint)Array.IndexOf(_stringArray, entry.value));
                        break;

                    case ByamlNodeType.PathIndex:
                        _writer.Write(_pathArray.IndexOf(entry.value));
                        break;

                    case ByamlNodeType.Dictionary:
                        _writer.Write(valStackPos + _dictionaries[(object)entry.value].offset);
                        break;

                    case ByamlNodeType.Array:
                        _writer.Write(valStackPos + _arrays[(object)entry.value].offset);
                        break;

                    case ByamlNodeType.Boolean:
                        _writer.Write(entry.value ? 1 : 0);
                        break;

                    case ByamlNodeType.Integer:
                    case ByamlNodeType.Float:
                    case ByamlNodeType.UInteger:
                        _writer.Write(entry.value);
                        break;

                    case ByamlNodeType.Double:
                    case ByamlNodeType.ULong:
                    case ByamlNodeType.Long:
                        _writer.Write(valStackPos + _eightByteValues[entry.value]);
                        return;

                    case ByamlNodeType.Null:
                        _writer.Write(0);
                        break;
                    }
                }
            }
        }
Пример #23
0
        public static Tuple <int, byte[]> PackN(SarcData data, int _align = -1)
        {
            int align = _align >= 0 ? _align : (int)GuessAlignment(data.Files);

            MemoryStream     o  = new MemoryStream();
            BinaryDataWriter bw = new BinaryDataWriter(o, false);

            bw.ByteOrder = data.endianness;
            bw.Write("SARC", BinaryStringFormat.NoPrefixOrTermination);
            bw.Write((UInt16)0x14);             // Chunk length
            bw.Write((UInt16)0xFEFF);           // BOM
            bw.Write((UInt32)0x00);             //filesize update later
            bw.Write((UInt32)0x00);             //Beginning of data
            bw.Write((UInt16)0x100);
            bw.Write((UInt16)0x00);
            bw.Write("SFAT", BinaryStringFormat.NoPrefixOrTermination);
            bw.Write((UInt16)0xc);
            bw.Write((UInt16)data.Files.Keys.Count);
            bw.Write((UInt32)0x00000065);
            List <uint> offsetToUpdate = new List <uint>();

            //Names must be sorted by hash
            string[] SortedNames = null;
            if (data.HashOnly)
            {
                SortedNames = data.Files.Keys.OrderBy(x => StringHashToUint(x)).ToArray();
            }
            else
            {
                SortedNames = data.Files.Keys.OrderBy(x => NameHash(x)).ToArray();
            }

            foreach (string k in SortedNames)
            {
                if (data.HashOnly)
                {
                    bw.Write(StringHashToUint(k));
                }
                else
                {
                    bw.Write(NameHash(k));
                }
                offsetToUpdate.Add((uint)bw.BaseStream.Position);
                bw.Write((UInt32)0);
                bw.Write((UInt32)0);
                bw.Write((UInt32)0);
            }
            bw.Write("SFNT", BinaryStringFormat.NoPrefixOrTermination);
            bw.Write((UInt16)0x8);
            bw.Write((UInt16)0);
            List <uint> StringOffsets = new List <uint>();

            foreach (string k in SortedNames)
            {
                StringOffsets.Add((uint)bw.BaseStream.Position);
                bw.Write(k, BinaryStringFormat.ZeroTerminated);
                bw.Align(4);
            }
            bw.Align(0x1000);             //TODO: check if works in odyssey
            List <uint> FileOffsets = new List <uint>();

            foreach (string k in SortedNames)
            {
                bw.Align((int)GuessFileAlignment(data.Files[k]));
                FileOffsets.Add((uint)bw.BaseStream.Position);
                bw.Write(data.Files[k]);
            }
            for (int i = 0; i < offsetToUpdate.Count; i++)
            {
                bw.BaseStream.Position = offsetToUpdate[i];
                if (!data.HashOnly)
                {
                    bw.Write(0x01000000 | ((StringOffsets[i] - StringOffsets[0]) / 4));
                }
                else
                {
                    bw.Write((UInt32)0);
                }
                bw.Write((UInt32)(FileOffsets[i] - FileOffsets[0]));
                bw.Write((UInt32)(FileOffsets[i] + data.Files[SortedNames[i]].Length - FileOffsets[0]));
            }
            bw.BaseStream.Position = 0x08;
            bw.Write((uint)bw.BaseStream.Length);
            bw.Write((uint)FileOffsets[0]);

            return(new Tuple <int, byte[]>(align, o.ToArray()));
        }
Пример #24
0
        public static byte[] pack(Dictionary <string, byte[]> files, int align = -1, ByteOrder endianness = ByteOrder.LittleEndian)
        {
            if (align < 0)
            {
                align = (int)GuessAlignment(files);
            }

            MemoryStream     o  = new MemoryStream();
            BinaryDataWriter bw = new BinaryDataWriter(o, false);

            bw.ByteOrder = endianness;
            bw.Write("SARC", BinaryStringFormat.NoPrefixOrTermination);
            bw.Write((UInt16)0x14);   // Chunk length
            bw.Write((UInt16)0xFEFF); // BOM
            bw.Write((UInt32)0x00);   //filesize update later
            bw.Write((UInt32)0x00);   //Beginning of data
            bw.Write((UInt32)0x00000100);
            bw.Write("SFAT", BinaryStringFormat.NoPrefixOrTermination);
            bw.Write((UInt16)0xc);
            bw.Write((UInt16)files.Keys.Count);
            bw.Write((UInt32)0x00000065);
            List <uint> offsetToUpdate = new List <uint>();

            foreach (string k in files.Keys)
            {
                bw.Write(NameHash(k));
                offsetToUpdate.Add((uint)bw.BaseStream.Position);
                bw.Write((UInt32)0);
                bw.Write((UInt32)0);
                bw.Write((UInt32)0);
            }
            bw.Write("SFNT", BinaryStringFormat.NoPrefixOrTermination);
            bw.Write((UInt16)0x8);
            bw.Write((UInt16)0);
            List <uint> StringOffsets = new List <uint>();

            foreach (string k in files.Keys)
            {
                StringOffsets.Add((uint)bw.BaseStream.Position);
                bw.Write(k, BinaryStringFormat.ZeroTerminated);
                bw.Align(4);
            }
            bw.Align(align);
            List <uint> FileOffsets = new List <uint>();

            foreach (string k in files.Keys)
            {
                FileOffsets.Add((uint)bw.BaseStream.Position);
                bw.Write(files[k]);
                bw.Align(align);
            }
            for (int i = 0; i < offsetToUpdate.Count; i++)
            {
                bw.BaseStream.Position = offsetToUpdate[i];
                bw.Write((UInt16)((StringOffsets[i] - StringOffsets[0]) / 4));
                bw.Write((UInt16)0x0100);
                bw.Write((UInt32)(FileOffsets[i] - FileOffsets[0]));
                bw.Write((UInt32)(FileOffsets[i] + files.Values.ToArray()[i].Length - FileOffsets[0]));
            }
            bw.BaseStream.Position = 0x08;
            bw.Write((uint)bw.BaseStream.Length);
            bw.Write((uint)FileOffsets[0]);
            return(o.ToArray());
        }
Пример #25
0
        protected override void ApplyChanges(BinaryDataWriter bin)
        {
            AddNewProperties();

            bin.ByteOrder = order;
            bin.Write((ushort)(Properties.Count + AddedProperties.Count + UnknownPropertiesCount));
            bin.Write((ushort)0);
            bin.Write(new byte[0xC * AddedProperties.Count]);
            bin.Write(data, 4, data.Length - 4);             //write rest of entries, adding new elements first doesn't break relative offets in the struct
            foreach (var m in Properties)
            {
                if ((byte)m.type != 1 && (byte)m.type != 2)
                {
                    continue;
                }
                m.ValueOffset += +0xC * AddedProperties.Count;
                bin.Position   = m.ValueOffset;
                if (m.value.Length != m.ValueCount)
                {
                    throw new Exception("Can't change the number of values of an usd1 property");
                }
                for (int i = 0; i < m.ValueCount; i++)
                {
                    if (m.type == EditableProperty.ValueType.int32)
                    {
                        bin.Write(int.Parse(m.value[i]));
                    }
                    else
                    {
                        bin.Write(float.Parse(m.value[i]));
                    }
                }
            }
            for (int i = 0; i < AddedProperties.Count; i++)
            {
                bin.Position = bin.BaseStream.Length;
                uint DataOffset = (uint)bin.BaseStream.Position;
                AddedProperties[i].ValueOffset = DataOffset;
                AddedProperties[i].ValueCount  = (ushort)AddedProperties[i].value.Length;
                for (int j = 0; j < AddedProperties[i].value.Length; j++)
                {
                    if (AddedProperties[i].type == EditableProperty.ValueType.int32)
                    {
                        bin.Write(int.Parse(AddedProperties[i].value[j]));
                    }
                    else
                    {
                        bin.Write(float.Parse(AddedProperties[i].value[j]));
                    }
                }
                uint NameOffest = (uint)bin.BaseStream.Position;
                bin.Write(AddedProperties[i].Name, BinaryStringFormat.ZeroTerminated);
                bin.Align(4);
                uint entryStart = (uint)(4 + i * 0xC);
                bin.BaseStream.Position = entryStart;
                bin.Write(NameOffest - entryStart);
                bin.Write(DataOffset - entryStart);
                bin.Write((ushort)AddedProperties[i].ValueCount);
                bin.Write((byte)AddedProperties[i].type);
                bin.Write((byte)0);
                OriginalProperties.Add(AddedProperties[i].Name);
            }

            Properties.AddRange(AddedProperties);
            AddedProperties.Clear();
        }
Пример #26
0
        public byte[] Write(ByteOrder byteOrder)
        {
            if (Models.Count != 8)
            {
                throw new Exception("The root octree is not complete");
            }

            var size = GlobalHeader.OctreeMax - GlobalHeader.OctreeOrigin;

            using (MemoryStream m = new MemoryStream())
            {
                BinaryDataWriter er = new BinaryDataWriter(m);
                //Write KCL Header
                er.ByteOrder = ByteOrder.BigEndian;                 //The signature is always big endian
                er.Write(0x02020000);
                er.ByteOrder = byteOrder;
                er.Write((UInt32)0x38);
                er.Write((UInt32)0x58);
                er.Write((UInt32)Models.Count);
                er.Write(GlobalHeader.OctreeOrigin);
                er.Write(GlobalHeader.OctreeMax);
                er.Write((UInt32)GlobalHeader.CoordShift);
                er.Write((UInt32)GlobalHeader.YShift);
                er.Write((UInt32)GlobalHeader.ZShift);
                er.Write((UInt32)GlobalHeader.Unknown1);
                List <KCLModel> WriteModels = new List <KCLModel>();
                uint            modelCount  = 0;
                for (int i = 0; i < 8; i++)
                {
                    if (Models[i] != null)
                    {
                        er.Write((UInt32)(0x80000000 | modelCount));
                        modelCount++;
                        WriteModels.Add(Models[i]);
                    }
                    else
                    {
                        er.Write((UInt32)(0xC0000000));
                    }
                }
                if (modelCount == 0)
                {
                    throw new Exception("No models in the global octree");
                }

                uint ModelListOff = (uint)er.BaseStream.Position;

                er.BaseStream.Position = 0xC;
                er.Write((UInt32)modelCount);
                er.BaseStream.Position = ModelListOff;

                for (int i = 0; i < modelCount; i++)                 //Update offsets later
                {
                    er.Write((UInt32)0);
                }

                for (int i = 0; i < modelCount; i++)
                {
                    er.Align(4);
                    uint pos = (uint)er.BaseStream.Position;
                    er.BaseStream.Position = ModelListOff + i * 4;
                    er.Write((UInt32)pos);
                    er.BaseStream.Position = pos;
                    WriteModel(er, WriteModels[i]);
                }

                return(m.ToArray());
            }
        }