private static object GetBoxAsObject(Stream stream, int size, MP4DataType type) { byte[] buffer = new byte[size]; if (stream.Read(buffer, 0, buffer.Length) != buffer.Length) { throw new MetaParseException("Unable to read full MP4 box content"); } switch (type) { case MP4DataType.UInt8_a: case MP4DataType.UInt8_b: if (buffer.Length != 1) { throw new MetaParseException($"Box content type {type} require data to be a single byte. number of bytes: {buffer.Length}."); } return((int)buffer[0]); case MP4DataType.Text: if (buffer.Length == 0) { return(String.Empty); } byte[] text = buffer.TakeWhile(c => c != '\0').ToArray(); return(iso_8859_1.GetString(text)); default: throw new NotImplementedException($"Unsupported box content type: {type}"); } }
private static Dictionary <MP4Tag, object> ParseIlstChild(Stream stream, string type) { Dictionary <MP4Tag, object> tags = new Dictionary <MP4Tag, object>(); byte[] childHeader = new byte[8]; if (stream.Read(childHeader, 0, childHeader.Length) != childHeader.Length) { throw new MetaParseException($"Unable to read full MP4 \"ilst.{type}\" header"); } int childSize = BitConverter.ToInt32(childHeader.Take(4).Reverse().ToArray(), 0); if (childSize < 8) { return(tags); } childSize -= 8; string childType = iso_8859_1.GetString(childHeader, 4, 4); if (childType != "data") { throw new MetaParseException($"MP4 \"ilst.{type}\" must have a child of type \"data\", actual: \"{childType}\""); } byte[] childFlags = new byte[4]; if (stream.Read(childFlags, 0, childFlags.Length) != childFlags.Length) { throw new MetaParseException($"Unable to read full MP4 \"ilst.{type}.{childType}\" flags"); } stream.Position += 4; // Ignore null bytes childSize -= 8; MP4DataType dataType = (MP4DataType)childFlags[3]; switch (type) { case "©alb": tags[MP4Tag.Album] = GetBoxAsObject(stream, childSize, dataType); break; case "©art": tags[MP4Tag.Artist] = GetBoxAsObject(stream, childSize, dataType); break; case "©cmt": tags[MP4Tag.Comment] = GetBoxAsObject(stream, childSize, dataType); break; case "©day": tags[MP4Tag.Year] = GetBoxAsObject(stream, childSize, dataType); break; case "©nam": tags[MP4Tag.Title] = GetBoxAsObject(stream, childSize, dataType); break; case "©gen": case "gnre": tags[MP4Tag.Genre] = GetBoxAsObject(stream, childSize, dataType); break; case "trkn": tags[MP4Tag.TrackNumber] = GetBoxAsObject(stream, childSize, dataType); break; case "disk": tags[MP4Tag.DiscNumber] = GetBoxAsObject(stream, childSize, dataType); break; case "©wrt": tags[MP4Tag.Composer] = GetBoxAsObject(stream, childSize, dataType); break; case "©too": tags[MP4Tag.Encoder] = GetBoxAsObject(stream, childSize, dataType); break; case "tmpo": tags[MP4Tag.BPM] = GetBoxAsObject(stream, childSize, dataType); break; case "cprt": tags[MP4Tag.Copyright] = GetBoxAsObject(stream, childSize, dataType); break; case "cpil": tags[MP4Tag.Composer] = GetBoxAsObject(stream, childSize, dataType); break; case "©grp": tags[MP4Tag.Grouping] = GetBoxAsObject(stream, childSize, dataType); break; case "catg": tags[MP4Tag.Category] = GetBoxAsObject(stream, childSize, dataType); break; case "keyw": tags[MP4Tag.Keyword] = GetBoxAsObject(stream, childSize, dataType); break; case "desc": tags[MP4Tag.Description] = GetBoxAsObject(stream, childSize, dataType); break; default: Trace.WriteLine($"[MP4Parser] ignoring ilst.{type}.{childType} data"); stream.Position += childSize; break; } return(tags); }