private void readFrames(BinaryReader source, TagInfo Tag, MetaDataIO.ReadTagParams readTagParams) { string frameName; string strValue; int frameDataSize; long valuePosition; int frameFlags; source.BaseStream.Seek(Tag.FileSize - Tag.DataShift - Tag.Size, SeekOrigin.Begin); // Read all stored fields for (int iterator = 0; iterator < Tag.FrameCount; iterator++) { frameDataSize = source.ReadInt32(); frameFlags = source.ReadInt32(); frameName = StreamUtils.ReadNullTerminatedString(source, Utils.Latin1Encoding); // Slightly more permissive than what APE specs indicate in terms of allowed characters ("Space(0x20), Slash(0x2F), Digits(0x30...0x39), Letters(0x41...0x5A, 0x61...0x7A)") valuePosition = source.BaseStream.Position; if ((frameDataSize > 0) && (frameDataSize <= 500)) { /* * According to spec : "Items are not zero-terminated like in C / C++. * If there's a zero character, multiple items are stored under the key and the items are separated by zero characters." * * => Values have to be splitted */ strValue = Utils.StripEndingZeroChars(Encoding.UTF8.GetString(source.ReadBytes(frameDataSize))); strValue = strValue.Replace('\0', Settings.InternalValueSeparator).Trim(); SetMetaField(frameName.Trim().ToUpper(), strValue, readTagParams.ReadAllMetaFrames); } else if (frameDataSize > 0) // Size > 500 => Probably an embedded picture { int picturePosition; PictureInfo.PIC_TYPE picType = decodeAPEPictureType(frameName); if (picType.Equals(PictureInfo.PIC_TYPE.Unsupported)) { addPictureToken(getImplementedTagType(), frameName); picturePosition = takePicturePosition(getImplementedTagType(), frameName); } else { addPictureToken(picType); picturePosition = takePicturePosition(picType); } if (readTagParams.ReadPictures || readTagParams.PictureStreamHandler != null) { // Description seems to be a null-terminated ANSI string containing // * The frame name // * A byte (0x2E) // * The picture type (3 characters; similar to the 2nd part of the mime-type) String description = StreamUtils.ReadNullTerminatedString(source, Utils.Latin1Encoding); ImageFormat imgFormat = ImageUtils.GetImageFormatFromMimeType(description.Substring(description.Length - 3, 3)); PictureInfo picInfo = new PictureInfo(imgFormat, picType, getImplementedTagType(), frameName, picturePosition); picInfo.Description = description; picInfo.PictureData = new byte[frameDataSize - description.Length - 1]; source.BaseStream.Read(picInfo.PictureData, 0, frameDataSize - description.Length - 1); tagData.Pictures.Add(picInfo); if (readTagParams.PictureStreamHandler != null) { MemoryStream mem = new MemoryStream(picInfo.PictureData); readTagParams.PictureStreamHandler(ref mem, picInfo.PicType, picInfo.NativeFormat, picInfo.TagType, picInfo.NativePicCode, picInfo.Position); mem.Close(); } } } source.BaseStream.Seek(valuePosition + frameDataSize, SeekOrigin.Begin); } }
public void readTagField(BinaryReader source, string zoneCode, string fieldName, ushort fieldDataType, int fieldDataSize, ReadTagParams readTagParams, bool isExtendedHeader = false, ushort languageIndex = 0, ushort streamNumber = 0) { string fieldValue = ""; bool setMeta = true; addFrameClass(fieldName, fieldDataType); if (0 == fieldDataType) // Unicode string { fieldValue = Utils.StripEndingZeroChars(Encoding.Unicode.GetString(source.ReadBytes(fieldDataSize))); } else if (1 == fieldDataType) // Byte array { if (fieldName.ToUpper().Equals("WM/PICTURE")) { byte picCode = source.ReadByte(); // TODO factorize : abstract PictureTypeDecoder + unsupported / supported decision in MetaDataIO ? PictureInfo.PIC_TYPE picType = ID3v2.DecodeID3v2PictureType(picCode); int picturePosition; if (picType.Equals(PictureInfo.PIC_TYPE.Unsupported)) { addPictureToken(MetaDataIOFactory.TAG_NATIVE, picCode); picturePosition = takePicturePosition(MetaDataIOFactory.TAG_NATIVE, picCode); } else { addPictureToken(picType); picturePosition = takePicturePosition(picType); } if (readTagParams.ReadPictures) { int picSize = source.ReadInt32(); string mimeType = StreamUtils.ReadNullTerminatedString(source, Encoding.Unicode); string description = StreamUtils.ReadNullTerminatedString(source, Encoding.Unicode); PictureInfo picInfo = PictureInfo.fromBinaryData(source.BaseStream, picSize, picType, getImplementedTagType(), picCode, picturePosition); picInfo.Description = description; tagData.Pictures.Add(picInfo); } setMeta = false; } else { source.BaseStream.Seek(fieldDataSize, SeekOrigin.Current); } } else if (2 == fieldDataType) // 16-bit Boolean (metadata); 32-bit Boolean (extended header) { if (isExtendedHeader) { fieldValue = source.ReadUInt32().ToString(); } else { fieldValue = source.ReadUInt16().ToString(); } } else if (3 == fieldDataType) // 32-bit unsigned integer { uint intValue = source.ReadUInt32(); if (fieldName.Equals("WM/GENRE", StringComparison.OrdinalIgnoreCase)) { intValue++; } fieldValue = intValue.ToString(); } else if (4 == fieldDataType) // 64-bit unsigned integer { fieldValue = source.ReadUInt64().ToString(); } else if (5 == fieldDataType) // 16-bit unsigned integer { fieldValue = source.ReadUInt16().ToString(); } else if (6 == fieldDataType) // 128-bit GUID; unused for now { source.BaseStream.Seek(fieldDataSize, SeekOrigin.Current); } if (setMeta) { SetMetaField(fieldName.Trim(), fieldValue, readTagParams.ReadAllMetaFrames, zoneCode, 0, streamNumber, decodeLanguage(source.BaseStream, languageIndex)); } }
private bool readFrames(BinaryReader source, TagInfo Tag, MetaDataIO.ReadTagParams readTagParams) { string frameName; string strValue; int frameDataSize; long valuePosition; int frameFlags; source.BaseStream.Seek(Tag.FileSize - Tag.DataShift - Tag.Size, SeekOrigin.Begin); // Read all stored fields for (int iterator = 0; iterator < Tag.FrameCount; iterator++) { frameDataSize = source.ReadInt32(); frameFlags = source.ReadInt32(); frameName = StreamUtils.ReadNullTerminatedString(source, Utils.Latin1Encoding); // Slightly more permissive than what APE specs indicate in terms of allowed characters ("Space(0x20), Slash(0x2F), Digits(0x30...0x39), Letters(0x41...0x5A, 0x61...0x7A)") valuePosition = source.BaseStream.Position; if (frameDataSize < 0 || valuePosition + frameDataSize > Tag.FileSize) { LogDelegator.GetLogDelegate()(Log.LV_ERROR, "Invalid value found while reading APEtag frame"); return(false); } if ((frameDataSize > 0) && (frameDataSize <= 1000)) { /* * According to spec : "Items are not zero-terminated like in C / C++. * If there's a zero character, multiple items are stored under the key and the items are separated by zero characters." * * => Values have to be splitted */ strValue = Utils.StripEndingZeroChars(Encoding.UTF8.GetString(source.ReadBytes(frameDataSize))); strValue = strValue.Replace('\0', Settings.InternalValueSeparator).Trim(); SetMetaField(frameName.Trim().ToUpper(), strValue, readTagParams.ReadAllMetaFrames); } else if (frameDataSize > 0 && !frameName.ToLower().Contains("lyrics")) // Size > 1000 => Probably an embedded picture { int picturePosition; PictureInfo.PIC_TYPE picType = decodeAPEPictureType(frameName); if (picType.Equals(PictureInfo.PIC_TYPE.Unsupported)) { addPictureToken(getImplementedTagType(), frameName); picturePosition = takePicturePosition(getImplementedTagType(), frameName); } else { addPictureToken(picType); picturePosition = takePicturePosition(picType); } if (readTagParams.ReadPictures) { // Description seems to be a null-terminated ANSI string containing // * The frame name // * A byte (0x2E) // * The picture type (3 characters; similar to the 2nd part of the mime-type) string description = StreamUtils.ReadNullTerminatedString(source, Utils.Latin1Encoding); PictureInfo picInfo = PictureInfo.fromBinaryData(source.BaseStream, frameDataSize - description.Length - 1, picType, getImplementedTagType(), frameName, picturePosition); picInfo.Description = description; tagData.Pictures.Add(picInfo); } } source.BaseStream.Seek(valuePosition + frameDataSize, SeekOrigin.Begin); } return(true); }