Exemple #1
0
        /// <summary>
        /// Adds a dictionary to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddDictionary(IDictionary value)
        {
            int index = this.objectTable.Count;

            BinaryPlistDictionary dict = new BinaryPlistDictionary(this.objectTable, value.Count);
            BinaryPlistItem       item = new BinaryPlistItem(dict);

            item.IsDictionary = true;
            this.objectTable.Add(item);

            foreach (object key in value.Keys)
            {
                dict.KeyReference.Add(this.AddObject(key));
                dict.ObjectReference.Add(this.AddObject(value[key]));

                this.objectRefCount += 2;
            }

            if (dict.KeyReference.Count < 15)
            {
                item.Marker.Add((byte)((byte)0xD0 | (byte)dict.KeyReference.Count));
            }
            else
            {
                item.Marker.Add((byte)0xDF);
                AddIntegerCount(item.Marker, dict.KeyReference.Count);
            }

            this.objectTableSize += item.Size;
            return(index);
        }
        /// <summary>
        /// Reads a dictionary value from the given reader, starting at the given index and of the given size.
        /// </summary>
        /// <param name="reader">The <see cref="BinaryReader"/> to read the dictionary value from.</param>
        /// <param name="index">The index in the stream the dictionary value starts at.</param>
        /// <param name="size">The number of items in the dictionary.</param>
        /// <returns>A dictionary value.</returns>
        private BinaryPlistDictionary ReadDictionary(BinaryReader reader, long index, int size)
        {
            BinaryPlistDictionary dictionary = new BinaryPlistDictionary(this.objectTable, size);
            int skip = size * this.objectRefSize;

            for (int i = 0; i < size; i++)
            {
                dictionary.KeyReference.Add((int)ReadInteger(reader, index + (i * this.objectRefSize), this.objectRefSize));
                dictionary.ObjectReference.Add((int)ReadInteger(reader, skip + index + (i * this.objectRefSize), this.objectRefSize));
            }

            return(dictionary);
        }
Exemple #3
0
        /// <summary>
        /// Writes a dictionary item to the given <see cref="BinaryWriter"/>.
        /// </summary>
        /// <param name="writer">The <see cref="BinaryWriter"/> to write to.</param>
        /// <param name="value">The dictionary item to write.</param>
        /// <returns>The number of bytes written.</returns>
        private int WriteDictionary(BinaryWriter writer, BinaryPlistItem value)
        {
            int size = value.Marker.Count;
            BinaryPlistDictionary dict = (BinaryPlistDictionary)value.Value;

            writer.Write(value.Marker.ToArray());

            foreach (int keyRef in dict.KeyReference)
            {
                size += WriteReferenceInteger(writer, keyRef, this.objectRefSize);
            }

            foreach (int objectRef in dict.ObjectReference)
            {
                size += WriteReferenceInteger(writer, objectRef, this.objectRefSize);
            }

            return(size);
        }
        /// <summary>
        /// Reads a binary plist from the given stream into an <see cref="IDictionary"/>.
        /// </summary>
        /// <param name="stream">The <see cref="Stream"/> to read.</param>
        /// <returns>The result plist <see cref="IDictionary"/>.</returns>
        public IDictionary ReadObject(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream", "stream cannot be null.");
            }

            if (!stream.CanRead)
            {
                throw new ArgumentException("The stream must be readable.", "stream");
            }

            Stream concreteStream        = stream;
            bool   disposeConcreteStream = false;

            if (!stream.CanSeek)
            {
                concreteStream = new MemoryStream();
                byte[] buffer = new byte[4096];
                int    count  = 0;

                while (0 < (count = stream.Read(buffer, 0, buffer.Length)))
                {
                    concreteStream.Write(buffer, 0, count);
                }

                concreteStream.Position = 0;
                disposeConcreteStream   = true;
            }

            try
            {
                Dictionary <object, object> dictionary = null;
                this.Reset();

                // Header + trailer = 40.
                if (stream.Length > 40)
                {
                    using (BinaryReader reader = new BinaryReader(concreteStream))
                    {
                        // Read the header.
                        stream.Position = 0;
                        int bpli    = reader.ReadInt32().ToBigEndianConditional();
                        int version = reader.ReadInt32().ToBigEndianConditional();

                        if (bpli != BinaryPlistWriter.HeaderMagicNumber || version != BinaryPlistWriter.HeaderVersionNumber)
                        {
                            throw new ArgumentException("The stream data does not start with required 'bplist00' header.", "stream");
                        }

                        // Read the trailer.
                        // The first six bytes of the first eight-byte block are unused, so offset by 26 instead of 32.
                        stream.Position           = stream.Length - 26;
                        this.offsetIntSize        = (int)reader.ReadByte();
                        this.objectRefSize        = (int)reader.ReadByte();
                        this.objectCount          = (int)reader.ReadInt64().ToBigEndianConditional();
                        this.topLevelObjectOffset = (int)reader.ReadInt64().ToBigEndianConditional();
                        this.offsetTableOffset    = (int)reader.ReadInt64().ToBigEndianConditional();
                        int offsetTableSize = this.offsetIntSize * this.objectCount;

                        // Ensure our sanity.
                        if (this.offsetIntSize < 1 ||
                            this.offsetIntSize > 8 ||
                            this.objectRefSize < 1 ||
                            this.objectRefSize > 8 ||
                            this.offsetTableOffset < 8 ||
                            this.topLevelObjectOffset >= this.objectCount ||
                            offsetTableSize + this.offsetTableOffset + 32 > stream.Length)
                        {
                            throw new ArgumentException("The stream data contains an invalid trailer.", "stream");
                        }

                        // Read the offset table and then the object table.
                        this.ReadOffsetTable(reader);
                        this.ReadObjectTable(reader);
                    }
                }
                else
                {
                    throw new ArgumentException("The stream is too short to be a valid binary plist.", "stream");
                }

                BinaryPlistDictionary root = this.objectTable[this.topLevelObjectOffset].Value as BinaryPlistDictionary;

                if (root != null)
                {
                    dictionary = root.ToDictionary();
                }
                else
                {
                    throw new InvalidOperationException("Unsupported root plist object: " + this.objectTable[this.topLevelObjectOffset].GetType() + ". A dictionary must be the root plist object.");
                }

                return(dictionary ?? new Dictionary <object, object>());
            }
            finally
            {
                if (disposeConcreteStream && concreteStream != null)
                {
                    concreteStream.Dispose();
                }
            }
        }
        /// <summary>
        /// Adds a dictionary to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddDictionary(IDictionary value)
        {
            int index = this.objectTable.Count;

            BinaryPlistDictionary dict = new BinaryPlistDictionary(this.objectTable, value.Count);
            BinaryPlistItem item = new BinaryPlistItem(dict);
            item.IsDictionary = true;
            this.objectTable.Add(item);

            foreach (object key in value.Keys)
            {
                dict.KeyReference.Add(this.AddObject(key));
                dict.ObjectReference.Add(this.AddObject(value[key]));

                this.objectRefCount += 2;
            }

            if (dict.KeyReference.Count < 15)
            {
                item.Marker.Add((byte)((byte)0xD0 | (byte)dict.KeyReference.Count));
            }
            else
            {
                item.Marker.Add((byte)0xDF);
                AddIntegerCount(item.Marker, dict.KeyReference.Count);
            }

            this.objectTableSize += item.Size;
            return index;
        }