public void WritePicture(BinaryWriter picW, byte[] pictureData, string mimeType, int pictureTypeCode, string picDescription) { picW.Write(StreamUtils.EncodeBEInt32(pictureTypeCode)); picW.Write(StreamUtils.EncodeBEInt32(mimeType.Length)); picW.Write(Utils.Latin1Encoding.GetBytes(mimeType)); picW.Write(StreamUtils.EncodeBEInt32(picDescription.Length)); picW.Write(Encoding.UTF8.GetBytes(picDescription)); ImageProperties props = ImageUtils.GetImageProperties(pictureData); picW.Write(StreamUtils.EncodeBEInt32(props.Width)); picW.Write(StreamUtils.EncodeBEInt32(props.Height)); picW.Write(StreamUtils.EncodeBEInt32(props.ColorDepth)); if (props.Format.Equals(ImageFormat.Gif)) { picW.Write(StreamUtils.EncodeBEInt32(props.NumColorsInPalette)); // Color num } else { picW.Write(0); } picW.Write(StreamUtils.EncodeBEInt32(pictureData.Length)); picW.Write(pictureData); }
private void writePictureFrame(BinaryWriter w, byte[] pictureData) { w.Write(StreamUtils.EncodeBEInt32(pictureData.Length)); // Pic size w.Write(0); // Pic data absolute offset; to be rewritten later w.Write(pictureData); }
/// <summary> /// Write the given field with the given writer, using the WMA-like format /// </summary> /// <param name="w">Write to write the fields to</param> /// <param name="fieldName">Field name</param> /// <param name="fieldValue">Field value</param> /// <param name="isNumeric">True if the field is numeric; false if not (will be formatted as string)</param> public static void WriteField(BinaryWriter w, string fieldName, string fieldValue, bool isNumeric) { long frameSizePos, midSizePos, finalFramePos; frameSizePos = w.BaseStream.Position; w.Write(0); // To be rewritten at the end of the method w.Write(StreamUtils.EncodeBEInt32(fieldName.Length)); w.Write(Utils.Latin1Encoding.GetBytes(fieldName)); w.Write((ushort)0); // Frame class ? w.Write(StreamUtils.EncodeBEInt16(1)); // ? (always 1) midSizePos = w.BaseStream.Position; w.Write(0); // To be rewritten at the end of the method if (isNumeric) { w.Write(StreamUtils.EncodeBEInt16(19)); // ?? (works for rating) w.Write(long.Parse(fieldValue)); // 64-bit little-endian integer ? } else { w.Write(StreamUtils.EncodeBEInt16(8)); // ?? (always 8) w.Write(Encoding.Unicode.GetBytes(fieldValue + '\0')); // String is null-terminated } finalFramePos = w.BaseStream.Position; // Go back to frame size locations to write their actual size w.BaseStream.Seek(midSizePos, SeekOrigin.Begin); w.Write(StreamUtils.EncodeBEInt32((int)(finalFramePos - midSizePos))); w.BaseStream.Seek(frameSizePos, SeekOrigin.Begin); w.Write(StreamUtils.EncodeBEInt32((int)(finalFramePos - frameSizePos))); w.BaseStream.Seek(finalFramePos, SeekOrigin.Begin); }
private void writeTagField(BinaryWriter w, string key, string value) { w.Write('\0'); // Unknown byte; always zero byte[] keyB = Encoding.UTF8.GetBytes(key); byte[] valueB = Encoding.UTF8.GetBytes(value); w.Write(StreamUtils.EncodeBEInt32(keyB.Length)); // Key length w.Write(StreamUtils.EncodeBEInt32(valueB.Length)); // Value length w.Write(keyB); w.Write(valueB); }
public void WriteID3v2EmbeddingHeader(BinaryWriter w, long tagSize) { w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_ID3)); if (isLittleEndian) { w.Write((int)tagSize); } else { w.Write(StreamUtils.EncodeBEInt32((int)tagSize)); } }
public static Int32 ToStream(BinaryWriter w, Boolean isLittleEndian, MetaDataIO meta) { var additionalFields = meta.AdditionalFields; w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_LIST)); var sizePos = w.BaseStream.Position; w.Write((Int32)0); // Placeholder for chunk size that will be rewritten at the end of the method w.Write(Utils.Latin1Encoding.GetBytes(PURPOSE_INFO)); // 'Classic' fields (NB : usually done within a loop by accessing MetaDataIO.tagData) IDictionary <String, String> writtenFields = new Dictionary <String, String>(); // Title var value = Utils.ProtectValue(meta.Title); if (0 == value.Length && additionalFields.Keys.Contains("info.INAM")) { value = additionalFields["info.INAM"]; } if (value.Length > 0) { writeSizeAndNullTerminatedString("INAM", value, w, writtenFields); } // Artist value = Utils.ProtectValue(meta.Artist); if (0 == value.Length && additionalFields.Keys.Contains("info.IART")) { value = additionalFields["info.IART"]; } if (value.Length > 0) { writeSizeAndNullTerminatedString("IART", value, w, writtenFields); } // Copyright value = Utils.ProtectValue(meta.Copyright); if (0 == value.Length && additionalFields.Keys.Contains("info.ICOP")) { value = additionalFields["info.ICOP"]; } if (value.Length > 0) { writeSizeAndNullTerminatedString("ICOP", value, w, writtenFields); } // Genre value = Utils.ProtectValue(meta.Genre); if (0 == value.Length && additionalFields.Keys.Contains("info.IGNR")) { value = additionalFields["info.IGNR"]; } if (value.Length > 0) { writeSizeAndNullTerminatedString("IGNR", value, w, writtenFields); } // Comment value = Utils.ProtectValue(meta.Comment); if (0 == value.Length && additionalFields.Keys.Contains("info.ICMT")) { value = additionalFields["info.ICMT"]; } if (value.Length > 0) { writeSizeAndNullTerminatedString("ICMT", value, w, writtenFields); } String shortKey; foreach (var key in additionalFields.Keys) { if (key.StartsWith("info.")) { shortKey = key.Substring(5, key.Length - 5).ToUpper(); if (!writtenFields.ContainsKey(key)) { if (additionalFields[key].Length > 0) { writeSizeAndNullTerminatedString(shortKey, additionalFields[key], w, writtenFields); } } } } var finalPos = w.BaseStream.Position; w.BaseStream.Seek(sizePos, SeekOrigin.Begin); if (isLittleEndian) { w.Write((Int32)(finalPos - sizePos - 4)); } else { w.Write(StreamUtils.EncodeBEInt32((Int32)(finalPos - sizePos - 4))); } return(14); }
protected override int write(TagData tag, BinaryWriter w, string zone) { int result = -1; // Default : leave as is if (zone.Equals(ZONE_TAGS)) { long nbTagsOffset = w.BaseStream.Position; w.Write(0); // Number of tags; will be rewritten at the end of the method // Mapped textual fields IDictionary <byte, string> map = tag.ToMap(); foreach (byte frameType in map.Keys) { if (map[frameType].Length > 0) // No frame with empty value { foreach (string s in frameMapping.Keys) { if (frameType == frameMapping[s]) { string value = formatBeforeWriting(frameType, tag, map); writeTagField(w, s, value); result++; break; } } } } // Other textual fields foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields) { if ((fieldInfo.TagType.Equals(MetaDataIOFactory.TAG_ANY) || fieldInfo.TagType.Equals(getImplementedTagType())) && !fieldInfo.MarkedForDeletion) { writeTagField(w, fieldInfo.NativeFieldCode, fieldInfo.Value); result++; } } w.BaseStream.Seek(nbTagsOffset, SeekOrigin.Begin); w.Write(StreamUtils.EncodeBEInt32(result)); // Number of tags } if (zone.Equals(ZONE_IMAGE)) { result = 0; foreach (PictureInfo picInfo in tag.Pictures) { // Picture has either to be supported, or to come from the right tag standard bool doWritePicture = !picInfo.PicType.Equals(PictureInfo.PIC_TYPE.Unsupported); if (!doWritePicture) { doWritePicture = (getImplementedTagType() == picInfo.TagType); } // It also has not to be marked for deletion doWritePicture = doWritePicture && (!picInfo.MarkedForDeletion); if (doWritePicture) { writePictureFrame(w, picInfo.PictureData); return(1); // Stop here; there can only be one picture in an AA file } } } return(result); }
public void WriteID3v2EmbeddingHeader(BinaryWriter w, long tagSize) { w.Write(Utils.Latin1Encoding.GetBytes(CHUNKTYPE_ID3TAG)); w.Write(StreamUtils.EncodeBEInt32((int)tagSize)); }
protected override int write(TagData tag, BinaryWriter w, string zone) { int result = 0; if (zone.Equals(CHUNKTYPE_NAME)) { if (tag.Title.Length > 0) { w.Write(Utils.Latin1Encoding.GetBytes(zone)); long sizePos = w.BaseStream.Position; w.Write(0); // Placeholder for field size that will be rewritten at the end of the method byte[] strBytes = Utils.Latin1Encoding.GetBytes(tag.Title); w.Write(strBytes); w.BaseStream.Seek(sizePos, SeekOrigin.Begin); w.Write(StreamUtils.EncodeBEInt32(strBytes.Length)); result++; } } else if (zone.Equals(CHUNKTYPE_AUTHOR)) { if (tag.Artist.Length > 0) { w.Write(Utils.Latin1Encoding.GetBytes(zone)); long sizePos = w.BaseStream.Position; w.Write(0); // Placeholder for field size that will be rewritten at the end of the method byte[] strBytes = Utils.Latin1Encoding.GetBytes(tag.Artist); w.Write(strBytes); w.BaseStream.Seek(sizePos, SeekOrigin.Begin); w.Write(StreamUtils.EncodeBEInt32(strBytes.Length)); result++; } } else if (zone.Equals(CHUNKTYPE_COPYRIGHT)) { if (tag.Copyright.Length > 0) { w.Write(Utils.Latin1Encoding.GetBytes(zone)); long sizePos = w.BaseStream.Position; w.Write(0); // Placeholder for field size that will be rewritten at the end of the method byte[] strBytes = Utils.Latin1Encoding.GetBytes(tag.Copyright); w.Write(strBytes); w.BaseStream.Seek(sizePos, SeekOrigin.Begin); w.Write(StreamUtils.EncodeBEInt32(strBytes.Length)); result++; } } else if (zone.StartsWith(CHUNKTYPE_ANNOTATION)) { // Do not write anything, this field is deprecated (Cf. specs "Use of this chunk is discouraged within FORM AIFC. The more refined Comments Chunk should be used instead") } else if (zone.StartsWith(CHUNKTYPE_COMMENTS)) { bool applicable = tag.Comment.Length > 0; if (!applicable && tag.AdditionalFields.Count > 0) { foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields) { applicable = (fieldInfo.NativeFieldCode.StartsWith(CHUNKTYPE_COMMENTS)); if (applicable) { break; } } } if (applicable) { ushort numComments = 0; w.Write(Utils.Latin1Encoding.GetBytes(CHUNKTYPE_COMMENTS)); long sizePos = w.BaseStream.Position; w.Write(0); // Placeholder for 'chunk size' field that will be rewritten at the end of the method w.Write((ushort)0); // Placeholder for 'number of comments' field that will be rewritten at the end of the method // First write generic comments (those linked to the Comment field) string[] comments = tag.Comment.Split(Settings.InternalValueSeparator); foreach (string s in comments) { writeCommentChunk(w, null, s); numComments++; } // Then write comments linked to a Marker ID if (tag.AdditionalFields != null && tag.AdditionalFields.Count > 0) { foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields) { if (fieldInfo.NativeFieldCode.StartsWith(CHUNKTYPE_COMMENTS)) { if (((CommentData)fieldInfo.SpecificData).MarkerId != 0) { writeCommentChunk(w, fieldInfo); numComments++; } } } } long dataEndPos = w.BaseStream.Position; w.BaseStream.Seek(sizePos, SeekOrigin.Begin); w.Write(StreamUtils.EncodeBEInt32((int)(dataEndPos - sizePos - 4))); w.Write(StreamUtils.EncodeBEUInt16(numComments)); result++; } } return(result); }
public static int ToStream(BinaryWriter w, bool isLittleEndian, MetaDataIO meta) { IDictionary <string, string> additionalFields = meta.AdditionalFields; w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_IXML)); long sizePos = w.BaseStream.Position; w.Write(0); // Placeholder for chunk size that will be rewritten at the end of the method XmlWriterSettings settings = new XmlWriterSettings(); settings.CloseOutput = false; settings.Encoding = Encoding.UTF8; XmlWriter writer = XmlWriter.Create(w.BaseStream, settings); //writer.Formatting = Formatting.None; writer.WriteStartDocument(); writer.WriteStartElement("BWFXML"); string[] path; string[] previousPath = null; bool first = true; string subkey; foreach (string key in additionalFields.Keys) { if (key.StartsWith("ixml.")) { path = key.Split('.'); if (first) { previousPath = path; first = false; } // Closes all terminated paths for (int i = previousPath.Length - 2; i >= 0; i--) { if ((path.Length <= i) || (path.Length > i && !path[i].Equals(previousPath[i]))) { writer.WriteEndElement(); } } // Opens all new paths for (int i = 0; i < path.Length - 1; i++) { if (previousPath.Length <= i || !path[i].Equals(previousPath[i])) { subkey = path[i]; if (subkey.Contains("[")) { subkey = subkey.Substring(0, subkey.IndexOf("[")); // Remove [x]'s } writer.WriteStartElement(subkey.ToUpper()); } } writer.WriteElementString(path[path.Length - 1], additionalFields[key]); previousPath = path; } } // Closes all terminated paths if (previousPath != null) { for (int i = previousPath.Length - 2; i >= 0; i--) { writer.WriteEndElement(); } } writer.Close(); long finalPos = w.BaseStream.Position; w.BaseStream.Seek(sizePos, SeekOrigin.Begin); if (isLittleEndian) { w.Write((int)(finalPos - sizePos - 4)); } else { w.Write(StreamUtils.EncodeBEInt32((int)(finalPos - sizePos - 4))); } return(14); }
public static int ToStream(BinaryWriter w, bool isLittleEndian, MetaDataIO meta) { IDictionary <string, string> additionalFields = meta.AdditionalFields; w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_BEXT)); long sizePos = w.BaseStream.Position; w.Write((int)0); // Placeholder for chunk size that will be rewritten at the end of the method // Text values string description = Utils.ProtectValue(meta.GeneralDescription); if (0 == description.Length && additionalFields.Keys.Contains("bext.description")) { description = additionalFields["bext.description"]; } writeFixedTextValue(description, 256, w); writeFixedFieldTextValue("bext.originator", 32, additionalFields, w); writeFixedFieldTextValue("bext.originatorReference", 32, additionalFields, w); writeFixedFieldTextValue("bext.originationDate", 10, additionalFields, w); writeFixedFieldTextValue("bext.originationTime", 8, additionalFields, w); // Int values writeFieldIntValue("bext.timeReference", additionalFields, w, (ulong)0); writeFieldIntValue("bext.version", additionalFields, w, (ushort)0); // UMID if (additionalFields.Keys.Contains("bext.UMID")) { if (Utils.IsHex(additionalFields["bext.UMID"])) { int usedValues = (int)Math.Floor(additionalFields["bext.UMID"].Length / 2.0); for (int i = 0; i < usedValues; i++) { w.Write(Convert.ToByte(additionalFields["bext.UMID"].Substring(i * 2, 2), 16)); } // Complete the field to 64 bytes for (int i = 0; i < 64 - usedValues; i++) { w.Write((byte)0); } } else { LogDelegator.GetLogDelegate()(Log.LV_WARNING, "'bext.UMID' : error writing field - hexadecimal notation required; " + additionalFields["bext.UMID"] + " found"); for (int i = 0; i < 64; i++) { w.Write((byte)0); } } } else { for (int i = 0; i < 64; i++) { w.Write((byte)0); } } // Float values writeField100DecimalValue("bext.loudnessValue", additionalFields, w, (short)0); writeField100DecimalValue("bext.loudnessRange", additionalFields, w, (short)0); writeField100DecimalValue("bext.maxTruePeakLevel", additionalFields, w, (short)0); writeField100DecimalValue("bext.maxMomentaryLoudness", additionalFields, w, (short)0); writeField100DecimalValue("bext.maxShortTermLoudness", additionalFields, w, (short)0); // Reserved for (int i = 0; i < 180; i++) { w.Write((byte)0); } // CodingHistory byte[] textData = new byte[0]; if (additionalFields.Keys.Contains("bext.codingHistory")) { textData = Utils.Latin1Encoding.GetBytes(additionalFields["bext.codingHistory"]); w.Write(textData); } w.Write(new byte[2] { 13, 10 } /* CR LF */); // Emulation of the BWFMetaEdit padding behaviour (256 characters) for (int i = 0; i < 256 - ((textData.Length + 2) % 256); i++) { w.Write((byte)0); } long finalPos = w.BaseStream.Position; w.BaseStream.Seek(sizePos, SeekOrigin.Begin); if (isLittleEndian) { w.Write((int)(finalPos - sizePos - 4)); } else { w.Write(StreamUtils.EncodeBEInt32((int)(finalPos - sizePos - 4))); } return(14); }
public static int ToStream(BinaryWriter w, bool isLittleEndian, MetaDataIO meta) { IDictionary <string, string> additionalFields = meta.AdditionalFields; w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_SAMPLE)); long sizePos = w.BaseStream.Position; w.Write(0); // Placeholder for chunk size that will be rewritten at the end of the method // Int values writeFieldIntValue("sample.manufacturer", additionalFields, w, 0); writeFieldIntValue("sample.product", additionalFields, w, 0); writeFieldIntValue("sample.period", additionalFields, w, 1); writeFieldIntValue("sample.MIDIUnityNote", additionalFields, w, 0); writeFieldIntValue("sample.MIDIPitchFraction", additionalFields, w, 0); writeFieldIntValue("sample.SMPTEFormat", additionalFields, w, 0); // SMPTE offset writeFieldIntValue("sample.SMPTEOffset.Hours", additionalFields, w, (sbyte)0); writeFieldIntValue("sample.SMPTEOffset.Minutes", additionalFields, w, (byte)0); writeFieldIntValue("sample.SMPTEOffset.Seconds", additionalFields, w, (byte)0); writeFieldIntValue("sample.SMPTEOffset.Frames", additionalFields, w, (byte)0); // == Sample loops // How many of them do we have ? -> count distinct indexes IList <string> keys = new List <string>(); foreach (string s in additionalFields.Keys) { if (s.StartsWith("sample.SampleLoop")) { string key = s.Substring(0, s.IndexOf("]") + 1); if (!keys.Contains(key)) { keys.Add(key); } } } w.Write(keys.Count); // Sample loops data size long sampleLoopsPos = w.BaseStream.Position; w.Write(0); // Placeholder for data size that will be rewritten at the end of the method // Sample loops data foreach (string key in keys) { writeFieldIntValue(key + ".CuePointId", additionalFields, w, 0); writeFieldIntValue(key + ".Type", additionalFields, w, 0); writeFieldIntValue(key + ".Start", additionalFields, w, 0); writeFieldIntValue(key + ".End", additionalFields, w, 0); writeFieldIntValue(key + ".Fraction", additionalFields, w, 0); writeFieldIntValue(key + ".PlayCount", additionalFields, w, 0); } // Write actual sample loops data size long finalPos = w.BaseStream.Position; w.BaseStream.Seek(sampleLoopsPos, SeekOrigin.Begin); w.Write((int)(finalPos - sampleLoopsPos - 4)); // Write actual tag size w.BaseStream.Seek(sizePos, SeekOrigin.Begin); if (isLittleEndian) { w.Write((int)(finalPos - sizePos - 4)); } else { w.Write(StreamUtils.EncodeBEInt32((int)(finalPos - sizePos - 4))); } return(10); }
public static int ToStream(BinaryWriter w, bool isLittleEndian, MetaDataIO meta) { IDictionary <string, string> additionalFields = meta.AdditionalFields; w.Write(Utils.Latin1Encoding.GetBytes(CHUNK_IXML)); long sizePos = w.BaseStream.Position; w.Write(0); // Placeholder for chunk size that will be rewritten at the end of the method XmlWriterSettings settings = new XmlWriterSettings(); settings.CloseOutput = false; settings.Encoding = Encoding.UTF8; XmlWriter writer = XmlWriter.Create(w.BaseStream, settings); //writer.Formatting = Formatting.None; writer.WriteStartDocument(); writer.WriteStartElement("BWFXML"); // Path notes : key = node path; value = node name Dictionary <string, string> pathNodes = new Dictionary <string, string>(); List <string> previousPathNodes = new List <string>(); string subkey; foreach (string key in additionalFields.Keys) { if (key.StartsWith("ixml.")) { // Create the list of path nodes List <string> singleNodes = new List <string>(key.Split('.')); singleNodes.RemoveAt(0); // Remove the "ixml" node StringBuilder nodePrefix = new StringBuilder(); pathNodes.Clear(); foreach (string nodeName in singleNodes) { nodePrefix.Append(".").Append(nodeName); pathNodes.Add(nodePrefix.ToString(), nodeName); } // Close all terminated (i.e. non present in current path) nodes in reverse order for (int i = previousPathNodes.Count - 2; i >= 0; i--) { if (!pathNodes.ContainsKey(previousPathNodes[i])) { writer.WriteEndElement(); } } // Opens all new (i.e. non present in previous path) nodes foreach (string nodePath in pathNodes.Keys) { if (!previousPathNodes.Contains(nodePath)) { subkey = pathNodes[nodePath]; if (subkey.Equals(singleNodes.Last())) { continue; // Last node is a leaf, not a node } if (subkey.Contains("[")) { subkey = subkey.Substring(0, subkey.IndexOf("[")); // Remove [x]'s } writer.WriteStartElement(subkey.ToUpper()); } } // Write the last node (=leaf) as a proper value writer.WriteElementString(singleNodes.Last(), additionalFields[key]); previousPathNodes = pathNodes.Keys.ToList(); } } // Closes all terminated paths if (previousPathNodes != null) { for (int i = previousPathNodes.Count - 2; i >= 0; i--) { writer.WriteEndElement(); } } writer.Close(); long finalPos = w.BaseStream.Position; w.BaseStream.Seek(sizePos, SeekOrigin.Begin); if (isLittleEndian) { w.Write((int)(finalPos - sizePos - 4)); } else { w.Write(StreamUtils.EncodeBEInt32((int)(finalPos - sizePos - 4))); } return(14); }