/// <summary> /// This method is used to take values of a specific metadata field from a MediaProperties object, /// and store the values in another MediaProperties object that is used for merging values /// from multiple MediaProperties objects. /// </summary> /// <param name="propName">Property name, usually acquired through Tags[CommonPropertyNames] enumeration.</param> /// <param name="mergedProps">The IMediaProperties object that will hold the merged values.</param> /// <param name="source">The IMediaProperties object that provides a set of values to copy from.</param> /// <returns></returns> private ArrayList GetMergedValues(string propName, IMediaProperties mergedProps, IMediaProperties source) { // contains a shallow copy of the results ArrayList results = new ArrayList(); // get the values from the merged table IList list = (IList)mergedProps[propName]; if (list != null) { if (list.Count > 0) { results.AddRange(list); } } bool allowsMultiple; PropertyMappings.PropertyNameToType(propName, out allowsMultiple); // get the values that we will be merging with list = (IList)source[propName]; if (list != null) { if (list.Count > 0) { if (allowsMultiple == false) { results = new ArrayList(); results.Add(list[0]); } else { results.AddRange(list); } } } return(results); }
/// <summary> /// Constructs an instance designed to extract a specific metadata property /// from an <see cref="IUPnPMedia"/> object /// </summary> /// <param name="property"> /// string formatted in the form "[namespace]: /// </param> /// <exception cref="OpenSource.UPnP.AV.CdsMetadata.Error_InvalidAttribute"> /// Thrown if the provided property maps to an invalid attribute, /// as per ContentDirectory metadata conventions. /// </exception> public TagExtractor(string property) { // obtain the specified namespace, tagname, and attribute name // for the metadata that needs to be extracted ParseNsTagAttrib(property, out m_Ns, out m_Tag, out m_Attrib); bool checkedTags = false; // Do some preprocessing that will properly set all of // the m_SearchXXX booleans to true to properly // indicate what objects the tag extractor should // examine. if (m_Ns == "") { // Blank namespace assumes DIDL-Lite top level tags. // Attempt to match the tag name against one of the // top level DIDL-Lite top level tags. Also accept // the case where the tag name is not specified, // in which case we assume any top-level DIDL-Lite // element. switch (m_Tag) { // search item objects case "item": this.m_SearchItem = true; break; // search container objects case "container": this.m_SearchContainer = true; break; // search resource objects case "res": this.m_SearchRes = true; break; // search any DIDL top level object? case "": if ( (string.Compare(this.m_Attrib, T[_ATTRIB.id]) == 0) || (string.Compare(this.m_Attrib, T[_ATTRIB.restricted]) == 0) || (string.Compare(this.m_Attrib, T[_ATTRIB.parentID]) == 0) || (string.Compare(this.m_Attrib, T[_ATTRIB.childCount]) == 0) || (string.Compare(this.m_Attrib, T[_ATTRIB.refID]) == 0) ) { // limit the search to item and container objects checkedTags = true; this.m_SearchItem = true; this.m_SearchContainer = true; } else if (string.Compare(this.m_Attrib, T[_ATTRIB.searchable]) == 0) { // limit the search to container objects checkedTags = true; this.m_SearchContainer = true; } else { // limit the search to resource objects this.m_SearchRes = true; } break; } if (!(this.m_SearchItem || this.m_SearchContainer || this.m_SearchRes)) { this.m_SearchDesc = true; } } else if ((m_Ns == "dc") || (m_Ns == "upnp")) { // if the namespace is dublin-core or upnp, then // we can't be searching vendor-specific metadata. this.m_SearchDesc = false; } // At this point, we're either configuring to extract // custom metadata or we're configuring to extract // CDS normative metadata. if (this.m_SearchDesc == false) { // If extracting CDS normative metadata... if (this.m_SearchItem || this.m_SearchContainer) { // If we're searching item and container elements if (!checkedTags) { // If by chance we haven't examined the attribute // that is to be extracted, then check the // attribute against the CDS normative attributes // for item and container elements. // string[] attribs = { T[_ATTRIB.id], T[_ATTRIB.parentID], T[_ATTRIB.restricted] }; // // bool c = this.CheckAttribute(this.m_Ns, this.m_Tag, this.m_Attrib, attribs); // if (!c) // { // throw new Error_InvalidAttribute(this.m_Attrib + " is not a legal attribute of the item or container element."); // } if ((m_Attrib != null) && (m_Attrib != "")) { bool c = true; if (this.m_SearchItem && this.m_SearchContainer) { string[] refid = { T[_ATTRIB.id], T[_ATTRIB.parentID], T[_ATTRIB.restricted], T[_ATTRIB.refID] }; c = this.CheckAttribute(this.m_Ns, this.m_Tag, this.m_Attrib, refid); if (!c) { throw new Error_InvalidAttribute(this.m_Attrib + " is not a legal attribute of an item or container element."); } } else if (this.m_SearchItem) { string[] refid = { T[_ATTRIB.id], T[_ATTRIB.parentID], T[_ATTRIB.restricted], T[_ATTRIB.refID] }; c = this.CheckAttribute(this.m_Ns, this.m_Tag, this.m_Attrib, refid); if (!c) { throw new Error_InvalidAttribute(this.m_Attrib + " is not a legal attribute of an item element."); } } else if (this.m_SearchContainer) { string[] searchable = { T[_ATTRIB.id], T[_ATTRIB.parentID], T[_ATTRIB.restricted], T[_ATTRIB.searchable] }; c = this.CheckAttribute(this.m_Ns, this.m_Tag, this.m_Attrib, searchable); if (!c) { throw new Error_InvalidAttribute(this.m_Attrib + " is not a legal attribute of a container element."); } } } } else { // Otherwise, we've already matched the attribute with a CDS normative // attribute and we're ok. } } else if (this.m_SearchRes) { // Compare the desired attribute for extraction and ensure // that the attribute is CDS-normative. if ((m_Attrib != null) && (m_Attrib != "")) { string[] attribs = { T[_ATTRIB.bitrate], T[_ATTRIB.bitsPerSample], T[_ATTRIB.colorDepth], T[_ATTRIB.duration], T[_ATTRIB.importUri], T[_ATTRIB.nrAudioChannels], T[_ATTRIB.protection], T[_ATTRIB.protocolInfo], T[_ATTRIB.resolution], T[_ATTRIB.sampleFrequency], T[_ATTRIB.size] }; bool c = this.CheckAttribute(this.m_Ns, this.m_Tag, this.m_Attrib, attribs); if (!c) { throw new Error_InvalidAttribute(this.m_Attrib + " is not a legal attribute of the res element."); } } } else { // Otherwise we're attempting to extract something from upnp: or dc: // In such a case, we'll take the element name and find the ICdsElement // class type and call the static GetPossibleAttributes() method. // This will provide us with a list of valid attributes for that particular // metadata class. Then we'll compare the attribute that we're // supposed to extract with the provided list and throw an exception // if no match exists. StringBuilder elementName = new StringBuilder(); elementName.AppendFormat("{0}:{1}", this.m_Ns, this.m_Tag); if (this.m_Attrib != "") { bool ignore; System.Type type = PropertyMappings.PropertyNameToType(elementName.ToString(), out ignore); MethodInfo mi = type.GetMethod("GetPossibleAttributes", BindingFlags.Public | BindingFlags.Static); if (mi != null) { IList possibleAttributes = (IList)mi.Invoke(null, null); if (possibleAttributes.Contains(this.m_Attrib) == false) { throw new Error_InvalidAttribute(this.m_Attrib + " is not a legal attribute of " + elementName.ToString()); } } else { throw new ApplicationException(type.ToString() + " does not implement GetPossibleAttributes."); } } } } else { // Do not extract custom metadata values for now. // throw new Error_InvalidAttribute("Cannot extract metadata value from <desc> elements or child elements in <desc> elements. Feature is not yet implemented."); } }