Ejemplo n.º 1
0
        internal void PrepareResourceIndices(SavingContext ctx)
        {
            foreach (AxmlAttribute attribute in Attributes)
            {
                attribute.PrepareResourceIndices(ctx);
            }

            foreach (AxmlElement element in Children)
            {
                element.PrepareResourceIndices(ctx);
            }
        }
Ejemplo n.º 2
0
        internal void PreparePooling(SavingContext ctx)
        {
            // First we need to write the namespaces declared within this element
            foreach (KeyValuePair <string, Uri> pair in DeclaredNamespaces)
            {
                ctx.StringPool.Add(pair.Key);
                ctx.StringPool.Add(pair.Value.ToString());
            }

            if (NamespaceUri != null)
            {
                ctx.StringPool.Add(NamespaceUri.ToString());
            }

            ctx.StringPool.Add(Name);

            // Sort the attributes in order of increasing resource Id, and alphabetical order in terms of the namespaces
            // Attributes with a namespace will also come before attributes without a namespace
            Attributes.Sort((a, b) =>
            {
                int resourceIdDiff = (a.ResourceId ?? -1) - (b.ResourceId ?? -1);
                if (resourceIdDiff != 0)
                {
                    return(resourceIdDiff);
                }

                if (a.Namespace == null)
                {
                    return(b.Namespace == null ? 0 : -1);
                }
                else
                {
                    return(b.Namespace == null ? 1 : String.CompareOrdinal(a.Namespace.ToString(), b.Namespace.ToString()));
                }
            });

            foreach (AxmlAttribute attribute in Attributes)
            {
                attribute.PreparePooling(ctx);
            }

            foreach (AxmlElement element in Children)
            {
                element.PreparePooling(ctx);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Saves the given root element to the given stream as AXML.
        /// </summary>
        /// <param name="stream">Stream to save to</param>
        /// <param name="rootElement">Root element of the document</param>
        public static void SaveDocument(Stream stream, AxmlElement rootElement)
        {
            BinaryWriter mainOutput = new BinaryWriter(stream);

            // Write the main elements chunk of the file to a MemoryStream first
            SavingContext ctx = new SavingContext();

            rootElement.PreparePooling(ctx);
            string[] stringPool = ctx.StringPool.PrepareForSavePhase(ctx.ResourceMap);

            rootElement.Save(ctx);
            MemoryStream mainChunkStream = (MemoryStream)ctx.Writer.BaseStream;


            int[] resourcePool = ctx.ResourceMap.Save();

            int stringPoolLength  = StringPoolSerializer.CalculatePoolLength(stringPool);
            int stringPoolPadding = (4 - stringPoolLength % 4) % 4;

            stringPoolLength += stringPoolPadding;            // Add padding to four bytes

            int resourcePoolLength = resourcePool.Length * 4; // Each pool item is an integer

            // The length of the main xml tag is that of the whole file, so also including the string pool, resource pool, and main chunk. (+ extra 8 + 8 = 16 bytes for string pool and resource pool header)
            mainOutput.WriteChunkHeader(ResourceType.Xml, stringPoolLength + resourcePoolLength + (int)mainChunkStream.Position + 16);

            mainOutput.WriteChunkHeader(ResourceType.StringPool, stringPoolLength);
            StringPoolSerializer.SaveStringPool(stringPool, mainOutput);
            for (int i = 0; i < stringPoolPadding; i++)
            {
                mainOutput.Write((byte)0);
            }

            mainOutput.WriteChunkHeader(ResourceType.XmlResourceMap, resourcePoolLength);
            foreach (int resource in resourcePool)
            {
                mainOutput.Write(resource);
            }

            // Save the main chunk of the file
            mainChunkStream.Position = 0;
            mainChunkStream.CopyTo(stream);
        }
Ejemplo n.º 4
0
        internal void Save(SavingContext ctx)
        {
            // First we need to write the namespaces declared within this element
            foreach (KeyValuePair <string, Uri> pair in DeclaredNamespaces)
            {
                ctx.Writer.WriteChunkHeader(ResourceType.XmlStartNamespace, 16); // Each namespace tag is 3 integers, so 3 * 4 = 12 bytes
                ctx.Writer.Write(TextLineNumber);
                ctx.Writer.Write(0xFFFFFFFF);
                ctx.Writer.Write(ctx.StringPool.GetIndex(pair.Key));
                ctx.Writer.Write(ctx.StringPool.GetIndex(pair.Value.ToString()));
            }

            ctx.Writer.WriteChunkHeader(ResourceType.XmlStartElement, 28 + 20 * Attributes.Count); // Each attribute is 5 integers, so 5 * 4 = 20 bytes of the tag
            ctx.Writer.Write(TextLineNumber);
            ctx.Writer.Write(0xFFFFFFFF);
            ctx.Writer.Write(NamespaceUri == null ? -1 : ctx.StringPool.GetIndex(NamespaceUri.ToString()));
            ctx.Writer.Write(ctx.StringPool.GetIndex(Name));
            ctx.Writer.Write(0x00140014);

            // Find the ID, class and style attribute indices if they exist
            short idAttributeIndex    = -1;
            short classAttributeIndex = -1;
            short styleAttributeIndex = -1;

            for (short i = 0; i < Attributes.Count; i++)
            {
                WrappedValue?wrappedValue = Attributes[i].Value as WrappedValue;
                if (wrappedValue == null)
                {
                    continue;
                }

                // Make sure to prevent multiple of these attributes, as this will save incorrectly
                switch (wrappedValue.Type)
                {
                case WrappedValueType.Id:
                    if (idAttributeIndex != -1)
                    {
                        throw new InvalidDataException("Cannot have multiple ID attributes on one element");
                    }
                    idAttributeIndex = i;
                    break;

                case WrappedValueType.Class:
                    if (classAttributeIndex != -1)
                    {
                        throw new InvalidDataException("Cannot have multiple class attributes on one element");
                    }
                    classAttributeIndex = i;
                    break;

                case WrappedValueType.Style:
                    if (styleAttributeIndex != -1)
                    {
                        throw new InvalidDataException("Cannot have multiple style attributes on one element");
                    }
                    styleAttributeIndex = i;
                    break;
                }
            }

            ctx.Writer.Write((short)Attributes.Count);
            // Stored indices are one above the actual ones
            ctx.Writer.Write((short)(idAttributeIndex + 1));
            ctx.Writer.Write((short)(classAttributeIndex + 1));
            ctx.Writer.Write((short)(styleAttributeIndex + 1));
            foreach (AxmlAttribute attribute in Attributes)
            {
                attribute.Save(ctx);
            }

            foreach (AxmlElement child in Children)
            {
                child.Save(ctx);
            }
            ctx.Writer.WriteChunkHeader(ResourceType.XmlEndElement, 16);
            ctx.Writer.Write(-1);
            ctx.Writer.Write(0xFFFFFFFF);
            ctx.Writer.Write(NamespaceUri == null ? -1 : ctx.StringPool.GetIndex(NamespaceUri.ToString()));
            ctx.Writer.Write(ctx.StringPool.GetIndex(Name));

            // End the namespaces stated by this element, as we have exited it
            foreach (KeyValuePair <string, Uri> pair in DeclaredNamespaces.Reverse())
            {
                ctx.Writer.WriteChunkHeader(ResourceType.XmlEndNamespace, 16); // Each namespace tag is 3 integers, so 3 * 4 = 12 bytes
                ctx.Writer.Write(TextLineNumber);
                ctx.Writer.Write(0xFFFFFFFF);
                ctx.Writer.Write(ctx.StringPool.GetIndex(pair.Key));
                ctx.Writer.Write(ctx.StringPool.GetIndex(pair.Value.ToString()));
            }
        }