This structure provides a representation of an Ogg page header.
Exemplo n.º 1
0
        /// <summary>
        ///    Reads the file with a specified read style.
        /// </summary>
        /// <param name="propertiesStyle">
        ///    A <see cref="ReadStyle" /> value specifying at what level
        ///    of accuracy to read the media properties, or <see
        ///    cref="ReadStyle.None" /> to ignore the properties.
        /// </param>
        private void Read(ReadStyle propertiesStyle)
        {
            long end;
            Dictionary <uint, Bitstream> streams = ReadStreams(null,
                                                               out end);
            List <ICodec> codecs = new List <ICodec> ();

            InvariantStartPosition = end;
            InvariantEndPosition   = Length;

            foreach (uint id in streams.Keys)
            {
                tag.AddComment(id,
                               streams [id].Codec.CommentData);
                codecs.Add(streams [id].Codec);
            }

            if (propertiesStyle == ReadStyle.None)
            {
                return;
            }

            PageHeader last_header = LastPageHeader;

            TimeSpan duration = streams [last_header
                                         .StreamSerialNumber].GetDuration(
                last_header.AbsoluteGranularPosition);

            properties = new Properties(duration, codecs);
        }
Exemplo n.º 2
0
 public Page(ByteVectorCollection packets, PageHeader header) : this(header)
 {
     if (packets == null)
     {
         throw new ArgumentNullException("packets");
     }
     this.packets = new ByteVectorCollection(packets);
     List<int> list = new List<int>();
     IEnumerator<ByteVector> enumerator = packets.GetEnumerator();
     try
     {
         while (enumerator.MoveNext())
         {
             ByteVector current = enumerator.Current;
             list.Add(current.Count);
         }
     }
     finally
     {
         if (enumerator == null)
         {
         }
         enumerator.Dispose();
     }
     header.PacketSizes = list.ToArray();
 }
Exemplo n.º 3
0
 public bool Equals(PageHeader other)
 {
     return(_packet_sizes == other._packet_sizes &&
            _version == other._version && _flags == other._flags &&
            _absolute_granular_position == other._absolute_granular_position &&
            _stream_serial_number == other._stream_serial_number &&
            _page_sequence_number == other._page_sequence_number &&
            _size == other._size && _data_size == other._data_size);
 }
Exemplo n.º 4
0
        public static void OverwriteSequenceNumbers(File file,
                                                    long position,
                                                    IDictionary <uint, int> shiftTable)
        {
            bool done = true;

            foreach (KeyValuePair <uint, int> pair in shiftTable)
            {
                if (pair.Value != 0)
                {
                    done = false;
                    break;
                }
            }

            if (done)
            {
                return;
            }

            while (position < file.Length)
            {
                PageHeader header = new PageHeader(file, position);
                int        size   = (int)(header.Size + header.DataSize);

                if (shiftTable.ContainsKey(header.StreamSerialNumber) &&
                    shiftTable [header.StreamSerialNumber] != 0)
                {
                    file.Seek(position);
                    ByteVector page_data = file.ReadBlock(size);

                    ByteVector new_data = ByteVector.FromUInt(
                        (uint)(header.PageSequenceNumber +
                               shiftTable [header.StreamSerialNumber]),
                        false);

                    for (int i = 18; i < 22; i++)
                    {
                        page_data [i] = new_data [i - 18];
                    }
                    for (int i = 22; i < 26; i++)
                    {
                        page_data [i] = 0;
                    }

                    new_data.Add(ByteVector.FromUInt(
                                     page_data.Checksum, false));
                    file.Seek(position + 18);
                    file.WriteBlock(new_data);
                }
                position += size;
            }
        }
Exemplo n.º 5
0
 /// <summary>
 ///    Checks whether or not the current instance is equal to
 ///    another instance of <see cref="PageHeader" />.
 /// </summary>
 /// <param name="other">
 ///    A <see cref="PageHeader" /> object to compare to the
 ///    current instance.
 /// </param>
 /// <returns>
 ///    A <see cref="bool" /> value indicating whether or not the
 ///    current instance is equal to <paramref name="other" />.
 /// </returns>
 /// <seealso cref="M:System.IEquatable`1.Equals" />
 public bool Equals(PageHeader other)
 {
     return(packet_sizes == other.packet_sizes &&
            version == other.version &&
            Flags == other.Flags &&
            absolute_granular_position ==
            other.absolute_granular_position &&
            StreamSerialNumber ==
            other.StreamSerialNumber &&
            PageSequenceNumber ==
            other.PageSequenceNumber &&
            Size == other.Size &&
            DataSize == other.DataSize);
 }
Exemplo n.º 6
0
 /// <summary>
 ///    Checks whether or not the current instance is equal to
 ///    another instance of <see cref="PageHeader" />.
 /// </summary>
 /// <param name="other">
 ///    A <see cref="PageHeader" /> object to compare to the
 ///    current instance.
 /// </param>
 /// <returns>
 ///    A <see cref="bool" /> value indicating whether or not the
 ///    current instance is equal to <paramref name="other" />.
 /// </returns>
 /// <seealso cref="M:System.IEquatable`1.Equals" />
 public bool Equals(PageHeader other)
 {
     return(packet_sizes == other.packet_sizes &&
            version == other.version &&
            flags == other.flags &&
            absolute_granular_position ==
            other.absolute_granular_position &&
            stream_serial_number ==
            other.stream_serial_number &&
            page_sequence_number ==
            other.page_sequence_number &&
            size == other.size &&
            data_size == other.data_size);
 }
Exemplo n.º 7
0
 public PageHeader(PageHeader original, uint offset, PageFlags flags)
 {
     this.version = original.version;
     this.flags = flags;
     this.absolute_granular_position = original.absolute_granular_position;
     this.stream_serial_number = original.stream_serial_number;
     this.page_sequence_number = original.page_sequence_number + offset;
     this.size = original.size;
     this.data_size = original.data_size;
     this.packet_sizes = new List<int>();
     if ((this.page_sequence_number == 0) && (((byte) (flags & PageFlags.FirstPacketContinued)) == 0))
     {
         this.flags = (PageFlags) ((byte) (this.flags | PageFlags.FirstPageOfStream));
     }
 }
Exemplo n.º 8
0
 public PageHeader(PageHeader original, uint offset, PageFlags flags)
 {
     version    = original.version;
     this.flags = flags;
     absolute_granular_position = original.absolute_granular_position;
     stream_serial_number       = original.stream_serial_number;
     page_sequence_number       = original.page_sequence_number + offset;
     size         = original.size;
     data_size    = original.data_size;
     packet_sizes = new List <int>();
     if (page_sequence_number == 0 && (flags & PageFlags.FirstPacketContinued) == 0)
     {
         this.flags |= PageFlags.FirstPageOfStream;
     }
 }
Exemplo n.º 9
0
 public Page(ByteVectorCollection packets, PageHeader header) :
     this(header)
 {
     if (packets == null)
     {
         throw new ArgumentNullException("packets");
     }
     this.packets = new ByteVectorCollection(packets);
     List <int> packet_sizes = new List <int>();
     foreach (ByteVector v in packets)
     {
         packet_sizes.Add(v.Count);
     }
     header.PacketSizes = packet_sizes.ToArray();
 }
Exemplo n.º 10
0
      public Page (ByteVectorCollection packets, PageHeader header) : this (header)
      {
         if (packets == null)
            throw new ArgumentNullException ("packets");
         
         this.packets = packets;

         List<int> packet_sizes = new List<int> ();

         // Build a page from the list of packets.
         foreach (ByteVector v in packets)
            packet_sizes.Add (v.Count);
         
         header.PacketSizes = packet_sizes.ToArray ();
      }
Exemplo n.º 11
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="PageHeader" /> by copying the values from another
        ///    instance, offsetting the page number and applying new
        ///    flags.
        /// </summary>
        /// <param name="original">
        ///    A <see cref="PageHeader"/> object to copy the values
        ///    from.
        /// </param>
        /// <param name="offset">
        ///    A <see cref="uint"/> value specifying how much to offset
        ///    the page sequence number in the new instance.
        /// </param>
        /// <param name="flags">
        ///    A <see cref="PageFlags"/> value specifying the flags to
        ///    use in the new instance.
        /// </param>
        public PageHeader(PageHeader original, uint offset, PageFlags flags)
        {
            version = original.version;
            Flags   = flags;
            absolute_granular_position = original.absolute_granular_position;
            StreamSerialNumber         = original.StreamSerialNumber;
            PageSequenceNumber         = original.PageSequenceNumber + offset;
            Size         = original.Size;
            DataSize     = original.DataSize;
            packet_sizes = new List <int> ();

            if (PageSequenceNumber == 0 && (flags & PageFlags.FirstPacketContinued) == 0)
            {
                Flags |= PageFlags.FirstPageOfStream;
            }
        }
Exemplo n.º 12
0
        public PageHeader(PageHeader original, uint offset, PageFlags flags)
        {
            _version = original._version;
            _flags   = flags;
            _absolute_granular_position = original._absolute_granular_position;
            _stream_serial_number       = original._stream_serial_number;
            _page_sequence_number       = original._page_sequence_number + offset;
            _size         = original._size;
            _data_size    = original._data_size;
            _packet_sizes = new List <int> ();

            if (_page_sequence_number == 0 && (flags & PageFlags.FirstPacketContinued) == 0)
            {
                _flags |= PageFlags.FirstPageOfStream;
            }
        }
Exemplo n.º 13
0
        /// <summary>
        ///    Repaginates the pages passed into the current instance to
        ///    handle changes made to the Xiph comment.
        /// </summary>
        /// <param name="change">
        ///    A <see cref="int" /> value reference containing the
        ///    the difference between the number of pages returned and
        ///    the number of pages that were added to the class.
        /// </param>
        /// <returns>
        ///    A <see cref="T:Page[]" /> containing the new page
        ///    collection.
        /// </returns>
        public Page [] Paginate(out int change)
        {
            // Ogg Pagination: Welcome to sucksville!
            // If you don't understand this, you're not alone.
            // It is confusing as Hell.

            // TODO: Document this method, in the mean time, there
            // is always http://xiph.org/ogg/doc/framing.html

            if (pages_read == 0)
            {
                change = 0;
                return(new Page [0]);
            }

            int count = pages_read;
            ByteVectorCollection packets = new ByteVectorCollection(
                this.packets);
            PageHeader  first_header = (PageHeader)first_page_header;
            List <Page> pages        = new List <Page> ();
            uint        index        = 0;
            bool        bos          = first_header.PageSequenceNumber == 0;

            if (bos)
            {
                pages.Add(new Page(new ByteVectorCollection(packets [0]), first_header));
                index++;
                packets.RemoveAt(0);
                count--;
            }

            int lacing_per_page = 0xfc;

            if (count > 0)
            {
                int total_lacing_bytes = 0;

                for (int i = 0; i < packets.Count; i++)
                {
                    total_lacing_bytes += GetLacingValueLength(
                        packets, i);
                }

                lacing_per_page = Math.Min(total_lacing_bytes / count + 1, lacing_per_page);
            }

            int lacing_bytes_used             = 0;
            ByteVectorCollection page_packets = new ByteVectorCollection();
            bool first_packet_continued       = false;

            while (packets.Count > 0)
            {
                int  packet_bytes = GetLacingValueLength(packets, 0);
                int  remaining    = lacing_per_page - lacing_bytes_used;
                bool whole_packet = packet_bytes <= remaining;
                if (whole_packet)
                {
                    page_packets.Add(packets [0]);
                    lacing_bytes_used += packet_bytes;
                    packets.RemoveAt(0);
                }
                else
                {
                    page_packets.Add(packets [0].Mid(0, remaining * 0xff));
                    packets [0]        = packets [0].Mid(remaining * 0xff);
                    lacing_bytes_used += remaining;
                }

                if (lacing_bytes_used == lacing_per_page)
                {
                    pages.Add(new Page(page_packets,
                                       new PageHeader(first_header,
                                                      index, first_packet_continued ?
                                                      PageFlags.FirstPacketContinued :
                                                      PageFlags.None)));
                    page_packets      = new ByteVectorCollection();
                    lacing_bytes_used = 0;
                    index++;
                    count--;
                    first_packet_continued = !whole_packet;
                }
            }

            if (page_packets.Count > 0)
            {
                pages.Add(new Page(page_packets,
                                   new PageHeader(
                                       first_header.StreamSerialNumber,
                                       index, first_packet_continued ?
                                       PageFlags.FirstPacketContinued :
                                       PageFlags.None)));
                index++;
                count--;
            }
            change = -count;
            return(pages.ToArray());
        }
Exemplo n.º 14
0
		public static void OverwriteSequenceNumbers (File file,
		                                             long position,
		                                             IDictionary<uint, int> shiftTable)
		{
			bool done = true;
			foreach (KeyValuePair<uint, int> pair in shiftTable)
				if (pair.Value != 0) {
					done = false;
					break;
				}
			
			if (done)
				return;
			
			while (position < file.Length) {
				PageHeader header = new PageHeader (file, position);
				int size = (int) (header.Size + header.DataSize);
				
				if (shiftTable.ContainsKey (header.StreamSerialNumber)
					&& shiftTable [header.StreamSerialNumber] != 0) {
					file.Seek (position);
					ByteVector page_data = file.ReadBlock (size);
					
					ByteVector new_data = ByteVector.FromUInt (
						(uint)(header.PageSequenceNumber +
						shiftTable [header.StreamSerialNumber]),
						false);
					
					for (int i = 18; i < 22; i ++)
						page_data [i] = new_data [i - 18];
					for (int i = 22; i < 26; i++)
						page_data [i] = 0;
					
					new_data.Add (ByteVector.FromUInt (
						page_data.Checksum, false));
					file.Seek (position + 18);
					file.WriteBlock (new_data);
				}
				position += size;
			}
		}
Exemplo n.º 15
0
 protected Page (PageHeader header)
 {
    this.header = header;
    packets = new ByteVectorCollection ();
 }
Exemplo n.º 16
0
 protected Page(PageHeader header)
 {
     this.header = header;
     packets     = new ByteVectorCollection();
 }
Exemplo n.º 17
0
 public static void OverwriteSequenceNumbers(TagLib.Ogg.File file, long position, IDictionary<uint, int> shiftTable)
 {
     if (file == null)
     {
         throw new ArgumentNullException("file");
     }
     if (shiftTable == null)
     {
         throw new ArgumentNullException("shiftTable");
     }
     bool flag = true;
     IEnumerator<KeyValuePair<uint, int>> enumerator = shiftTable.GetEnumerator();
     try
     {
         while (enumerator.MoveNext())
         {
             KeyValuePair<uint, int> current = enumerator.Current;
             if (current.Value != 0)
             {
                 flag = false;
                 goto Label_0065;
             }
         }
     }
     finally
     {
         if (enumerator == null)
         {
         }
         enumerator.Dispose();
     }
 Label_0065:
     if (flag)
     {
         return;
     }
     while (position < (file.Length - 0x1bL))
     {
         PageHeader header = new PageHeader(file, position);
         int length = (int) (header.Size + header.DataSize);
         if (shiftTable.ContainsKey(header.StreamSerialNumber) && (shiftTable[header.StreamSerialNumber] != 0))
         {
             file.Seek(position);
             ByteVector vector = file.ReadBlock(length);
             ByteVector data = ByteVector.FromUInt(header.PageSequenceNumber + ((uint) ((long) shiftTable[header.StreamSerialNumber])), false);
             for (int i = 0x12; i < 0x16; i++)
             {
                 vector[i] = data[i - 0x12];
             }
             for (int j = 0x16; j < 0x1a; j++)
             {
                 vector[j] = 0;
             }
             data.Add(ByteVector.FromUInt(vector.Checksum, false));
             file.Seek(position + 0x12L);
             file.WriteBlock(data);
         }
         position += length;
     }
 }
Exemplo n.º 18
0
 /// <summary>
 ///    Checks whether or not the current instance is equal to
 ///    another instance of <see cref="PageHeader" />.
 /// </summary>
 /// <param name="other">
 ///    A <see cref="PageHeader" /> object to compare to the
 ///    current instance.
 /// </param>
 /// <returns>
 ///    A <see cref="bool" /> value indicating whether or not the
 ///    current instance is equal to <paramref name="other" />.
 /// </returns>
 /// <seealso cref="M:System.IEquatable`1.Equals" />
 public bool Equals(PageHeader other)
 {
     return packet_sizes == other.packet_sizes &&
         version == other.version &&
         flags == other.flags &&
         absolute_granular_position ==
             other.absolute_granular_position &&
         stream_serial_number ==
             other.stream_serial_number &&
         page_sequence_number ==
             other.page_sequence_number &&
         size == other.size &&
         data_size == other.data_size;
 }
Exemplo n.º 19
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="PageHeader" /> by copying the values from another
        ///    instance, offsetting the page number and applying new
        ///    flags.
        /// </summary>
        /// <param name="original">
        ///    A <see cref="PageHeader"/> object to copy the values
        ///    from.
        /// </param>
        /// <param name="offset">
        ///    A <see cref="uint"/> value specifying how much to offset
        ///    the page sequence number in the new instance.
        /// </param>
        /// <param name="flags">
        ///    A <see cref="PageFlags"/> value specifying the flags to
        ///    use in the new instance.
        /// </param>
        public PageHeader(PageHeader original, uint offset,
		                   PageFlags flags)
        {
            version = original.version;
            this.flags = flags;
            absolute_granular_position =
                original.absolute_granular_position;
            stream_serial_number = original.stream_serial_number;
            page_sequence_number =
                original.page_sequence_number + offset;
            size = original.size;
            data_size = original.data_size;
            packet_sizes = new List<int> ();

            if (page_sequence_number == 0 &&
                (flags & PageFlags.FirstPacketContinued) == 0)
                this.flags |= PageFlags.FirstPageOfStream;
        }
Exemplo n.º 20
0
		/// <summary>
		///    Overwrites all page headers in a file starting at a
		///    specified position, shifting the page sequence numbers
		///    a set amount.
		/// </summary>
		/// <param name="file">
		///    A <see cref="File" /> object containing the file to
		///    update.
		/// </param>
		/// <param name="position">
		///    A <see cref="long" /> value specify at what position to
		///    start updating.
		/// </param>
		/// <param name="shiftTable">
		///    A <see cref="T:System.Collections.Generic.IDictionary`2"
		///    /> object where the key is the serial number of the
		///    stream to update and the value is the amount to offset
		///    the page sequence numbers in the stream.
		/// </param>
		/// <exception cref="ArgumentNullException">
		///    <paramref name="file" /> or <paramref name="shiftTable"
		///    /> is <see langword="null" />.
		/// </exception>
		/// <remarks>
		///    When the number of pages in a stream changes, all
		///    subsequent pages in the stream need to have their page
		///    sequence number update in order to remain valid.
		///    Additionally, when the page sequence number changes, the
		///    page needs to have its checksum recomputed. This makes
		///    for a costly recalculation if large comment data is
		///    added.
		/// </remarks>
		public static void OverwriteSequenceNumbers (File file,
		                                             long position,
		                                             IDictionary<uint, int> shiftTable)
		{
			if (file == null)
				throw new ArgumentNullException ("file");
			
			if (shiftTable == null)
				throw new ArgumentNullException ("shiftTable");
			
			// Check to see if there are no changes to be made.
			bool done = true;
			foreach (KeyValuePair<uint, int> pair in shiftTable)
				if (pair.Value != 0) {
					done = false;
					break;
				}
			
			// If the file is fine, quit.
			if (done)
				return;
			
			while (position < file.Length - 27) {
				PageHeader header = new PageHeader (file, position);
				int size = (int) (header.Size + header.DataSize);
				
				if (shiftTable.ContainsKey (header.StreamSerialNumber)
					&& shiftTable [header.StreamSerialNumber] != 0) {
					file.Seek (position);
					ByteVector page_data = file.ReadBlock (size);
					
					ByteVector new_data = ByteVector.FromUInt (
						(uint)(header.PageSequenceNumber +
						shiftTable [header.StreamSerialNumber]),
						false);
					
					for (int i = 18; i < 22; i ++)
						page_data [i] = new_data [i - 18];
					for (int i = 22; i < 26; i++)
						page_data [i] = 0;
					
					new_data.Add (ByteVector.FromUInt (
						page_data.Checksum, false));
					file.Seek (position + 18);
					file.WriteBlock (new_data);
				}
				position += size;
			}
		}
Exemplo n.º 21
0
 public bool Equals(PageHeader other)
 {
     return (((((this.packet_sizes == other.packet_sizes) && (this.version == other.version)) && ((this.flags == other.flags) && (this.absolute_granular_position == other.absolute_granular_position))) && (((this.stream_serial_number == other.stream_serial_number) && (this.page_sequence_number == other.page_sequence_number)) && (this.size == other.size))) && (this.data_size == other.data_size));
 }
Exemplo n.º 22
0
        /// <summary>
        ///    Overwrites all page headers in a file starting at a
        ///    specified position, shifting the page sequence numbers
        ///    a set amount.
        /// </summary>
        /// <param name="file">
        ///    A <see cref="File" /> object containing the file to
        ///    update.
        /// </param>
        /// <param name="position">
        ///    A <see cref="long" /> value specify at what position to
        ///    start updating.
        /// </param>
        /// <param name="shiftTable">
        ///    A <see cref="T:System.Collections.Generic.IDictionary`2"
        ///    /> object where the key is the serial number of the
        ///    stream to update and the value is the amount to offset
        ///    the page sequence numbers in the stream.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="file" /> or <paramref name="shiftTable"
        ///    /> is <see langword="null" />.
        /// </exception>
        /// <remarks>
        ///    When the number of pages in a stream changes, all
        ///    subsequent pages in the stream need to have their page
        ///    sequence number update in order to remain valid.
        ///    Additionally, when the page sequence number changes, the
        ///    page needs to have its checksum recomputed. This makes
        ///    for a costly recalculation if large comment data is
        ///    added.
        /// </remarks>
        public static void OverwriteSequenceNumbers(File file,
                                                    long position,
                                                    IDictionary <uint, int> shiftTable)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            if (shiftTable == null)
            {
                throw new ArgumentNullException("shiftTable");
            }

            // Check to see if there are no changes to be made.
            bool done = true;

            foreach (KeyValuePair <uint, int> pair in shiftTable)
            {
                if (pair.Value != 0)
                {
                    done = false;
                    break;
                }
            }

            // If the file is fine, quit.
            if (done)
            {
                return;
            }

            while (position < file.Length - 27)
            {
                PageHeader header = new PageHeader(file, position);
                int        size   = (int)(header.Size + header.DataSize);

                if (shiftTable.ContainsKey(header.StreamSerialNumber) &&
                    shiftTable [header.StreamSerialNumber] != 0)
                {
                    file.Seek(position);
                    ByteVector page_data = file.ReadBlock(size);

                    ByteVector new_data = ByteVector.FromUInt(
                        (uint)(header.PageSequenceNumber +
                               shiftTable [header.StreamSerialNumber]),
                        false);

                    for (int i = 18; i < 22; i++)
                    {
                        page_data [i] = new_data [i - 18];
                    }
                    for (int i = 22; i < 26; i++)
                    {
                        page_data [i] = 0;
                    }

                    new_data.Add(ByteVector.FromUInt(
                                     page_data.Checksum, false));
                    file.Seek(position + 18);
                    file.WriteBlock(new_data);
                }
                position += size;
            }
        }
Exemplo n.º 23
0
        public Page[] Paginate(out int change)
        {
            if (pages_read == 0)
            {
                change = 0;
                return(new Page[0]);
            }
            int count = pages_read;
            ByteVectorCollection packets      = new ByteVectorCollection(this.packets);
            PageHeader           first_header = (PageHeader)first_page_header;
            List <Page>          pages        = new List <Page>();
            uint index = 0;
            bool bos   = first_header.PageSequenceNumber == 0;

            if (bos)
            {
                pages.Add(new Page(new ByteVectorCollection(packets[0]), first_header));
                index++;
                packets.RemoveAt(0);
                count--;
            }
            int lacing_per_page = 0xfc;

            if (count > 0)
            {
                int total_lacing_bytes = 0;
                for (int i = 0; i < packets.Count; i++)
                {
                    total_lacing_bytes += GetLacingValueLength(packets, i);
                }
                lacing_per_page = Math.Min(total_lacing_bytes / count + 1, lacing_per_page);
            }
            int lacing_bytes_used             = 0;
            ByteVectorCollection page_packets = new ByteVectorCollection();
            bool first_packet_continued       = false;

            while (packets.Count > 0)
            {
                int  packet_bytes = GetLacingValueLength(packets, 0);
                int  remaining    = lacing_per_page - lacing_bytes_used;
                bool whole_packet = packet_bytes <= remaining;
                if (whole_packet)
                {
                    page_packets.Add(packets[0]);
                    lacing_bytes_used += packet_bytes;
                    packets.RemoveAt(0);
                }
                else
                {
                    page_packets.Add(packets[0].Mid(0, remaining * 0xff));
                    packets[0]         = packets[0].Mid(remaining * 0xff);
                    lacing_bytes_used += remaining;
                }
                if (lacing_bytes_used == lacing_per_page)
                {
                    pages.Add(new Page(page_packets, new PageHeader(first_header, index, first_packet_continued?PageFlags.FirstPacketContinued:PageFlags.None)));
                    page_packets      = new ByteVectorCollection();
                    lacing_bytes_used = 0;
                    index++;
                    count--;
                    first_packet_continued = !whole_packet;
                }
            }
            if (page_packets.Count > 0)
            {
                pages.Add(new Page(page_packets, new PageHeader(first_header.StreamSerialNumber, index, first_packet_continued?PageFlags.FirstPacketContinued:PageFlags.None)));
                index++;
                count--;
            }
            change = -count;
            return(pages.ToArray());
        }