diff options
Diffstat (limited to 'database/object.cpp')
-rw-r--r-- | database/object.cpp | 1702 |
1 files changed, 1702 insertions, 0 deletions
diff --git a/database/object.cpp b/database/object.cpp new file mode 100644 index 0000000..748078d --- /dev/null +++ b/database/object.cpp @@ -0,0 +1,1702 @@ +/* + * File: object.cpp + * Author: savop + * + * Created on 11. September 2009, 20:39 + */ + +#include <string.h> +#include <stdio.h> +#include <upnp/upnptools.h> +#include <vdr/recording.h> +#include <vector> +#include "database.h" +#include <vdr/tools.h> +#include <upnp/ixml.h> +#include "metadata.h" +#include "object.h" +#include "../common.h" +#include "resources.h" + +cUPnPResource::cUPnPResource(){ + this->mBitrate = 0; + this->mBitsPerSample = 0; + this->mColorDepth = 0; + this->mDuration = NULL; + this->mImportURI = NULL; + this->mNrAudioChannels = 0; + this->mObjectID = 0; + this->mProtocolInfo = NULL; + this->mResolution = NULL; + this->mResource = NULL; + this->mResourceID = 0; + this->mSampleFrequency = 0; + this->mSize = 0; + this->mContentType = NULL; +} + +off64_t cUPnPResource::getFileSize() const { + return (this->mSize) ? this->mSize : -1; +} + +time_t cUPnPResource::getLastModification() const { + time_t Time; + const cRecording* Recording; + const cEvent* Event; + switch(this->mResourceType){ + case UPNP_RESOURCE_CHANNEL: + case UPNP_RESOURCE_URL: + Time = time(NULL); + break; + case UPNP_RESOURCE_RECORDING: + Recording = Recordings.GetByName(this->mResource); + Event = (Recording)?Recording->Info()->GetEvent():NULL; + Time = (Event)?Event->EndTime():time(NULL); + break; + case UPNP_RESOURCE_FILE: + //break; + default: + ERROR("Invalid resource type. This resource might be broken"); + Time = -1; + } + return Time; +} + +static int CompareUPnPObjects(const void *a, const void *b){ + const cUPnPClassObject *la = *(const cUPnPClassObject **)a; + const cUPnPClassObject *lb = *(const cUPnPClassObject **)b; + return la->Compare(*lb); +} + +cUPnPObjects::cUPnPObjects(){} + +cUPnPObjects::~cUPnPObjects(){} + +void cUPnPObjects::SortBy(const char* Property, bool Descending){ + int n = Count(); + cUPnPClassObject *a[n]; + cUPnPClassObject *object = (cUPnPClassObject *)objects; + int i = 0; + while (object && i < n) { + object->setSortCriteria(Property, Descending); + a[i++] = object; + object = (cUPnPClassObject *)object->Next(); + } + qsort(a, n, sizeof(cUPnPClassObject *), CompareUPnPObjects); + objects = lastObject = NULL; + for (i = 0; i < n; i++) { + a[i]->Unlink(); + count--; + Add(a[i]); + } +} + + /**********************************************\ + * * + * UPnP Objects * + * * + \**********************************************/ + + /**********************************************\ + * * + * Object * + * * + \**********************************************/ + +cUPnPClassObject::cUPnPClassObject(){ + this->mID = -1; + this->mResources = new cList<cUPnPResource>; + this->mResourcesID = new cHash<cUPnPResource>; + this->mParent = NULL; + this->mClass = NULL; + this->mCreator = NULL; + this->mTitle = NULL; + this->mWriteStatus = WS_UNKNOWN; + this->mRestricted = true; + this->mDIDLFragment = NULL; + this->mSortCriteria = NULL; + this->mLastModified = NULL; +} + +cUPnPClassObject::~cUPnPClassObject(){ + if(this->mParent) this->mParent->getContainer()->removeObject(this); + this->mResources->Clear(); + this->mResourcesID->Clear(); + delete this->mResources; + delete this->mResourcesID; + free(this->mDIDLFragment); +} + +int cUPnPClassObject::Compare(const cListObject& ListObject) const { + char* Value1 = NULL; char* Value2 = NULL; int ret = 0; + cUPnPClassObject* Object = (cUPnPClassObject*)&ListObject; + if(Object->getProperty(this->mSortCriteria, &Value1) && + this->getProperty(this->mSortCriteria, &Value2)){ + ret = strcmp(Value1, Value2); + if(this->mSortDescending) ret *= -1; + } + return ret; +} + +void cUPnPClassObject::setSortCriteria(const char* Property, bool Descending){ + this->mSortCriteria = Property; + this->mSortDescending = Descending; +} + +void cUPnPClassObject::clearSortCriteria(){ + this->mSortCriteria = NULL; + this->mSortDescending = false; +} + +int cUPnPClassObject::setID(cUPnPObjectID ID){ + MESSAGE("Set ID from %s to %s", *this->getID(),*ID); + if((int)ID < 0){ + ERROR("Invalid object ID '%s'",*ID); + return -1; + } + this->mID = ID; + return 0; +} + +int cUPnPClassObject::setParent(cUPnPClassContainer* Parent){ + if(Parent==NULL){ + MESSAGE("Object '%s' elected as root object", *this->getID()); + } + // unregister from old parent + if(this->mParent && Parent != this->mParent){ + this->mParent->getContainer()->removeObject(this); + } + this->mParent = Parent; + return 0; +} + +int cUPnPClassObject::setClass(const char* Class){ + if( !strcasecmp(Class, UPNP_CLASS_ALBUM) || + !strcasecmp(Class, UPNP_CLASS_AUDIO) || + !strcasecmp(Class, UPNP_CLASS_AUDIOBC) || + !strcasecmp(Class, UPNP_CLASS_AUDIOBOOK) || + !strcasecmp(Class, UPNP_CLASS_CONTAINER) || + !strcasecmp(Class, UPNP_CLASS_GENRE) || + !strcasecmp(Class, UPNP_CLASS_IMAGE) || + !strcasecmp(Class, UPNP_CLASS_ITEM) || + !strcasecmp(Class, UPNP_CLASS_MOVIE) || + !strcasecmp(Class, UPNP_CLASS_MOVIEGENRE) || + !strcasecmp(Class, UPNP_CLASS_MUSICALBUM) || + !strcasecmp(Class, UPNP_CLASS_MUSICARTIST) || + !strcasecmp(Class, UPNP_CLASS_MUSICGENRE) || + !strcasecmp(Class, UPNP_CLASS_MUSICTRACK) || + !strcasecmp(Class, UPNP_CLASS_MUSICVIDCLIP) || + !strcasecmp(Class, UPNP_CLASS_OBJECT) || + !strcasecmp(Class, UPNP_CLASS_PERSON) || + !strcasecmp(Class, UPNP_CLASS_PHOTO) || + !strcasecmp(Class, UPNP_CLASS_PHOTOALBUM) || + !strcasecmp(Class, UPNP_CLASS_PLAYLIST) || + !strcasecmp(Class, UPNP_CLASS_PLAYLISTCONT) || + !strcasecmp(Class, UPNP_CLASS_STORAGEFOLD) || + !strcasecmp(Class, UPNP_CLASS_STORAGESYS) || + !strcasecmp(Class, UPNP_CLASS_STORAGEVOL) || + !strcasecmp(Class, UPNP_CLASS_TEXT) || + !strcasecmp(Class, UPNP_CLASS_VIDEO) || + !strcasecmp(Class, UPNP_CLASS_VIDEOBC) + ){ + this->mClass = strdup0(Class); + return 0; + } + else { + ERROR("Invalid or unsupported class '%s'", Class); + return -1; + } +} + +int cUPnPClassObject::setTitle(const char* Title){ + if(Title==NULL){ + ERROR("Title is empty but required"); + return -1; + } + this->mTitle = strdup0(Title); + return 0; +} + +int cUPnPClassObject::setCreator(const char* Creator){ + this->mCreator = strdup0(Creator); + return 0; +} + +int cUPnPClassObject::setRestricted(bool Restricted){ + this->mRestricted = Restricted; + return 0; +} + +int cUPnPClassObject::setWriteStatus(int WriteStatus){ + if( WriteStatus == WS_MIXED || + WriteStatus == WS_NOT_WRITABLE || + WriteStatus == WS_PROTECTED || + WriteStatus == WS_UNKNOWN || + WriteStatus == WS_WRITABLE){ + this->mWriteStatus = WriteStatus; + return 0; + } + else { + ERROR("Invalid write status '%d'", WriteStatus); + return -1; + } +} + +bool cUPnPClassObject::getProperty(const char* Property, char** Value) const { + cString Val; + if(!strcasecmp(Property, SQLITE_COL_OBJECTID) || !strcasecmp(Property, UPNP_PROP_OBJECTID)){ + Val = *this->getID(); + } + else if(!strcasecmp(Property, SQLITE_COL_PARENTID) || !strcasecmp(Property, UPNP_PROP_PARENTID)){ + Val = *this->getParentID(); + } + else if(!strcasecmp(Property, SQLITE_COL_CLASS) || !strcasecmp(Property, UPNP_PROP_CLASS)){ + Val = this->getClass(); + } + else if(!strcasecmp(Property, SQLITE_COL_TITLE) || !strcasecmp(Property, UPNP_PROP_TITLE)){ + Val = this->getTitle(); + } + else if(!strcasecmp(Property, SQLITE_COL_CREATOR) || !strcasecmp(Property, UPNP_PROP_CREATOR)){ + Val = this->getCreator(); + } + else if(!strcasecmp(Property, SQLITE_COL_RESTRICTED) || !strcasecmp(Property, UPNP_PROP_RESTRICTED)){ + Val = this->isRestricted()?"1":"0"; + } + else if(!strcasecmp(Property, SQLITE_COL_WRITESTATUS) || !strcasecmp(Property, UPNP_PROP_WRITESTATUS)){ + Val = cString::sprintf("%d",this->getWriteStatus()); + } + else { + ERROR("Invalid property '%s'", Property); + return false; + } + *Value = strdup0(*Val); + return true; +} + +cStringList* cUPnPClassObject::getPropertyList(){ + cStringList* Properties = new cStringList; + Properties->Append(strdup(UPNP_PROP_CREATOR)); + Properties->Append(strdup(UPNP_PROP_WRITESTATUS)); + return Properties; +} + +bool cUPnPClassObject::setProperty(const char* Property, const char* Value){ + int ret; + if(!strcasecmp(Property, SQLITE_COL_OBJECTID) || !strcasecmp(Property, UPNP_PROP_OBJECTID)){ + ERROR("Not allowed to set object ID by hand"); + return false; + } + else if(!strcasecmp(Property, SQLITE_COL_PARENTID) || !strcasecmp(Property, UPNP_PROP_PARENTID)){ + ERROR("Not allowed to set parent ID by hand"); + return false; + } + else if(!strcasecmp(Property, SQLITE_COL_CLASS) || !strcasecmp(Property, UPNP_PROP_CLASS)){ + ERROR("Not allowed to set class by hand"); + return false; + } + else if(!strcasecmp(Property, SQLITE_COL_TITLE) || !strcasecmp(Property, UPNP_PROP_TITLE)){ + ret = this->setTitle(Value); + } + else if(!strcasecmp(Property, SQLITE_COL_CREATOR) || !strcasecmp(Property, UPNP_PROP_CREATOR)){ + ret = this->setCreator(Value); + } + else if(!strcasecmp(Property, SQLITE_COL_RESTRICTED) || !strcasecmp(Property, UPNP_PROP_RESTRICTED)){ + ret = this->setRestricted(atoi(Value)==1?true:false); + } + else if(!strcasecmp(Property, SQLITE_COL_WRITESTATUS) || !strcasecmp(Property, UPNP_PROP_WRITESTATUS)){ + ret= this->setWriteStatus(atoi(Value)); + } + else { + ERROR("Invalid property '%s'", Property); + return false; + } + return ret<0?false:true; +} + +int cUPnPClassObject::addResource(cUPnPResource* Resource){ + MESSAGE("Adding resource #%d", Resource->getID()); + if(!Resource){ + ERROR("No resource"); + return -1; + } + this->mResources->Add(Resource); + this->mResourcesID->Add(Resource, Resource->getID()); + return 0; +} + +int cUPnPClassObject::removeResource(cUPnPResource* Resource){ + if(!Resource){ + ERROR("No resource"); + return -1; + } + this->mResourcesID->Del(Resource, Resource->getID()); + this->mResources->Del(Resource); + return 0; +} + + /**********************************************\ + * * + * Item * + * * + \**********************************************/ + +cUPnPClassItem::cUPnPClassItem(){ + this->setClass(UPNP_CLASS_ITEM); + this->mReference = NULL; +} + +int cUPnPClassItem::setReference(cUPnPClassItem* Reference){ + this->mReference = Reference; + return 0; +} + +cStringList* cUPnPClassItem::getPropertyList(){ + cStringList* Properties = cUPnPClassObject::getPropertyList(); + Properties->Append(strdup(UPNP_PROP_REFERENCEID)); + return Properties; +} + +bool cUPnPClassItem::getProperty(const char* Property, char** Value) const { + + if(!strcasecmp(Property, SQLITE_COL_REFERENCEID) || !strcasecmp(Property, UPNP_PROP_REFERENCEID)){ + *Value = strdup0(*this->getReferenceID()); + } + else return cUPnPClassObject::getProperty(Property, Value); + return true; +} + +bool cUPnPClassItem::setProperty(const char* Property, const char* Value){ + return cUPnPClassObject::setProperty(Property, Value); +} + +IXML_Node* cUPnPClassItem::createDIDLFragment(IXML_Document* Document, cStringList* Filter){ + this->mDIDLFragment = Document; + + MESSAGE("==(%s)= %s =====", *this->getID(), this->getTitle()); + MESSAGE("ParentID: %s", *this->getParentID()); + MESSAGE("Restricted: %s", this->isRestricted()?"1":"0"); + MESSAGE("Class: %s", this->getClass()); + + IXML_Node* Didl = ixmlNode_getFirstChild((IXML_Node*) this->mDIDLFragment); + + IXML_Element* eItem = ixmlDocument_createElement(this->mDIDLFragment, "item"); + ixmlElement_setAttribute(eItem, att(UPNP_PROP_OBJECTID), *this->getID()); + ixmlElement_setAttribute(eItem, att(UPNP_PROP_PARENTID), *this->getParentID()); + ixmlElement_setAttribute(eItem, att(UPNP_PROP_RESTRICTED), this->isRestricted()?"1":"0"); + + ixmlNode_appendChild(Didl, (IXML_Node*) eItem); + + IXML_Element* eTitle = ixmlDocument_createElement(this->mDIDLFragment, UPNP_PROP_TITLE); + IXML_Node* Title = ixmlDocument_createTextNode(this->mDIDLFragment, this->getTitle()); + + IXML_Element* eClass = ixmlDocument_createElement(this->mDIDLFragment, UPNP_PROP_CLASS); + IXML_Node* Class = ixmlDocument_createTextNode(this->mDIDLFragment, this->getClass()); + + ixmlNode_appendChild((IXML_Node*) eTitle, Title); + ixmlNode_appendChild((IXML_Node*) eClass, Class); + ixmlNode_appendChild((IXML_Node*) eItem, (IXML_Node*) eTitle); + ixmlNode_appendChild((IXML_Node*) eItem, (IXML_Node*) eClass); + +// if(Filter==NULL || Filter->Find(UPNP_PROP_CREATOR)) ixmlAddProperty(this->mDIDLFragment, eItem, UPNP_PROP_CREATOR, this->getCreator()); +// if(Filter==NULL || Filter->Find(UPNP_PROP_WRITESTATUS)) ixmlAddProperty(this->mDIDLFragment, eItem, UPNP_PROP_WRITESTATUS, itoa(this->getWriteStatus())); +// if(Filter==NULL || Filter->Find(UPNP_PROP_REFERENCEID)) ixmlAddProperty(this->mDIDLFragment, eItem, UPNP_PROP_REFERENCEID, *this->getReferenceID()); + + for(cUPnPResource* Resource = this->getResources()->First(); Resource; Resource = this->getResources()->Next(Resource)){ + MESSAGE("Resource: %s", Resource->getResource()); + MESSAGE("Protocolinfo: %s", Resource->getProtocolInfo()); + + cString URLBase = cString::sprintf("http://%s:%d", UpnpGetServerIpAddress(), UpnpGetServerPort()); + cString ResourceURL = cString::sprintf("%s%s/get?resId=%d", *URLBase, UPNP_DIR_SHARES, Resource->getID()); + + MESSAGE("Resource-URI: %s", *ResourceURL); + + IXML_Element* eRes = ixmlDocument_createElement(this->mDIDLFragment, UPNP_PROP_RESOURCE); + IXML_Node* Res = ixmlDocument_createTextNode(this->mDIDLFragment, *ResourceURL); + ixmlNode_appendChild((IXML_Node*) eRes, Res); + + if(Resource->getBitrate()) ixmlElement_setAttribute(eRes, att(UPNP_PROP_BITRATE), itoa(Resource->getBitrate())); + if(Resource->getBitsPerSample()) ixmlElement_setAttribute(eRes, att(UPNP_PROP_BITSPERSAMPLE), itoa(Resource->getBitsPerSample())); + if(Resource->getColorDepth()) ixmlElement_setAttribute(eRes, att(UPNP_PROP_COLORDEPTH), itoa(Resource->getColorDepth())); + if(Resource->getDuration()) ixmlElement_setAttribute(eRes, att(UPNP_PROP_DURATION), Resource->getDuration()); + if(Resource->getProtocolInfo()) ixmlElement_setAttribute(eRes, att(UPNP_PROP_PROTOCOLINFO), Resource->getProtocolInfo()); + + ixmlNode_appendChild((IXML_Node*) eItem, (IXML_Node*) eRes); + } + + return (IXML_Node*)eItem; +} + + /**********************************************\ + * * + * Container * + * * + \**********************************************/ + +cUPnPClassContainer::cUPnPClassContainer(){ + this->setClass(UPNP_CLASS_CONTAINER); + this->mChildren = new cUPnPObjects; + this->mChildrenID = new cHash<cUPnPClassObject>; + this->mContainerType = NULL; + this->mUpdateID = 0; + this->mSearchable = false; +} + +cUPnPClassContainer::~cUPnPClassContainer(){ + delete this->mChildren; + delete this->mChildrenID; +} + +IXML_Node* cUPnPClassContainer::createDIDLFragment(IXML_Document* Document, cStringList* Filter){ + this->mDIDLFragment = Document; + + MESSAGE("===(%s)= %s =====", *this->getID(), this->getTitle()); + MESSAGE("ParentID: %s", *this->getParentID()); + MESSAGE("Restricted: %s", this->isRestricted()?"1":"0"); + MESSAGE("Class: %s", this->getClass()); + + IXML_Node* Didl = ixmlNode_getFirstChild((IXML_Node*) this->mDIDLFragment); + IXML_Element* eItem = ixmlDocument_createElement(this->mDIDLFragment, "container"); + ixmlElement_setAttribute(eItem, att(UPNP_PROP_OBJECTID), *this->getID()); + ixmlElement_setAttribute(eItem, att(UPNP_PROP_PARENTID), *this->getParentID()); + ixmlElement_setAttribute(eItem, att(UPNP_PROP_RESTRICTED), this->isRestricted()?"1":"0"); + ixmlNode_appendChild(Didl, (IXML_Node*) eItem); + + IXML_Element* eTitle = ixmlDocument_createElement(this->mDIDLFragment, UPNP_PROP_TITLE); + IXML_Node* Title = ixmlDocument_createTextNode(this->mDIDLFragment, this->getTitle()); + + IXML_Element* eClass = ixmlDocument_createElement(this->mDIDLFragment, UPNP_PROP_CLASS); + IXML_Node* Class = ixmlDocument_createTextNode(this->mDIDLFragment, this->getClass()); + + ixmlNode_appendChild((IXML_Node*) eTitle, Title); + ixmlNode_appendChild((IXML_Node*) eClass, Class); + ixmlNode_appendChild((IXML_Node*) eItem, (IXML_Node*) eTitle); + ixmlNode_appendChild((IXML_Node*) eItem, (IXML_Node*) eClass); + + return (IXML_Node*)eItem; +} + +int cUPnPClassContainer::setUpdateID(unsigned int UID){ + this->mUpdateID = UID; + return 0; +} + +cStringList* cUPnPClassContainer::getPropertyList(){ + cStringList* Properties = cUPnPClassObject::getPropertyList(); + Properties->Append(strdup(UPNP_PROP_DLNA_CONTAINERTYPE)); + Properties->Append(strdup(UPNP_PROP_SEARCHABLE)); + return Properties; +} + +bool cUPnPClassContainer::setProperty(const char* Property, const char* Value){ + int ret; + if(!strcasecmp(Property, SQLITE_COL_DLNA_CONTAINERTYPE) || !strcasecmp(Property, UPNP_PROP_DLNA_CONTAINERTYPE)){ + ret = this->setContainerType(Value); + } + else if(!strcasecmp(Property, SQLITE_COL_SEARCHABLE) || !strcasecmp(Property, UPNP_PROP_SEARCHABLE)){ + ret = this->setSearchable(Value); + } + else if(!strcasecmp(Property, SQLITE_COL_CONTAINER_UID)){ + ret = this->setUpdateID((unsigned int)atoi(Value)); + } + else return cUPnPClassObject::setProperty(Property, Value); + return ret<0?false:true; +} + +bool cUPnPClassContainer::getProperty(const char* Property, char** Value) const { + cString Val; + if(!strcasecmp(Property, SQLITE_COL_DLNA_CONTAINERTYPE) || !strcasecmp(Property, UPNP_PROP_DLNA_CONTAINERTYPE)){ + Val = this->getContainerType(); + } + else if(!strcasecmp(Property, SQLITE_COL_SEARCHABLE) || !strcasecmp(Property, UPNP_PROP_SEARCHABLE)){ + Val = this->isSearchable()?"1":"0"; + } + else if(!strcasecmp(Property, SQLITE_COL_CONTAINER_UID)){ + Val = cString::sprintf("%d", this->getUpdateID()); + } + else return cUPnPClassObject::getProperty(Property, Value); + *Value = strdup0(*Val); + return true; +} + +void cUPnPClassContainer::addObject(cUPnPClassObject* Object){ + MESSAGE("Adding object (ID:%s) to container (ID:%s)", *Object->getID(), *this->getID()); + this->mChildren->Add(Object); + this->mChildrenID->Add(Object, (unsigned int)Object->getID()); + Object->setParent(this); +} + +void cUPnPClassContainer::removeObject(cUPnPClassObject* Object){ + MESSAGE("Removing object (ID:%s) from container (ID:%s)", *Object->getID(), *this->getID()); + this->mChildrenID->Del(Object, (unsigned int)Object->getID()); + this->mChildren->Del(Object, false); + Object->mParent = NULL; +} + +cUPnPClassObject* cUPnPClassContainer::getObject(cUPnPObjectID ID) const { + MESSAGE("Getting object (ID:%s)", *ID); + if((int)ID < 0){ + ERROR("Invalid object ID"); + return NULL; + } + return this->mChildrenID->Get((unsigned int)ID); +} + +int cUPnPClassContainer::setContainerType(const char* Type){ + if(Type==NULL){ + this->mContainerType = Type; + } + else if(!strcasecmp(Type, DLNA_CONTAINER_TUNER)){ + this->mContainerType = Type; + } + else { + ERROR("Invalid container type '%s'",Type); + return -1; + } + return 0; +} + +int cUPnPClassContainer::addSearchClass(cClass SearchClass){ + this->mSearchClasses.push_back(SearchClass); + return 0; +} + +int cUPnPClassContainer::delSearchClass(cClass SearchClass){ + tClassVector::iterator it = this->mSearchClasses.begin(); + cClass Class; + for(unsigned int i=0; i<this->mSearchClasses.size(); i++){ + Class = this->mSearchClasses[i]; + if(Class == SearchClass){ + this->mSearchClasses.erase(it+i); + return 0; + } + } + return -1; +} + +int cUPnPClassContainer::addCreateClass(cClass CreateClass){ + this->mCreateClasses.push_back(CreateClass); + return 0; +} + +int cUPnPClassContainer::delCreateClass(cClass CreateClass){ + tClassVector::iterator it = this->mCreateClasses.begin(); + cClass Class; + for(unsigned int i=0; i<this->mCreateClasses.size(); i++){ + Class = this->mCreateClasses[i]; + if(Class == CreateClass){ + this->mCreateClasses.erase(it+i); + return 0; + } + } + return -1; +} + +int cUPnPClassContainer::setSearchClasses(std::vector<cClass> SearchClasses){ + this->mSearchClasses = SearchClasses; + return 0; +} + +int cUPnPClassContainer::setCreateClasses(std::vector<cClass> CreateClasses){ + this->mCreateClasses = CreateClasses; + return 0; +} + +int cUPnPClassContainer::setSearchable(bool Searchable){ + this->mSearchable = Searchable; + return 0; +} + +bool cUPnPClassContainer::isUpdated(){ + static unsigned int lastUpdateID = this->getUpdateID(); + if(lastUpdateID != this->getUpdateID()){ + lastUpdateID = this->getUpdateID(); + return true; + } + else return false; +} + + /**********************************************\ + * * + * Video item * + * * + \**********************************************/ + +cUPnPClassVideoItem::cUPnPClassVideoItem(){ + this->setClass(UPNP_CLASS_VIDEO); + this->mGenre = NULL; + this->mLongDescription = NULL; + this->mProducers = NULL; + this->mRating = NULL; + this->mActors = NULL; + this->mDirectors = NULL; + this->mDescription = NULL; + this->mPublishers = NULL; + this->mLanguage = NULL; + this->mRelations = NULL; +} + +cUPnPClassVideoItem::~cUPnPClassVideoItem(){ +} + +//cString cUPnPClassVideoItem::createDIDLFragment(cStringList* Filter){ +// return NULL; +//} + +cStringList* cUPnPClassVideoItem::getPropertyList(){ + cStringList* Properties = cUPnPClassItem::getPropertyList(); + Properties->Append(strdup(UPNP_PROP_LONGDESCRIPTION)); + Properties->Append(strdup(UPNP_PROP_PRODUCER)); + Properties->Append(strdup(UPNP_PROP_GENRE)); + Properties->Append(strdup(UPNP_PROP_RATING)); + Properties->Append(strdup(UPNP_PROP_ACTOR)); + Properties->Append(strdup(UPNP_PROP_DIRECTOR)); + Properties->Append(strdup(UPNP_PROP_DESCRIPTION)); + Properties->Append(strdup(UPNP_PROP_PUBLISHER)); + Properties->Append(strdup(UPNP_PROP_LANGUAGE)); + Properties->Append(strdup(UPNP_PROP_RELATION)); + return Properties; +} + +bool cUPnPClassVideoItem::getProperty(const char* Property, char** Value) const { + cString Val; + if(!strcasecmp(Property,SQLITE_COL_GENRE) || !strcasecmp(Property,UPNP_PROP_GENRE)){ + Val = this->getGenre(); + } + else if(!strcasecmp(Property,SQLITE_COL_LONGDESCRIPTION) || !strcasecmp(Property,UPNP_PROP_LONGDESCRIPTION)){ + Val = this->getLongDescription(); + } + else if(!strcasecmp(Property,SQLITE_COL_PRODUCER) || !strcasecmp(Property,UPNP_PROP_PRODUCER)){ + Val = this->getProducers(); + } + else if(!strcasecmp(Property,SQLITE_COL_RATING) || !strcasecmp(Property,UPNP_PROP_RATING)){ + Val = this->getRating(); + } + else if(!strcasecmp(Property,SQLITE_COL_ACTOR) || !strcasecmp(Property,UPNP_PROP_ACTOR)){ + Val = this->getActors(); + } + else if(!strcasecmp(Property,SQLITE_COL_DIRECTOR) || !strcasecmp(Property,UPNP_PROP_DIRECTOR)){ + Val = this->getDirectors(); + } + else if(!strcasecmp(Property,SQLITE_COL_DESCRIPTION) || !strcasecmp(Property,UPNP_PROP_DESCRIPTION)){ + Val = this->getDescription(); + } + else if(!strcasecmp(Property,SQLITE_COL_PUBLISHER) || !strcasecmp(Property,UPNP_PROP_PUBLISHER)){ + Val = this->getPublishers(); + } + else if(!strcasecmp(Property,SQLITE_COL_LANGUAGE) || !strcasecmp(Property,UPNP_PROP_LANGUAGE)){ + Val = this->getLanguage(); + } + else if(!strcasecmp(Property,SQLITE_COL_RELATION) || !strcasecmp(Property,UPNP_PROP_RELATION)){ + Val = this->getRelations(); + } + else return cUPnPClassItem::getProperty(Property, Value); + *Value = strdup0(*Val); + return true; +} + +bool cUPnPClassVideoItem::setProperty(const char* Property, const char* Value){ + bool ret; + if(!strcasecmp(Property,SQLITE_COL_GENRE) || !strcasecmp(Property,UPNP_PROP_GENRE)){ + ret = this->setGenre(Value); + } + else if(!strcasecmp(Property,SQLITE_COL_LONGDESCRIPTION) || !strcasecmp(Property,UPNP_PROP_LONGDESCRIPTION)){ + ret = this->setLongDescription(Value); + } + else if(!strcasecmp(Property,SQLITE_COL_PRODUCER) || !strcasecmp(Property,UPNP_PROP_PRODUCER)){ + ret = this->setProducers(Value); + } + else if(!strcasecmp(Property,SQLITE_COL_RATING) || !strcasecmp(Property,UPNP_PROP_RATING)){ + ret = this->setRating(Value); + } + else if(!strcasecmp(Property,SQLITE_COL_ACTOR) || !strcasecmp(Property,UPNP_PROP_ACTOR)){ + ret = this->setActors(Value); + } + else if(!strcasecmp(Property,SQLITE_COL_DIRECTOR) || !strcasecmp(Property,UPNP_PROP_DIRECTOR)){ + ret = this->setDirectors(Value); + } + else if(!strcasecmp(Property,SQLITE_COL_DESCRIPTION) || !strcasecmp(Property,UPNP_PROP_DESCRIPTION)){ + ret = this->setDescription(Value); + } + else if(!strcasecmp(Property,SQLITE_COL_PUBLISHER) || !strcasecmp(Property,UPNP_PROP_PUBLISHER)){ + ret = this->setPublishers(Value); + } + else if(!strcasecmp(Property,SQLITE_COL_LANGUAGE) || !strcasecmp(Property,UPNP_PROP_LANGUAGE)){ + ret = this->setLanguage(Value); + } + else if(!strcasecmp(Property,SQLITE_COL_RELATION) || !strcasecmp(Property,UPNP_PROP_RELATION)){ + ret = this->setRelations(Value); + } + else return cUPnPClassItem::setProperty(Property, Value); + return ret<0?false:true; +} + +int cUPnPClassVideoItem::setActors(const char* Actors){ + this->mActors = Actors; + return 0; +} + +int cUPnPClassVideoItem::setGenre(const char* Genre){ + this->mGenre = Genre; + return 0; +} + +int cUPnPClassVideoItem::setDescription(const char* Description){ + this->mDescription = Description; + return 0; +} + +int cUPnPClassVideoItem::setLongDescription(const char* LongDescription){ + this->mLongDescription = LongDescription; + return 0; +} + +int cUPnPClassVideoItem::setProducers(const char* Producers){ + this->mProducers = Producers; + return 0; +} + +int cUPnPClassVideoItem::setRating(const char* Rating){ + this->mRating = Rating; + return 0; +} + +int cUPnPClassVideoItem::setDirectors(const char* Directors){ + this->mDirectors = Directors; + return 0; +} + +int cUPnPClassVideoItem::setPublishers(const char* Publishers){ + this->mPublishers = Publishers; + return 0; +} + +int cUPnPClassVideoItem::setLanguage(const char* Language){ + this->mLanguage = Language; + return 0; +} + +int cUPnPClassVideoItem::setRelations(const char* Relations){ + this->mRelations = Relations; + return 0; +} + + /**********************************************\ + * * + * Video Broadcast item * + * * + \**********************************************/ + +cUPnPClassVideoBroadcast::cUPnPClassVideoBroadcast(){ + this->setClass(UPNP_CLASS_VIDEOBC); + this->mIcon = NULL; + this->mRegion = NULL; + this->mChannelNr = 0; +} + +cUPnPClassVideoBroadcast::~cUPnPClassVideoBroadcast(){ +} + +//cString cUPnPClassVideoBroadcast::createDIDLFragment(cStringList* Filter){ +// return NULL; +//} + +cStringList* cUPnPClassVideoBroadcast::getPropertyList(){ + cStringList* Properties = cUPnPClassVideoItem::getPropertyList(); + Properties->Append(strdup(UPNP_PROP_CHANNELNAME)); + Properties->Append(strdup(UPNP_PROP_CHANNELNR)); + Properties->Append(strdup(UPNP_PROP_ICON)); + Properties->Append(strdup(UPNP_PROP_REGION)); + return Properties; +} + +bool cUPnPClassVideoBroadcast::setProperty(const char* Property, const char* Value){ + bool ret; + if(!strcasecmp(Property, SQLITE_COL_CHANNELNAME) || !strcasecmp(Property, UPNP_PROP_CHANNELNAME)){ + ret = this->setChannelName(Value); + } + else if(!strcasecmp(Property, SQLITE_COL_CHANNELNR) || !strcasecmp(Property, UPNP_PROP_CHANNELNR)){ + ret = this->setChannelNr(atoi(Value)); + } + else if(!strcasecmp(Property, SQLITE_COL_ICON) || !strcasecmp(Property, UPNP_PROP_ICON)){ + ret = this->setIcon(Value); + } + else if(!strcasecmp(Property, SQLITE_COL_REGION) || !strcasecmp(Property, UPNP_PROP_REGION)){ + ret = this->setRegion(Value); + } + else return cUPnPClassVideoItem::setProperty(Property, Value); + return ret<0?false:true; +} + +bool cUPnPClassVideoBroadcast::getProperty(const char* Property, char** Value) const { + cString Val; + if(!strcasecmp(Property, SQLITE_COL_CHANNELNAME) || !strcasecmp(Property, UPNP_PROP_CHANNELNAME)){ + Val = this->getChannelName(); + } + else if(!strcasecmp(Property, SQLITE_COL_CHANNELNR) || !strcasecmp(Property, UPNP_PROP_CHANNELNR)){ + Val = itoa(this->getChannelNr()); + } + else if(!strcasecmp(Property, SQLITE_COL_ICON) || !strcasecmp(Property, UPNP_PROP_ICON)){ + Val = this->getIcon(); + } + else if(!strcasecmp(Property, SQLITE_COL_REGION) || !strcasecmp(Property, UPNP_PROP_REGION)){ + Val = this->getRegion(); + } + else return cUPnPClassVideoItem::getProperty(Property, Value); + *Value = strdup0(*Val); + return true; +} + +int cUPnPClassVideoBroadcast::setChannelName(const char* ChannelName){ + this->mChannelName = ChannelName; + return 0; +} + +int cUPnPClassVideoBroadcast::setChannelNr(int ChannelNr){ + this->mChannelNr = ChannelNr; + return 0; +} + +int cUPnPClassVideoBroadcast::setIcon(const char* IconURI){ + this->mIcon = IconURI; + return 0; +} + +int cUPnPClassVideoBroadcast::setRegion(const char* Region){ + this->mRegion = Region; + return 0; +} + + /**********************************************\ + * * + * Mediator factory * + * * + \**********************************************/ + +cUPnPObjectFactory* cUPnPObjectFactory::mInstance = NULL; + +cUPnPObjectFactory* cUPnPObjectFactory::getInstance(){ + if(!cUPnPObjectFactory::mInstance) + cUPnPObjectFactory::mInstance = new cUPnPObjectFactory(); + + if(cUPnPObjectFactory::mInstance) return cUPnPObjectFactory::mInstance; + else return NULL; +} + +cUPnPObjectFactory::cUPnPObjectFactory(){ + this->mDatabase = cSQLiteDatabase::getInstance(); +} + +void cUPnPObjectFactory::registerMediator(const char* UPnPClass, cMediatorInterface* Mediator){ + if(UPnPClass == NULL){ + ERROR("Class is undefined"); + return; + } + if(Mediator == NULL){ + ERROR("Mediator is undefined"); + return; + } + MESSAGE("Registering mediator for class '%s'", UPnPClass); + this->mMediators[UPnPClass] = Mediator; + MESSAGE("Now %d mediators registered", this->mMediators.size()); + return; +} + +void cUPnPObjectFactory::unregisterMediator(const char* UPnPClass, bool freeMediator){ + if(UPnPClass == NULL){ + ERROR("Class is undefined"); + return; + } + tMediatorMap::iterator MediatorIterator = this->mMediators.find(UPnPClass); + if(MediatorIterator==this->mMediators.end()){ + ERROR("No such mediator found for class '%s'", UPnPClass); + return; + } + MESSAGE("Unregistering mediator for class '%s'", UPnPClass); + this->mMediators.erase(MediatorIterator); + if(freeMediator) delete MediatorIterator->second; + MESSAGE("Now %d mediators registered", this->mMediators.size()); + return; +} + +cMediatorInterface* cUPnPObjectFactory::findMediatorByID(cUPnPObjectID ID){ + cString Format = "SELECT %s FROM %s WHERE %s=%s"; + cString Statement = NULL, Column = NULL, Value = NULL, Class = NULL; + cRows* Rows; cRow* Row; + Statement = cString::sprintf(Format, SQLITE_COL_CLASS, SQLITE_TABLE_OBJECTS, SQLITE_COL_OBJECTID, *ID); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return NULL; + } + Rows = this->mDatabase->getResultRows(); + if(!Rows->fetchRow(&Row)){ + ERROR("No such object with ID '%s'",*ID); + return NULL; + } + while(Row->fetchColumn(&Column, &Value)){ + if(!strcasecmp(Column, SQLITE_COL_CLASS)){ + Class = strdup0(*Value); + } + } + return this->findMediatorByClass(Class); +} + +cMediatorInterface* cUPnPObjectFactory::findMediatorByClass(const char* Class){ + if(!Class){ ERROR("No class specified"); return NULL; } + MESSAGE("Searching for mediator '%s' in %d mediators", Class, this->mMediators.size()); + tMediatorMap::iterator MediatorIterator = this->mMediators.find(Class); + if(MediatorIterator==this->mMediators.end()){ + ERROR("No matching mediator for class '%s'",Class); + return NULL; + } + else { + return MediatorIterator->second; + } +} + +cUPnPClassObject* cUPnPObjectFactory::getObject(cUPnPObjectID ID){ + cMediatorInterface* Mediator = this->findMediatorByID(ID); + if(Mediator) return Mediator->getObject(ID); + else { + return NULL; + } +} + +cUPnPClassObject* cUPnPObjectFactory::createObject(const char* UPnPClass, const char* Title, bool Restricted){ + cMediatorInterface* Mediator = this->findMediatorByClass(UPnPClass); + return Mediator->createObject(Title, Restricted); +} + +int cUPnPObjectFactory::deleteObject(cUPnPClassObject* Object){ + cMediatorInterface* Mediator = this->findMediatorByClass(Object->getClass()); + return Mediator->deleteObject(Object); +} + +int cUPnPObjectFactory::clearObject(cUPnPClassObject* Object){ + cMediatorInterface* Mediator = this->findMediatorByClass(Object->getClass()); + return Mediator->clearObject(Object); +} + +int cUPnPObjectFactory::saveObject(cUPnPClassObject* Object){ + cMediatorInterface* Mediator = this->findMediatorByClass(Object->getClass()); + return Mediator->saveObject(Object); +} + + /**********************************************\ + * * + * Mediators * + * * + \**********************************************/ + + /**********************************************\ + * * + * Object mediator * + * * + \**********************************************/ + +cUPnPObjectMediator::cUPnPObjectMediator(cMediaDatabase* MediaDatabase) : + mMediaDatabase(MediaDatabase){ + this->mDatabase = cSQLiteDatabase::getInstance(); +} + +cUPnPObjectMediator::~cUPnPObjectMediator(){ + delete this->mDatabase; + delete this->mMediaDatabase; +} + +int cUPnPObjectMediator::saveObject(cUPnPClassObject* Object){ + bool succesful = true; + + this->mDatabase->startTransaction(); + if(Object->getID() == -1) succesful = false; + else if(this->objectToDatabase(Object)) succesful = false; + else succesful = true; + + if(succesful){ + this->mDatabase->commitTransaction(); + Object->setModified(); + this->mMediaDatabase->cacheObject(Object); + this->mMediaDatabase->updateSystemID(); + return 0; + } + else { + this->mDatabase->rollbackTransaction(); + return -1; + } + return -1; +} + +int cUPnPObjectMediator::deleteObject(cUPnPClassObject* Object){ + cString Statement = NULL; + cString Format = "DELETE FROM %s WHERE %s=%s"; + Statement = cString::sprintf(Format, SQLITE_TABLE_OBJECTS, SQLITE_COL_OBJECTID, *Object->getID()); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + #ifdef SQLITE_CASCADE_DELETES + this->clearObject(Object); + #endif + delete Object; Object = NULL; + return 0; +} + +int cUPnPObjectMediator::clearObject(cUPnPClassObject* Object){ + cUPnPClassContainer* Container = Object->getContainer(); + if(Container){ + cList<cUPnPClassObject>* List = Container->getObjectList(); + for(cUPnPClassObject* Child = List->First(); Child; Child = List->Next(Child)){ + if(this->deleteObject(Child)) return -1; + } + } + return 0; +} + +int cUPnPObjectMediator::initializeObject(cUPnPClassObject* Object, const char* Class, const char* Title, bool Restricted){ + cUPnPObjectID ObjectID = this->mMediaDatabase->getNextObjectID(); + if(Object->setID(ObjectID)){ + ERROR("Error while setting ID"); + return -1; + } + cUPnPClassObject* Root = this->mMediaDatabase->getObjectByID(0); + if(Root){ + Root->getContainer()->addObject(Object); + } + else { + Object->setParent(NULL); + } + if(Object->setClass(Class)){ + ERROR("Error while setting class"); + return -1; + } + if(Object->setTitle(Title)){ + ERROR("Error while setting title"); + return -1; + } + if(Object->setRestricted(Restricted)){ + ERROR("Error while setting restriction"); + return -1; + } + char* escapedTitle; + escapeSQLite(Object->getTitle(), &escapedTitle); + cString Statement = cString::sprintf("INSERT INTO %s (%s, %s, %s, %s, %s) VALUES (%s, %s, '%s', '%s', %d)", + SQLITE_TABLE_OBJECTS, + SQLITE_COL_OBJECTID, + SQLITE_COL_PARENTID, + SQLITE_COL_CLASS, + SQLITE_COL_TITLE, + SQLITE_COL_RESTRICTED, + *Object->getID(), + *Object->getParentID(), + Object->getClass(), + escapedTitle, + Object->isRestricted()?1:0 + ); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + free(escapedTitle); + return 0; +} + +cUPnPClassObject* cUPnPObjectMediator::getObject(cUPnPObjectID){ WARNING("Getting instance of class 'Object' forbidden"); return NULL; } + +cUPnPClassObject* cUPnPObjectMediator::createObject(const char*, bool){ WARNING("Getting instance of class 'Object' forbidden"); return NULL; } + +int cUPnPObjectMediator::objectToDatabase(cUPnPClassObject* Object){ + cString Format = "UPDATE %s SET %s WHERE %s='%s'"; + //cString Format = "INSERT OR REPLACE INTO %s (%s) VALUES (%s);"; + cString Statement=NULL; + cString Set=NULL; + //cString Columns=NULL, Values=NULL; + char *Value=NULL; + cString Properties[] = { + SQLITE_COL_OBJECTID, + SQLITE_COL_PARENTID, + SQLITE_COL_CLASS, + SQLITE_COL_TITLE, + SQLITE_COL_RESTRICTED, + SQLITE_COL_CREATOR, + SQLITE_COL_WRITESTATUS, + NULL + }; + for(cString* Property = Properties; *(*Property)!=NULL; Property++){ + //Columns = cString::sprintf("%s%s%s", *Columns?*Columns:"", *Columns?",":"", *(*Property)); + if(!Object->getProperty(*Property, &Value)){ + ERROR("No such property '%s' in object with ID '%s'",*(*Property),*Object->getID()); + return -1; + } + char *escapedValue; + escapeSQLite(Value, &escapedValue); + //Values = cString::sprintf("%s%s'%s'", *Values?*Values:"", *Values?",":"", Value?Value:"NULL"); + Set = cString::sprintf("%s%s%s='%s'", *Set?*Set:"", *Set?",":"", *(*Property), escapedValue?escapedValue:"NULL"); + + } + Statement = cString::sprintf(Format, SQLITE_TABLE_OBJECTS, *Set, SQLITE_COL_OBJECTID, *Object->getID()); + //Statement = cString::sprintf(Format, SQLITE_TABLE_OBJECTS, *Columns, *Values); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + return 0; +} + +int cUPnPObjectMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID){ + cString Format = "SELECT * FROM %s WHERE %s=%s"; + cString Statement = NULL, Column = NULL, Value = NULL; + cRows* Rows; cRow* Row; + Statement = cString::sprintf(Format, SQLITE_TABLE_OBJECTS, SQLITE_COL_OBJECTID, *ID); +// MESSAGE("Fehler hier"); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + Rows = this->mDatabase->getResultRows(); + if(!Rows->fetchRow(&Row)){ + ERROR("No such object with ID '%s'",*ID); + return -1; + } + while(Row->fetchColumn(&Column, &Value)){ + if(!strcasecmp(Column, SQLITE_COL_OBJECTID)){ + if(Object->setID(atoi(Value))){ + ERROR("Error while setting object ID"); + return -1; + } + this->mMediaDatabase->cacheObject(Object); + } + else if(!strcasecmp(Column, SQLITE_COL_PARENTID)){ + cUPnPObjectID RefID = atoi(Value); + cUPnPClassContainer* ParentObject; + if(RefID == -1){ + ParentObject = NULL; + } + else { + ParentObject = (cUPnPClassContainer*)this->mMediaDatabase->getObjectByID(RefID); + if(!ParentObject){ + ERROR("No such parent with ID '%s' found.",*RefID); + return -1; + } + } + Object->setParent(ParentObject); + } + else if(!strcasecmp(Column, SQLITE_COL_CLASS)){ + if(Object->setClass(Value)){ + ERROR("Error while setting class"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_TITLE)){ + if(Object->setTitle(Value)){ + ERROR("Error while setting title"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_RESTRICTED)){ + if(Object->setRestricted(atoi(Value)==1?true:false)){ + ERROR("Error while setting restriction"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_CREATOR)){ + if(Object->setCreator(Value)){ + ERROR("Error while setting creator"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_WRITESTATUS)){ + if(Object->setWriteStatus(atoi(Value))){ + ERROR("Error while setting write status"); + return -1; + } + } + } + cUPnPResources::getInstance()->getResourcesOfObject(Object); + return 0; +} + + /**********************************************\ + * * + * Item mediator * + * * + \**********************************************/ + +cUPnPItemMediator::cUPnPItemMediator(cMediaDatabase* MediaDatabase) : + cUPnPObjectMediator(MediaDatabase){} + +int cUPnPItemMediator::objectToDatabase(cUPnPClassObject* Object){ + if(cUPnPObjectMediator::objectToDatabase(Object)) return -1; + cString Format = "INSERT OR REPLACE INTO %s (%s) VALUES (%s);"; + cString Statement=NULL, Columns=NULL, Values=NULL; + char *Value=NULL; + cString Properties[] = { + SQLITE_COL_OBJECTID, + SQLITE_COL_REFERENCEID, + NULL + }; + for(cString* Property = Properties; *(*Property); Property++){ + Columns = cString::sprintf("%s%s%s", *Columns?*Columns:"", *Columns?",":"", *(*Property)); + if(!Object->getProperty(*Property, &Value)){ + ERROR("No such property '%s' in object with ID '%s'",*(*Property),*Object->getID()); + return -1; + } + char *escapedValue; + escapeSQLite(Value, &escapedValue); + Values = cString::sprintf("%s%s'%s'", *Values?*Values:"", *Values?",":"", escapedValue?escapedValue:"NULL"); + + } + Statement = cString::sprintf(Format, SQLITE_TABLE_ITEMS, *Columns, *Values); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + return 0; +} + +int cUPnPItemMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID){ + if(cUPnPObjectMediator::databaseToObject(Object,ID)){ + ERROR("Error while loading object"); + return -1; + } + cUPnPClassItem* Item = (cUPnPClassItem*) Object; + cString Format = "SELECT * FROM %s WHERE %s=%s"; + cString Statement = NULL, Column = NULL, Value = NULL; + cRows* Rows; cRow* Row; + Statement = cString::sprintf(Format, SQLITE_TABLE_ITEMS, SQLITE_COL_OBJECTID, *ID); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + Rows = this->mDatabase->getResultRows(); + if(!Rows->fetchRow(&Row)){ + MESSAGE("No item properties found"); + return 0; + } + while(Row->fetchColumn(&Column, &Value)){ + if(!strcasecmp(Column, SQLITE_COL_REFERENCEID)){ + cUPnPObjectID RefID = atoi(Value); + cUPnPClassItem* RefObject; + if(RefID == -1){ + RefObject = NULL; + } + else { + RefObject = (cUPnPClassItem*)this->mMediaDatabase->getObjectByID(RefID); + if(!RefObject){ + ERROR("No such reference item with ID '%s' found.",*RefID); + return -1; + } + } + Item->setReference(RefObject); + } + } + return 0; +} + +cUPnPClassItem* cUPnPItemMediator::getObject(cUPnPObjectID ID){ + MESSAGE("Getting Item with ID '%s'",*ID); + cUPnPClassItem* Object = new cUPnPClassItem; + if(this->databaseToObject(Object, ID)) return NULL; + return Object; +} + +cUPnPClassItem* cUPnPItemMediator::createObject(const char* Title, bool Restricted){ + MESSAGE("Creating Item '%s'",Title); + cUPnPClassItem* Object = new cUPnPClassItem; + if(this->initializeObject(Object, UPNP_CLASS_ITEM, Title, Restricted)) return NULL; + return Object; +} + + /**********************************************\ + * * + * Container mediator * + * * + \**********************************************/ + +cUPnPContainerMediator::cUPnPContainerMediator(cMediaDatabase* MediaDatabase) : + cUPnPObjectMediator(MediaDatabase){} + +int cUPnPContainerMediator::objectToDatabase(cUPnPClassObject* Object){ + if(cUPnPObjectMediator::objectToDatabase(Object)) return -1; + cUPnPClassContainer* Container = (cUPnPClassContainer*)Object; + cString Format = "INSERT OR REPLACE INTO %s (%s) VALUES (%s);"; + cString Statement=NULL, Columns=NULL, Values=NULL; + char *Value=NULL; + cString Properties[] = { + SQLITE_COL_OBJECTID, + SQLITE_COL_DLNA_CONTAINERTYPE, + SQLITE_COL_SEARCHABLE, + SQLITE_COL_CONTAINER_UID, + NULL + }; + for(cString* Property = Properties; *(*Property); Property++){ + Columns = cString::sprintf("%s%s%s", *Columns?*Columns:"", *Columns?",":"", *(*Property)); + if(!Container->getProperty(*Property, &Value)){ + ERROR("No such property '%s' in object with ID '%s'",*(*Property),*Container->getID()); + return -1; + } + char *escapedValue; + escapeSQLite(Value, &escapedValue); + Values = cString::sprintf("%s%s'%s'", *Values?*Values:"", *Values?",":"", escapedValue?escapedValue:"NULL"); + } + Statement = cString::sprintf(Format, SQLITE_TABLE_CONTAINERS, *Columns, *Values); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + for(unsigned int i=0; i<Container->getSearchClasses()->size(); i++){ + cClass Class = Container->getSearchClasses()->at(i); + Columns = cString::sprintf("%s,%s,%s", SQLITE_COL_OBJECTID, SQLITE_COL_CLASS, SQLITE_COL_CLASSDERIVED); + Values = cString::sprintf("'%s','%s','%s'", *Container->getID(), *Class.ID, Class.includeDerived?"1":"0"); + Statement = cString::sprintf(Format, SQLITE_TABLE_SEARCHCLASS, *Columns, *Values); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + } + // Create classes not necessary at the moment + return 0; +} + +int cUPnPContainerMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID){ + if(cUPnPObjectMediator::databaseToObject(Object,ID)){ + ERROR("Error while loading object"); + return -1; + } + cUPnPClassContainer* Container = (cUPnPClassContainer*)Object; + cString Format = "SELECT * FROM %s WHERE %s=%s"; + cString Statement = NULL, Column = NULL, Value = NULL; + cRows* Rows; cRow* Row; + Statement = cString::sprintf(Format, SQLITE_TABLE_CONTAINERS, SQLITE_COL_OBJECTID, *ID); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + Rows = this->mDatabase->getResultRows(); + if(!Rows->fetchRow(&Row)){ + MESSAGE("No item properties found"); + return 0; + } + while(Row->fetchColumn(&Column, &Value)){ + if(!strcasecmp(Column, SQLITE_COL_DLNA_CONTAINERTYPE)){ + if(Container->setContainerType(Value)){ + ERROR("Error while setting container type"); + return -1; + } + } + if(!strcasecmp(Column, SQLITE_COL_CONTAINER_UID)){ + if(Container->setUpdateID((unsigned int)atoi(Value))){ + ERROR("Error while setting update ID"); + return -1; + } + } + if(!strcasecmp(Column, SQLITE_COL_SEARCHABLE)){ + if(Container->setSearchable(atoi(Value)==1?true:false)){ + ERROR("Error while setting searchable"); + return -1; + } + } + } + Statement = cString::sprintf("SELECT %s FROM %s WHERE %s=%s", SQLITE_COL_OBJECTID, + SQLITE_TABLE_OBJECTS, + SQLITE_COL_PARENTID, + *ID); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + Rows = this->mDatabase->getResultRows(); + while(Rows->fetchRow(&Row)){ + while(Row->fetchColumn(&Column, &Value)){ + if(!strcasecmp(Column, SQLITE_COL_OBJECTID)){ + Container->addObject(this->mMediaDatabase->getObjectByID(atoi(Value))); + } + } + } + Statement = cString::sprintf(Format, SQLITE_TABLE_SEARCHCLASS, SQLITE_COL_OBJECTID, *ID); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + std::vector<cClass> SearchClasses; + Rows = this->mDatabase->getResultRows(); + while(Rows->fetchRow(&Row)){ + cClass Class; + while(Row->fetchColumn(&Column, &Value)){ + if(!strcasecmp(Column, SQLITE_COL_CLASS)){ + Class.ID = strdup0(*Value); + } + else if(!strcasecmp(Column, SQLITE_COL_CLASSDERIVED)){ + Class.includeDerived = atoi(Value)==1?"true":"false"; + } + } + SearchClasses.push_back(Class); + } + if(Container->setSearchClasses(SearchClasses)){ + ERROR("Error while setting search classes"); + return -1; + } + return 0; +} + +cUPnPClassContainer* cUPnPContainerMediator::createObject(const char* Title, bool Restricted){ + MESSAGE("Creating Container '%s'",Title); + cUPnPClassContainer* Object = new cUPnPClassContainer; + if(this->initializeObject(Object, UPNP_CLASS_CONTAINER, Title, Restricted)) return NULL; + return Object; +} + +cUPnPClassContainer* cUPnPContainerMediator::getObject(cUPnPObjectID ID){ + MESSAGE("Getting Container with ID '%s'",*ID); + cUPnPClassContainer* Object = new cUPnPClassContainer; + if(this->databaseToObject(Object, ID)) return NULL; + return Object; +} + + /**********************************************\ + * * + * Video item mediator * + * * + \**********************************************/ + +cUPnPVideoItemMediator::cUPnPVideoItemMediator(cMediaDatabase* MediaDatabase) : + cUPnPItemMediator(MediaDatabase){} + +cUPnPClassVideoItem* cUPnPVideoItemMediator::createObject(const char* Title, bool Restricted){ + MESSAGE("Creating Video item '%s'",Title); + cUPnPClassVideoItem* Object = new cUPnPClassVideoItem; + if(this->initializeObject(Object, UPNP_CLASS_VIDEO, Title, Restricted)) return NULL; + return Object; +} + +cUPnPClassVideoItem* cUPnPVideoItemMediator::getObject(cUPnPObjectID ID){ + MESSAGE("Getting Video item with ID '%s'",*ID); + cUPnPClassVideoItem* Object = new cUPnPClassVideoItem; + if(this->databaseToObject(Object, ID)) return NULL; + return Object; +} + +int cUPnPVideoItemMediator::objectToDatabase(cUPnPClassObject* Object){ + if(cUPnPItemMediator::objectToDatabase(Object)) return -1; + cUPnPClassVideoItem* VideoItem = (cUPnPClassVideoItem*)Object; + cString Format = "INSERT OR REPLACE INTO %s (%s) VALUES (%s);"; + cString Statement=NULL, Columns=NULL, Values=NULL; + char *Value=NULL; + cString Properties[] = { + SQLITE_COL_OBJECTID, + SQLITE_COL_GENRE, + SQLITE_COL_LONGDESCRIPTION, + SQLITE_COL_PRODUCER, + SQLITE_COL_RATING, + SQLITE_COL_ACTOR, + SQLITE_COL_DIRECTOR, + SQLITE_COL_DESCRIPTION, + SQLITE_COL_PUBLISHER, + SQLITE_COL_LANGUAGE, + SQLITE_COL_RELATION, + NULL + }; + for(cString* Property = Properties; *(*Property); Property++){ + Columns = cString::sprintf("%s%s%s", *Columns?*Columns:"", *Columns?",":"", *(*Property)); + if(!VideoItem->getProperty(*Property, &Value)){ + ERROR("No such property '%s' in object with ID '%s'",*(*Property),* VideoItem->getID()); + return -1; + } + char *escapedValue; + escapeSQLite(Value, &escapedValue); + Values = cString::sprintf("%s%s'%s'", *Values?*Values:"", *Values?",":"", escapedValue?escapedValue:"NULL"); + + } + Statement = cString::sprintf(Format, SQLITE_TABLE_VIDEOITEMS, *Columns, *Values); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + return 0; +} + +int cUPnPVideoItemMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID){ + if(cUPnPItemMediator::databaseToObject(Object,ID)){ + ERROR("Error while loading object"); + return -1; + } + cUPnPClassVideoItem* VideoItem = (cUPnPClassVideoItem*)Object; + cString Format = "SELECT * FROM %s WHERE %s=%s"; + cString Statement = NULL, Column = NULL, Value = NULL; + cRows* Rows; cRow* Row; + Statement = cString::sprintf(Format, SQLITE_TABLE_VIDEOITEMS, SQLITE_COL_OBJECTID, *ID); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + Rows = this->mDatabase->getResultRows(); + if(!Rows->fetchRow(&Row)){ + MESSAGE("No item properties found"); + return 0; + } + while(Row->fetchColumn(&Column, &Value)){ + if(!strcasecmp(Column, SQLITE_COL_GENRE)){ + if(VideoItem->setGenre(Value)){ + ERROR("Error while setting genre"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_LONGDESCRIPTION)){ + if(VideoItem->setLongDescription(Value)){ + ERROR("Error while setting long description"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_PRODUCER)){ + if(VideoItem->setProducers(Value)){ + ERROR("Error while setting producers"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_RATING)){ + if(VideoItem->setRating(Value)){ + ERROR("Error while setting rating"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_ACTOR)){ + if(VideoItem->setActors(Value)){ + ERROR("Error while setting actors"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_DIRECTOR)){ + if(VideoItem->setDirectors(Value)){ + ERROR("Error while setting directors"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_DESCRIPTION)){ + if(VideoItem->setDescription(Value)){ + ERROR("Error while setting description"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_PUBLISHER)){ + if(VideoItem->setPublishers(Value)){ + ERROR("Error while setting publishers"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_LANGUAGE)){ + if(VideoItem->setLanguage(Value)){ + ERROR("Error while setting language"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_RELATION)){ + if(VideoItem->setRelations(Value)){ + ERROR("Error while setting relations"); + return -1; + } + } + } + return 0; +} + + /**********************************************\ + * * + * Video broadcast item mediator * + * * + \**********************************************/ + +cUPnPVideoBroadcastMediator::cUPnPVideoBroadcastMediator(cMediaDatabase* MediaDatabase) : + cUPnPVideoItemMediator(MediaDatabase){} + +cUPnPClassVideoBroadcast* cUPnPVideoBroadcastMediator::createObject(const char* Title, bool Restricted){ + MESSAGE("Creating Video broadcast '%s'",Title); + cUPnPClassVideoBroadcast* Object = new cUPnPClassVideoBroadcast; + if(this->initializeObject(Object, UPNP_CLASS_VIDEOBC, Title, Restricted)) return NULL; + return Object; +} + +cUPnPClassVideoBroadcast* cUPnPVideoBroadcastMediator::getObject(cUPnPObjectID ID){ + MESSAGE("Getting Video broadcast with ID '%s'",*ID); + cUPnPClassVideoBroadcast* Object = new cUPnPClassVideoBroadcast; + if(this->databaseToObject(Object, ID)) return NULL; + return Object; +} + +int cUPnPVideoBroadcastMediator::objectToDatabase(cUPnPClassObject* Object){ + if(cUPnPVideoItemMediator::objectToDatabase(Object)) return -1; + cUPnPClassVideoBroadcast* VideoBroadcast = (cUPnPClassVideoBroadcast*)Object; + cString Format = "INSERT OR REPLACE INTO %s (%s) VALUES (%s);"; + cString Statement=NULL, Columns=NULL, Values=NULL; + char *Value=NULL; + cString Properties[] = { + SQLITE_COL_OBJECTID, + SQLITE_COL_ICON, + SQLITE_COL_REGION, + SQLITE_COL_CHANNELNAME, + SQLITE_COL_CHANNELNR, + NULL + }; + for(cString* Property = Properties; *(*Property); Property++){ + Columns = cString::sprintf("%s%s%s", *Columns?*Columns:"", *Columns?",":"", *(*Property)); + if(!VideoBroadcast->getProperty(*Property, &Value)){ + ERROR("No such property '%s' in object with ID '%s'",*(*Property),* VideoBroadcast->getID()); + return -1; + } + char *escapedValue; + escapeSQLite(Value, &escapedValue); + Values = cString::sprintf("%s%s'%s'", *Values?*Values:"", *Values?",":"", escapedValue?escapedValue:"NULL"); + + } + Statement = cString::sprintf(Format, SQLITE_TABLE_VIDEOBROADCASTS, *Columns, *Values); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + return 0; +} + +int cUPnPVideoBroadcastMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID){ + if(cUPnPVideoItemMediator::databaseToObject(Object,ID)){ + ERROR("Error while loading object"); + return -1; + } + cUPnPClassVideoBroadcast* VideoBroadcast = (cUPnPClassVideoBroadcast*)Object; + cString Format = "SELECT * FROM %s WHERE %s=%s"; + cString Statement = NULL, Column = NULL, Value = NULL; + cRows* Rows; cRow* Row; + Statement = cString::sprintf(Format, SQLITE_TABLE_VIDEOBROADCASTS, SQLITE_COL_OBJECTID, *ID); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + Rows = this->mDatabase->getResultRows(); + if(!Rows->fetchRow(&Row)){ + MESSAGE("No item properties found"); + return 0; + } + while(Row->fetchColumn(&Column, &Value)){ + if(!strcasecmp(Column, SQLITE_COL_ICON)){ + if(VideoBroadcast->setIcon(Value)){ + ERROR("Error while setting icon"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_REGION)){ + if(VideoBroadcast->setRegion(Value)){ + ERROR("Error while setting region"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_CHANNELNR)){ + if(VideoBroadcast->setChannelNr(atoi(Value))){ + ERROR("Error while setting channel number"); + return -1; + } + } + else if(!strcasecmp(Column, SQLITE_COL_CHANNELNAME)){ + if(VideoBroadcast->setChannelName(Value)){ + ERROR("Error while setting channel name"); + return -1; + } + } + } + return 0; +}
\ No newline at end of file |