Ejemplo n.º 1
0
        public void WritePicture(BinaryWriter picW, byte[] pictureData, string mimeType, int pictureTypeCode, string picDescription)
        {
            picW.Write(StreamUtils.EncodeBEInt32(pictureTypeCode));
            picW.Write(StreamUtils.EncodeBEInt32(mimeType.Length));
            picW.Write(Utils.Latin1Encoding.GetBytes(mimeType));
            picW.Write(StreamUtils.EncodeBEInt32(picDescription.Length));
            picW.Write(Encoding.UTF8.GetBytes(picDescription));

            ImageProperties props = ImageUtils.GetImageProperties(pictureData);

            picW.Write(StreamUtils.EncodeBEInt32(props.Width));
            picW.Write(StreamUtils.EncodeBEInt32(props.Height));
            picW.Write(StreamUtils.EncodeBEInt32(props.ColorDepth));
            if (props.Format.Equals(ImageFormat.Gif))
            {
                picW.Write(StreamUtils.EncodeBEInt32(props.NumColorsInPalette));    // Color num
            }
            else
            {
                picW.Write(0);
            }

            picW.Write(StreamUtils.EncodeBEInt32(pictureData.Length));
            picW.Write(pictureData);
        }
Ejemplo n.º 2
0
        private void writePictureFrame(BinaryWriter w, byte[] pictureData)
        {
            w.Write(StreamUtils.EncodeBEInt32(pictureData.Length)); // Pic size
            w.Write(0);                                             // Pic data absolute offset; to be rewritten later

            w.Write(pictureData);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Write the given field with the given writer, using the WMA-like format
        /// </summary>
        /// <param name="w">Write to write the fields to</param>
        /// <param name="fieldName">Field name</param>
        /// <param name="fieldValue">Field value</param>
        /// <param name="isNumeric">True if the field is numeric; false if not (will be formatted as string)</param>
        public static void WriteField(BinaryWriter w, string fieldName, string fieldValue, bool isNumeric)
        {
            long frameSizePos, midSizePos, finalFramePos;

            frameSizePos = w.BaseStream.Position;

            w.Write(0); // To be rewritten at the end of the method
            w.Write(StreamUtils.EncodeBEInt32(fieldName.Length));
            w.Write(Utils.Latin1Encoding.GetBytes(fieldName));
            w.Write((ushort)0);                    // Frame class ?
            w.Write(StreamUtils.EncodeBEInt16(1)); // ? (always 1)
            midSizePos = w.BaseStream.Position;
            w.Write(0);                            // To be rewritten at the end of the method

            if (isNumeric)
            {
                w.Write(StreamUtils.EncodeBEInt16(19)); // ?? (works for rating)
                w.Write(long.Parse(fieldValue));        // 64-bit little-endian integer ?
            }
            else
            {
                w.Write(StreamUtils.EncodeBEInt16(8));                 // ?? (always 8)
                w.Write(Encoding.Unicode.GetBytes(fieldValue + '\0')); // String is null-terminated
            }

            finalFramePos = w.BaseStream.Position;
            // Go back to frame size locations to write their actual size
            w.BaseStream.Seek(midSizePos, SeekOrigin.Begin);
            w.Write(StreamUtils.EncodeBEInt32((int)(finalFramePos - midSizePos)));

            w.BaseStream.Seek(frameSizePos, SeekOrigin.Begin);
            w.Write(StreamUtils.EncodeBEInt32((int)(finalFramePos - frameSizePos)));
            w.BaseStream.Seek(finalFramePos, SeekOrigin.Begin);
        }
Ejemplo n.º 4
0
 private void writeTagField(BinaryWriter w, string key, string value)
 {
     w.Write('\0'); // Unknown byte; always zero
     byte[] keyB   = Encoding.UTF8.GetBytes(key);
     byte[] valueB = Encoding.UTF8.GetBytes(value);
     w.Write(StreamUtils.EncodeBEInt32(keyB.Length));   // Key length
     w.Write(StreamUtils.EncodeBEInt32(valueB.Length)); // Value length
     w.Write(keyB);
     w.Write(valueB);
 }
Ejemplo n.º 5
0
 public void WriteID3v2EmbeddingHeader(BinaryWriter w, long tagSize)
 {
     w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_ID3));
     if (isLittleEndian)
     {
         w.Write((int)tagSize);
     }
     else
     {
         w.Write(StreamUtils.EncodeBEInt32((int)tagSize));
     }
 }
Ejemplo n.º 6
0
        public static Int32 ToStream(BinaryWriter w, Boolean isLittleEndian, MetaDataIO meta)
        {
            var additionalFields = meta.AdditionalFields;

            w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_LIST));

            var sizePos = w.BaseStream.Position;

            w.Write((Int32)0); // Placeholder for chunk size that will be rewritten at the end of the method

            w.Write(Utils.Latin1Encoding.GetBytes(PURPOSE_INFO));

            // 'Classic' fields (NB : usually done within a loop by accessing MetaDataIO.tagData)
            IDictionary <String, String> writtenFields = new Dictionary <String, String>();
            // Title
            var value = Utils.ProtectValue(meta.Title);

            if (0 == value.Length && additionalFields.Keys.Contains("info.INAM"))
            {
                value = additionalFields["info.INAM"];
            }
            if (value.Length > 0)
            {
                writeSizeAndNullTerminatedString("INAM", value, w, writtenFields);
            }
            // Artist
            value = Utils.ProtectValue(meta.Artist);
            if (0 == value.Length && additionalFields.Keys.Contains("info.IART"))
            {
                value = additionalFields["info.IART"];
            }
            if (value.Length > 0)
            {
                writeSizeAndNullTerminatedString("IART", value, w, writtenFields);
            }
            // Copyright
            value = Utils.ProtectValue(meta.Copyright);
            if (0 == value.Length && additionalFields.Keys.Contains("info.ICOP"))
            {
                value = additionalFields["info.ICOP"];
            }
            if (value.Length > 0)
            {
                writeSizeAndNullTerminatedString("ICOP", value, w, writtenFields);
            }
            // Genre
            value = Utils.ProtectValue(meta.Genre);
            if (0 == value.Length && additionalFields.Keys.Contains("info.IGNR"))
            {
                value = additionalFields["info.IGNR"];
            }
            if (value.Length > 0)
            {
                writeSizeAndNullTerminatedString("IGNR", value, w, writtenFields);
            }
            // Comment
            value = Utils.ProtectValue(meta.Comment);
            if (0 == value.Length && additionalFields.Keys.Contains("info.ICMT"))
            {
                value = additionalFields["info.ICMT"];
            }
            if (value.Length > 0)
            {
                writeSizeAndNullTerminatedString("ICMT", value, w, writtenFields);
            }

            String shortKey;

            foreach (var key in additionalFields.Keys)
            {
                if (key.StartsWith("info."))
                {
                    shortKey = key.Substring(5, key.Length - 5).ToUpper();
                    if (!writtenFields.ContainsKey(key))
                    {
                        if (additionalFields[key].Length > 0)
                        {
                            writeSizeAndNullTerminatedString(shortKey, additionalFields[key], w, writtenFields);
                        }
                    }
                }
            }

            var finalPos = w.BaseStream.Position;

            w.BaseStream.Seek(sizePos, SeekOrigin.Begin);
            if (isLittleEndian)
            {
                w.Write((Int32)(finalPos - sizePos - 4));
            }
            else
            {
                w.Write(StreamUtils.EncodeBEInt32((Int32)(finalPos - sizePos - 4)));
            }

            return(14);
        }
Ejemplo n.º 7
0
        protected override int write(TagData tag, BinaryWriter w, string zone)
        {
            int result = -1; // Default : leave as is

            if (zone.Equals(ZONE_TAGS))
            {
                long nbTagsOffset = w.BaseStream.Position;
                w.Write(0); // Number of tags; will be rewritten at the end of the method

                // Mapped textual fields
                IDictionary <byte, string> map = tag.ToMap();
                foreach (byte frameType in map.Keys)
                {
                    if (map[frameType].Length > 0) // No frame with empty value
                    {
                        foreach (string s in frameMapping.Keys)
                        {
                            if (frameType == frameMapping[s])
                            {
                                string value = formatBeforeWriting(frameType, tag, map);
                                writeTagField(w, s, value);
                                result++;
                                break;
                            }
                        }
                    }
                }

                // Other textual fields
                foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields)
                {
                    if ((fieldInfo.TagType.Equals(MetaDataIOFactory.TAG_ANY) || fieldInfo.TagType.Equals(getImplementedTagType())) && !fieldInfo.MarkedForDeletion)
                    {
                        writeTagField(w, fieldInfo.NativeFieldCode, fieldInfo.Value);
                        result++;
                    }
                }

                w.BaseStream.Seek(nbTagsOffset, SeekOrigin.Begin);
                w.Write(StreamUtils.EncodeBEInt32(result)); // Number of tags
            }
            if (zone.Equals(ZONE_IMAGE))
            {
                result = 0;
                foreach (PictureInfo picInfo in tag.Pictures)
                {
                    // Picture has either to be supported, or to come from the right tag standard
                    bool doWritePicture = !picInfo.PicType.Equals(PictureInfo.PIC_TYPE.Unsupported);
                    if (!doWritePicture)
                    {
                        doWritePicture = (getImplementedTagType() == picInfo.TagType);
                    }
                    // It also has not to be marked for deletion
                    doWritePicture = doWritePicture && (!picInfo.MarkedForDeletion);

                    if (doWritePicture)
                    {
                        writePictureFrame(w, picInfo.PictureData);
                        return(1); // Stop here; there can only be one picture in an AA file
                    }
                }
            }

            return(result);
        }
Ejemplo n.º 8
0
 public void WriteID3v2EmbeddingHeader(BinaryWriter w, long tagSize)
 {
     w.Write(Utils.Latin1Encoding.GetBytes(CHUNKTYPE_ID3TAG));
     w.Write(StreamUtils.EncodeBEInt32((int)tagSize));
 }
Ejemplo n.º 9
0
        protected override int write(TagData tag, BinaryWriter w, string zone)
        {
            int result = 0;

            if (zone.Equals(CHUNKTYPE_NAME))
            {
                if (tag.Title.Length > 0)
                {
                    w.Write(Utils.Latin1Encoding.GetBytes(zone));
                    long sizePos = w.BaseStream.Position;
                    w.Write(0); // Placeholder for field size that will be rewritten at the end of the method

                    byte[] strBytes = Utils.Latin1Encoding.GetBytes(tag.Title);
                    w.Write(strBytes);

                    w.BaseStream.Seek(sizePos, SeekOrigin.Begin);
                    w.Write(StreamUtils.EncodeBEInt32(strBytes.Length));

                    result++;
                }
            }
            else if (zone.Equals(CHUNKTYPE_AUTHOR))
            {
                if (tag.Artist.Length > 0)
                {
                    w.Write(Utils.Latin1Encoding.GetBytes(zone));
                    long sizePos = w.BaseStream.Position;
                    w.Write(0); // Placeholder for field size that will be rewritten at the end of the method

                    byte[] strBytes = Utils.Latin1Encoding.GetBytes(tag.Artist);
                    w.Write(strBytes);

                    w.BaseStream.Seek(sizePos, SeekOrigin.Begin);
                    w.Write(StreamUtils.EncodeBEInt32(strBytes.Length));

                    result++;
                }
            }
            else if (zone.Equals(CHUNKTYPE_COPYRIGHT))
            {
                if (tag.Copyright.Length > 0)
                {
                    w.Write(Utils.Latin1Encoding.GetBytes(zone));
                    long sizePos = w.BaseStream.Position;
                    w.Write(0); // Placeholder for field size that will be rewritten at the end of the method

                    byte[] strBytes = Utils.Latin1Encoding.GetBytes(tag.Copyright);
                    w.Write(strBytes);

                    w.BaseStream.Seek(sizePos, SeekOrigin.Begin);
                    w.Write(StreamUtils.EncodeBEInt32(strBytes.Length));

                    result++;
                }
            }
            else if (zone.StartsWith(CHUNKTYPE_ANNOTATION))
            {
                // Do not write anything, this field is deprecated (Cf. specs "Use of this chunk is discouraged within FORM AIFC. The more refined Comments Chunk should be used instead")
            }
            else if (zone.StartsWith(CHUNKTYPE_COMMENTS))
            {
                bool applicable = tag.Comment.Length > 0;
                if (!applicable && tag.AdditionalFields.Count > 0)
                {
                    foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields)
                    {
                        applicable = (fieldInfo.NativeFieldCode.StartsWith(CHUNKTYPE_COMMENTS));
                        if (applicable)
                        {
                            break;
                        }
                    }
                }

                if (applicable)
                {
                    ushort numComments = 0;
                    w.Write(Utils.Latin1Encoding.GetBytes(CHUNKTYPE_COMMENTS));
                    long sizePos = w.BaseStream.Position;
                    w.Write(0);         // Placeholder for 'chunk size' field that will be rewritten at the end of the method
                    w.Write((ushort)0); // Placeholder for 'number of comments' field that will be rewritten at the end of the method

                    // First write generic comments (those linked to the Comment field)
                    string[] comments = tag.Comment.Split(Settings.InternalValueSeparator);
                    foreach (string s in comments)
                    {
                        writeCommentChunk(w, null, s);
                        numComments++;
                    }

                    // Then write comments linked to a Marker ID
                    if (tag.AdditionalFields != null && tag.AdditionalFields.Count > 0)
                    {
                        foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields)
                        {
                            if (fieldInfo.NativeFieldCode.StartsWith(CHUNKTYPE_COMMENTS))
                            {
                                if (((CommentData)fieldInfo.SpecificData).MarkerId != 0)
                                {
                                    writeCommentChunk(w, fieldInfo);
                                    numComments++;
                                }
                            }
                        }
                    }


                    long dataEndPos = w.BaseStream.Position;

                    w.BaseStream.Seek(sizePos, SeekOrigin.Begin);
                    w.Write(StreamUtils.EncodeBEInt32((int)(dataEndPos - sizePos - 4)));
                    w.Write(StreamUtils.EncodeBEUInt16(numComments));

                    result++;
                }
            }

            return(result);
        }
Ejemplo n.º 10
0
        public static int ToStream(BinaryWriter w, bool isLittleEndian, MetaDataIO meta)
        {
            IDictionary <string, string> additionalFields = meta.AdditionalFields;

            w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_IXML));

            long sizePos = w.BaseStream.Position;

            w.Write(0); // Placeholder for chunk size that will be rewritten at the end of the method


            XmlWriterSettings settings = new XmlWriterSettings();

            settings.CloseOutput = false;
            settings.Encoding    = Encoding.UTF8;

            XmlWriter writer = XmlWriter.Create(w.BaseStream, settings);

            //writer.Formatting = Formatting.None;


            writer.WriteStartDocument();
            writer.WriteStartElement("BWFXML");

            string[] path;
            string[] previousPath = null;
            bool     first        = true;
            string   subkey;

            foreach (string key in additionalFields.Keys)
            {
                if (key.StartsWith("ixml."))
                {
                    path = key.Split('.');
                    if (first)
                    {
                        previousPath = path;
                        first        = false;
                    }

                    // Closes all terminated paths
                    for (int i = previousPath.Length - 2; i >= 0; i--)
                    {
                        if ((path.Length <= i) || (path.Length > i && !path[i].Equals(previousPath[i])))
                        {
                            writer.WriteEndElement();
                        }
                    }

                    // Opens all new paths
                    for (int i = 0; i < path.Length - 1; i++)
                    {
                        if (previousPath.Length <= i || !path[i].Equals(previousPath[i]))
                        {
                            subkey = path[i];
                            if (subkey.Contains("["))
                            {
                                subkey = subkey.Substring(0, subkey.IndexOf("["));                       // Remove [x]'s
                            }
                            writer.WriteStartElement(subkey.ToUpper());
                        }
                    }

                    writer.WriteElementString(path[path.Length - 1], additionalFields[key]);

                    previousPath = path;
                }
            }

            // Closes all terminated paths
            if (previousPath != null)
            {
                for (int i = previousPath.Length - 2; i >= 0; i--)
                {
                    writer.WriteEndElement();
                }
            }
            writer.Close();


            long finalPos = w.BaseStream.Position;

            w.BaseStream.Seek(sizePos, SeekOrigin.Begin);
            if (isLittleEndian)
            {
                w.Write((int)(finalPos - sizePos - 4));
            }
            else
            {
                w.Write(StreamUtils.EncodeBEInt32((int)(finalPos - sizePos - 4)));
            }

            return(14);
        }
Ejemplo n.º 11
0
        public static int ToStream(BinaryWriter w, bool isLittleEndian, MetaDataIO meta)
        {
            IDictionary <string, string> additionalFields = meta.AdditionalFields;

            w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_BEXT));

            long sizePos = w.BaseStream.Position;

            w.Write((int)0); // Placeholder for chunk size that will be rewritten at the end of the method

            // Text values
            string description = Utils.ProtectValue(meta.GeneralDescription);

            if (0 == description.Length && additionalFields.Keys.Contains("bext.description"))
            {
                description = additionalFields["bext.description"];
            }

            writeFixedTextValue(description, 256, w);
            writeFixedFieldTextValue("bext.originator", 32, additionalFields, w);
            writeFixedFieldTextValue("bext.originatorReference", 32, additionalFields, w);
            writeFixedFieldTextValue("bext.originationDate", 10, additionalFields, w);
            writeFixedFieldTextValue("bext.originationTime", 8, additionalFields, w);

            // Int values
            writeFieldIntValue("bext.timeReference", additionalFields, w, (ulong)0);
            writeFieldIntValue("bext.version", additionalFields, w, (ushort)0);

            // UMID
            if (additionalFields.Keys.Contains("bext.UMID"))
            {
                if (Utils.IsHex(additionalFields["bext.UMID"]))
                {
                    int usedValues = (int)Math.Floor(additionalFields["bext.UMID"].Length / 2.0);
                    for (int i = 0; i < usedValues; i++)
                    {
                        w.Write(Convert.ToByte(additionalFields["bext.UMID"].Substring(i * 2, 2), 16));
                    }
                    // Complete the field to 64 bytes
                    for (int i = 0; i < 64 - usedValues; i++)
                    {
                        w.Write((byte)0);
                    }
                }
                else
                {
                    LogDelegator.GetLogDelegate()(Log.LV_WARNING, "'bext.UMID' : error writing field - hexadecimal notation required; " + additionalFields["bext.UMID"] + " found");
                    for (int i = 0; i < 64; i++)
                    {
                        w.Write((byte)0);
                    }
                }
            }
            else
            {
                for (int i = 0; i < 64; i++)
                {
                    w.Write((byte)0);
                }
            }


            // Float values
            writeField100DecimalValue("bext.loudnessValue", additionalFields, w, (short)0);
            writeField100DecimalValue("bext.loudnessRange", additionalFields, w, (short)0);
            writeField100DecimalValue("bext.maxTruePeakLevel", additionalFields, w, (short)0);
            writeField100DecimalValue("bext.maxMomentaryLoudness", additionalFields, w, (short)0);
            writeField100DecimalValue("bext.maxShortTermLoudness", additionalFields, w, (short)0);

            // Reserved
            for (int i = 0; i < 180; i++)
            {
                w.Write((byte)0);
            }

            // CodingHistory
            byte[] textData = new byte[0];
            if (additionalFields.Keys.Contains("bext.codingHistory"))
            {
                textData = Utils.Latin1Encoding.GetBytes(additionalFields["bext.codingHistory"]);
                w.Write(textData);
            }
            w.Write(new byte[2] {
                13, 10
            } /* CR LF */);

            // Emulation of the BWFMetaEdit padding behaviour (256 characters)
            for (int i = 0; i < 256 - ((textData.Length + 2) % 256); i++)
            {
                w.Write((byte)0);
            }


            long finalPos = w.BaseStream.Position;

            w.BaseStream.Seek(sizePos, SeekOrigin.Begin);
            if (isLittleEndian)
            {
                w.Write((int)(finalPos - sizePos - 4));
            }
            else
            {
                w.Write(StreamUtils.EncodeBEInt32((int)(finalPos - sizePos - 4)));
            }

            return(14);
        }
Ejemplo n.º 12
0
        public static int ToStream(BinaryWriter w, bool isLittleEndian, MetaDataIO meta)
        {
            IDictionary <string, string> additionalFields = meta.AdditionalFields;

            w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_SAMPLE));

            long sizePos = w.BaseStream.Position;

            w.Write(0); // Placeholder for chunk size that will be rewritten at the end of the method

            // Int values
            writeFieldIntValue("sample.manufacturer", additionalFields, w, 0);
            writeFieldIntValue("sample.product", additionalFields, w, 0);
            writeFieldIntValue("sample.period", additionalFields, w, 1);
            writeFieldIntValue("sample.MIDIUnityNote", additionalFields, w, 0);
            writeFieldIntValue("sample.MIDIPitchFraction", additionalFields, w, 0);
            writeFieldIntValue("sample.SMPTEFormat", additionalFields, w, 0);

            // SMPTE offset
            writeFieldIntValue("sample.SMPTEOffset.Hours", additionalFields, w, (sbyte)0);
            writeFieldIntValue("sample.SMPTEOffset.Minutes", additionalFields, w, (byte)0);
            writeFieldIntValue("sample.SMPTEOffset.Seconds", additionalFields, w, (byte)0);
            writeFieldIntValue("sample.SMPTEOffset.Frames", additionalFields, w, (byte)0);

            // == Sample loops

            // How many of them do we have ? -> count distinct indexes
            IList <string> keys = new List <string>();

            foreach (string s in additionalFields.Keys)
            {
                if (s.StartsWith("sample.SampleLoop"))
                {
                    string key = s.Substring(0, s.IndexOf("]") + 1);
                    if (!keys.Contains(key))
                    {
                        keys.Add(key);
                    }
                }
            }
            w.Write(keys.Count);

            // Sample loops data size
            long sampleLoopsPos = w.BaseStream.Position;

            w.Write(0); // Placeholder for data size that will be rewritten at the end of the method

            // Sample loops data
            foreach (string key in keys)
            {
                writeFieldIntValue(key + ".CuePointId", additionalFields, w, 0);
                writeFieldIntValue(key + ".Type", additionalFields, w, 0);
                writeFieldIntValue(key + ".Start", additionalFields, w, 0);
                writeFieldIntValue(key + ".End", additionalFields, w, 0);
                writeFieldIntValue(key + ".Fraction", additionalFields, w, 0);
                writeFieldIntValue(key + ".PlayCount", additionalFields, w, 0);
            }

            // Write actual sample loops data size
            long finalPos = w.BaseStream.Position;

            w.BaseStream.Seek(sampleLoopsPos, SeekOrigin.Begin);
            w.Write((int)(finalPos - sampleLoopsPos - 4));

            // Write actual tag size
            w.BaseStream.Seek(sizePos, SeekOrigin.Begin);
            if (isLittleEndian)
            {
                w.Write((int)(finalPos - sizePos - 4));
            }
            else
            {
                w.Write(StreamUtils.EncodeBEInt32((int)(finalPos - sizePos - 4)));
            }

            return(10);
        }
Ejemplo n.º 13
0
        public static int ToStream(BinaryWriter w, bool isLittleEndian, MetaDataIO meta)
        {
            IDictionary <string, string> additionalFields = meta.AdditionalFields;

            w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_IXML));

            long sizePos = w.BaseStream.Position;

            w.Write(0); // Placeholder for chunk size that will be rewritten at the end of the method


            XmlWriterSettings settings = new XmlWriterSettings();

            settings.CloseOutput = false;
            settings.Encoding    = Encoding.UTF8;

            XmlWriter writer = XmlWriter.Create(w.BaseStream, settings);

            //writer.Formatting = Formatting.None;


            writer.WriteStartDocument();
            writer.WriteStartElement("BWFXML");

            // Path notes : key = node path; value = node name
            Dictionary <string, string> pathNodes = new Dictionary <string, string>();
            List <string> previousPathNodes       = new List <string>();
            string        subkey;

            foreach (string key in additionalFields.Keys)
            {
                if (key.StartsWith("ixml."))
                {
                    // Create the list of path nodes
                    List <string> singleNodes = new List <string>(key.Split('.'));
                    singleNodes.RemoveAt(0); // Remove the "ixml" node

                    StringBuilder nodePrefix = new StringBuilder();
                    pathNodes.Clear();
                    foreach (string nodeName in singleNodes)
                    {
                        nodePrefix.Append(".").Append(nodeName);
                        pathNodes.Add(nodePrefix.ToString(), nodeName);
                    }

                    // Close all terminated (i.e. non present in current path) nodes in reverse order
                    for (int i = previousPathNodes.Count - 2; i >= 0; i--)
                    {
                        if (!pathNodes.ContainsKey(previousPathNodes[i]))
                        {
                            writer.WriteEndElement();
                        }
                    }

                    // Opens all new (i.e. non present in previous path) nodes
                    foreach (string nodePath in pathNodes.Keys)
                    {
                        if (!previousPathNodes.Contains(nodePath))
                        {
                            subkey = pathNodes[nodePath];
                            if (subkey.Equals(singleNodes.Last()))
                            {
                                continue;                                    // Last node is a leaf, not a node
                            }
                            if (subkey.Contains("["))
                            {
                                subkey = subkey.Substring(0, subkey.IndexOf("["));                       // Remove [x]'s
                            }
                            writer.WriteStartElement(subkey.ToUpper());
                        }
                    }

                    // Write the last node (=leaf) as a proper value
                    writer.WriteElementString(singleNodes.Last(), additionalFields[key]);

                    previousPathNodes = pathNodes.Keys.ToList();
                }
            }

            // Closes all terminated paths
            if (previousPathNodes != null)
            {
                for (int i = previousPathNodes.Count - 2; i >= 0; i--)
                {
                    writer.WriteEndElement();
                }
            }
            writer.Close();


            long finalPos = w.BaseStream.Position;

            w.BaseStream.Seek(sizePos, SeekOrigin.Begin);
            if (isLittleEndian)
            {
                w.Write((int)(finalPos - sizePos - 4));
            }
            else
            {
                w.Write(StreamUtils.EncodeBEInt32((int)(finalPos - sizePos - 4)));
            }

            return(14);
        }