/// <summary>
 /// <see cref="DvMediaContainer"/> objects
 /// use this method to event changes in their state. This
 /// method simply fires the
 /// <see cref="DvRootContainer.OnContainerChanged"/>
 /// event.
 /// </summary>
 /// <param name="thisChanged"></param>
 internal void FireOnContainerChanged(DvMediaContainer thisChanged)
 {
     if (this.OnContainerChanged != null)
     {
         this.OnContainerChanged(this, thisChanged);
     }
 }
 /// <summary>
 /// Creates a 
 /// <see cref="DvMediaContainer"/>
 /// object, given a metadata instantiation
 /// block.
 /// </summary>
 /// <param name="info">
 /// The metadata to use when instantiating the media.
 /// </param>
 /// <returns>a new media container</returns>
 public static DvMediaContainer CreateContainer(MediaBuilder.container info)
 {
     DvMediaContainer newObj = new DvMediaContainer();
     MediaBuilder.SetObjectProperties(newObj, info);
     newObj.TrackMetadataChanges = true;
     return newObj;
 }
        /// <summary>
        /// Creates a
        /// <see cref="DvMediaContainer"/>
        /// object, given a metadata instantiation
        /// block.
        /// </summary>
        /// <param name="info">
        /// The metadata to use when instantiating the media.
        /// </param>
        /// <returns>a new media container</returns>
        public static DvMediaContainer CreateContainer(MediaBuilder.container info)
        {
            DvMediaContainer newObj = new DvMediaContainer();

            MediaBuilder.SetObjectProperties(newObj, info);
            newObj.TrackMetadataChanges = true;
            return(newObj);
        }
        /// <summary>
        /// Calls DvMediaContainer.CheckProtection() if the item has a parent.
        /// This method is used to prevent
        /// public programmers from doing a set() on the Parent
        /// property.
        /// </summary>
        /// <param name="st"></param>
        public override void CheckRuntimeBindings(StackTrace st)
        {
#if (DEBUG)
            if (this.Parent != null)
            {
                DvMediaContainer parent = (DvMediaContainer)this.Parent;

                parent.CheckRuntimeBindings(st);
            }
#endif
        }
        private static void EnableMetadataTracking(IDvMedia dvm)
        {
            DvMediaContainer dvc = dvm as DvMediaContainer;
            DvMediaItem      dvi = dvm as DvMediaItem;

            if (dvc != null)
            {
                dvc.TrackMetadataChanges = true;
                foreach (IDvMedia child in dvc.CompleteList)
                {
                    EnableMetadataTracking(child);
                }
            }
            else if (dvi != null)
            {
                dvi.TrackMetadataChanges = true;
            }
        }
        /// <summary>
        /// <para>
        /// Calls the parent container's
        /// <see cref="DvMediaContainer.NotifyRootOfChange"/> method.
        /// </para>
        ///
        /// <para>
        /// Enumerates through this item's reference items and instructs
        /// each to notify their parents of the change.
        /// </para>
        /// </summary>
        /// <exception cref="InvalidCastException">
        /// Thrown when parent container is not a <see cref="DvMediaContainer"/> object.
        /// </exception>
        public void NotifyRootOfChange()
        {
            DvMediaContainer mc = (DvMediaContainer)this.m_Parent;

            if (mc != null)
            {
                mc.NotifyRootOfChange();
            }

            this.LockReferenceList();
            if (this.m_ReferringItems != null)
            {
                foreach (IDvItem refItem in this.m_ReferringItems)
                {
                    mc = (DvMediaContainer)refItem.Parent;
                    if (mc != null)
                    {
                        mc.NotifyRootOfChange();
                    }
                }
            }
            this.UnlockReferenceList();
        }
        /// <summary>
        /// Updates the metadata of container, container's children, and
        /// resources associated with both.
        /// 
        /// <para>
        /// We currently use a file system watcher to manage the metadata
        /// for most things. The only thing we don't do is calcuate the
        /// used storage space of a folder and other storage stats.
        /// </para>
        /// </summary>
        /// <param name="container"></param>
        private void Sink_UpdateContainerMetadata(DvMediaContainer container)
        {
            // Determine the used space by calculating the sum of the storage used by all child objects' resources.
            /*
            long storageUsed = 0;
            if (container.Class.FullClassName.StartsWith("object.container.storage"))
            {
                foreach (IUPnPMedia child in container.CompleteList)
                {
                    foreach (IMediaResource res in child.Resources)
                    {
                        if (res.HasSize)
                        {
                            // silly UPnP-AV/CDS authors forgot to make size into
                            // a signed value, so i'll just fudge the value here
                            // so that I remain schema-compliant in every way...
                            // AV Forum should eventually change this though.
                            long v;
                            if (res.Size.m_Value > long.MaxValue)
                            {
                                v = long.MaxValue;
                            }
                            else
                            {
                                v = (long) res.Size.m_Value;
                            }
                            storageUsed += v;
                        }
                    }
                }

                container.SetPropertyValue_Long(Tags.GetInstance()[CommonPropertyNames.storageUsed], storageUsed);
            }
            */
        }
        /// <summary>
        /// This recursively method serializes the content hierarchy.
        /// </summary>
        /// <param name="fstream"></param>
        /// <param name="container"></param>
        private void SerializeContainer(BinaryFormatter formatter, FileStream fstream, DvMediaContainer container, Hashtable refItems)
        {
            IList children = container.CompleteList;

            // Indicate that a container is being serialized, then
            // serialize the metadata for this container,
            // and serialize the number of children,
            // then recursively serialize
            formatter.Serialize(fstream, container);
            formatter.Serialize(fstream, children.Count);
            foreach (IUPnPMedia child in children)
            {
                DvMediaContainer dvc = child as DvMediaContainer;
                DvMediaItem dvi = child as DvMediaItem;

                if (dvc != null)
                {
                    this.SerializeContainer(formatter, fstream, dvc, refItems);
                }
                else if (dvi != null)
                {
                    // This is an item, so serialize the media item.
                    // If the item is a refItem, provide a mapping
                    // from item ID to refID.
                    formatter.Serialize(fstream, dvi);

                    if (dvi.IsReference)
                    {
                        if ((dvi.RefID != null) && (dvi.RefID != ""))
                        {
                            refItems[dvi.ID] = dvi.RefID;
                        }
                    }
                }
                else
                {
                    throw new ApplicationException("The MediaServer has a IUPnPMedia item with ID=\"" + child.ID +"\" that is neither a DvMediaItem nor a DvMediaContainer.");
                }
            }
        }
        /// <summary>
        /// Changes the target media object's parent to a different parent.
        /// </summary>
        /// <param name="target">target object</param>
        /// <param name="np">new parent</param>
        /// <exception cref="InvalidCastException">
        /// Thrown when the target's current parent is not a <see cref="DvMediaContainer"/>.
        /// </exception>
        internal static void ChangeParent2(IDvMedia target, DvMediaContainer np)
        {
            Exception  error          = null;
            IUPnPMedia errorDuplicate = null;

            IDvMedia[] removeThese = new IDvMedia[1];
            removeThese[0] = target;

            DvMediaContainer dvp = (DvMediaContainer)target.Parent;

            // fire about to remove event
            if (dvp.OnChildrenToRemove != null)
            {
                dvp.OnChildrenToRemove(dvp, removeThese);
            }

            // acquire locks
            dvp.m_LockListing.AcquireWriterLock(-1);
            np.m_LockListing.AcquireWriterLock(-1);

            try
            {
                // remove target from current parent
                int i = dvp.HashingMethod.Get(dvp.m_Listing, target);
                dvp.m_Listing.RemoveAt(i);
                target.Parent = null;
                if (dvp.m_Listing.Count == 0)
                {
                    dvp.m_Listing = null;
                }

                // add target to new parent
                if (np.m_Listing == null)
                {
                    np.m_Listing = new ArrayList();
                }
                try
                {
                    np.HashingMethod.Set(np.m_Listing, target, true);
                    target.Parent = np;
                }
                catch (KeyCollisionException)
                {
                    errorDuplicate = target;
                }
            }
            catch (Exception e)
            {
                error = e;
            }

            // release locks
            np.m_LockListing.ReleaseWriterLock();
            dvp.m_LockListing.ReleaseWriterLock();

            // throw exceptions if appropriate
            if (error != null)
            {
                throw new Exception("Unexpected rrror in DvMediaContainer.ChangeParent2", error);
            }

            if (errorDuplicate != null)
            {
                throw new Error_DuplicateIdException(errorDuplicate);
            }

            // fire children removed event
            if (dvp.OnChildrenRemoved != null)
            {
                dvp.OnChildrenRemoved(dvp, removeThese);
            }

            // notify upnp network that two containers changed.
            dvp.NotifyRootOfChange();
            np.NotifyRootOfChange();
        }
        private bool AddDirectoryEx(DvMediaContainer container, DirectoryInfo directory)
        {
            if (directory.Exists == false) return false;

            MediaBuilder.storageFolder storageInfo = new MediaBuilder.storageFolder(directory.Name);
            storageInfo.Searchable = true;
            storageInfo.IsRestricted = false;
            DvMediaContainer newContainer = DvMediaBuilder.CreateContainer(storageInfo);
            newContainer.OnChildrenRemoved += new DvDelegates.Delegate_OnChildrenRemove(this.Sink_OnChildRemoved);
            newContainer.Callback_UpdateMetadata = new DvMediaContainer.Delegate_UpdateMetadata(this.Sink_UpdateContainerMetadata);

            InnerMediaDirectory mediadir = new InnerMediaDirectory();
            mediadir.directory = directory;
            mediadir.directoryname = directory.FullName;
            mediadir.watcher = new FileSystemWatcher(directory.FullName);
            mediadir.watcher.Changed += new FileSystemEventHandler(OnDirectoryChangedSink);
            mediadir.watcher.Created += new FileSystemEventHandler(OnDirectoryCreatedSink);
            mediadir.watcher.Deleted += new FileSystemEventHandler(OnDirectoryDeletedSink);
            mediadir.watcher.Renamed += new RenamedEventHandler(OnFileSystemRenameSink);
            mediadir.restricted = true;
            mediadir.readOnly = true;

            watcherTable.Add(mediadir.watcher,newContainer);
            mediadir.watcher.EnableRaisingEvents = true;

            newContainer.Tag = mediadir;

            FileInfo[] files = directory.GetFiles();
            ArrayList addedFiles = new ArrayList(files.Length);
            foreach (FileInfo file in files)
            {
                IDvMedia newObj = CreateObjFromFile(file, new ArrayList());
                if (newObj != null)
                {
                    addedFiles.Add(newObj);
                    totalFileCount++;
                }
            }

            newContainer.AddObjects(addedFiles, true);

            // Add the new container to an existing container.
            container.AddObject(newContainer, true);

            foreach (IDvMedia item in addedFiles)
            {
                if (item.Class.IsA(MediaBuilder.StandardMediaClasses.AudioItem))
                {
                    this.m_AudioItems.AddReference((DvMediaItem)item);
                }
                else if (item.Class.IsA(MediaBuilder.StandardMediaClasses.ImageItem))
                {
                    this.m_ImageItems.AddReference((DvMediaItem)item);
                }
                else if (item.Class.IsA(MediaBuilder.StandardMediaClasses.VideoItem))
                {
                    this.m_VideoItems.AddReference((DvMediaItem)item);
                }
                else if (item.Class.IsA(MediaBuilder.StandardMediaClasses.PlaylistContainer))
                {
                    // References to playlists are not allowed, so we have to build
                    // completely new instances of the container and its resources.
                    // However the new container can have references to the items.
                    DvMediaContainer originalC = (DvMediaContainer) item;

                    MediaBuilder.playlistContainer plcInfo = new MediaBuilder.playlistContainer(originalC.Title);
                    DvMediaContainer newC = DvMediaBuilder.CreateContainer(plcInfo);

                    foreach (DvMediaResource res in originalC.Resources)
                    {
                        ResourceBuilder.AllResourceAttributes resAttribs = new ResourceBuilder.AllResourceAttributes();
                        resAttribs.contentUri = res.ContentUri;
                        foreach (string attribute in res.ValidAttributes)
                        {
                            object obj = res[attribute];
                            _RESATTRIB attribName = (_RESATTRIB) Enum.Parse(typeof(_RESATTRIB), attribute, true);

                            switch (attribName)
                            {
                                case _RESATTRIB.bitrate:
                                    resAttribs.bitrate = (_UInt) obj;
                                    break;
                                case _RESATTRIB.bitsPerSample:
                                    resAttribs.bitsPerSample = (_UInt) obj;
                                    break;
                                case _RESATTRIB.colorDepth:
                                    resAttribs.colorDepth = (_UInt) obj;
                                    break;
                                case _RESATTRIB.duration:
                                    resAttribs.duration = (_TimeSpan) obj;
                                    break;
                                case _RESATTRIB.importUri:
                                    //do not allow import
                                    break;
                                case _RESATTRIB.nrAudioChannels:
                                    resAttribs.nrAudioChannels = (_UInt) obj;
                                    break;
                                case _RESATTRIB.protection:
                                    resAttribs.protection = (string) obj;
                                    break;
                                case _RESATTRIB.protocolInfo:
                                    resAttribs.protocolInfo = new ProtocolInfoString(((ProtocolInfoString)obj).ToString());
                                    break;
                                case _RESATTRIB.resolution:
                                    resAttribs.resolution = (ImageDimensions) obj;
                                    break;
                                case _RESATTRIB.sampleFrequency:
                                    resAttribs.sampleFrequency = (_UInt) obj;
                                    break;
                                case _RESATTRIB.size:
                                    resAttribs.size = (_ULong) obj;
                                    break;
                            }
                        }
                        DvMediaResource newCR = DvResourceBuilder.CreateResource(resAttribs, false);
                        newCR.AllowImport = res.AllowImport;
                        newCR.CheckAutomapFileExists = res.CheckAutomapFileExists;
                        newCR.HideContentUri = res.HideContentUri;
                        newCR.MakeStreamAtHttpGetTime = res.MakeStreamAtHttpGetTime;
                        newCR.Tag = res.Tag;

                        newC.AddResource(newCR);
                    }

                    // The child container should only have items.
                    // If the child-container has child containers, then
                    // then this is bad because those child playlists
                    // should have been converted to a flat list
                    // in the recursive building of the hierarchy
                    foreach (DvMediaItem childItem in originalC.CompleteList)
                    {
                        newC.AddReference(childItem);
                    }

                    this.m_Playlists.AddObject(newC, true);
                }
            }

            DirectoryInfo[] directories = directory.GetDirectories();
            foreach (DirectoryInfo dir in directories)
            {
                AddDirectoryEx(newContainer,dir);
            }

            totalDirectoryCount++;
            if (OnStatsChanged != null) OnStatsChanged(this);
            return true;
        }
        public void ResetCoreRoot()
        {
            MediaBuilder.SetNextID(0);
            rootContainer = mediaServer.Root;

            MediaBuilder.container containerImagesInfo = new MediaBuilder.container("All Image Items");
            containerImagesInfo.IsRestricted = true;

            MediaBuilder.container containerAudioItemsInfo = new MediaBuilder.container("All Audio Items");
            containerAudioItemsInfo.IsRestricted = true;

            MediaBuilder.container containerVideoItemsInfo = new MediaBuilder.container("All Video Items");
            containerVideoItemsInfo.IsRestricted = true;

            MediaBuilder.container containerPlaylistsInfo = new MediaBuilder.container("All Playlists");
            containerPlaylistsInfo.IsRestricted = true;

            m_ImageItems = (DvMediaContainer) DvMediaBuilder.CreateContainer(containerImagesInfo);

            m_AudioItems = (DvMediaContainer) DvMediaBuilder.CreateContainer(containerAudioItemsInfo);

            m_VideoItems = (DvMediaContainer) DvMediaBuilder.CreateContainer(containerVideoItemsInfo);

            m_Playlists = (DvMediaContainer) DvMediaBuilder.CreateContainer(containerPlaylistsInfo);

            rootContainer.AddObject(m_ImageItems, true);
            rootContainer.AddObject(m_AudioItems, true);
            rootContainer.AddObject(m_VideoItems, true);
            rootContainer.AddObject(m_Playlists, true);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="container"></param>
        /// <param name="formatter"></param>
        /// <param name="fstream"></param>
        private void DeserializeContainer(DvMediaContainer container, BinaryFormatter formatter, FileStream fstream)
        {
            // get number of children in container
            int count = (int) formatter.Deserialize (fstream);

            ArrayList children = new ArrayList(count);
            object obj;
            DvMediaItem dvi;
            DvMediaContainer dvc;
            for (int i=0; i<count; i++)
            {
                try
                {
                    obj = formatter.Deserialize(fstream);
                }
                catch (Exception e)
                {
                    throw new SerializationException("Error deserializing a child of containerID=\"" +container.ID+ "\" Title=\"" +container.Title+ "\".", e);
                }

                dvi = obj as DvMediaItem;
                dvc = obj as DvMediaContainer;

                if (dvc != null)
                {
                    this.DeserializeContainer(dvc, formatter, fstream);
                    children.Add(dvc);
                }
                else if (dvi != null)
                {
                    children.Add(dvi);
                }
                else
                {
                    throw new ApplicationException("The MediaServer deserialized an object that is neither a DvMediaItem nor a DvMediaContainer.");
                }

            }
            container.AddObjects(children, true);
        }
        /// <summary>
        /// Method executes when the root container indicates that a descendent container has changed.
        /// Method's purpose is to cause the ContainerUpdateIDs state variable to event
        /// the change.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="thisChanged"></param>
        private void Sink_ContainerChanged(DvRootContainer sender, DvMediaContainer thisChanged)
        {
            this.Lock_SystemUpdateID.WaitOne();
            this.ContentDirectory.Evented_SystemUpdateID = this.ContentDirectory.Evented_SystemUpdateID + 1;
            this.Lock_SystemUpdateID.ReleaseMutex();

            this.Lock_ContainerUpdateIDs.WaitOne();
            StringBuilder sb = new StringBuilder(20);
            sb.AppendFormat("{0}{1}{2}", thisChanged.ID, Accumulator_ContainerUpdateIDs.Delimitor, thisChanged.UpdateID);
            this.ContentDirectory.Evented_ContainerUpdateIDs = sb.ToString();
            this.Lock_ContainerUpdateIDs.ReleaseMutex();
        }
        /// <summary>
        /// Method executes when a control point invokes the ContentDirectory.UpdateObject action.
        /// The caller must specify the object to be modified, the old XML values to replace,
        /// and the new XML values to use.
        /// </summary>
        /// <param name="objectID">update media object with this ID</param>
        /// <param name="currentTagValue">
        /// Comma separated value list of current XML elements in the object.
        /// Empty value or double comma indicates that a new XML element is to be created.
        /// CDS spec defines that the text of the XML elements must match
        /// exactly with the text provided by the server. This means
        /// XML attributes have to be in the correct order within the XML element.
        /// XML elements need not be in any particular order though.. just the
        /// text between the commas separating things need to be that way.
        /// The order of XML elements correspond with the order of replacement
        /// XML elements.
        /// </param>
        /// <param name="newTagValue">
        /// Comma separated value list of new/replace XML elements in the object.
        /// Empty value or double comma indicates that an existing XML element is to be deleted.
        /// The order of XML elements correspond with the order of current
        /// XML elements.
        /// </param>
        private void SinkCd_UpdateObject(System.String objectID, System.String currentTagValue, System.String newTagValue)
        {
            try
            {
                // Ensure that the specified object actually exists
                IDvMedia obj = (IDvMedia) this.GetCdsEntry(objectID);

                if (obj == null)
                {
                    throw new Error_NoSuchObject("("+objectID+")");
                }
                else if (obj.IsReference)
                {
                    throw new UPnPCustomException(830, "This server will not allow UpdateObject() on a reference.");
                }

                // Set up text parsers.
                DText currentTagParser = new DText();
                DText newTagParser = new DText();

                currentTagParser.ATTRMARK = ",";
                newTagParser.ATTRMARK = ",";

                currentTagParser[0] = currentTagValue;
                newTagParser[0] = newTagValue;

                // ensure that the number of old xml values is equal
                // to the number of new values

                // BUG - Need to fix a case where the XML values include commas.

                int nFrags = currentTagParser.DCOUNT();
                int nFrags2 = newTagParser.DCOUNT();

                if (nFrags != nFrags2)
                {
                    throw new Error_ParameterMismatch("The number of tag/value pairs is not the same between currentTagValue and newTagValue.");
                }

                // determine the base URL using the IP address and port
                // where the request came in from and then
                // build an DIDL-Lite representation of the
                // object that needs updating

                //TODO: get all interfaces
                string baseUrl = this.GetBaseUrlByInterface();
                ArrayList properties = new ArrayList();
                ArrayList entries = new ArrayList();
                entries.Add(obj);

                string oldXml;
                try
                {
                    oldXml = BuildXmlRepresentation(baseUrl, properties, entries);
                }
                catch (Exception e)
                {
                    throw (e);
                }

                //  At this point oldXml represents the object we're trying to
                //  update, in an xml string format. Now go and replace (or add) all
                //  of the text values appropriately.
                //

                string newXml = oldXml;
                for (int i=1; i <= nFrags; i++)
                {
                    // grab the old and new value XML fragments

                    string oldFrag = currentTagParser[i].Trim();
                    string newFrag = newTagParser[i].Trim();

                    if (
                        ((oldFrag.StartsWith("<") == false) || (oldFrag.EndsWith(">") == false)) &&
                        (oldFrag != "")
                        )
                    {
                        throw new Error_InvalidCurrentTagValue("Invalid args. (" + oldFrag + ") is not an xml element.");
                    }

                    int pos = newXml.IndexOf(oldFrag);
                    if ((oldFrag != "") && (pos < 0))
                    {
                        throw new Error_InvalidCurrentTagValue("Cannot find xml element (" +oldFrag+ ").");
                    }

                    if (oldFrag == "")
                    {
                        // The old value XML fragment indicates that a completely
                        // new XML element needs to be added.
                        if (obj.IsContainer)
                        {
                            StringBuilder newVal = new StringBuilder(newFrag.Length + 10);
                            newVal.AppendFormat("{0}</container>");
                            newXml = newXml.Replace("</container>", newVal.ToString());
                        }
                        else
                        {
                            StringBuilder newVal = new StringBuilder(newFrag.Length + 10);
                            newVal.AppendFormat("{0}</item>", newFrag);
                            newXml = newXml.Replace("</item>", newVal.ToString());
                        }
                    }
                    else
                    {
                        // The new value XML fragment indicates that a current
                        // XML fragment must be deleted.
                        if (newFrag == "")
                        {
                            newXml = newXml.Replace(oldFrag, "");
                        }
                        else
                        {
                            newXml = newXml.Replace(oldFrag, newFrag);
                        }
                    }
                }

                // At this point newXml represents what the proposed object should
                // look like with new changes. We'll continue by casting the
                // string into an xmldocument and instantiating a new IDvMedia
                // instance, making sure to keep the ID specified within the newXml.
                //

                // Cast the string into an XmlDocument so that we can instantiate
                // a media object using an XmlElement object.

                XmlDocument xmldoc = new XmlDocument();
                xmldoc.LoadXml(newXml);

                XmlNodeList didlheader = xmldoc.GetElementsByTagName(T[_DIDL.DIDL_Lite]);
                XmlNode didlRoot = didlheader[0];
                XmlElement xmlElement = (XmlElement) didlRoot.ChildNodes[0];

                IDvMedia newObj;
                if (obj.IsContainer)
                {
                    newObj = new DvMediaContainer(xmlElement);
                }
                else
                {
                    newObj = new DvMediaItem(xmlElement);
                }

                // Iterate through the resources of the new object
                // and ensure that resources that carried over
                // from the original object's metadata are
                // properly mapped in the new object's list.
                // This way, upper software layers cannot effectively
                // tell the difference if a comparison-by-value is done.

                foreach (IMediaResource newRes in newObj.Resources)
                {
                    string uri = newRes.ContentUri;
                    int pos = uri.IndexOf(this.m_VirtualDirName);

                    if (pos > 0)
                    {
                        // ensure that contentUri and importUri values don't violate automapping rule
                        string subUri = uri.Substring(pos + this.m_VirtualDirName.Length);
                        DText DirectiveParser = new DText();
                        DirectiveParser.ATTRMARK = "/";

                        DirectiveParser[0] = subUri;
                        string resourceID = DirectiveParser[2];
                        string objID = DirectiveParser[3];
                        System.Diagnostics.Debug.Assert(objID == objectID);
                        IDvResource res = this.GetResource(objectID, resourceID);

                        newRes[T[_RESATTRIB.importUri]] = null;
                        newRes.ContentUri = res.ContentUri;
                    }
                }

                // Request upper software components to accept/reject
                // request to change metadata. The delegate should
                // throw an exception (preferably UPnPCustomExeption)
                // to indicate a rejection.
                if (this.OnRequestChangeMetadata != null)
                {
                    this.OnRequestChangeMetadata (this, obj, newObj);
                }

                // If no rejection, then use the metadata of the new object
                // and apply it to the existing object.
                obj.UpdateObject(newObj);
            }
            catch (Exception e)
            {
                Exception ne = new Exception("MediaServer.SinkCd_UpdateObject()", e);
                throw ne;
            }

            this.m_Stats.UpdateObject++;
            this.FireStatsChange();
        }
 /// <summary>
 /// <see cref="DvMediaContainer"/> objects
 /// use this method to event changes in their state. This
 /// method simply fires the 
 /// <see cref="DvRootContainer.OnContainerChanged"/>
 /// event.
 /// </summary>
 /// <param name="thisChanged"></param>
 internal void FireOnContainerChanged(DvMediaContainer thisChanged)
 {
     if (this.OnContainerChanged != null)
     {
         this.OnContainerChanged(this, thisChanged);
     }
 }
        private void ValidateBranch(DvMediaContainer branchFrom, IDvMedia branch, bool allowNewLocalResources)
        {
            DvMediaContainer parent = branchFrom;
            string basePath = "";
            if (allowNewLocalResources)
            {
                /// The parent container's TAG field will have one of two things:
                ///		1) string representation of the local path that it maps to..
                ///		2) InnerMediaDirectory structure describing the local path that it maps to.
                ///		3) Empty string value or null if no mapping to a local file.
                ///
                if (parent.Tag == null)
                {
                }
                else if (parent.Tag.GetType() == new InnerMediaDirectory().GetType())
                {
                    InnerMediaDirectory imd = (InnerMediaDirectory) parent.Tag;
                    basePath = imd.directory.FullName + "\\";
                }
                else if (parent.Tag.GetType() == typeof(string))
                {
                    basePath = parent.Tag + "\\";
                }

                /// The new branch must be a storage container in order to
                /// map to a local file of sort. May consider making
                /// the class more restricted to object.container.storageFolder.
                ///
                if (branch.IsContainer)
                {
                    DvMediaContainer container = (DvMediaContainer) branch;

                    if (container.Class.ToString().StartsWith("object.container.storage"))
                    //if (true)
                    {
                        container.Tag = basePath + container.Title;
                    }
                    else
                    {
                        container.Tag = null;
                    }
                }
            }

            if (branch.IsContainer)
            {
                DvMediaContainer container = (DvMediaContainer) branch;
                foreach (IDvMedia child in container.CompleteList)
                {
                    ValidateBranch(container, child, allowNewLocalResources);
                }
            }
            else if (branch.IsItem)
            {
            }
            else
            {
                throw new Exception("Error: Could not validate branch. Branch must be a container, reference, or item.");
            }

            if (branch.IsReference == false)
            {
                /// Each of these resources should be actual children of the item.
                /// They should not be resources obtained through a reference.
                /// This impelementation does not allow references to declare
                /// their own resources.
                ///
                IList resources = branch.Resources;
                if (resources != null)
                {
                    if (resources.Count > 0)
                    {
                        foreach (DvMediaResource res in resources)
                        {
                            if (res.ContentUri.StartsWith(DvMediaResource.AUTOMAPFILE))
                            {
                                if (allowNewLocalResources)
                                {
                                    string filePath = res.ContentUri.Substring(DvMediaResource.AUTOMAPFILE.Length);

                                    if (File.Exists(filePath))
                                    {
                                        if (Directory.Exists(filePath))
                                        {
                                            throw new UPnPCustomException(810, "The specified local file-uri is a directory. (" +res.ContentUri+")");
                                        }

                                        FileInfo fi = new FileInfo(filePath);

                                        string protocol = "http-get";
                                        string network = "*";
                                        string mime;
                                        string classType;
                                        MimeTypes.ExtensionToMimeType(fi.Extension, out mime, out classType);
                                        string info = "*";

                                        StringBuilder sb = new StringBuilder(100);
                                        sb.AppendFormat("{0}:{1}:{2}:{3}", protocol, network, mime, info);

                                        ProtocolInfoString protInfo = new ProtocolInfoString(sb.ToString());
                                        res.SetProtocolInfo(protInfo);
                                    }
                                    else
                                    {
                                        throw new UPnPCustomException(811, "The specified local file-uri does not exist. (" +res.ContentUri+")");
                                    }
                                }
                                else
                                {
                                    throw new Error_BadMetadata("Cannot create local http-get resources that are descendents from the specified container.");
                                }
                            }
                            else if ((res.ContentUri == "") && (basePath != ""))
                            {
                                // Get a unique filename where we can save the binary when it gets imported
                                // or sent.
                                string filePath = res.GenerateLocalFilePath(basePath);

                                /// Set the content uri to map to the determined local path...
                                /// although it's understood that the file does not exist yet.
                                ///
                                res.SetContentUri(filePath);
                            }
                            else if (res.ContentUri != "")
                            {
                                string importUri = res.ImportUri;
                                //int x = 3;
                            }
                            else
                            {
                                throw new Error_RestrictedObject("The container specified does not allow creation of storage containers or resources.");
                            }
                        }
                    }
                }
            }
        }
 public void Dispose()
 {
     rootContainer = null;
     mediaServer.Dispose();
     mediaServer = null;
     serverCore = null;
     this.m_DeviceWatcher = null;
     this.m_DeviceWatcher.OnSniff -= new OpenSource.UPnP.UPnPDeviceWatcher.SniffHandler(this.Sink_DeviceWatcherSniff);
 }
        private void Handle_OnRequestAddBranch(MediaServerDevice sender, DvMediaContainer parentContainer, ref IDvMedia[] addTheseBranches)
        {
            Exception error = null;
            this.m_LockRoot.WaitOne();

            try
            {
                if (parentContainer == this.mediaServer.Root)
                {
                    throw new Error_RestrictedObject("Cannot create objects directly in the root container.");
                }
                else if (parentContainer.IsRestricted)
                {
                    throw new Error_RestrictedObject("Cannot create objects in a restricted container.");
                }

                InnerMediaDirectory mediadir = (InnerMediaDirectory) parentContainer.Tag;
                bool allowNewLocalResources = true;
                if (mediadir != null)
                {
                    allowNewLocalResources = Directory.Exists(mediadir.directory.FullName);
                }
                foreach (IDvMedia branch in addTheseBranches)
                {
                    // Throw an exception if ANYTHING is bad. Add is always
                    // atomic per request.
                    //
                    ValidateBranch(parentContainer, branch, allowNewLocalResources);
                }

                foreach (IDvMedia branch in addTheseBranches)
                {
                    // No exceptions were thrown so go ahead and add new
                    // files and directories to the local file system
                    // for the new tree.
                    //
                    if (branch.IsReference == true)
                    {
                        parentContainer.AddBranch(branch);
                    }
                    else
                    {
                        ModifyLocalFileSystem(parentContainer, branch);
                    }
                }
            }
            catch (Exception e)
            {
                error = e;
            }
            this.m_LockRoot.ReleaseMutex();

            if (error != null)
            {
                throw new ApplicationException("Handle_OnRequestAddBranch()", error);
            }
        }
        public void UpdatePermissionsEx(DvMediaContainer container, bool restricted, bool readOnly)
        {
            //			if (readOnly)
            //			{
            //				//container.WriteStatus = OpenSource.UPnP.AV.CdsMetadata.EnumWriteStatus.NOT_WRITABLE;
            //			}
            //			else
            //			{
            //				//container.WriteStatus = OpenSource.UPnP.AV.CdsMetadata.EnumWriteStatus.WRITABLE;
            //			}
            container.IsRestricted = restricted;

            foreach (DvMediaItem i in container.Items)
            {
            //				if (readOnly)
            //				{
            //					//i.WriteStatus = OpenSource.UPnP.AV.CdsMetadata.EnumWriteStatus.NOT_WRITABLE;
            //				}
            //				else
            //				{
            //					//i.WriteStatus = OpenSource.UPnP.AV.CdsMetadata.EnumWriteStatus.WRITABLE;
            //				}
                i.IsRestricted = restricted;

                foreach (DvMediaResource res in i.Resources)
                {
                    if ((container.IsRestricted == false) && (i.IsRestricted == false))
                    {
                        res.AllowImport = true;
                    }
                    else
                    {
                        res.AllowImport = false;
                    }
                }
            }

            foreach (DvMediaContainer c in container.Containers)
            {
                UpdatePermissionsEx(c,restricted,readOnly);
            }
        }
 private void Handle_OnRequestRemoveBranch(MediaServerDevice sender, DvMediaContainer parentContainer, IDvMedia removeThisBranch)
 {
     Exception error = null;
     this.m_LockRoot.WaitOne();
     try
     {
         parentContainer.RemoveBranch(removeThisBranch);
     }
     catch (Exception e)
     {
         error = e;
     }
     this.m_LockRoot.ReleaseMutex();
     if (error != null)
     {
         throw new ApplicationException("Handle_OnRequestRemoveBranch()", error);
     }
 }
        private void AdjustContainer(DvMediaContainer c)
        {
            InnerMediaDirectory imd = c.Tag as InnerMediaDirectory;
            bool dirExists = false;

            // Remove non-root containers if the associated directory no longer exists.
            if (c.IsRootContainer == false)
            {
                if (imd != null)
                {
                    imd.directory = new DirectoryInfo(imd.directoryname);
                    if (imd.directory.Exists == false)
                    {
                        c.Parent.RemoveObject(c);
                    }
                    else
                    {
                        dirExists = true;
                    }
                }
            }

            // c.CompleteList returns a shallow copy
            foreach (IDvMedia dv in c.CompleteList)
            {
                if (dv.IsContainer)
                {
                    this.AdjustContainer((DvMediaContainer) dv);
                }
                else if (dv.IsReference)
                {
                    // ignore references
                }
                else
                {
                    // this is an item; dv.Resources returns a shallow copy
                    foreach (IDvResource res in dv.Resources)
                    {
                        if (res.ContentUri.StartsWith(MediaResource.AUTOMAPFILE))
                        {
                            string localPath = res.ContentUri.Remove(0, MediaResource.AUTOMAPFILE.Length);
                            int quesMark = localPath.LastIndexOf('?');
                            if (quesMark >= 0)
                            {
                                localPath = localPath.Substring(0, localPath.LastIndexOf('?'));
                            }

                            if (File.Exists(localPath) == false)
                            {
                                dv.RemoveResource(res);
                            }
                        }
                    }

                    // if the item has no resources, remove it
                    if (dv.Resources.Length == 0)
                    {
                        dv.Parent.RemoveObject(dv);
                    }
                }
            }

            if (dirExists)
            {
                this.totalDirectoryCount++;

                // Scan the directory for containers and files that don't exist
                // in the current tree
                DirectoryInfo[] subdirs = imd.directory.GetDirectories();
                FileInfo[] files = imd.directory.GetFiles();
                IList containers = c.Containers;
                IList items = c.Items;

                foreach (DirectoryInfo subdir in subdirs)
                {
                    bool found = false;
                    foreach (IDvContainer dvc in containers)
                    {
                        InnerMediaDirectory imd2 = dvc.Tag as InnerMediaDirectory;

                        if (imd2 != null)
                        {
                            // this container has a mapping to a local directory,
                            // so determine if the container matches the
                            // target name
                            if (string.Compare(subdir.FullName, imd2.directoryname, true) == 0)
                            {
                                found = true;
                                break;
                            }
                        }
                    }

                    if (found == false)
                    {
                        // the subdirectory wasn't found as a container in the tree,
                        // so go ahead and add it
                        this.AddDirectoryEx(c, subdir);
                    }
                }

                foreach (FileInfo file in files)
                {
                    bool found = false;
                    foreach (IDvItem dvi in items)
                    {
                        if (dvi.IsReference == false)
                        {
                            bool foundRes = false;
                            foreach (IDvResource res in dvi.Resources)
                            {
                                string localPath = res.ContentUri.Remove(0, MediaResource.AUTOMAPFILE.Length);
                                int quesMark = localPath.LastIndexOf('?');
                                if (quesMark >= 0)
                                {
                                    localPath = localPath.Substring(0, localPath.LastIndexOf('?'));
                                }

                                if (string.Compare(localPath, file.FullName, true) == 0)
                                {
                                    foundRes = true;
                                }
                                break;
                            }

                            if (foundRes)
                            {
                                found = true;
                                break;
                            }
                        }
                    }

                    foreach (IDvContainer dvc in containers)
                    {
                        if (dvc.Class.IsA(MediaBuilder.StandardMediaClasses.PlaylistContainer))
                        {
                            FileInfo plfi = dvc.Tag as FileInfo;
                            if (plfi != null)
                            {
                                if (string.Compare(plfi.FullName, file.FullName, true) == 0)
                                {
                                    found = true;
                                }
                            }
                        }
                    }

                    if (found == false)
                    {
                        // the file wasn't found as a resource in the
                        // content hierarchy, so go ahead and add it
                        IDvMedia newItem = this.CreateObjFromFile(file, new ArrayList());
                        c.AddObject(newItem, true);
                    }

                    // we either already had a media item for the file, or we just added one
                    this.totalFileCount++;
                }

                // Also initialize inner media directory objects with a file
                // system watcher if the directory still exists.
                // We do this at the end because we don't want to subscribe
                // to changes until after we've added files.
                imd.watcher = new FileSystemWatcher(imd.directory.FullName);
                imd.watcher.Changed += new FileSystemEventHandler(OnDirectoryChangedSink);
                imd.watcher.Created += new FileSystemEventHandler(OnDirectoryCreatedSink);
                imd.watcher.Deleted += new FileSystemEventHandler(OnDirectoryDeletedSink);
                imd.watcher.Renamed += new RenamedEventHandler(OnFileSystemRenameSink);
            }
        }
        private void ModifyLocalFileSystem(DvMediaContainer branchFrom, IDvMedia branch)
        {
            DvMediaContainer parent = (DvMediaContainer) branchFrom;

            IList resources = branch.Resources;

            if (branch.IsContainer)
            {
                DvMediaContainer container = (DvMediaContainer) branch;
                if (container.Class.ToString().StartsWith("object.container.storage"))
                {
                    // This container is a storage container of some sort
                    // so it should map to local directory.
                    //
                    string newDirPath = "";
                    if (container.Tag != null)
                    {
                        newDirPath = container.Tag.ToString();
                    }

                    // Make a directory representing this container
                    // and set the container's tag to point to the
                    // media dir info.
                    //
                    DirectoryInfo newDirInfo = Directory.CreateDirectory(newDirPath);
                    InnerMediaDirectory mediadir = new InnerMediaDirectory();
                    mediadir.directory = newDirInfo;
                    mediadir.directoryname = newDirInfo.FullName;
                    container.Tag = mediadir;
                }
                else if (container.Class.ToString().StartsWith("object.container"))
                {
                    // This is a container, but it doesn't nececessarily map
                    // to a local directory. The container subtree may have
                    // items and references, so persist them virtually
                    // in the hierarchy but not on disk.
                    //
                    container.Tag = null;
                }

                foreach (IDvMedia child in container.CompleteList)
                {
                    ModifyLocalFileSystem(container, child);
                }
            }
        }
        private void RemoveContainerEx(DvMediaContainer container)
        {
            InnerMediaDirectory mediadir = (InnerMediaDirectory)container.Tag;
            mediadir.watcher.EnableRaisingEvents = false;
            watcherTable.Remove(mediadir.watcher);
            mediadir.watcher.Changed -= new FileSystemEventHandler(OnDirectoryChangedSink);
            mediadir.watcher.Created -= new FileSystemEventHandler(OnDirectoryCreatedSink);
            mediadir.watcher.Deleted -= new FileSystemEventHandler(OnDirectoryDeletedSink);
            mediadir.watcher.Renamed -= new RenamedEventHandler(OnFileSystemRenameSink);
            mediadir.watcher.Dispose();
            mediadir.watcher = null;
            mediadir.directory = null;

            RemoveInnerContainers(container);

            totalDirectoryCount--;
            totalFileCount -= container.Items.Count;
            if (OnStatsChanged != null) OnStatsChanged(this);
        }
        private void RemoveInnerContainers(DvMediaContainer container)
        {
            foreach (DvMediaContainer c in container.Containers)
            {
                InnerMediaDirectory mediadir = c.Tag as InnerMediaDirectory;
                if (mediadir != null)
                {
                    mediadir.watcher.EnableRaisingEvents = false;
                    watcherTable.Remove(mediadir.watcher);
                    mediadir.watcher.Changed -= new FileSystemEventHandler(OnDirectoryChangedSink);
                    mediadir.watcher.Created -= new FileSystemEventHandler(OnDirectoryCreatedSink);
                    mediadir.watcher.Deleted -= new FileSystemEventHandler(OnDirectoryDeletedSink);
                    mediadir.watcher.Renamed -= new RenamedEventHandler(OnFileSystemRenameSink);
                    mediadir.watcher.Dispose();
                    mediadir.watcher = null;
                    mediadir.directory = null;

                    RemoveInnerContainers(c);
                    totalFileCount -= c.Items.Count;
                    container.RemoveBranch(c);
                    totalDirectoryCount--;
                    if (OnStatsChanged != null) OnStatsChanged(this);
                }
                else if (c.Tag.GetType() == typeof(FileInfo))
                {
                    // this is a playlist container, so decrement
                    // the file count
                    totalFileCount--;
                }
            }
        }
 /// <summary>
 /// Changes this object's parent to another container.
 /// Strongly recommended that this container already
 /// share the object's current hierarchy.
 /// </summary>
 /// <param name="diffParent"></param>
 /// <exception cref="InvalidCastException">
 /// Thrown if this object was improperly added to a
 /// container that is not a <see cref="DvMediaContainer"/>.
 /// </exception>
 public void ChangeParent(IDvContainer diffParent)
 {
     DvMediaContainer.ChangeParent2(this, (DvMediaContainer)diffParent);
 }
        /// <summary>
        /// Changes the target media object's parent to a different parent.
        /// </summary>
        /// <param name="target">target object</param>
        /// <param name="np">new parent</param>
        /// <exception cref="InvalidCastException">
        /// Thrown when the target's current parent is not a <see cref="DvMediaContainer"/>.
        /// </exception>
        internal static void ChangeParent2(IDvMedia target, DvMediaContainer np)
        {
            Exception error = null;
            IUPnPMedia errorDuplicate = null;
            IDvMedia[] removeThese = new IDvMedia[1];
            removeThese[0] = target;

            DvMediaContainer dvp = (DvMediaContainer) target.Parent;

            // fire about to remove event
            if (dvp.OnChildrenToRemove != null)
            {
                dvp.OnChildrenToRemove(dvp, removeThese);
            }

            // acquire locks
            dvp.m_LockListing.AcquireWriterLock(-1);
            np.m_LockListing.AcquireWriterLock(-1);

            try
            {
                // remove target from current parent
                int i = dvp.HashingMethod.Get(dvp.m_Listing, target);
                dvp.m_Listing.RemoveAt(i);
                target.Parent = null;
                if (dvp.m_Listing.Count == 0) { dvp.m_Listing = null; }

                // add target to new parent
                if (np.m_Listing == null) { np.m_Listing = new ArrayList(); }
                try
                {
                    np.HashingMethod.Set(np.m_Listing, target, true);
                    target.Parent = np;
                }
                catch (KeyCollisionException)
                {
                    errorDuplicate = target;
                }
            }
            catch (Exception e)
            {
                error = e;
            }

            // release locks
            np.m_LockListing.ReleaseWriterLock();
            dvp.m_LockListing.ReleaseWriterLock();

            // throw exceptions if appropriate
            if (error != null)
            {
                throw new Exception("Unexpected rrror in DvMediaContainer.ChangeParent2", error);
            }

            if (errorDuplicate != null)
            {
                throw new Error_DuplicateIdException(errorDuplicate);
            }

            // fire children removed event
            if (dvp.OnChildrenRemoved != null)
            {
                dvp.OnChildrenRemoved (dvp, removeThese);
            }

            // notify upnp network that two containers changed.
            dvp.NotifyRootOfChange();
            np.NotifyRootOfChange();
        }