Represents an item in a binary plist's object table.
Example #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);
        }
Example #2
0
        /// <summary>
        /// Adds a date to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddDate(DateTime value)
        {
            if (!this.uniques.Contains(value))
            {
                int    index  = this.objectTable.Count;
                byte[] buffer = BitConverter.GetBytes(value.ToUniversalTime().Subtract(ReferenceDate).TotalSeconds);

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(buffer);
                }

                BinaryPlistItem item = new BinaryPlistItem(value);
                item.Marker.Add((byte)0x33);
                item.SetByteValue(buffer);

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                this.uniques.SetIndex(value, index);
                return(index);
            }

            return(this.uniques.GetIndex(value));
        }
Example #3
0
        /// <summary>
        /// Adds a float to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddFloat(float value)
        {
            if (!this.uniques.Contains(value))
            {
                int    index  = this.objectTable.Count;
                byte[] buffer = BitConverter.GetBytes(value);

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(buffer);
                }

                BinaryPlistItem item = new BinaryPlistItem(value);
                item.Marker.Add((byte)((byte)0x20 | (byte)Math.Log(buffer.Length, 2)));
                item.SetByteValue(buffer);

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                this.uniques.SetIndex(value, index);
                return(index);
            }

            return(this.uniques.GetIndex(value));
        }
Example #4
0
        /// <summary>
        /// Adds an array to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddArray(IEnumerable value)
        {
            int index = this.objectTable.Count;

            BinaryPlistArray array = new BinaryPlistArray(this.objectTable);
            BinaryPlistItem  item  = new BinaryPlistItem(array);

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

            foreach (object obj in value)
            {
                array.ObjectReference.Add(this.AddObject(obj));
                this.objectRefCount++;
            }

            if (array.ObjectReference.Count < 15)
            {
                item.Marker.Add((byte)((byte)0xA0 | (byte)array.ObjectReference.Count));
            }
            else
            {
                item.Marker.Add((byte)0xAF);
                AddIntegerCount(item.Marker, array.ObjectReference.Count);
            }

            this.objectTableSize += item.Size;
            return(index);
        }
Example #5
0
        /// <summary>
        /// Writes an array item to the given <see cref="BinaryWriter"/>.
        /// </summary>
        /// <param name="writer">The <see cref="BinaryWriter"/> to write to.</param>
        /// <param name="value">The array item to write.</param>
        /// <returns>The number of bytes written.</returns>
        private int WriteArray(BinaryWriter writer, BinaryPlistItem value)
        {
            int size = value.Marker.Count;
            BinaryPlistArray array = (BinaryPlistArray)value.Value;

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

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

            return(size);
        }
Example #6
0
        /// <summary>
        /// Adds a string to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddString(string value)
        {
            if (!this.uniques.Contains(value))
            {
                int    index = this.objectTable.Count;
                bool   ascii = value.IsAscii();
                byte[] buffer;

                BinaryPlistItem item = new BinaryPlistItem(value);

                if (value.Length < 15)
                {
                    item.Marker.Add((byte)((byte)(ascii ? 0x50 : 0x60) | (byte)value.Length));
                }
                else
                {
                    item.Marker.Add((byte)(ascii ? 0x5F : 0x6F));
                    AddIntegerCount(item.Marker, value.Length);
                }

                if (ascii)
                {
                    buffer = Encoding.ASCII.GetBytes(value);
                }
                else
                {
                    buffer = Encoding.Unicode.GetBytes(value);

                    if (BitConverter.IsLittleEndian)
                    {
                        for (int i = 0; i < buffer.Length; i++)
                        {
                            byte l = buffer[i];
                            buffer[i] = buffer[++i];
                            buffer[i] = l;
                        }
                    }
                }

                item.SetByteValue(buffer);

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                this.uniques.SetIndex(value, index);
                return(index);
            }

            return(this.uniques.GetIndex(value));
        }
Example #7
0
        /// <summary>
        /// Adds an integer to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddInteger(long value)
        {
            if (!this.uniques.Contains(value))
            {
                int index = this.objectTable.Count;

                BinaryPlistItem item = new BinaryPlistItem(value);
                item.SetByteValue(GetIntegerBytes(value));
                item.Marker.Add((byte)((byte)0x10 | (byte)Math.Log(item.ByteValue.Count, 2)));

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                this.uniques.SetIndex(value, index);
                return(index);
            }

            return(this.uniques.GetIndex(value));
        }
Example #8
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);
        }
Example #9
0
        /// <summary>
        /// Adds arbitrary data to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddData(object value)
        {
            int index = this.objectTable.Count, count = 0, bufferIndex = 0;

            byte[] buffer = value as byte[];

            if (buffer == null)
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, value);

                    stream.Position = 0;
                    buffer          = new byte[stream.Length];

                    while (0 < (count = stream.Read(buffer, 0, buffer.Length - bufferIndex)))
                    {
                        bufferIndex += count;
                    }
                }
            }

            BinaryPlistItem item = new BinaryPlistItem(value);

            item.SetByteValue(buffer);

            if (buffer.Length < 15)
            {
                item.Marker.Add((byte)((byte)0x40 | (byte)buffer.Length));
            }
            else
            {
                item.Marker.Add(0x4F);
                AddIntegerCount(item.Marker, buffer.Length);
            }

            this.objectTable.Add(item);
            this.objectTableSize += item.Size;

            return(index);
        }
Example #10
0
        /// <summary>
        /// Adds a primitive to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddPrimitive(bool?value)
        {
            if (!value.HasValue || !this.uniques.Contains(value.Value))
            {
                int index = this.objectTable.Count;

                BinaryPlistItem item = new BinaryPlistItem(value);
                item.Marker.Add(value.HasValue ? (value.Value ? (byte)0x9 : (byte)0x8) : (byte)0);

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                if (value.HasValue)
                {
                    this.uniques.SetIndex(value.Value, index);
                }

                return(index);
            }

            return(this.uniques.GetIndex(value.Value));
        }
Example #11
0
        /// <summary>
        /// Reads the object table from the given reader.
        /// </summary>
        /// <param name="reader">The reader to read the object table from.</param>
        private void ReadObjectTable(BinaryReader reader)
        {
            byte            marker;
            bool?           primitive;
            int             size, intSize;
            long            parsedInt;
            BinaryPlistItem item;

            for (int i = 0; i < this.objectCount; i++)
            {
                reader.BaseStream.Position = this.offsetTable[i];
                marker = reader.ReadByte();
                var hexMarker     = marker.ToString("X2");
                var firstHalf     = marker >> 4;
                var bottomHalf    = (marker & 0xf0) >> 4;
                var type          = marker & 0xF0;
                var @caseHex      = type.ToString("X2");
                var hexFirstHalf  = firstHalf.ToString("X2");
                var hexBottomHalf = bottomHalf.ToString("X2");
                // The first half of the byte is the base marker.
                switch (type)
                {
                case 0x00:
                    if (ReadPrimitive(reader, reader.BaseStream.Position - 1, out primitive))
                    {
                        this.objectTable.Add(new BinaryPlistItem(primitive));
                    }

                    break;

                case 0x10:
                    size      = 1 << (marker & 0xf);
                    parsedInt = ReadInteger(reader, reader.BaseStream.Position, size);

                    if (size < 4)
                    {
                        this.objectTable.Add(new BinaryPlistItem((short)parsedInt));
                    }
                    else if (size < 8)
                    {
                        this.objectTable.Add(new BinaryPlistItem((int)parsedInt));
                    }
                    else
                    {
                        this.objectTable.Add(new BinaryPlistItem(parsedInt));
                    }

                    break;

                case 0x20:
                    size = 1 << (marker & 0xf);
                    this.objectTable.Add(new BinaryPlistItem(ReadReal(reader, reader.BaseStream.Position, size)));
                    break;

                case 0x30:
                    size = marker & 0xf;

                    this.objectTable.Add(new BinaryPlistItem(ReadDate(reader, reader.BaseStream.Position, 8)));

                    break;

                case 0x40:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    this.objectTable.Add(new BinaryPlistItem(ReadData(reader, reader.BaseStream.Position, size)));
                    break;

                case 0x50:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    this.objectTable.Add(new BinaryPlistItem(ReadAsciiString(reader, reader.BaseStream.Position, size)));
                    break;

                case 0x60:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    this.objectTable.Add(new BinaryPlistItem(ReadUnicodeString(reader, reader.BaseStream.Position, size)));
                    break;

                case 0x80:
                    size = (marker & 0xf) + 1;
                    this.objectTable.Add(new BinaryPlistItem(ReadUniqueId(reader, reader.BaseStream.Position, size)));
                    break;

                case 0xA0:
                case 0xC0:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    item         = new BinaryPlistItem(this.ReadArray(reader, reader.BaseStream.Position, size));
                    item.IsArray = true;
                    this.objectTable.Add(item);
                    break;

                case 0xD0:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    item = new BinaryPlistItem(this.ReadDictionary(reader, reader.BaseStream.Position, size));
                    item.IsDictionary = true;
                    this.objectTable.Add(item);
                    break;

                default:
                    throw new InvalidOperationException("An invalid marker was found while reading the object table: " + marker.ToBinaryString());
                }
            }
        }
        /// <summary>
        /// Adds a date to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddDate(DateTime value)
        {
            if (!this.uniques.Contains(value))
            {
                int index = this.objectTable.Count;
                byte[] buffer = BitConverter.GetBytes(value.ToUniversalTime().Subtract(ReferenceDate).TotalSeconds);

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(buffer);
                }

                BinaryPlistItem item = new BinaryPlistItem(value);
                item.Marker.Add((byte)0x33);
                item.SetByteValue(buffer);

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                this.uniques.SetIndex(value, index);
                return index;
            }

            return this.uniques.GetIndex(value);
        }
        /// <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>
        /// Adds a float to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddFloat(float value)
        {
            if (!this.uniques.Contains(value))
            {
                int index = this.objectTable.Count;
                byte[] buffer = BitConverter.GetBytes(value);

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(buffer);
                }

                BinaryPlistItem item = new BinaryPlistItem(value);
                item.Marker.Add((byte)((byte)0x20 | (byte)Math.Log(buffer.Length, 2)));
                item.SetByteValue(buffer);

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                this.uniques.SetIndex(value, index);
                return index;
            }

            return this.uniques.GetIndex(value);
        }
        /// <summary>
        /// Adds arbitrary data to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddData(object value)
        {
            int index = this.objectTable.Count, count = 0, bufferIndex = 0;
            byte[] buffer = value as byte[];

            if (buffer == null)
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, value);

                    stream.Position = 0;
                    buffer = new byte[stream.Length];

                    while (0 < (count = stream.Read(buffer, 0, buffer.Length - bufferIndex)))
                    {
                        bufferIndex += count;
                    }
                }
            }

            BinaryPlistItem item = new BinaryPlistItem(value);
            item.SetByteValue(buffer);

            if (buffer.Length < 15)
            {
                item.Marker.Add((byte)((byte)0x40 | (byte)buffer.Length));
            }
            else
            {
                item.Marker.Add(0x4F);
                AddIntegerCount(item.Marker, buffer.Length);
            }

            this.objectTable.Add(item);
            this.objectTableSize += item.Size;

            return index;
        }
        /// <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>
        /// Writes an array item to the given <see cref="BinaryWriter"/>.
        /// </summary>
        /// <param name="writer">The <see cref="BinaryWriter"/> to write to.</param>
        /// <param name="value">The array item to write.</param>
        /// <returns>The number of bytes written.</returns>
        private int WriteArray(BinaryWriter writer, BinaryPlistItem value)
        {
            int size = value.Marker.Count;
            BinaryPlistArray array = (BinaryPlistArray)value.Value;

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

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

            return size;
        }
        /// <summary>
        /// Adds a string to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddString(string value)
        {
            if (!this.uniques.Contains(value))
            {
                int index = this.objectTable.Count;
                bool ascii = value.IsAscii();
                byte[] buffer;

                BinaryPlistItem item = new BinaryPlistItem(value);

                if (value.Length < 15)
                {
                    item.Marker.Add((byte)((byte)(ascii ? 0x50 : 0x60) | (byte)value.Length));
                }
                else
                {
                    item.Marker.Add((byte)(ascii ? 0x5F : 0x6F));
                    AddIntegerCount(item.Marker, value.Length);
                }

                if (ascii)
                {
                    buffer = Encoding.ASCII.GetBytes(value);
                }
                else
                {
                    buffer = Encoding.Unicode.GetBytes(value);

                    if (BitConverter.IsLittleEndian)
                    {
                        for (int i = 0; i < buffer.Length; i++)
                        {
                            byte l = buffer[i];
                            buffer[i] = buffer[++i];
                            buffer[i] = l;
                        }
                    }
                }

                item.SetByteValue(buffer);

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                this.uniques.SetIndex(value, index);
                return index;
            }

            return this.uniques.GetIndex(value);
        }
        /// <summary>
        /// Adds a primitive to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddPrimitive(bool? value)
        {
            if (!value.HasValue || !this.uniques.Contains(value.Value))
            {
                int index = this.objectTable.Count;

                BinaryPlistItem item = new BinaryPlistItem(value);
                item.Marker.Add(value.HasValue ? (value.Value ? (byte)0x9 : (byte)0x8) : (byte)0);

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                if (value.HasValue)
                {
                    this.uniques.SetIndex(value.Value, index);
                }

                return index;
            }

            return this.uniques.GetIndex(value.Value);
        }
        /// <summary>
        /// Adds an integer to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddInteger(long value)
        {
            if (!this.uniques.Contains(value))
            {
                int index = this.objectTable.Count;

                BinaryPlistItem item = new BinaryPlistItem(value);
                item.SetByteValue(GetIntegerBytes(value));
                item.Marker.Add((byte)((byte)0x10 | (byte)Math.Log(item.ByteValue.Count, 2)));

                this.objectTable.Add(item);
                this.objectTableSize += item.Size;

                this.uniques.SetIndex(value, index);
                return index;
            }

            return this.uniques.GetIndex(value);
        }
        /// <summary>
        /// Reads the object table from the given reader.
        /// </summary>
        /// <param name="reader">The reader to read the object table from.</param>
        private void ReadObjectTable(BinaryReader reader)
        {
            byte            marker;
            bool?           primitive;
            int             size, intSize;
            long            parsedInt;
            BinaryPlistItem item;

            for (int i = 0; i < this.objectCount; i++)
            {
                reader.BaseStream.Position = this.offsetTable[i];
                marker = reader.ReadByte();

                // The first half of the byte is the base marker.
                switch ((marker & 0xf0) >> 4)
                {
                case 0:
                    if (ReadPrimitive(reader, reader.BaseStream.Position - 1, out primitive))
                    {
                        this.objectTable.Add(new BinaryPlistItem(primitive));
                    }

                    break;

                case 1:
                    size      = 1 << (marker & 0xf);
                    parsedInt = ReadInteger(reader, reader.BaseStream.Position, size);

                    if (size < 4)
                    {
                        this.objectTable.Add(new BinaryPlistItem((short)parsedInt));
                    }
                    else if (size < 8)
                    {
                        this.objectTable.Add(new BinaryPlistItem((int)parsedInt));
                    }
                    else
                    {
                        this.objectTable.Add(new BinaryPlistItem(parsedInt));
                    }

                    break;

                case 2:
                    size = 1 << (marker & 0xf);
                    this.objectTable.Add(new BinaryPlistItem(ReadReal(reader, reader.BaseStream.Position, size)));
                    break;

                case 3:
                    size = marker & 0xf;

                    if (size == 3)
                    {
                        this.objectTable.Add(new BinaryPlistItem(ReadDate(reader, reader.BaseStream.Position, 8)));
                    }
                    else
                    {
                        throw new InvalidOperationException("Unsupported date size: " + size.ToBinaryString());
                    }

                    break;

                case 4:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    this.objectTable.Add(new BinaryPlistItem(ReadData(reader, reader.BaseStream.Position, size)));
                    break;

                case 5:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    this.objectTable.Add(new BinaryPlistItem(ReadAsciiString(reader, reader.BaseStream.Position, size)));
                    break;

                case 6:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    this.objectTable.Add(new BinaryPlistItem(ReadUnicodeString(reader, reader.BaseStream.Position, size)));
                    break;

                case 8:
                    size = (marker & 0xf) + 1;
                    this.objectTable.Add(new BinaryPlistItem(ReadUniqueId(reader, reader.BaseStream.Position, size)));
                    break;

                case 10:
                case 12:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    item         = new BinaryPlistItem(this.ReadArray(reader, reader.BaseStream.Position, size));
                    item.IsArray = true;
                    this.objectTable.Add(item);
                    break;

                case 13:
                    size = marker & 0xf;

                    if (size == 15)
                    {
                        intSize = 1 << (reader.ReadByte() & 0xf);
                        size    = (int)ReadInteger(reader, reader.BaseStream.Position, intSize);
                    }

                    item = new BinaryPlistItem(this.ReadDictionary(reader, reader.BaseStream.Position, size));
                    item.IsDictionary = true;
                    this.objectTable.Add(item);
                    break;

                default:
                    throw new InvalidOperationException("An invalid marker was found while reading the object table: " + marker.ToBinaryString());
                }
            }
        }
        /// <summary>
        /// Adds an array to the internal object table.
        /// </summary>
        /// <param name="value">The value to add.</param>
        /// <returns>The index of the added value.</returns>
        private int AddArray(IEnumerable value)
        {
            int index = this.objectTable.Count;

            BinaryPlistArray array = new BinaryPlistArray(this.objectTable);
            BinaryPlistItem item = new BinaryPlistItem(array);
            item.IsArray = true;
            this.objectTable.Add(item);

            foreach (object obj in value)
            {
                array.ObjectReference.Add(this.AddObject(obj));
                this.objectRefCount++;
            }

            if (array.ObjectReference.Count < 15)
            {
                item.Marker.Add((byte)((byte)0xA0 | (byte)array.ObjectReference.Count));
            }
            else
            {
                item.Marker.Add((byte)0xAF);
                AddIntegerCount(item.Marker, array.ObjectReference.Count);
            }

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