public void UnitE_Big24ToInt() { var buf = new byte[] { 0x12, 0xA4, 0xCD, 0x45 }; var result = ConvertTo.FromBig24ToInt32(buf, 1); Assert.AreEqual(result.GetType(), typeof(Int32)); Assert.AreEqual(0xA4CD45, result); }
public Model(Stream stream, byte[] hdr, string path) { base._data = Data = new FlacFormat(this, stream, path); Data.MetadataBlockStreamInfoSize = ConvertTo.FromBig24ToInt32(hdr, 5); if (Data.MetadataBlockStreamInfoSize < 34) { IssueModel.Add($"Bad metablock size of {Data.MetadataBlockStreamInfoSize}", Severity.Fatal); return; } var bb = new byte[Data.MetadataBlockStreamInfoSize]; Data.ValidSize = 8; Data.fbs.Position = Data.ValidSize; var got = Data.fbs.Read(bb, 0, Data.MetadataBlockStreamInfoSize); if (got != Data.MetadataBlockStreamInfoSize) { IssueModel.Add("File truncated", Severity.Fatal); return; } Data.MinBlockSize = ConvertTo.FromBig16ToInt32(bb, 0); Data.MinBlockSize = ConvertTo.FromBig16ToInt32(bb, 2); Data.MinFrameSize = ConvertTo.FromBig24ToInt32(bb, 4); Data.MaxFrameSize = ConvertTo.FromBig24ToInt32(bb, 7); Data.MetaSampleRate = bb[10] << 12 | bb[11] << 4 | bb[12] >> 4; Data.ChannelCount = ((bb[12] & 0x0E) >> 1) + 1; Data.BitsPerSample = (((bb[12] & 1) << 4) | (bb[13] >> 4)) + 1; Data.TotalSamples = ((bb[13] & 0x0F) << 32) | bb[14] << 24 | bb[15] << 16 | bb[16] << 8 | bb[17]; Data.mHdr = bb; Data.storedAudioDataMD5 = new byte[16]; Array.Copy(bb, 18, Data.storedAudioDataMD5, 0, 16); Data.ValidSize += Data.MetadataBlockStreamInfoSize; for (;;) { bb = new byte[12]; try { Data.fbs.Position = Data.ValidSize; } catch (EndOfStreamException) { IssueModel.Add("File truncated near meta data", Severity.Fatal); return; } Data.fbs.Position = Data.ValidSize; got = Data.fbs.Read(bb, 0, 4); if (got != 4) { IssueModel.Add("File truncated near meta data", Severity.Fatal); return; } var blockSize = ConvertTo.FromBig24ToInt32(bb, 1); Data.ValidSize += 4; switch ((FlacBlockType)(bb[0] & 0x7F)) { case FlacBlockType.Padding: Data.Blocks.AddPad(blockSize); break; case FlacBlockType.Application: got = Data.fbs.Read(bb, 0, 4); if (got != 4) { IssueModel.Add("File truncated near tags", Severity.Fatal); return; } int appId = ConvertTo.FromBig32ToInt32(bb, 0); Data.Blocks.AddApp(blockSize, appId); break; case FlacBlockType.SeekTable: var st = new byte[blockSize]; got = Data.fbs.Read(st, 0, blockSize); if (got != blockSize) { IssueModel.Add("File truncated near seek table", Severity.Fatal); return; } Data.Blocks.AddSeekTable(blockSize, st); break; case FlacBlockType.Tags: bb = new byte[blockSize]; Data.fbs.Position = Data.ValidSize; got = Data.fbs.Read(bb, 0, blockSize); if (got != blockSize) { IssueModel.Add("File truncated near tags", Severity.Fatal); return; } if (Data.Blocks.Tags != null) { IssueModel.Add("Contains multiple tag blocks", Severity.Error); } else { Data.Blocks.AddTags(blockSize, bb); } break; case FlacBlockType.CueSheet: var sb = new byte[284]; got = Data.fbs.Read(sb, 0, 284); if (got != 284) { IssueModel.Add("File truncated near cuesheet", Severity.Fatal); return; } var isCD = (sb[24] & 0x80) != 0; int trackCount = sb[283]; Data.Blocks.AddCuesheet(blockSize, isCD, trackCount); break; case FlacBlockType.Picture: var pb = new byte[blockSize]; got = Data.fbs.Read(pb, 0, blockSize); if (got != blockSize) { IssueModel.Add("File truncated near picture", Severity.Fatal); return; } var picType = (PicType)ConvertTo.FromBig32ToInt32(pb, 0); var mimeLen = ConvertTo.FromBig32ToInt32(pb, 4); var mime = Encoding.UTF8.GetString(pb, 8, mimeLen); var descLen = ConvertTo.FromBig32ToInt32(pb, mimeLen + 8); var desc = Encoding.UTF8.GetString(pb, mimeLen + 12, descLen); var width = ConvertTo.FromBig32ToInt32(pb, mimeLen + descLen + 12); var height = ConvertTo.FromBig32ToInt32(pb, mimeLen + descLen + 16); Data.Blocks.AddPic(blockSize, picType, width, height); break; default: IssueModel.Add("Encountered unexpected metadata block type of " + (bb[0] & 0x7F), Severity.Fatal); return; } Data.ValidSize += blockSize; if ((bb[0] & 0x80) != 0) { break; } } try { Data.fbs.Position = Data.ValidSize; } catch (EndOfStreamException) { IssueModel.Add("File truncated near frame header", Severity.Fatal); return; } got = Data.fbs.Read(bb, 0, 4); if (got != 4) { IssueModel.Add("File truncated", Severity.Fatal); return; } // Detect frame header sync code if (bb[0] != 0xFF || (bb[1] & 0xFC) != 0xF8) { IssueModel.Add("Audio data not found", Severity.Fatal); return; } Data.mediaPosition = Data.ValidSize; Data.SampleOrFrameNumber = Data.fbs.ReadWobbly(out byte[] wtfBuf); if (Data.SampleOrFrameNumber < 0) { IssueModel.Add("File truncated or badly formed sample/frame number.", Severity.Fatal); return; } Array.Copy(wtfBuf, 0, bb, 4, wtfBuf.Length); int bPos = 4 + wtfBuf.Length; Data.RawBlockingStrategy = bb[1] & 1; Data.RawBlockSize = bb[2] >> 4; if (Data.RawBlockSize == 0) { Data.BlockSize = 0; } else if (Data.RawBlockSize == 1) { Data.BlockSize = 192; } else if (Data.RawBlockSize >= 2 && Data.RawBlockSize <= 5) { Data.BlockSize = 576 * (1 << (Data.RawBlockSize - 2)); } else if (Data.RawBlockSize == 6) { got = Data.fbs.Read(bb, bPos, 1); Data.BlockSize = bb[bPos] + 1; bPos += 1; } else if (Data.RawBlockSize == 7) { got = Data.fbs.Read(bb, bPos, 2); Data.BlockSize = (bb[bPos] << 8) + bb[bPos + 1] + 1; bPos += 2; } else { Data.BlockSize = 256 * (1 << (Data.RawBlockSize - 8)); } Data.RawSampleRate = bb[2] & 0xF; if (Data.RawSampleRate == 0xC) { got = Data.fbs.Read(bb, bPos, 1); Data.SampleRateText = bb[bPos] + "kHz"; bPos += 1; } else if (Data.RawSampleRate == 0xD || Data.RawSampleRate == 0xE) { got = Data.fbs.Read(bb, bPos, 2); Data.SampleRateText = (bb[bPos] << 8).ToString() + bb[bPos + 1] + (Data.RawSampleRate == 0xD? " Hz" : " kHz"); bPos += 2; } else if (Data.RawSampleRate == 0) { Data.SampleRateText = Data.MetaSampleRate.ToString() + " Hz"; } else { Data.SampleRateText = SampleRateMap[Data.RawSampleRate]; } Data.RawChannelAssignment = bb[3] >> 4; Data.RawSampleSize = (bb[3] & 0xE) >> 1; if (Data.RawSampleSize == 0) { Data.SampleSizeText = Data.BitsPerSample.ToString() + " bits"; } else { Data.SampleSizeText = SampleSizeMap[Data.RawSampleSize]; } Data.aHdr = new byte[bPos]; Array.Copy(bb, Data.aHdr, bPos); Data.ValidSize += bPos; Data.fbs.Position = Data.ValidSize; int octet = Data.fbs.ReadByte(); if (octet < 0) { IssueModel.Add("File truncated near CRC-8", Severity.Fatal); return; } Data.StoredAudioHeaderCRC8 = (Byte)octet; try { Data.fbs.Position = Data.mediaPosition; } catch (EndOfStreamException) { IssueModel.Add("File truncated near audio data", Severity.Fatal); return; } try { Data.fbs.Position = Data.FileSize - 2; } catch (EndOfStreamException) { IssueModel.Add("File truncated looking for end", Severity.Fatal); return; } bb = new byte[2]; if (Data.fbs.Read(bb, 0, 2) != 2) { IssueModel.Add("Read failed on audio block CRC-16", Severity.Fatal); return; } Data.StoredAudioBlockCRC16 = (UInt16)(bb[0] << 8 | bb[1]); Data.MediaCount = Data.FileSize - Data.mediaPosition; GetDiagnostics(); }