/// <summary>
        /// Throws an exception if the media object should not be added
        /// as a child.
        /// </summary>
        /// <param name="media"></param>
        /// <returns></returns>
        /// <exception cref="InvalidCastException">
        /// Thrown if the "media" argument is not an <see cref="IDvItem"/> or an <see cref="IDvContainer"/> object.
        /// Also thrown if the underlying referenced item of "media" is not an <see cref="IDvItem"/>.
        /// </exception>
        /// <exception cref="Error_PendingDeleteException">
        /// Thrown if the underlying referenced item of "media" is slated for deletion.
        /// </exception>
        private void ThrowExceptionIfBad(IDvMedia media)
        {
            if (media.IsItem)
            {
                // perform an explicit cast - throws InvalidCastException if error
                IDvItem dvItem = (IDvItem)media;

                if (media.IsReference)
                {
                    IDvItem underlying = dvItem.RefItem as IDvItem;
                    if (underlying == null)
                    {
                        throw new InvalidCastException("Cannot convert media.RefItem to IDvItem");
                    }
                    else if (underlying.IsDeletePending)
                    {
                        throw new Error_PendingDeleteException(underlying);
                    }
                }
            }
            else
            {
                // perform an explicit cast - throws InvalidCastException if error
                IDvContainer dvContainer = (IDvContainer)media;
            }
        }
 /// <summary>
 /// Tells the owning object that something has changed.
 /// </summary>
 /// <exception cref="InvalidCastException">
 /// thrown if the owner is not a <see cref="IDvMedia"/> object.
 /// </exception>
 private void NotifyOwnerOfChange()
 {
     if (this.Owner != null)
     {
         IDvMedia owner = (IDvMedia)this.Owner;
         owner.NotifyRootOfChange();
     }
 }
        /// <summary>
        /// AddObject() requires that the child be an <see cref="IDvMedia"/> object.
        /// </summary>
        /// <param name="newObject"></param>
        /// <param name="overWrite"></param>
        /// <exception cref="InvalidCastException">
        /// Thrown if the added object is not an <see cref="IDvMedia"/> object.
        /// </exception>
        public override void AddObject(IUPnPMedia newObject, bool overWrite)
        {
            IDvMedia dv = (IDvMedia)newObject;

#if (DEBUG)
            this.ThrowExceptionIfBad(dv);
#endif
            base.AddObject(newObject, overWrite);

            this.NotifyRootOfChange();
        }
        /// <summary>
        /// This removes a container or item object from
        /// the child list. It is used by other
        /// RemoveXXX methods defined in this class
        /// and implements the portion that allows
        /// proper media server eventing.
        /// <para>
        /// Method properly tells items to notify all other
        /// items that reference it that it will be deleted.
        /// </para>
        /// <para>
        /// Method properly tells containers to recursively
        /// remove their child objects, so that descendent
        /// reference items are properly removed.
        /// </para>
        /// </summary>
        /// <param name="removeThis"></param>
        public override void RemoveObject(IUPnPMedia removeThis)
        {
            IDvMedia     dv        = removeThis as IDvMedia;
            IDvItem      item      = removeThis as IDvItem;
            IDvContainer container = removeThis as IDvContainer;

            // Before we go about doing any removal operations,
            // we fire the event to indicate this object is
            // about to be removed.
            ArrayList removeThese = new ArrayList(1);

            removeThese.Add(removeThis);
            if (this.OnChildrenToRemove != null)
            {
                this.OnChildrenToRemove(this, removeThese);
            }

            if (item != null)
            {
                // Notify any and all referring items that
                // this object is about to be removed
                // from its parent.
                item.NotifyPendingDelete();
            }
            else if (container != null)
            {
                // Instruct all child containers to
                // remove their own children.
                IList children = container.CompleteList;
                foreach (IDvMedia child in children)
                {
                    container.RemoveObject(child);
                }
            }

            // go ahead and remove this object
            base.RemoveObject(removeThis);

            // Notify that the child has formerly been
            // removed.
            if (this.OnChildrenRemoved != null)
            {
                this.OnChildrenRemoved(this, removeThese);
            }

            this.NotifyRootOfChange();
        }
        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;
            }
        }
Exemplo n.º 6
0
        public static void WriteInnerXmlResources(IUPnPMedia mo, InnerXmlWriter.DelegateShouldPrintResources shouldPrintResources, ToXmlFormatter formatter, ToXmlData data, XmlTextWriter xmlWriter)
        {
            IDvMedia    dvm  = (IDvMedia)mo;
            ToXmlDataDv txdv = (ToXmlDataDv)data;

            if (shouldPrintResources(txdv.DesiredProperties))
            {
                if (txdv.BaseUris == null)
                {
                    txdv.BaseUris = new ArrayList();
                }
                if (txdv.BaseUris.Count == 0)
                {
                    txdv.BaseUris.Add(txdv.BaseUri);
                }

                ToXmlFormatter resFormatter = formatter;
                resFormatter.StartElement  = null;
                resFormatter.EndElement    = null;
                resFormatter.WriteInnerXml = null;
                resFormatter.WriteValue    = null;

                // Code is unfinished - intended to allow a media object to
                // print duplicate resource elements so that each resource
                // is printed once for every available network interface.

                foreach (string baseUri in txdv.BaseUris)
                {
                    txdv.BaseUri = baseUri;
                    foreach (IMediaResource res in dvm.MergedResources)
                    {
                        // Set up the resource formatter to use the
                        // default StartElement, EndElement, WriteInnerXml, and WriteValue
                        // implementations. This stuff has no effect
                        // if the WriteResource field has been assigned.
                        res.ToXml(resFormatter, txdv, xmlWriter);
                    }
                }
            }
        }
        /// <summary>
        /// Method executes when a control point invokes the ContentDirectory.CreateReference action.
        /// Method is supposed to create a child item that points to an existing
        /// media item that is somewhere else in the content hierarchy.
        /// The method should throw exceptions if related media objects are not
        /// found and should also prevent control points from creating
        /// references to other containers.
        /// </summary>
        /// <param name="containerID">Create a child item in this container.</param>
        /// <param name="objectID">The new child item should refer to this item.</param>
        /// <param name="NewID">Return the object ID of the new child item.</param>
        private void SinkCd_CreateReference(System.String containerID, System.String objectID, out System.String NewID)
        {
            // ensure that we can find the container where new child should be.
            DvMediaContainer parent = this.GetContainer(containerID);

            if (parent == null)
            {
                throw new Error_NoSuchContainer("("+containerID+")");
            }

            // ensure we can find item that is being referenced
            DvMediaItem refItem = this.GetItem(objectID);

            if (refItem == null)
            {
                throw new Error_NoSuchObject("("+objectID+")");
            }

            // create a new object that points to the referenced item
            refItem.LockReferenceList();
            IDvItem newItem = refItem.CreateReference();
            refItem.UnlockReferenceList();

            // request application logic for approval in adding this new item.
            // Application logic should throw an exception, preferably a UPnPCustomException,
            // to indicate a rejection
            IDvMedia[] branch = new IDvMedia[1];
            branch[0] = newItem;
            if (this.OnRequestAddBranch != null)
            {
                this.OnRequestAddBranch(this, parent, ref branch);
            }
            else
            {
                throw new Error_InvalidServerConfiguration("CreateReference() cannot be supported until the vendor configures the server correctly.");
            }

            // set the value for new ID
            NewID = newItem.ID;

            this.m_Stats.CreateReference++;
            this.FireStatsChange();
        }
        /// <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 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.");
                            }
                        }
                    }
                }
            }
        }
        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 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);
     }
 }
 /// <summary>
 /// Adds an item, container, or a complete content subtree to this container.
 /// If the branch is a multiple-item subtree, then the programmer should
 /// take care to ensure that the proposed sub-tree is stable by itself.
 /// <para>
 /// This method is somewhat different than <see cref="DvMediaContainer.AddObject"/>()
 /// in that the added branch is assigned a new unique id from 
 /// <see cref="MediaBuilder.GetUniqueId"/>(). Such a methodology absolves the
 /// application-logic from requiring <see cref="MediaBuilder.PrimeNextId"/>()
 /// to prevent object ID collisions. Programmers should be careful when mixing
 /// use of <see cref="DvMediaContainer.AddObject"/>() and
 /// AddBranch(), as improper use can still cause ID collisions. As a general rule,
 /// application logic that uses <see cref="DvMediaContainer.AddObject"/>()
 /// should always use <see cref="MediaBuilder.PrimeNextId"/>() to prime the
 /// media object counter and application logic that always uses AddBranch()
 /// need not do this.
 /// </para>
 /// </summary>
 /// <param name="branch">An item, container, or multiple-item subtree.</param>
 /// <exception cref="InvalidCastException">
 /// Thrown if the branch is not a <see cref="IDvItem"/> or a <see cref="IDvContainer"/>.
 /// </exception>
 public virtual void AddBranch(IDvMedia branch)
 {
     branch.ID = MediaBuilder.GetUniqueId();
     this.AddObject(branch, false);
 }
 /// <summary>
 /// <para>
 /// Removes an item, container, or a complete content subtree from this container.
 /// If the branch is a multiple-item subtree, then the effect is
 /// recursive and immediately reflected in the advertised content hierarchy.
 /// </para>
 ///
 /// <para>
 /// Although the actual MediaResource objects are effectively removed
 /// from advertisment in the content hierarchy, the local binaries associated
 /// with those resources are automatically deleted by this routine. The
 /// ContentDirectory spec indicates that the deletion of binaries is an
 /// implementation specific issue, and so this implementation requires that
 /// control-points (or internal control logic) delete the binaries in a
 /// manner external to this function.
 /// </para>
 /// </summary>
 /// <param name="branch">An item, container, or multiple-item subtree.</param>
 public virtual void RemoveBranch(IDvMedia branch)
 {
     this.RemoveObject(branch);
 }
 /// <summary>
 /// <para>
 /// Removes an item, container, or a complete content subtree from this container.
 /// If the branch is a multiple-item subtree, then the effect is
 /// recursive and immediately reflected in the advertised content hierarchy.
 /// </para>
 /// 
 /// <para>
 /// Although the actual MediaResource objects are effectively removed
 /// from advertisment in the content hierarchy, the local binaries associated 
 /// with those resources are automatically deleted by this routine. The
 /// ContentDirectory spec indicates that the deletion of binaries is an
 /// implementation specific issue, and so this implementation requires that
 /// control-points (or internal control logic) delete the binaries in a
 /// manner external to this function.
 /// </para>
 /// </summary>
 /// <param name="branch">An item, container, or multiple-item subtree.</param>
 public virtual void RemoveBranch(IDvMedia branch)
 {
     this.RemoveObject(branch);
 }
        /// <summary>
        /// Method executes when a control point invokes the ContentDirectory.CreateObject action.
        /// The invoker is supposed to provide most of the valid DIDL-Lite XML for the new object.
        /// This method will construct a new media object, assign a unique object ID, 
        /// assign appropriate importUri and contentUri values to empty resource attributes
        /// and then output the new object ID as well as the current DIDL-Lite representaiton
        /// of the object.
        /// <para>
        /// The method supports a vendor specific override, where multiple objects can be
        /// created in a single call, by means of using the same syntax as the normal, except
        /// container elements can have child item/container elements, representing
        /// an entire subtree. Can also have multiple item or container elements under DIDL-Lite
        /// tag to indicate multiple subtrees.
        /// </para>
        /// <para>
        /// The method supports a vendor specific override, where resource elements in the
        /// DIDL-Lite can specify the <see cref="MediaResource.AUTOMAPFILE"/> convention
        /// to automatically add locally mapped files. This does assume the control poitn
        /// has intimate knowledge about the file system used by this media server.
        /// </para>
        /// </summary>
        /// <param name="containerID">Create new object in this container.</param>
        /// <param name="Elements">Partial DIDL-Lite document to create the actual object(s).</param>
        /// <param name="objectID">Object ID for created media object.</param>
        /// <param name="Result">DIDL-Lite response for the created object(s).</param>
        private void SinkCd_CreateObject(System.String containerID, System.String Elements, out System.String objectID, out System.String Result)
        {
            try
            {
                DvMediaContainer parent = this.GetContainer(containerID);

                if (parent == null)
                {
                    throw new Error_NoSuchObject("The container \""+containerID+"\" does not exist.");
                }

                // builds new subtrees under containerID using the XML in Elements.
                ArrayList newBranches = DvMediaBuilder.BuildMediaBranches(Elements);

                // At this point, newBranches contains a list of IDvMedia objects
                // that are proposed for addition to the content hierarchy.

                if (this.OnRequestAddBranch != null)
                {
                    IDvMedia[] addTheseBranches = new IDvMedia[newBranches.Count];
                    for (int x=0; x < newBranches.Count; x++)
                    {
                        addTheseBranches[x] = (IDvMedia) newBranches[x];
                    }
                    newBranches = null;
                    this.OnRequestAddBranch (this, parent, ref addTheseBranches);

                    // Reflect the new branches in the tree.
                    //
                    foreach (IDvMedia branch in addTheseBranches)
                    {
                        // Use AddObject() instead of AddBranch()
                        // because the branch already has a unique ID
                        // generated from MediaBuilder.GetUniqueId().

                        //parent.AddBranch(branch);
                        parent.AddObject(branch, false);
                    }

                    // Initialize structures used to process output for this method.
                    //
                    StringBuilder newIds = new StringBuilder(9 * addTheseBranches.Length);
                    StringBuilder sbXml = null;
                    StringWriter sw = null;
                    MemoryStream ms = null;
                    XmlTextWriter xmlWriter = null;

                    // Write the xml response for the operation
                    //
                    if (ENCODE_UTF8)
                    {
                        ms = new MemoryStream(XML_BUFFER_SIZE);
                        xmlWriter = new XmlTextWriter(ms, System.Text.Encoding.UTF8);
                    }
                    else
                    {
                        sbXml = new StringBuilder(XML_BUFFER_SIZE);
                        sw = new StringWriter(sbXml);
                        xmlWriter = new XmlTextWriter(sw);
                    }

                    xmlWriter.Formatting = System.Xml.Formatting.Indented;
                    xmlWriter.Namespaces = true;

                    // recurse new subtrees and write DIDL-Lite stuff
                    MediaObject.WriteResponseHeader(xmlWriter);
                    RecurseNewBranches(addTheseBranches, newIds, xmlWriter);
                    MediaObject.WriteResponseFooter(xmlWriter);
                    xmlWriter.Flush();

                    objectID = newIds.ToString();

                    // properly recast string for UTF8 or UTF-16
                    if (ENCODE_UTF8)
                    {
                        int startPos = 3;
                        int len = (int) ms.ToArray().Length - startPos;
                        UTF8Encoding utf8e = new UTF8Encoding(false, true);
                        Result = utf8e.GetString(ms.ToArray(), startPos, len);
                    }
                    else
                    {
                        Result = sbXml.ToString();
                    }

                    xmlWriter.Close();
                }
                else
                {
                    throw new Error_InvalidServerConfiguration("CreateObject() cannot be supported until the vendor configures the server correctly.");
                }
            }
            catch (Exception e)
            {
                Exception ne = new Exception("MediaServerDevice.CreateObject()", e);
                throw ne;
            }

            this.m_Stats.CreateObject++;
            this.FireStatsChange();
        }
Exemplo n.º 16
0
        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>
        /// 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();
        }
 /// <summary>
 /// Adds an item, container, or a complete content subtree to this container.
 /// If the branch is a multiple-item subtree, then the programmer should
 /// take care to ensure that the proposed sub-tree is stable by itself.
 /// <para>
 /// This method is somewhat different than <see cref="DvMediaContainer.AddObject"/>()
 /// in that the added branch is assigned a new unique id from
 /// <see cref="MediaBuilder.GetUniqueId"/>(). Such a methodology absolves the
 /// application-logic from requiring <see cref="MediaBuilder.PrimeNextId"/>()
 /// to prevent object ID collisions. Programmers should be careful when mixing
 /// use of <see cref="DvMediaContainer.AddObject"/>() and
 /// AddBranch(), as improper use can still cause ID collisions. As a general rule,
 /// application logic that uses <see cref="DvMediaContainer.AddObject"/>()
 /// should always use <see cref="MediaBuilder.PrimeNextId"/>() to prime the
 /// media object counter and application logic that always uses AddBranch()
 /// need not do this.
 /// </para>
 /// </summary>
 /// <param name="branch">An item, container, or multiple-item subtree.</param>
 /// <exception cref="InvalidCastException">
 /// Thrown if the branch is not a <see cref="IDvItem"/> or a <see cref="IDvContainer"/>.
 /// </exception>
 public virtual void AddBranch(IDvMedia branch)
 {
     branch.ID = MediaBuilder.GetUniqueId();
     this.AddObject(branch, false);
 }
        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);
            }
        }
        private void Handle_OnRequestChangeMetadata(MediaServerDevice sender, IDvMedia oldObject, IDvMedia newObject)
        {
            Exception error = null;
            this.m_LockRoot.WaitOne();

            try
            {

                /// TODO: Add permissions logic
                ///
                /// The following metadata fields must be the same between the old and new objects.
                ///		ID,
                ///		refID
                ///		Parent
                ///		IsRestricted
                ///
                if (oldObject.IsRestricted)
                {
                    //Allow everything for now
                    //throw new Error_RestrictedObject("Cannot modify a restricted object.");
                }

                if (oldObject.ID != newObject.ID)
                {
                    throw new Error_ReadOnlyTag("Cannot modify ID");
                }

                if (oldObject.IsContainer != newObject.IsContainer)
                {
                    throw new Error_BadMetadata("Cannot change containers into items.");
                }

                if (oldObject.IsItem != newObject.IsItem)
                {
                    throw new Error_BadMetadata("Cannot change items into containers.");
                }

                if (oldObject.IsRestricted != newObject.IsRestricted)
                {
                    throw new Error_ReadOnlyTag("Cannot change the \"restricted\" attribute.");
                }

                if ((oldObject.IsReference) || (newObject.IsReference))
                {
                    if (oldObject.IsReference == newObject.IsReference)
                    {
                        DvMediaItem oldItem = (DvMediaItem) oldObject;
                        DvMediaItem newItem = (DvMediaItem) newObject;

                        string refid1 = oldItem.RefID;
                        string refid2 = newItem.RefID;

                        if (string.Compare(refid1, refid2) != 0)
                        {
                            throw new Error_ReadOnlyTag("Cannot change the \"refID\" attribute.");
                        }
                    }
                    else
                    {
                        throw new Error_BadMetadata("Cannot change a reference item into a non-reference.");
                    }
                }
            }
            catch (Exception e)
            {
                error = e;
            }
            this.m_LockRoot.ReleaseMutex();
            if (error != null)
            {
                throw new ApplicationException("Handle_OnRequestChangeMetadata()", error);
            }

            // TODO: Actually check validity for metadata of media objects and their resources.
        }
        /// <summary>
        /// Throws an exception if the media object should not be added
        /// as a child.
        /// </summary>
        /// <param name="media"></param>
        /// <returns></returns>
        /// <exception cref="InvalidCastException">
        /// Thrown if the "media" argument is not an <see cref="IDvItem"/> or an <see cref="IDvContainer"/> object.
        /// Also thrown if the underlying referenced item of "media" is not an <see cref="IDvItem"/>.
        /// </exception>
        /// <exception cref="Error_PendingDeleteException">
        /// Thrown if the underlying referenced item of "media" is slated for deletion.
        /// </exception>
        private void ThrowExceptionIfBad(IDvMedia media)
        {
            if (media.IsItem)
            {
                // perform an explicit cast - throws InvalidCastException if error
                IDvItem dvItem = (IDvItem) media;

                if (media.IsReference)
                {
                    IDvItem underlying = dvItem.RefItem as IDvItem;
                    if (underlying == null)
                    {
                        throw new InvalidCastException("Cannot convert media.RefItem to IDvItem");
                    }
                    else if (underlying.IsDeletePending)
                    {
                        throw new Error_PendingDeleteException(underlying);
                    }
                }
            }
            else
            {
                // perform an explicit cast - throws InvalidCastException if error
                IDvContainer dvContainer = (IDvContainer) media;
            }
        }