private bool ReadFieldInstance(StreamBuffer sb, long maximumFieldSize) { if (sb == null) throw new ArgumentNullException("sb"); string identifier = sb.ReadString(FieldIdentifierLength); string strFieldSize = sb.ReadString(FieldSizeLength); int fieldSize; if (!Int32.TryParse(strFieldSize, out fieldSize)) { #if DEBUG return false;//throw new InvalidDataException(String.Format("Size value for field {0} is not an int: {1}", identifier, strFieldSize)); #else return false; #endif } Identifier = identifier; _data = new byte[fieldSize]; sb.Read(_data, fieldSize); if (!IsValidData(_data)) return false; Data = _data; return true; }
/// <summary> /// Reads a <see cref="MpaFrame"/> from a <see cref="Stream"/>. /// </summary> /// <param name="stream">The stream.</param> /// <returns> /// true if found; otherwise, null. /// </returns> /// <exception cref="System.ArgumentNullException">Thrown if stream is null.</exception> private bool ReadFrame(StreamBuffer stream) { if (stream == null) throw new ArgumentNullException("stream"); StartOffset = stream.Position; if (!ParseHeader(stream)) return false; int frameLength = FrameLength, audioDataLength = 0; if (frameLength > FrameHeaderSize) audioDataLength = frameLength - FrameHeaderSize; if (audioDataLength == 0) return true; if ((stream.Length - stream.Position) < audioDataLength) { // Truncated audio data. audioDataLength = (int)(stream.Length - stream.Position); } AudioData = new byte[audioDataLength]; int bytesDataRead = stream.Read(AudioData, 0, audioDataLength); // Read the CRC // Create a buffer to read the CRC stored after the frame (2 bytes) if (bytesDataRead >= 2) { byte[] crc = new byte[2]; Buffer.BlockCopy(AudioData, 0, crc, 0, 2); Crc = StreamBuffer.SwitchEndianness(BitConverter.ToInt16(crc, 0)); } EndOffset = stream.Position; return true; }
private static ApeHeader ReadHeader(StreamBuffer stream, long startHeaderPosition, long endHeaderPosition) { if (stream == null) throw new ArgumentNullException("stream"); stream.Position = startHeaderPosition; while (startHeaderPosition < endHeaderPosition) { int y = 0; while (stream.ReadByte() == TagIdentifierBytes[y++]) { startHeaderPosition++; if (y != TagIdentifierBytes.Length) continue; ApeHeader hdr = new ApeHeader { Position = stream.Position - TagIdentifierBytes.Length, Version = (ApeVersion)(stream.ReadLittleEndianInt32() / 1000), Size = stream.ReadLittleEndianInt32(), FrameCount = stream.ReadLittleEndianInt32(), Flags = stream.ReadLittleEndianInt32(), ReservedBytes = new byte[8] }; stream.Read(hdr.ReservedBytes, 8); if (IsValidTag(hdr)) return hdr; startHeaderPosition -= ApeTag.HeaderSize; stream.Position = startHeaderPosition + 1; break; } startHeaderPosition++; } return null; }
/// <summary> /// Reads the header. /// </summary> /// <param name="sb">The <see cref="StreamBuffer"/>.</param> /// <returns> /// true if the header is read and valid; otherwise, false. /// </returns> /// <exception cref="System.ArgumentNullException">Thrown if <paramref name="sb"/> is null.</exception> private bool ReadHeader(StreamBuffer sb) { if (sb == null) throw new ArgumentNullException("sb"); long startPosition = sb.Position; // Sync code '11111111111110' _header = sb.ReadBigEndianInt32(); if (((_header >> 18) & FrameSync) != FrameSync) return false; /* Blocking strategy: •0 : fixed-block size stream; frame header encodes the frame number •1 : variable-block size stream; frame header encodes the sample number */ long num = ReadBigEndianUtf8Int64(sb, out _sampleFrameNumberBytes); switch (BlockingStrategy) { case FlacBlockingStrategy.FixedBlocksize: Samples = num; FrameNumber = num * (FlacStream.StreamInfoMetadataBlocks.Any() ? FlacStream.StreamInfoMetadataBlocks.First().MinimumBlockSize : 1); break; case FlacBlockingStrategy.VariableBlocksize: Samples = num; FrameNumber = -1; break; } /* Block size in inter-channel samples: •0000 : reserved •0001 : 192 samples •0010-0101 : 576 * (2 ^ (n - 2)) samples, i.e. 576/1152/2304/4608 •0110 : get 8 bit (block size - 1) from end of header •0111 : get 16 bit (block size - 1) from end of header •1000-1111 : 256 * (2 ^ (n - 8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/3276 */ int blockSize = (_header >> 12) & 0xF; switch (blockSize) { case 0x01: BlockSize = 192; break; case 0x02: case 0x03: case 0x04: case 0x05: BlockSize = 576 << (blockSize - 2); break; case 0x06: BlockSize = sb.ReadByte() + 1; break; case 0x07: BlockSize = sb.ReadBigEndianInt16() + 1; break; default: BlockSize = 256 << (blockSize - 8); break; } /* Sample rate: •0000 : get from STREAMINFO metadata block •0001 : 88.2kHz •0010 : 176.4kHz •0011 : 192kHz •0100 : 8kHz •0101 : 16kHz •0110 : 22.05kHz •0111 : 24kHz •1000 : 32kHz •1001 : 44.1kHz •1010 : 48kHz •1011 : 96kHz •1100 : get 8 bit sample rate (in kHz) from end of header •1101 : get 16 bit sample rate (in Hz) from end of header •1110 : get 16 bit sample rate (in tens of Hz) from end of header •1111 : invalid, to prevent sync-fooling string of 1s */ int samplingRate = (_header >> 8) & 0xF; if (samplingRate == 0x00) { SamplingRate = FlacStream.StreamInfoMetadataBlocks.Any() ? FlacStream.StreamInfoMetadataBlocks.First().SampleRate : 0; } else if (samplingRate <= 0x0B) { SamplingRate = SampleRates[samplingRate]; } else { switch (samplingRate) { case 0x0C: // Sample rate in kHz SamplingRate = sb.ReadByte() * 1000; break; case 0x0D: // Sample rate in Hz SamplingRate = sb.ReadBigEndianInt16(); break; case 0x0E: // Sample rate in 10s of Hz SamplingRate = sb.ReadBigEndianInt16() * 10; break; } } /* Channel assignment •0000-0111 : (number of independent channels)-1. Where defined, the channel order follows SMPTE/ITU-R recommendations. The assignments are as follows: ◦1 channel: mono ◦2 channels: left, right ◦3 channels: left, right, center ◦4 channels: front left, front right, back left, back right ◦5 channels: front left, front right, front center, back/surround left, back/surround right ◦6 channels: front left, front right, front center, LFE, back/surround left, back/surround right ◦7 channels: front left, front right, front center, LFE, back center, side left, side right ◦8 channels: front left, front right, front center, LFE, back left, back right, side left, side right •1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel •1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel •1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel •1011-1111 : reserved */ int channelAssignment = (_header >> 4) & 0xF; if (channelAssignment < 0x08) { ChannelAssignment = FlacChannelAssignment.Independent; Channels = channelAssignment + 1; } else { Channels = 2; switch (channelAssignment) { case 0x08: ChannelAssignment = FlacChannelAssignment.LeftSide; break; case 0x09: ChannelAssignment = FlacChannelAssignment.RightSide; break; case 0x0A: ChannelAssignment = FlacChannelAssignment.MidSide; break; } } /* Sample size in bits: •000 : get from STREAMINFO metadata block •001 : 8 bits per sample •010 : 12 bits per sample •011 : reserved •100 : 16 bits per sample •101 : 20 bits per sample •110 : 24 bits per sample •111 : reserved */ int sampleSize = (_header >> 0x01) & 0x07; SampleSize = (sampleSize == 0x00) ? (FlacStream.StreamInfoMetadataBlocks.Any() ? FlacStream.StreamInfoMetadataBlocks.First().BitsPerSample : 0) : SampleSizes[sampleSize]; _crc8 = sb.ReadByte(); long endPosition = sb.Position; long length = endPosition - startPosition; byte[] crcBytes = new byte[length]; sb.Position -= length; sb.Read(crcBytes, (int)length); byte crc8 = Crc8.Calculate(crcBytes); if (_crc8 != crc8) throw new InvalidDataException("Corrupt CRC8."); return true; }
////------------------------------------------------------------------------------------------------------------------------------ private static long ReadBigEndianUtf8Int64(StreamBuffer sb, out byte[] utf8Bytes) { //// Decoded long range Coded value //// 0000 0000 ・00 0000 007F 0xxxxxxx //// 0000 0080 ・00 0000 07FF 110xxxxx 10xxxxxx //// 0000 0800 ・00 0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx //// 0001 0000 ・00 001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx //// 0020 0000 ・00 03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx //// 0400 0000 ・00 7FFF FFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx //// 8000 0000 ・0F FFFF FFFF 11111110 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // Where xxx represent the bits in the uncoded value, in the same order. const int ByteCountMask = 0x80; // 10000000 const int ByteMask = 0x3F; // 00111111 int byteCount = 1; long value = sb.ReadByte(); if (value > ByteCountMask) { int bytes = 0; while (((value << bytes) & ByteCountMask) == ByteCountMask) bytes++; value &= ByteMask >> (bytes - 1); for (int i = bytes - 1; i > 0; i--) value = (value << (6 * i)) | ((long)sb.ReadByte() & ByteMask); byteCount += bytes - 1; } sb.Position -= byteCount; utf8Bytes = new byte[byteCount]; sb.Read(utf8Bytes, byteCount); return value; }
private static MusicMatchHeader ReadHeaderFooter(StreamBuffer stream, long startHeaderPosition, long endHeaderPosition, IList<byte> identifierBytes, TagOrigin tagOrigin) { if (stream == null) throw new ArgumentNullException("stream"); stream.Position = startHeaderPosition; while (startHeaderPosition < endHeaderPosition) { int y = 0; while (stream.ReadByte() == identifierBytes[y++]) { startHeaderPosition++; if (y != identifierBytes.Count) continue; if (tagOrigin == TagOrigin.Start) { MusicMatchHeader header = new MusicMatchHeader { Position = stream.Position - identifierBytes.Count, Padding1 = new byte[2], Padding2 = new byte[2], Padding3 = new byte[2], SpacePadding2 = new byte[226] }; // 0x00 0x00 Padding stream.Read(header.Padding1, header.Padding1.Length); // <8-byte numerical ASCII string> header.XingEncoderVersion = stream.ReadString(8); // 0x00 0x00 Padding stream.Read(header.Padding2, header.Padding2.Length); // Xing encoder version <8-byte numerical ASCII string> header.MusicMatchVersion = stream.ReadString(8); // 0x00 0x00 Padding stream.Read(header.Padding3, header.Padding3.Length); // Space padding <226 * 0x20 > stream.Read(header.SpacePadding2, header.SpacePadding2.Length); ValidateHeader(header, null); return header; } if (tagOrigin == TagOrigin.End) { MusicMatchHeader footer = new MusicMatchHeader { Position = stream.Position - identifierBytes.Count, SpacePadding1 = new byte[13], SpacePadding2 = new byte[12] }; // Space padding <13 * 0x20> stream.Read(footer.SpacePadding1, 13); // version <4-byte numerical ASCII string> e.g. 3.05 footer.MusicMatchVersion = stream.ReadString(4); // Space padding <12 * 0x20> stream.Read(footer.SpacePadding2, 12); ValidateHeader(null, footer); return footer; } } startHeaderPosition++; } return null; }
private bool ReadItem(ApeVersion version, int valueSize, StreamBuffer stream, long maximumItemSize) { if (stream == null) throw new ArgumentNullException("stream"); // Check if the item size indicated is really the size of the item. // Some files just aren't... properly written. byte[] data = new byte[valueSize]; int dataBytesRead = stream.Read(data, valueSize); int bytesLeftInStream = (int)(maximumItemSize - dataBytesRead); if ((valueSize > 0) && (bytesLeftInStream > 0) && (dataBytesRead >= valueSize)) { using (StreamBuffer dataBuffer = new StreamBuffer(data)) { // See if there's a next item. // Try to find the start of the next item. long startPositionNextItem = stream.Position; long bytesUntilNextItem = GetBytesUntilNextItem(version, stream, maximumItemSize - valueSize); stream.Position = startPositionNextItem; // Seems that the size indicated by the item is not the total size of the item; read the extra bytes here. if (bytesUntilNextItem > 0) { data = new byte[bytesUntilNextItem]; stream.Read(data, data.Length); dataBuffer.Write(data); } data = dataBuffer.ToByteArray(); } } Data = data; return true; }
////------------------------------------------------------------------------------------------------------------------------------ private static FlacMetadataBlock ReadBlock(StreamBuffer stream) { int flags = stream.ReadByte(); // Length int length = stream.ReadBigEndianInt(3); if (length >= stream.Length) return null; byte[] data = new byte[length]; stream.Read(data, length); FlacMetadataBlock metadataBlock; FlacMetadataBlockType blockType = (FlacMetadataBlockType)(flags & HeaderFlags.BlockType); switch (blockType) { case FlacMetadataBlockType.Padding: metadataBlock = new FlacPaddingMetadataBlock(); break; case FlacMetadataBlockType.Application: metadataBlock = new FlacApplicationMetadataBlock(); break; case FlacMetadataBlockType.StreamInfo: metadataBlock = new FlacStreamInfoMetadataBlock(); break; case FlacMetadataBlockType.SeekTable: metadataBlock = new FlacSeekTableMetadataBlock(); break; case FlacMetadataBlockType.VorbisComment: metadataBlock = new FlacVorbisCommentsMetadataBlock(); break; case FlacMetadataBlockType.CueSheet: metadataBlock = new FlacCueSheetMetadataBlock(); break; case FlacMetadataBlockType.Picture: metadataBlock = new FlacPictureMetadataBlock(); break; default: metadataBlock = new FlacMetadataBlock(); break; } metadataBlock.Flags = flags; metadataBlock.Data = data; return metadataBlock; }
/// <summary> /// Reads the <see cref="Id3v2FrameEncodingType"/> from the stream. /// </summary> /// <param name="streamBuffer">The stream buffer.</param> /// <returns> /// The <see cref="Id3v2FrameEncodingType"/>. /// </returns> /// <remarks> /// Since the encoding type is first read from the stream, the position should be set to the byte containing the encoding type. /// If the encoding type is <see cref="Id3v2FrameEncodingType.UTF16LittleEndian"/>, /// it will try to read the byte order marker from the stream /// to see if the encoding type is <see cref="Id3v2FrameEncodingType.UTF16BigEndian"/>. /// If no byte order marker is found or if the byte order marker is not recognized, /// it will return <see cref="Id3v2FrameEncodingType.UTF16LittleEndian"/> as default encoding. /// <para /> /// The position of the stream will not be modified. /// </remarks> public static Id3v2FrameEncodingType ReadEncodingTypeFromStream(StreamBuffer streamBuffer) { int encodingByte = streamBuffer.ReadByte(); if ((encodingByte == -1) || !IsValidEncodingType(encodingByte)) return Id3v2FrameEncodingType.Default; if (encodingByte > (byte)Id3v2FrameEncodingType.UTF16LittleEndian) encodingByte += 1; // Cast the encoding type. Id3v2FrameEncodingType encodingType = (Id3v2FrameEncodingType)encodingByte; // If it's not little endian, then we don't need to figure out if it's little or big; return here. if (encodingType != Id3v2FrameEncodingType.UTF16LittleEndian) return encodingType; // See which byte order the frame encoding is. byte[] byteOrderMarker = new byte[2]; // Not enough bytes available; probably little endian then. if (streamBuffer.Read(byteOrderMarker, 2, false) < 2) return Id3v2FrameEncodingType.UTF16LittleEndian; // Little endian byte order marker? if (((byteOrderMarker[0] == 0xFF) && (byteOrderMarker[1] == 0xFE)) || ((byteOrderMarker[0] == 0x00) && (byteOrderMarker[1] == 0x00))) return Id3v2FrameEncodingType.UTF16LittleEndian; // Big endian byte order marker? if ((byteOrderMarker[0] == 0xFE) && (byteOrderMarker[1] == 0xFF)) return Id3v2FrameEncodingType.UTF16BigEndian; // Default to little endian. return Id3v2FrameEncodingType.UTF16LittleEndian; }
public void ReadTestMovePositionTrue() { byte[] msBuffer = { 0x90, 0x10, 0xAA, 0x02, 0xFF }; StreamBuffer target = new StreamBuffer(msBuffer); byte[] buffer = new byte[msBuffer.Length]; target.Read(buffer, msBuffer.Length); Assert.IsTrue(target.Position == msBuffer.Length); }
public void ReadTestByteArraysAreEqualUsingMemoryStream() { byte[] msBuffer = { 0x90, 0x10, 0xAA, 0x02, 0xFF }; MemoryStream ms = new MemoryStream(msBuffer); StreamBuffer target = new StreamBuffer(ms); byte[] buffer = new byte[msBuffer.Length]; target.Read(buffer, 0, msBuffer.Length); Assert.IsTrue(msBuffer.SequenceEqual(buffer)); }
public void ReadTestAmountOfBytesReadUsingMemoryStream() { byte[] msBuffer = { 0x90, 0x10, 0xAA, 0x02, 0xFF }; MemoryStream ms = new MemoryStream(msBuffer); StreamBuffer target = new StreamBuffer(ms); byte[] buffer = new byte[msBuffer.Length]; int expected = msBuffer.Length; int actual = target.Read(buffer, 0, expected); Assert.AreEqual(expected, actual); }