public void StreamUtils_BE24UintConverters() { uint intValue = 0x00873529; Assert.AreEqual((uint)0x00FFFFFF, StreamUtils.DecodeBEUInt24(new byte[3] { 0xFF, 0xFF, 0xFF })); byte[] byteValue = StreamUtils.EncodeBEUInt24(intValue); Assert.AreEqual(intValue, StreamUtils.DecodeBEUInt24(byteValue)); }
// TODO : support for CUESHEET block public bool Read(BinaryReader source, ReadTagParams readTagParams) { bool result = false; if (readTagParams.ReadTag && null == vorbisTag) { vorbisTag = new VorbisTag(false, false, false, false); } initialPaddingOffset = -1; initialPaddingSize = 0; byte[] aMetaDataBlockHeader; long position; uint blockLength; byte blockType; int blockIndex; bool isLast; bool paddingFound = false; long blockEndOffset = -1; readHeader(source); // Process data if loaded and header valid if (header.IsValid()) { int channels = (header.Info[12] >> 1) & 0x7; switch (channels) { case 0b0000: channelsArrangement = MONO; break; case 0b0001: channelsArrangement = STEREO; break; case 0b0010: channelsArrangement = ISO_3_0_0; break; case 0b0011: channelsArrangement = QUAD; break; case 0b0100: channelsArrangement = ISO_3_2_0; break; case 0b0101: channelsArrangement = ISO_3_2_1; break; case 0b0110: channelsArrangement = LRCLFECrLssRss; break; case 0b0111: channelsArrangement = LRCLFELrRrLssRss; break; case 0b1000: channelsArrangement = JOINT_STEREO_LEFT_SIDE; break; case 0b1001: channelsArrangement = JOINT_STEREO_RIGHT_SIDE; break; case 0b1010: channelsArrangement = JOINT_STEREO_MID_SIDE; break; default: channelsArrangement = UNKNOWN; break; } sampleRate = header.Info[10] << 12 | header.Info[11] << 4 | header.Info[12] >> 4; bitsPerSample = (byte)(((header.Info[12] & 1) << 4) | (header.Info[13] >> 4) + 1); samples = header.Info[14] << 24 | header.Info[15] << 16 | header.Info[16] << 8 | header.Info[17]; if (0 == (header.MetaDataBlockHeader[1] & FLAG_LAST_METADATA_BLOCK)) // metadata block exists { blockIndex = 0; vorbisTag.Clear(); if (readTagParams.PrepareForWriting) { if (null == zones) { zones = new List <Zone>(); } else { zones.Clear(); } blockEndOffset = source.BaseStream.Position; } do // Read all metadata blocks { aMetaDataBlockHeader = source.ReadBytes(4); isLast = (aMetaDataBlockHeader[0] & FLAG_LAST_METADATA_BLOCK) > 0; // last flag ( first bit == 1 ) blockIndex++; blockLength = StreamUtils.DecodeBEUInt24(aMetaDataBlockHeader, 1); blockType = (byte)(aMetaDataBlockHeader[0] & 0x7F); // decode metablock type position = source.BaseStream.Position; if (blockType == META_VORBIS_COMMENT) // Vorbis metadata { if (readTagParams.PrepareForWriting) { zones.Add(new Zone(blockType + "", position - 4, (int)blockLength + 4, new byte[0], blockType)); } vorbisTag.Read(source, readTagParams); } else if ((blockType == META_PADDING) && (!paddingFound)) // Padding block (skip any other padding block) { if (readTagParams.PrepareForWriting) { zones.Add(new Zone(PADDING_ZONE_NAME, position - 4, (int)blockLength + 4, new byte[0], blockType)); } initialPaddingSize = blockLength; initialPaddingOffset = position; paddingFound = true; source.BaseStream.Seek(blockLength, SeekOrigin.Current); } else if (blockType == META_PICTURE) // Picture (NB: as per FLAC specs, pictures must be embedded at the FLAC level, not in the VorbisComment !) { if (readTagParams.PrepareForWriting) { zones.Add(new Zone(blockType + "", position - 4, (int)blockLength + 4, new byte[0], blockType)); } vorbisTag.ReadPicture(source.BaseStream, readTagParams); } else // Unhandled block; needs to be zoned anyway to be able to manage the 'isLast' flag at write-time { if (readTagParams.PrepareForWriting) { zones.Add(new Zone(blockType + "", position - 4, (int)blockLength + 4, new byte[0], blockType)); } } if (blockType < 7) { source.BaseStream.Seek(position + blockLength, SeekOrigin.Begin); blockEndOffset = position + blockLength; } else { // Abnormal header : incorrect size and/or misplaced last-metadata-block flag break; } }while (!isLast); if (readTagParams.PrepareForWriting) { bool vorbisTagFound = false; bool pictureFound = false; foreach (Zone zone in zones) { if (zone.Flag == META_PICTURE) { pictureFound = true; } else if (zone.Flag == META_VORBIS_COMMENT) { vorbisTagFound = true; } } if (!vorbisTagFound) { zones.Add(new Zone(META_VORBIS_COMMENT + "", blockEndOffset, 0, new byte[0], META_VORBIS_COMMENT)); } if (!pictureFound) { zones.Add(new Zone(META_PICTURE + "", blockEndOffset, 0, new byte[0], META_PICTURE)); } // Padding must be the last block for it to correctly absorb size variations of the other blocks if (!paddingFound && Settings.AddNewPadding) { zones.Add(new Zone(PADDING_ZONE_NAME, blockEndOffset, 0, new byte[0], META_PADDING)); } } } } if (isValid()) { audioOffset = source.BaseStream.Position; // we need that to calculate the bitrate result = true; } return(result); }
public void StreamUtils_Exceptions() { Assert.IsFalse(StreamUtils.ArrEqualsArr(new byte[1], new byte[2])); Assert.IsFalse(StreamUtils.StringEqualsArr(".", new char[2])); try { StreamUtils.DecodeBEUInt16(new byte[1]); Assert.Fail(); } catch { } try { StreamUtils.DecodeUInt16(new byte[1]); Assert.Fail(); } catch { } try { StreamUtils.DecodeInt16(new byte[1]); Assert.Fail(); } catch { } try { StreamUtils.DecodeBEInt16(new byte[1]); Assert.Fail(); } catch { } try { StreamUtils.DecodeBEInt24(new byte[2]); Assert.Fail(); } catch { } try { StreamUtils.DecodeBEUInt24(new byte[2]); Assert.Fail(); } catch { } try { StreamUtils.EncodeBEUInt24(0x01FFFFFF); Assert.Fail(); } catch { } try { StreamUtils.DecodeBEUInt32(new byte[3]); Assert.Fail(); } catch { } try { StreamUtils.DecodeUInt32(new byte[3]); Assert.Fail(); } catch { } try { StreamUtils.DecodeBEInt32(new byte[3]); Assert.Fail(); } catch { } try { StreamUtils.DecodeInt32(new byte[3]); Assert.Fail(); } catch { } try { StreamUtils.DecodeUInt64(new byte[7]); Assert.Fail(); } catch { } try { StreamUtils.DecodeBEInt64(new byte[7]); Assert.Fail(); } catch { } try { StreamUtils.DecodeSynchSafeInt(new byte[6]); Assert.Fail(); } catch { } try { StreamUtils.DecodeSynchSafeInt32(new byte[6]); Assert.Fail(); } catch { } try { StreamUtils.EncodeSynchSafeInt(1, 0); Assert.Fail(); } catch { } try { StreamUtils.EncodeSynchSafeInt(1, 6); Assert.Fail(); } catch { } try { StreamUtils.ReadBits(new BinaryReader(new MemoryStream()), 0, 0); Assert.Fail(); } catch { } try { StreamUtils.ReadBits(new BinaryReader(new MemoryStream()), 0, 33); Assert.Fail(); } catch { } }
public Boolean Read(BinaryReader source, ReadTagParams readTagParams) { var result = false; if (readTagParams.ReadTag && null == vorbisTag) { vorbisTag = new VorbisTag(false, false, false); } Byte[] aMetaDataBlockHeader; Int64 position; UInt32 blockLength; Int32 blockType; Int32 blockIndex; Boolean isLast; var bPaddingFound = false; readHeader(source); // Process data if loaded and header valid if (header.IsValid()) { channels = (Byte)(((header.Info[12] >> 1) & 0x7) + 1); sampleRate = (header.Info[10] << 12 | header.Info[11] << 4 | header.Info[12] >> 4); bitsPerSample = (Byte)(((header.Info[12] & 1) << 4) | (header.Info[13] >> 4) + 1); samples = (header.Info[14] << 24 | header.Info[15] << 16 | header.Info[16] << 8 | header.Info[17]); if (0 == (header.MetaDataBlockHeader[1] & 0x80)) // metadata block exists { blockIndex = 0; if (readTagParams.PrepareForWriting) { if (null == zones) { zones = new List <Zone>(); } else { zones.Clear(); } firstBlockPosition = source.BaseStream.Position; } do // read more metadata blocks if available { aMetaDataBlockHeader = source.ReadBytes(4); isLast = ((aMetaDataBlockHeader[0] & 0x80) > 0); // last flag ( first bit == 1 ) blockIndex++; blockLength = StreamUtils.DecodeBEUInt24(aMetaDataBlockHeader, 1); blockType = (aMetaDataBlockHeader[0] & 0x7F); // decode metablock type position = source.BaseStream.Position; if (blockType == META_VORBIS_COMMENT) // Vorbis metadata { if (readTagParams.PrepareForWriting) { zones.Add(new Zone(ZONE_VORBISTAG, position - 4, (Int32)blockLength + 4, new Byte[0], (Byte)(isLast ? 1 : 0))); } vorbisTag.Read(source, readTagParams); } else if ((blockType == META_PADDING) && (!bPaddingFound)) // Padding block { padding = blockLength; // if we find more skip & put them in metablock array paddingLast = ((aMetaDataBlockHeader[0] & 0x80) != 0); paddingIndex = blockIndex; bPaddingFound = true; source.BaseStream.Seek(padding, SeekOrigin.Current); // advance into file till next block or audio data start } else if (blockType == META_PICTURE) { if (readTagParams.PrepareForWriting) { zones.Add(new Zone(ZONE_PICTURE, position - 4, (Int32)blockLength + 4, new Byte[0], (Byte)(isLast ? 1 : 0))); } vorbisTag.ReadPicture(source.BaseStream, readTagParams); } // TODO : support for CUESHEET block if (blockType < 7) { source.BaseStream.Seek(position + blockLength, SeekOrigin.Begin); } else { // Abnormal header : incorrect size and/or misplaced last-metadata-block flag break; } }while (!isLast); if (readTagParams.PrepareForWriting) { var vorbisTagFound = false; var pictureFound = false; foreach (var zone in zones) { if (zone.Name.Equals(ZONE_PICTURE)) { pictureFound = true; } else if (zone.Name.Equals(ZONE_VORBISTAG)) { vorbisTagFound = true; } } if (!vorbisTagFound) { zones.Add(new Zone(ZONE_VORBISTAG, firstBlockPosition, 0, new Byte[0])); } if (!pictureFound) { zones.Add(new Zone(ZONE_PICTURE, firstBlockPosition, 0, new Byte[0])); } } } } if (isValid()) { audioOffset = source.BaseStream.Position; // we need that to rebuild the file if nedeed result = true; } return(result); }
public bool Read(BinaryReader source, ReadTagParams readTagParams) { bool result = false; if (readTagParams.ReadTag && null == vorbisTag) { vorbisTag = new VorbisTag(false, false, false); } byte[] aMetaDataBlockHeader; long position; uint blockLength; int blockType; int blockIndex; bool isLast; bool bPaddingFound = false; readHeader(source); // Process data if loaded and header valid if (header.IsValid()) { int channels = (header.Info[12] >> 1) & 0x7; switch (channels) { case 0b0000: channelsArrangement = MONO; break; case 0b0001: channelsArrangement = STEREO; break; case 0b0010: channelsArrangement = ISO_3_0_0; break; case 0b0011: channelsArrangement = QUAD; break; case 0b0100: channelsArrangement = ISO_3_2_0; break; case 0b0101: channelsArrangement = ISO_3_2_1; break; case 0b0110: channelsArrangement = LRCLFECrLssRss; break; case 0b0111: channelsArrangement = LRCLFELrRrLssRss; break; case 0b1000: channelsArrangement = JOINT_STEREO_LEFT_SIDE; break; case 0b1001: channelsArrangement = JOINT_STEREO_RIGHT_SIDE; break; case 0b1010: channelsArrangement = JOINT_STEREO_MID_SIDE; break; default: channelsArrangement = UNKNOWN; break; } sampleRate = (header.Info[10] << 12 | header.Info[11] << 4 | header.Info[12] >> 4); bitsPerSample = (byte)(((header.Info[12] & 1) << 4) | (header.Info[13] >> 4) + 1); samples = (header.Info[14] << 24 | header.Info[15] << 16 | header.Info[16] << 8 | header.Info[17]); if (0 == (header.MetaDataBlockHeader[1] & 0x80)) // metadata block exists { blockIndex = 0; vorbisTag.Clear(); if (readTagParams.PrepareForWriting) { if (null == zones) { zones = new List <Zone>(); } else { zones.Clear(); } firstBlockPosition = source.BaseStream.Position; } do // read more metadata blocks if available { aMetaDataBlockHeader = source.ReadBytes(4); isLast = ((aMetaDataBlockHeader[0] & 0x80) > 0); // last flag ( first bit == 1 ) blockIndex++; blockLength = StreamUtils.DecodeBEUInt24(aMetaDataBlockHeader, 1); blockType = (aMetaDataBlockHeader[0] & 0x7F); // decode metablock type position = source.BaseStream.Position; if (blockType == META_VORBIS_COMMENT) // Vorbis metadata { if (readTagParams.PrepareForWriting) { zones.Add(new Zone(ZONE_VORBISTAG, position - 4, (int)blockLength + 4, new byte[0], (byte)(isLast ? 1 : 0))); } vorbisTag.Read(source, readTagParams); } else if ((blockType == META_PADDING) && (!bPaddingFound)) // Padding block { padding = blockLength; // if we find more skip & put them in metablock array paddingLast = ((aMetaDataBlockHeader[0] & 0x80) != 0); paddingIndex = blockIndex; bPaddingFound = true; source.BaseStream.Seek(padding, SeekOrigin.Current); // advance into file till next block or audio data start } else if (blockType == META_PICTURE) { if (readTagParams.PrepareForWriting) { zones.Add(new Zone(ZONE_PICTURE, position - 4, (int)blockLength + 4, new byte[0], (byte)(isLast ? 1 : 0))); } vorbisTag.ReadPicture(source.BaseStream, readTagParams); } // TODO : support for CUESHEET block if (blockType < 7) { source.BaseStream.Seek(position + blockLength, SeekOrigin.Begin); } else { // Abnormal header : incorrect size and/or misplaced last-metadata-block flag break; } }while (!isLast); if (readTagParams.PrepareForWriting) { bool vorbisTagFound = false; bool pictureFound = false; foreach (Zone zone in zones) { if (zone.Name.Equals(ZONE_PICTURE)) { pictureFound = true; } else if (zone.Name.Equals(ZONE_VORBISTAG)) { vorbisTagFound = true; } } if (!vorbisTagFound) { zones.Add(new Zone(ZONE_VORBISTAG, firstBlockPosition, 0, new byte[0])); } if (!pictureFound) { zones.Add(new Zone(ZONE_PICTURE, firstBlockPosition, 0, new byte[0])); } } } } if (isValid()) { audioOffset = source.BaseStream.Position; // we need that to rebuild the file if nedeed result = true; } return(result); }