/* * INTEL CONFIDENTIAL * Copyright (c) 2002 - 2005 Intel Corporation. All rights reserved. * * The source code contained or described herein and all documents * related to the source code ("Material") are owned by Intel * Corporation or its suppliers or licensors. Title to the * Material remains with Intel Corporation or its suppliers and * licensors. The Material contains trade secrets and proprietary * and confidential information of Intel or its suppliers and * licensors. The Material is protected by worldwide copyright and * trade secret laws and treaty provisions. No part of the Material * may be used, copied, reproduced, modified, published, uploaded, * posted, transmitted, distributed, or disclosed in any way without * Intel's prior express written permission. * No license under any patent, copyright, trade secret or other * intellectual property right is granted to or conferred upon you * by disclosure or delivery of the Materials, either expressly, by * implication, inducement, estoppel or otherwise. Any license * under such intellectual property rights must be express and * approved by Intel in writing. * * $Workfile: ILibParsers.c * $Revision: #1.0.1922.38347 * $Author: Intel Corporation, Intel Device Builder * $Date: Wednesday, April 06, 2005 * * * */ #ifdef WCN /* #if defined(WINSOCK2) #include #include #elif defined(WINSOCK1) #include #include #endif */ /* #if defined(WIN32) && !defined(_WIN32_WCE) #define _CRTDBG_MAP_ALLOC #include #endif */ #include "ILibParsers.h" //#ifdef _POSIX //#include //#endif //#define DEBUGSTATEMENT(x) //#define MINPORTNUMBER 50000 //#define PORTNUMBERRANGE 15000 //#define UPNP_MAX_WAIT 86400 // 24 Hours //#if defined(WIN32) || defined(_WIN32_WCE) // static sem_t ILibChainLock = NULL; //#else // extern int errno; // static sem_t ILibChainLock; //#endif //static int ILibChainLock_RefCounter = 0; /* static int malloc_counter = 0; void* dbg_malloc(int sz) { ++malloc_counter; return((void*)malloc(sz)); } void dbg_free(void* ptr) { --malloc_counter; free(ptr); } int dbg_GetCount() { return(malloc_counter); } */ // // All of the following structures are meant to be private internal structures // struct ILibStackNode { void *Data; struct ILibStackNode *Next; }; /* struct ILibQueueNode { struct ILibStackNode *Head; struct ILibStackNode *Tail; sem_t LOCK; }; */ /* struct HashNode_Root { struct HashNode *Root; sem_t LOCK; }; */ /* struct HashNode { struct HashNode *Next; struct HashNode *Prev; int KeyHash; char *KeyValue; int KeyLength; void *Data; }; */ /* struct HashNodeEnumerator { struct HashNode *node; }; */ /* struct ILibLinkedListNode { void *Data; struct ILibLinkedListNode_Root *Root; struct ILibLinkedListNode *Next; struct ILibLinkedListNode *Previous; }; */ /* struct ILibLinkedListNode_Root { sem_t LOCK; long count; struct ILibLinkedListNode *Head; struct ILibLinkedListNode *Tail; }; */ /* #ifdef WINSOCK2 int ILibGetLocalIPAddressNetMask(int address) { SOCKET s; DWORD bytesReturned; SOCKADDR_IN* pAddrInet; INTERFACE_INFO localAddr[10]; // Assume there will be no more than 10 IP interfaces int numLocalAddr; int i; if((s = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0)) == INVALID_SOCKET) { fprintf (stderr, "Socket creation failed\n"); return(0); } // Enumerate all IP interfaces if(WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0, &localAddr, sizeof(localAddr), &bytesReturned, NULL, NULL) == SOCKET_ERROR) { fprintf(stderr, "WSAIoctl fails with error %d\n", GetLastError()); closesocket(s); return(0); } closesocket(s); // Display interface information numLocalAddr = (bytesReturned/sizeof(INTERFACE_INFO)); for (i=0; isin_addr.S_un.S_addr == address) { pAddrInet = (SOCKADDR_IN*)&localAddr[i].iiNetmask; return(pAddrInet->sin_addr.s_addr); } } return(0); } #endif */ /*! \fn ILibGetLocalIPAddressList(int** pp_int) \brief Gets a list of IP Addresses \para \b NOTE: \a pp_int must be freed \param[out] pp_int Array of IP Addresses \returns Number of IP Addresses returned */ /* int ILibGetLocalIPAddressList(int** pp_int) { // // Winsock2 will use an Ioctl call to fetch the IPAddress list // #if defined(WINSOCK2) int i; char buffer[16*sizeof(SOCKET_ADDRESS_LIST)]; DWORD bufferSize; SOCKET TempSocket = socket(AF_INET,SOCK_DGRAM,0); WSAIoctl(TempSocket,SIO_ADDRESS_LIST_QUERY,NULL,0,buffer,16*sizeof(SOCKET_ADDRESS_LIST),&bufferSize,NULL,NULL); *pp_int = (int*)malloc(sizeof(int)*(1+((SOCKET_ADDRESS_LIST*)buffer)->iAddressCount)); for (i = 0;i < ((SOCKET_ADDRESS_LIST*)buffer)->iAddressCount;++i) { (*pp_int)[i] = ((struct sockaddr_in*)(((SOCKET_ADDRESS_LIST*)buffer)->Address[i].lpSockaddr))->sin_addr.s_addr; } (*pp_int)[i] = inet_addr("127.0.0.1"); closesocket(TempSocket); return(1+((SOCKET_ADDRESS_LIST*)buffer)->iAddressCount); #elif defined(WINSOCK1) // // Winsock1 will use gethostbyname to fetch the IPAddress List // char name[256]; int i = 0; int num = 0; struct hostent *entry; gethostname(name,256); entry = (struct hostent*)gethostbyname(name); if (entry->h_length != 4) return 0; while (entry->h_addr_list[num]!=0) ++num; *pp_int = (int*)malloc(sizeof(int)*num); for (i = 0;i < num;++i) { (*pp_int)[i] = *((u_long*)entry->h_addr_list[i]); } return num; #elif _POSIX // // Posix will also use an Ioctl call to get the IPAddress List // char szBuffer[16*sizeof(struct ifreq)]; struct ifconf ifConf; struct ifreq ifReq; int nResult; int LocalSock; struct sockaddr_in LocalAddr; int tempresults[16]; int ctr=0; int i; // Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. if ((LocalSock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { DEBUGSTATEMENT(printf("Can't do that\r\n")); exit(1); } // Get the interface configuration information... ifConf.ifc_len = sizeof szBuffer; ifConf.ifc_ifcu.ifcu_buf = (caddr_t)szBuffer; nResult = ioctl(LocalSock, SIOCGIFCONF, &ifConf); if (nResult < 0) { DEBUGSTATEMENT(printf("ioctl error\r\n")); exit(1); } // Cycle through the list of interfaces looking for IP addresses. for (i = 0;(i < ifConf.ifc_len);) { struct ifreq *pifReq = (struct ifreq *)((caddr_t)ifConf.ifc_req + i); i += sizeof *pifReq; // See if this is the sort of interface we want to deal with. strcpy (ifReq.ifr_name, pifReq -> ifr_name); if (ioctl (LocalSock, SIOCGIFFLAGS, &ifReq) < 0) { DEBUGSTATEMENT(printf("Can't get flags\r\n")); exit(1); } // Skip loopback, point-to-point and down interfaces, // except don't skip down interfaces // if we're trying to get a list of configurable interfaces. if ((ifReq.ifr_flags & IFF_LOOPBACK) || (!(ifReq.ifr_flags & IFF_UP))) { continue; } if (pifReq -> ifr_addr.sa_family == AF_INET) { // Get a pointer to the address... memcpy (&LocalAddr, &pifReq -> ifr_addr, sizeof pifReq -> ifr_addr); if (LocalAddr.sin_addr.s_addr != htonl (INADDR_LOOPBACK)) { tempresults[ctr] = LocalAddr.sin_addr.s_addr; ++ctr; } } } close(LocalSock); *pp_int = (int*)malloc(sizeof(int)*(ctr)); memcpy(*pp_int,tempresults,sizeof(int)*ctr); return(ctr); #endif } */ /* struct ILibChain { void (*PreSelect)(void* object,fd_set *readset, fd_set *writeset, fd_set *errorset, int* blocktime); void (*PostSelect)(void* object,int slct, fd_set *readset, fd_set *writeset, fd_set *errorset); void (*Destroy)(void* object); }; */ /* struct LifeTimeMonitorData { unsigned long ExpirationTick; void *data; void (*CallbackPtr)(void *data); void (*DestroyPtr)(void *data); struct LifeTimeMonitorData *Prev; struct LifeTimeMonitorData *Next; }; */ /* struct ILibLifeTime { void (*PreSelect)(void* object,fd_set *readset, fd_set *writeset, fd_set *errorset, int* blocktime); void (*PostSelect)(void* object,int slct, fd_set *readset, fd_set *writeset, fd_set *errorset); void (*Destroy)(void* object); struct LifeTimeMonitorData *LM; void *Chain; void *Reserved; sem_t SyncLock; }; */ /* struct ILibBaseChain { int TerminateFlag; #if defined(WIN32) || defined(_WIN32_WCE) SOCKET Terminate; #else FILE *TerminateReadPipe; FILE *TerminateWritePipe; #endif void *Object; void *Next; }; */ // // Do not Modify this method. // This decompresses compressed string blocks, which is used to store the // various description documents // /* char* ILibDecompressString(unsigned char* CurrentCompressed, const int bufferLength, const int DecompressedLength) { unsigned char *RetVal = (char*)malloc(DecompressedLength+1); unsigned char *CurrentUnCompressed = RetVal; unsigned char *EndPtr = RetVal + DecompressedLength; int offset,length; do { // UnCompressed Data Block memcpy(CurrentUnCompressed,CurrentCompressed+1,(int)*CurrentCompressed); //MEMCHECK(assert((int)*CurrentCompressed <= (DecompressedLength+1) );) CurrentUnCompressed += (int)*CurrentCompressed; CurrentCompressed += 1+((int)*CurrentCompressed); // CompressedBlock #ifdef REQUIRES_MEMORY_ALIGNMENT length = (unsigned short)((*(CurrentCompressed)) & 63); offset = ((unsigned short)(*(CurrentCompressed+1))<<2) + (((unsigned short)(*(CurrentCompressed))) >> 6); #else length = (*((unsigned short*)(CurrentCompressed)))&((unsigned short)63); offset = (*((unsigned short*)(CurrentCompressed)))>>6; #endif memcpy(CurrentUnCompressed,CurrentUnCompressed-offset,length); //MEMCHECK(assert(length <= (DecompressedLength+1)-(CurrentUnCompressed - RetVal));) CurrentCompressed += 2; CurrentUnCompressed += length; } while(CurrentUnCompressed < EndPtr); RetVal[DecompressedLength] = 0; return(RetVal); } */ /*! \fn ILibCreateChain() \brief Creates an empty Chain \returns Chain */ /* void *ILibCreateChain() { struct ILibBaseChain *RetVal = (struct ILibBaseChain*)malloc(sizeof(struct ILibBaseChain)); #if defined(WIN32) || defined(_WIN32_WCE) WORD wVersionRequested; WSADATA wsaData; #ifdef WINSOCK1 wVersionRequested = MAKEWORD( 1, 1 ); #elif WINSOCK2 wVersionRequested = MAKEWORD( 2, 0 ); #endif if (WSAStartup( wVersionRequested, &wsaData ) != 0) {exit(1);} RetVal->Terminate = socket(AF_INET, SOCK_DGRAM, 0); #endif memset(RetVal,0,sizeof(struct ILibBaseChain)); #ifdef _POSIX long timeptr = 0; time(&timeptr); srand(timeptr); #else srand((unsigned int)time(NULL)); #endif RetVal->Object = NULL; RetVal->Next = NULL; RetVal->TerminateFlag = 0; #if defined(WIN32) || defined(_WIN32_WCE) RetVal->Terminate = socket(AF_INET, SOCK_DGRAM, 0); #endif if(ILibChainLock_RefCounter==0) { sem_init(&ILibChainLock,0,1); } return(RetVal); } */ /*! \fn ILibAddToChain(void *Chain, void *object) \brief Add links to the chain \para \b Note: All objects added to the chain must extend/implement ILibChain \param Chain The chain to add the link to \param object The link to add to the chain */ /* void ILibAddToChain(void *Chain, void *object) { struct ILibBaseChain *chain = (struct ILibBaseChain*)Chain; // // Add link to the end of the chain (Linked List) // while(chain->Next!=NULL) { chain = chain->Next; } if(chain->Object!=NULL) { chain->Next = (struct ILibBaseChain*)malloc(sizeof(struct ILibBaseChain)); chain = chain->Next; } chain->Object = object; chain->Next = NULL; } */ /*! \fn ILibForceUnBlockChain(void *Chain) \brief Forces a Chain to unblock, and check for pending operations \param Chain The chain to unblock */ /* void ILibForceUnBlockChain(void *Chain) { struct ILibBaseChain *c = (struct ILibBaseChain*)Chain; #if defined(WIN32) || defined(_WIN32_WCE) SOCKET temp; #endif sem_wait(&ILibChainLock); #if defined(WIN32) || defined(_WIN32_WCE) // // Closing the socket will trigger the select on Windows // temp = c->Terminate; c->Terminate = ~0; closesocket(temp); #else // // Writing data on the pipe will trigger the select on Posix // if(c->TerminateWritePipe!=NULL) { fprintf(c->TerminateWritePipe," "); fflush(c->TerminateWritePipe); } #endif sem_post(&ILibChainLock); } */ /*! \fn ILibStartChain(void *Chain) \brief Starts a Chain \para This method will use the current thread. This thread will be refered to as the microstack thread. All events and processing will be done on this thread. This method will not return until ILibStopChain is called. \param Chain The chain to start */ /* void ILibStartChain(void *Chain) { struct ILibBaseChain *c = (struct ILibBaseChain*)Chain; struct ILibBaseChain *temp; fd_set readset; fd_set errorset; fd_set writeset; struct timeval tv; int slct; int v; #if !defined(WIN32) && !defined(_WIN32_WCE) int TerminatePipe[2]; int flags; #endif // // Use this thread as if it's our own. Keep looping until we are signaled to stop // FD_ZERO(&readset); FD_ZERO(&errorset); FD_ZERO(&writeset); #if !defined(WIN32) && !defined(_WIN32_WCE) // // For posix, we need to use a pipe to force unblock the select loop // pipe(TerminatePipe); flags = fcntl(TerminatePipe[0],F_GETFL,0); // // We need to set the pipe to nonblock, so we can blindly empty the pipe // fcntl(TerminatePipe[0],F_SETFL,O_NONBLOCK|flags); ((struct ILibBaseChain*)Chain)->TerminateReadPipe = fdopen(TerminatePipe[0],"r"); ((struct ILibBaseChain*)Chain)->TerminateWritePipe = fdopen(TerminatePipe[1],"w"); #endif while(((struct ILibBaseChain*)Chain)->TerminateFlag==0) { slct = 0; FD_ZERO(&readset); FD_ZERO(&errorset); FD_ZERO(&writeset); tv.tv_sec = UPNP_MAX_WAIT; tv.tv_usec = 0; sem_wait(&ILibChainLock); #if defined(WIN32) || defined(_WIN32_WCE) // // Check the fake socket, for ILibForceUnBlockChain // if(((struct ILibBaseChain*)Chain)->Terminate==~0) { slct = -1; } else { FD_SET(((struct ILibBaseChain*)Chain)->Terminate,&errorset); } #else // // Put the Read end of the Pipe in the FDSET, for ILibForceUnBlockChain // FD_SET(TerminatePipe[0],&readset); #endif sem_post(&ILibChainLock); // // Iterate through all the PreSelect function pointers in the chain // c = (struct ILibBaseChain*)Chain; while(c!=NULL && c->Object!=NULL) { if(((struct ILibChain*)c->Object)->PreSelect!=NULL) { #ifdef MEMORY_CHECK #ifdef WIN32 _CrtCheckMemory(); #endif #endif v = (tv.tv_sec*1000) + (tv.tv_usec/1000); ((struct ILibChain*)c->Object)->PreSelect(c->Object,&readset,&writeset,&errorset,&v); tv.tv_sec = v/1000; tv.tv_usec = 1000*(v%1000); #ifdef MEMORY_CHECK #ifdef WIN32 _CrtCheckMemory(); #endif #endif } c = c->Next; } // // If this flag is set, force the max block time to be zero // if(slct!=0) { tv.tv_sec = 0; tv.tv_usec = 0; } // // The actual Select Statement // slct = select(FD_SETSIZE,&readset,&writeset,&errorset,&tv); if(slct==-1) { // // If the select simply timed out, we need to clear these sets // FD_ZERO(&readset); FD_ZERO(&writeset); FD_ZERO(&errorset); } #if defined(WIN32) || defined(_WIN32_WCE) // // Reinitialise our fake socket if necessary // if(((struct ILibBaseChain*)Chain)->Terminate==~0) { ((struct ILibBaseChain*)Chain)->Terminate = socket(AF_INET,SOCK_DGRAM,0); } #else if(FD_ISSET(TerminatePipe[0],&readset)) { // // Empty the pipe // while(fgetc(((struct ILibBaseChain*)Chain)->TerminateReadPipe)!=EOF) { } } #endif // // Iterate through all of the PostSelect in the chain // c = (struct ILibBaseChain*)Chain; while(c!=NULL && c->Object!=NULL) { if(((struct ILibChain*)c->Object)->PostSelect!=NULL) { #ifdef MEMORY_CHECK #ifdef WIN32 _CrtCheckMemory(); #endif #endif ((struct ILibChain*)c->Object)->PostSelect(c->Object,slct,&readset,&writeset,&errorset); #ifdef MEMORY_CHECK #ifdef WIN32 _CrtCheckMemory(); #endif #endif } c = c->Next; } } // // This loop will start, when the Chain was signaled to quit. Clean up the chain // by iterating through all the Destroy. // c = (struct ILibBaseChain*)Chain; while(c!=NULL && c->Object!=NULL) { if(((struct ILibChain*)c->Object)->Destroy!=NULL) { ((struct ILibChain*)c->Object)->Destroy(c->Object); } // // After calling the Destroy, we free the link // free(c->Object); c = c->Next; } // // Now we actually free the chain // c = (struct ILibBaseChain*)Chain; #if !defined(WIN32) && !defined(_WIN32_WCE) // // Free the pipe resources // fclose(c->TerminateReadPipe); fclose(c->TerminateWritePipe); #endif while(c!=NULL) { temp = c->Next; free(c); c = temp; } #ifdef WIN32 WSACleanup(); #endif if(ILibChainLock_RefCounter==1) { sem_destroy(&ILibChainLock); } --ILibChainLock_RefCounter; } */ /*! \fn ILibStopChain(void *Chain) \brief Stops a chain \para This will signal the microstack thread to shutdown. When the chain cleans itself up, the thread that is blocked on ILibStartChain will return. \param Chain The Chain to stop */ /* void ILibStopChain(void *Chain) { ((struct ILibBaseChain*)Chain)->TerminateFlag = 1; ILibForceUnBlockChain(Chain); } */ /*! \fn ILibDestructXMLNodeList(struct ILibXMLNode *node) \brief Frees resources from an XMLNodeList tree that was returned from ILibParseXML \param node The XML Tree to clean up */ void ILibDestructXMLNodeList(struct ILibXMLNode *node) { struct ILibXMLNode *temp; while(node!=NULL) { temp = node->Next; /* if(node->Reserved2!=NULL) { // If there was a namespace table, delete it ILibDestroyHashTree(node->Reserved2); } */ free(node); node = temp; } } /*! \fn ILibDestructXMLAttributeList(struct ILibXMLAttribute *attribute) \brief Frees resources from an AttributeList that was returned from ILibGetXMLAttributes \param attribute The Attribute Tree to clean up */ /* void ILibDestructXMLAttributeList(struct ILibXMLAttribute *attribute) { struct ILibXMLAttribute *temp; while(attribute!=NULL) { temp = attribute->Next; free(attribute); attribute = temp; } } */ /*! \fn ILibProcessXMLNodeList(struct ILibXMLNode *nodeList) \brief Pro-process an XML node list \para Checks XML for validity, while at the same time populate helper properties on each node, such as Parent, Peer, etc, to aid in XML parsing. \param nodeList The XML Tree to process \returns 0 if the XML is valid, nonzero otherwise */ int ILibProcessXMLNodeList(struct ILibXMLNode *nodeList) { int RetVal = 0; struct ILibXMLNode *current = nodeList; struct ILibXMLNode *temp; void *TagStack; ILibCreateStack(&TagStack); // // Iterate through the node list, and setup all the pointers // such that all StartElements have pointers to EndElements, // And all StartElements have pointers to siblings and parents. // while(current!=NULL) { if(memcmp(current->Name,"!",1)==0) { // Comment temp = current; current = (struct ILibXMLNode*)ILibPeekStack(&TagStack); if(current!=NULL) { current->Next = temp->Next; } else { current = temp; } } else if(current->StartTag!=0) { // Start Tag current->Parent = ILibPeekStack(&TagStack); ILibPushStack(&TagStack,current); } else { // Close Tag // // Check to see if there is supposed to be an EndElement // temp = (struct ILibXMLNode*)ILibPopStack(&TagStack); if(temp!=NULL) { // // Checking to see if this EndElement is correct in scope // if(temp->NameLength==current->NameLength && memcmp(temp->Name,current->Name,current->NameLength)==0) { // // Now that we know this EndElement is correct, set the Peer // pointers of the previous sibling // if(current->Next!=NULL) { if(current->Next->StartTag!=0) { temp->Peer = current->Next; } } temp->ClosingTag = current; current->StartingTag = temp; } else { // Illegal Close Tag Order RetVal = -2; break; } } else { // Illegal Close Tag RetVal = -1; break; } } current = current->Next; } // // If there are still elements in the stack, that means not all the StartElements // have associated EndElements, which means this XML is not valid XML. // if(TagStack!=NULL) { // Incomplete XML RetVal = -3; ILibClearStack(&TagStack); } return(RetVal); } /*! \fn ILibXML_LookupNamespace(struct ILibXMLNode *currentLocation, char *prefix, int prefixLength) \brief Resolves a namespace prefix from the scope of the given node \param currentLocation The node used to start the resolve \param prefix The namespace prefix to resolve \param prefixLength The lenght of the prefix \returns The resolved namespace. NULL if unable to resolve */ /* char* ILibXML_LookupNamespace(struct ILibXMLNode *currentLocation, char *prefix, int prefixLength) { struct ILibXMLNode *temp = currentLocation; int done=0; char* RetVal = ""; // // If the specified Prefix is zero length, we interpret that to mean // they want to lookup the default namespace // if(prefixLength==0) { // // This is the default namespace prefix // prefix = "xmlns"; prefixLength = 5; } // // From the current node, keep traversing up the parents, until we find a match. // Each step we go up, is a step wider in scope. // do { if(temp->Reserved2!=NULL) { if(ILibHasEntry(temp->Reserved2,prefix,prefixLength)!=0) { // // As soon as we find the namespace declaration, stop // iterating the tree, as it would be a waste of time // RetVal = (char*)ILibGetEntry(temp->Reserved2,prefix,prefixLength); done=1; } } temp = temp->Parent; }while(temp!=NULL && done==0); return(RetVal); } */ /*! \fn ILibXML_BuildNamespaceLookupTable(struct ILibXMLNode *node) \brief Builds the lookup table used by ILibXML_LookupNamespace \param node This node will be the highest scoped */ /* void ILibXML_BuildNamespaceLookupTable(struct ILibXMLNode *node) { struct ILibXMLAttribute *attr,*currentAttr; struct ILibXMLNode *current = node; // // Iterate through all the StartElements, and build a table of the declared namespaces // while(current!=NULL) { if(current->StartTag!=0) { // // Reserved2 is the HashTable containing the fully qualified namespace // keyed by the namespace prefix // current->Reserved2 = ILibInitHashTree(); currentAttr = attr = ILibGetXMLAttributes(current); if(attr!=NULL) { // // Iterate through all the attributes to find namespace declarations // while(currentAttr!=NULL) { if(currentAttr->NameLength==5 && memcmp(currentAttr->Name,"xmlns",5)==0) { // Default Namespace Declaration currentAttr->Value[currentAttr->ValueLength]=0; ILibAddEntry(current->Reserved2,"xmlns",5,currentAttr->Value); } else if(currentAttr->PrefixLength==5 && memcmp(currentAttr->Prefix,"xmlns",5)==0) { // Other Namespace Declaration currentAttr->Value[currentAttr->ValueLength]=0; ILibAddEntry(current->Reserved2,currentAttr->Name,currentAttr->NameLength,currentAttr->Value); } currentAttr=currentAttr->Next; } ILibDestructXMLAttributeList(attr); } } current = current->Next; } } */ /*! \fn ILibReadInnerXML(struct ILibXMLNode *node, char **RetVal) \brief Reads the data segment from an ILibXMLNode \para The data is a pointer into the original string that the XML was read from. \param node The node to read the data from \param RetVal The data \returns The length of the data read */ int ILibReadInnerXML(struct ILibXMLNode *node, char **RetVal) { struct ILibXMLNode *x = node; int length = 0; void *TagStack; *RetVal = NULL; // // Starting with the current StartElement, we use this stack to find the matching // EndElement, so we can figure out what we need to return // ILibCreateStack(&TagStack); do { if(x->StartTag!=0) {ILibPushStack(&TagStack,x);} if(x!=NULL) { x = x->Next; } else { return(0); } }while(!(x->StartTag==0 && ILibPopStack(&TagStack)==node && x->NameLength==node->NameLength && memcmp(x->Name,node->Name,node->NameLength)==0)); // // The Reserved fields of the StartElement and EndElement are used as pointers representing // the data segment of the XML // length = (int)((char*)x->Reserved - (char*)node->Reserved - 1); if(length<0) {length=0;} *RetVal = (char*)node->Reserved; return(length); } /*! \fn ILibGetXMLAttributes(struct ILibXMLNode *node) \breif Reads the attributes from an XML node \param node The node to read the attributes from \returns A linked list of attributes */ /* struct ILibXMLAttribute *ILibGetXMLAttributes(struct ILibXMLNode *node) { struct ILibXMLAttribute *RetVal = NULL; struct ILibXMLAttribute *current = NULL; char *c; int EndReserved = (node->EmptyTag==0)?1:2; int i; int CheckName = node->Name[node->NameLength]==0?1:0; struct parser_result *xml; struct parser_result_field *field,*field2; struct parser_result *temp2; struct parser_result *temp3; // // The reserved field is used to show where the data segments start and stop. We // can also use them to figure out where the attributes start and stop // c = (char*)node->Reserved - 1; while(*c!='<') { // // The Reserved field of the StartElement points to the first character after // the '>' of the StartElement. Just work our way backwards to find the start of // the StartElement // c = c -1; } c = c +1; // // Now that we isolated the string in between the '<' and the '>' we can parse the // string as delimited by ' ', because thats what delineates attributes. We need // to use ILibParseStringAdv because these attributes can be within quotation marks // // // But before we start, replace linefeeds and carriage-return-linefeeds to spaces // for(i=0;i<(int)((char*)node->Reserved - c -EndReserved);++i) { if(c[i]==10 || c[i]==13 || c[i]==9 || c[i]==0) { c[i]=' '; } } xml = ILibParseStringAdv(c,0,(int)((char*)node->Reserved - c -EndReserved)," ",1); field = xml->FirstResult; // // We skip the first token, because the first token, is the Element name // if(field!=NULL) {field = field->NextResult;} // // Iterate through all the other tokens, as these are all attributes // while(field!=NULL) { if(field->datalength>0) { if(RetVal==NULL) { // // If we haven't already created an Attribute node, create it now // RetVal = (struct ILibXMLAttribute*)malloc(sizeof(struct ILibXMLAttribute)); RetVal->Next = NULL; } else { // // We already created an Attribute node, so simply create a new one, and // attach it on the beginning of the old one. // current = (struct ILibXMLAttribute*)malloc(sizeof(struct ILibXMLAttribute)); current->Next = RetVal; RetVal = current; } // // Parse each token by the ':' // If this results in more than one token, we can figure that the first token // is the namespace prefix // temp2 = ILibParseStringAdv(field->data,0,field->datalength,":",1); if(temp2->NumResults==1) { // // This attribute has no prefix, so just parse on the '=' // The first token is the attribute name, the other is the value // RetVal->Prefix = NULL; RetVal->PrefixLength = 0; temp3 = ILibParseStringAdv(field->data,0,field->datalength,"=",1); if(temp3->NumResults==1) { // // There were whitespaces around the '=' // field2 = field->NextResult; while(field2!=NULL) { if(!(field2->datalength==1 && memcmp(field2->data,"=",1)==0) && field2->datalength>0) { ILibDestructParserResults(temp3); temp3 = ILibParseStringAdv(field->data,0,(int)((field2->data-field->data)+field2->datalength),"=",1); field = field2; break; } field2 = field2->NextResult; } } } else { // // Since there is a namespace prefix, seperate that out, and parse the remainder // on the '=' to figure out what the attribute name and value are // RetVal->Prefix = temp2->FirstResult->data; RetVal->PrefixLength = temp2->FirstResult->datalength; temp3 = ILibParseStringAdv(field->data,RetVal->PrefixLength+1,field->datalength-RetVal->PrefixLength-1,"=",1); if(temp3->NumResults==1) { // // There were whitespaces around the '=' // field2 = field->NextResult; while(field2!=NULL) { if(!(field2->datalength==1 && memcmp(field2->data,"=",1)==0) && field2->datalength>0) { ILibDestructParserResults(temp3); temp3 = ILibParseStringAdv(field->data,RetVal->PrefixLength+1,(int)((field2->data-field->data)+field2->datalength-RetVal->PrefixLength-1),"=",1); field = field2; break; } field2 = field2->NextResult; } } } // // After attaching the pointers, we can free the results, as all the data // is a pointer into the original string. We can think of the nodes we created // as templates. Once done, we don't need them anymore. // ILibDestructParserResults(temp2); RetVal->Parent = node; RetVal->Name = temp3->FirstResult->data; RetVal->Value = temp3->LastResult->data; RetVal->NameLength = ILibTrimString(&(RetVal->Name),temp3->FirstResult->datalength); RetVal->ValueLength = ILibTrimString(&(RetVal->Value),temp3->LastResult->datalength); // // Remove the Quote or Apostraphe if it exists // if(RetVal->ValueLength>=2 && (RetVal->Value[0]=='"' || RetVal->Value[0]=='\'')) { RetVal->Value += 1; RetVal->ValueLength -= 2; } ILibDestructParserResults(temp3); } field = field->NextResult; } ILibDestructParserResults(xml); if(CheckName) { node->Name[node->NameLength]=0; } return(RetVal); } */ /*! \fn ILibParseXML(char *buffer, int offset, int length) \brief Parses an XML string. \para The strings are never copied. Everything is referenced via pointers into the original buffer \param buffer The string to parse \param offset starting index of \a buffer \param length Length of \a buffer \returns A tree of ILibXMLNodes, representing the XML document */ struct ILibXMLNode *ILibParseXML(char *buffer, int offset, int length) { struct parser_result *xml; struct parser_result_field *field; struct parser_result *temp; struct parser_result *temp2; struct parser_result *temp3; char* TagName; int TagNameLength; int StartTag; int EmptyTag; int i; struct ILibXMLNode *RetVal = NULL; struct ILibXMLNode *current = NULL; struct ILibXMLNode *x = NULL; char *NSTag; int NSTagLength; // // Even though "technically" the first character of an XML document must be < // we're going to be nice, and not enforce that // while(buffer[offset]!='<' && length>0) { ++offset; --length; } if(length==0) { // Garbage in Garbage out :) RetVal = (struct ILibXMLNode*)malloc(sizeof(struct ILibXMLNode)); memset(RetVal,0,sizeof(struct ILibXMLNode)); return(RetVal); } // // All XML Elements start with a '<' character. If we delineate the string with // this character, we can go from there. // xml = ILibParseString(buffer,offset,length,"<",1); field = xml->FirstResult; while(field!=NULL) { // // Ignore the XML declarator // if(field->datalength !=0 && memcmp(field->data,"?",1)!=0) { EmptyTag = 0; if(memcmp(field->data,"/",1)==0) { // // The first character after the '<' was a '/', so we know this is the // EndElement // StartTag = 0; field->data = field->data+1; field->datalength -= 1; // // If we look for the '>' we can find the end of this element // temp2 = ILibParseString(field->data,0,field->datalength,">",1); } else { // // The first character after the '<' was not a '/' so we know this is a // StartElement // StartTag = -1; // // If we look for the '>' we can find the end of this element // temp2 = ILibParseString(field->data,0,field->datalength,">",1); if(temp2->FirstResult->datalength>0 && temp2->FirstResult->data[temp2->FirstResult->datalength-1]=='/') { // // If this element ended with a '/' this is an EmptyElement // EmptyTag = -1; } } // // Parsing on the ' ', we can isolate the Element name from the attributes. // The first token, being the element name // temp = ILibParseString(temp2->FirstResult->data,0,temp2->FirstResult->datalength," ",1); // // Now that we have the token that contains the element name, we need to parse on the ":" // because we need to figure out what the namespace qualifiers are // temp3 = ILibParseString(temp->FirstResult->data,0,temp->FirstResult->datalength,":",1); if(temp3->NumResults==1) { // // If there is only one token, there was no namespace prefix. // The whole token is the attribute name // NSTag = NULL; NSTagLength = 0; TagName = temp3->FirstResult->data; TagNameLength = temp3->FirstResult->datalength; } else { // // The first token is the namespace prefix, the second is the attribute name // NSTag = temp3->FirstResult->data; NSTagLength = temp3->FirstResult->datalength; TagName = temp3->FirstResult->NextResult->data; TagNameLength = temp3->FirstResult->NextResult->datalength; } ILibDestructParserResults(temp3); // // Iterate through the tag name, to figure out what the exact length is, as // well as check to see if its an empty element // for(i=0;i')||(TagName[i]=='\t')||(TagName[i]=='\r')||(TagName[i]=='\n') ) { if(i!=0) { if(TagName[i]=='/') { EmptyTag = -1; } TagNameLength = i; break; } } } if(TagNameLength!=0) { // // Instantiate a new ILibXMLNode for this element // x = (struct ILibXMLNode*)malloc(sizeof(struct ILibXMLNode)); memset(x,0,sizeof(struct ILibXMLNode)); x->Name = TagName; x->NameLength = TagNameLength; x->StartTag = StartTag; x->NSTag = NSTag; x->NSLength = NSTagLength; if(StartTag==0) { // // The Reserved field of StartElements point to te first character before // the '<'. // x->Reserved = field->data; do { (char*)x->Reserved -= 1; }while(*((char*)x->Reserved)=='<'); } else { // // The Reserved field of EndElements point to the end of the element // x->Reserved = temp2->LastResult->data; } if(RetVal==NULL) { RetVal = x; } else { current->Next = x; } current = x; if(EmptyTag!=0) { // // If this was an empty element, we need to create a bogus EndElement, // just so the tree is consistent. No point in introducing unnecessary complexity // x = (struct ILibXMLNode*)malloc(sizeof(struct ILibXMLNode)); memset(x,0,sizeof(struct ILibXMLNode)); x->Name = TagName; x->NameLength = TagNameLength; x->NSTag = NSTag; x->NSLength = NSTagLength; x->Reserved = current->Reserved; current->EmptyTag = -1; current->Next = x; current = x; } } ILibDestructParserResults(temp2); ILibDestructParserResults(temp); } field = field->NextResult; } ILibDestructParserResults(xml); return(RetVal); } /*! \fn ILibQueue_Create() \brief Create an empty Queue \returns An empty queue */ /* void *ILibQueue_Create() { return(ILibLinkedList_Create()); } */ /*! \fn ILibQueue_Lock(void *q) \brief Locks a queue \param q The queue to lock */ /* void ILibQueue_Lock(void *q) { ILibLinkedList_Lock(q); } */ /*! \fn ILibQueue_UnLock(void *q) \brief Unlocks a queue \param q The queue to unlock */ /* void ILibQueue_UnLock(void *q) { ILibLinkedList_UnLock(q); } */ /*! \fn ILibQueue_Destroy(void *q) \brief Frees the resources associated with a queue \param q The queue to free */ /* void ILibQueue_Destroy(void *q) { ILibLinkedList_Destroy(q); } */ /*! \fn ILibQueue_IsEmpty(void *q) \brief Checks to see if a queue is empty \param q The queue to check \returns zero value if not empty, non-zero if empty */ /* int ILibQueue_IsEmpty(void *q) { return(ILibLinkedList_GetNode_Head(q)==NULL?1:0); } */ /*! \fn ILibQueue_EnQueue(void *q, void *data) \brief Add an item to the queue \param q The queue to add to \param data The data to add to the queue */ /* void ILibQueue_EnQueue(void *q, void *data) { ILibLinkedList_AddTail(q,data); } */ /*! \fn ILibQueue_DeQueue(void *q) \brief Removes an item from the queue \param q The queue to pop the item from \returns The item popped off the queue. NULL if empty */ /* void *ILibQueue_DeQueue(void *q) { void *RetVal = NULL; void *node; node = ILibLinkedList_GetNode_Head(q); if(node!=NULL) { RetVal = ILibLinkedList_GetDataFromNode(node); ILibLinkedList_Remove(node); } return(RetVal); } */ /*! \fn ILibQueue_PeekQueue(void *q) \brief Peeks at an item from the queue \param q The queue to peek an item from \returns The item from the queue. NULL if empty */ /* void *ILibQueue_PeekQueue(void *q) { void *RetVal = NULL; void *node; node = ILibLinkedList_GetNode_Head(q); if(node!=NULL) { RetVal = ILibLinkedList_GetDataFromNode(node); } return(RetVal); } */ /*! \fn ILibCreateStack(void **TheStack) \brief Creates an empty Stack \para This module uses a void* that is preinitialized to NULL, eg:
void *stack = NULL;
ILibCreateStack(&stack);
\param TheStack A void* to use for the stack. Simply pass in a void* by reference */ void ILibCreateStack(void **TheStack) { *TheStack = NULL; } /*! \fn ILibPushStack(void **TheStack, void *data) \brief Push an item onto the stack \param TheStack The stack to push to \param data The data to push onto the stack */ void ILibPushStack(void **TheStack, void *data) { struct ILibStackNode *RetVal = (struct ILibStackNode*)malloc(sizeof(struct ILibStackNode)); RetVal->Data = data; RetVal->Next = *TheStack; *TheStack = RetVal; } /*! \fn ILibPopStack(void **TheStack) \brief Pop an item from the stack \param TheStack The stack to pop from \returns The item that was popped from the stack */ void *ILibPopStack(void **TheStack) { void *RetVal = NULL; void *Temp; if(*TheStack!=NULL) { RetVal = ((struct ILibStackNode*)*TheStack)->Data; Temp = *TheStack; *TheStack = ((struct ILibStackNode*)*TheStack)->Next; free(Temp); } return(RetVal); } /*! \fn ILibPeekStack(void **TheStack) \brief Peek at an item from the stack \param TheStack The stack to peek from \returns The item that is currently on the top of the stack */ void *ILibPeekStack(void **TheStack) { void *RetVal = NULL; if(*TheStack!=NULL) { RetVal = ((struct ILibStackNode*)*TheStack)->Data; } return(RetVal); } /*! \fn ILibClearStack(void **TheStack) \brief Clears all the items from the stack \param TheStack The stack to clear */ void ILibClearStack(void **TheStack) { void *Temp = *TheStack; do { ILibPopStack(&Temp); }while(Temp!=NULL); *TheStack = NULL; } /*! \fn ILibHashTree_Lock(void *hashtree) \brief Locks a HashTree \param hashtree The HashTree to lock */ /* void ILibHashTree_Lock(void *hashtree) { struct HashNode_Root *r = (struct HashNode_Root*)hashtree; sem_wait(&(r->LOCK)); } */ /*! \fn ILibHashTree_UnLock(void *hashtree) \brief Unlocks a HashTree \param hashtree The HashTree to unlock */ /* void ILibHashTree_UnLock(void *hashtree) { struct HashNode_Root *r = (struct HashNode_Root*)hashtree; sem_post(&(r->LOCK)); } */ /*! \fn ILibDestroyHashTree(void *tree) \brief Frees resources associated with a HashTree \param hashtree The HashTree to free */ /* void ILibDestroyHashTree(void *tree) { struct HashNode_Root *r = (struct HashNode_Root*)tree; struct HashNode *c = r->Root; struct HashNode *n; sem_destroy(&(r->LOCK)); while(c!=NULL) { // // Iterate through each node, and free all the resources // n = c->Next; if(c->KeyValue!=NULL) {free(c->KeyValue);} free(c); c = n; } free(r); } */ /*! \fn ILibHashTree_GetEnumerator(void *tree) \brief Returns an Enumerator for a HashTree \para Functionally identicle to an IDictionaryEnumerator in .NET \param tree The HashTree to get an enumerator for \returns An enumerator */ /* void *ILibHashTree_GetEnumerator(void *tree) { // // The enumerator is basically a state machine that keeps track of which node we are at // in the tree. So initialize it to the root. // struct HashNodeEnumerator *en = (struct HashNodeEnumerator*)malloc(sizeof(struct HashNodeEnumerator)); en->node = ((struct HashNode_Root*)tree)->Root; return(en); } */ /*! \fn ILibHashTree_DestroyEnumerator(void *tree_enumerator) \brief Frees resources associated with an Enumerator created by ILibHashTree_GetEnumerator \param tree_enumerator The enumerator to free */ /* void ILibHashTree_DestroyEnumerator(void *tree_enumerator) { // // The enumerator just contains a pointer, so we can just free the enumerator // free(tree_enumerator); } */ /*! \fn ILibHashTree_MoveNext(void *tree_enumerator) \brief Advances an enumerator to the next item \param tree_enumerator The enumerator to advance \returns A zero value if successful, nonzero if no more items */ /* int ILibHashTree_MoveNext(void *tree_enumerator) { struct HashNodeEnumerator *en = (struct HashNodeEnumerator*)tree_enumerator; if(en->node!=NULL) { // // Advance the enumerator to point to the next node. If there is a node // return 0, else return 1 // en->node = en->node->Next; return(en->node!=NULL?0:1); } else { // // There are no more nodes, so just return 1 // return(1); } } */ /*! \fn ILibHashTree_GetValue(void *tree_enumerator, char **key, int *keyLength, void **data) \brief Reads from the current item of an enumerator \param tree_enumerator The enumerator to read from \param key The key of the current item \param keyLength The length of the key of the current item \param data The data of the current item */ /* void ILibHashTree_GetValue(void *tree_enumerator, char **key, int *keyLength, void **data) { struct HashNodeEnumerator *en = (struct HashNodeEnumerator*)tree_enumerator; // // All we do, is just assign the pointers. // if(key!=NULL){*key = en->node->KeyValue;} if(keyLength!=NULL){*keyLength = en->node->KeyLength;} if(data!=NULL){*data = en->node->Data;} } */ /*! \fn ILibInitHashTree() \brief Creates an empty ILibHashTree \returns An empty ILibHashTree */ /* void* ILibInitHashTree() { struct HashNode_Root *Root = (struct HashNode_Root*)malloc(sizeof(struct HashNode_Root)); struct HashNode *RetVal = (struct HashNode*)malloc(sizeof(struct HashNode)); memset(RetVal,0,sizeof(struct HashNode)); Root->Root = RetVal; sem_init(&(Root->LOCK),0,1); return(Root); } */ /*! \fn ILibGetHashValue(void *key, int keylength) \brief Calculates a numeric Hash from a given string \para Used by ILibHashTree methods \param key The string to hash \param keylength The length of the string to hash \returns A hash value */ /* int ILibGetHashValue(void *key, int keylength) { int HashValue=0; char TempValue[4]; if(keylength<=4) { // // If the key length is <= 4, the hash is just the key expressed as an integer // memset(TempValue,0,4); memcpy(TempValue,key,keylength); //MEMCHECK(assert(keylength<=4);) HashValue = *((int*)TempValue); } else { // // If the key length is >4, the hash is the first 4 bytes XOR with the last 4 // memcpy(TempValue,key,4); HashValue = *((int*)TempValue); memcpy(TempValue,(char*)key+(keylength-4),4); HashValue = HashValue^(*((int*)TempValue)); // // If the key length is >= 10, the hash is also XOR with the middle 4 bytes // if(keylength>=10) { memcpy(TempValue,(char*)key+(keylength/2),4); HashValue = HashValue^(*((int*)TempValue)); } } return(HashValue); } */ // // Determines if a key entry exists in a HashTree, and creates it if requested // /* struct HashNode* ILibFindEntry(void *hashtree, void *key, int keylength, int create) { struct HashNode *current = ((struct HashNode_Root*)hashtree)->Root; int HashValue = ILibGetHashValue(key,keylength); int done = 0; if(keylength==0){return(NULL);} // // Iterate through our tree to see if we can find this key entry // while(done==0) { // // Integer compares are very fast, this will weed out most non-matches // if(current->KeyHash==HashValue) { // // Verify this is really a match // #ifdef ASUS_UPNP_DEBUG printf("current->KeyValue=%s\n", current->KeyValue); #endif if(current->KeyLength==keylength && memcmp(current->KeyValue,key,keylength)==0) { return(current); } } if(current->Next!=NULL) { current = current->Next; } else if(create!=0) { #ifdef ASUS_UPNP_DEBUG printf("Create an entry: KeyValue=%s\n", (char*)key); #endif // // If there is no match, and the create flag is set, we need to create an entry // current->Next = (struct HashNode*)malloc(sizeof(struct HashNode)); memset(current->Next,0,sizeof(struct HashNode)); current->Next->Prev = current; current->Next->KeyHash = HashValue; current->Next->KeyValue = (void*)malloc(keylength+1); memcpy(current->Next->KeyValue,key,keylength); current->Next->KeyValue[keylength]=0; current->Next->KeyLength = keylength; return(current->Next); } else { return(NULL); } } return(NULL); } */ /*! \fn ILibHasEntry(void *hashtree, char* key, int keylength) \brief Determines if a key entry exists in a HashTree \param hashtree The HashTree to operate on \param key The key \param keylength The length of the key \returns 0 if does not exist, nonzero otherwise */ /* int ILibHasEntry(void *hashtree, char* key, int keylength) { // // This can be duplicated by calling Find entry, but setting the create flag to false // return(ILibFindEntry(hashtree,key,keylength,0)!=NULL?1:0); } */ /*! \fn ILibAddEntry(void* hashtree, char* key, int keylength, void *value) \brief Adds an item to the HashTree \param hashtree The HashTree to operate on \param key The key \param keylength The length of the key \param value The data to add into the HashTree */ /* void ILibAddEntry(void* hashtree, char* key, int keylength, void *value) { // // This can be duplicated by calling FindEntry, and setting create to true // struct HashNode* n = ILibFindEntry(hashtree,key,keylength,1); n->Data = value; } */ /*! \fn ILibGetEntry(void *hashtree, char* key, int keylength) \brief Gets an item from a HashTree \param hashtree The HashTree to operate on \param key The key \param keylength The length of the key \returns The data in the HashTree. NULL if key does not exist */ /* void* ILibGetEntry(void *hashtree, char* key, int keylength) { // // This can be duplicated by calling FindEntry and setting create to false. // If a match is found, just return the data // struct HashNode* n = ILibFindEntry(hashtree,key,keylength,0); if(n==NULL) { return(NULL); } else { return(n->Data); } } */ /*! \fn ILibDeleteEntry(void *hashtree, char* key, int keylength) \brief Deletes a keyed item from the HashTree \param hashtree The HashTree to operate on \param key The key \param keylength The length of the key */ /* void ILibDeleteEntry(void *hashtree, char* key, int keylength) { // // First find the entry // struct HashNode* n = ILibFindEntry(hashtree,key,keylength,0); if(n!=NULL) { // // Then remove it from the tree // n->Prev->Next = n->Next; if(n->Next!=NULL) { n->Next->Prev = n->Prev; } free(n->KeyValue); free(n); } } */ /*! \fn ILibGetLong(char *TestValue, int TestValueLength, long* NumericValue) \brief Reads a long value from a string, in a validating fashion \param TestValue The string to read from \param TestValueLength The length of the string \param NumericValue The long value extracted from the string \returns 0 if succesful, nonzero if there was an error */ /* int ILibGetLong(char *TestValue, int TestValueLength, long* NumericValue) { char* StopString; char* TempBuffer2 = (char*)malloc(1+sizeof(char)*19); char* TempBuffer = (char*)malloc(1+sizeof(char)*TestValueLength); memcpy(TempBuffer,TestValue,TestValueLength); TempBuffer[TestValueLength] = '\0'; *NumericValue = strtol(TempBuffer,&StopString,10); if(*StopString!='\0') { // // If strtol stopped somewhere other than the end, there was an error // free(TempBuffer); free(TempBuffer2); return(-1); } else { // // Now just check errno to see if there was an error reported // free(TempBuffer); free(TempBuffer2); if(errno!=ERANGE) { return(0); } else { return(-1); } } } */ /*! \fn ILibGetULong(char *TestValue, int TestValueLength, long* NumericValue) \brief Reads an unsigned long value from a string, in a validating fashion \param TestValue The string to read from \param TestValueLength The length of the string \param NumericValue The long value extracted from the string \returns 0 if succesful, nonzero if there was an error */ /* int ILibGetULong(const char *TestValue, const int TestValueLength, unsigned long* NumericValue){ char* StopString; char* TempBuffer2 = (char*)malloc(1+sizeof(char)*19); char* TempBuffer = (char*)malloc(1+sizeof(char)*TestValueLength); memcpy(TempBuffer,TestValue,TestValueLength); TempBuffer[TestValueLength] = '\0'; *NumericValue = strtoul(TempBuffer,&StopString,10); if(*StopString!='\0') { free(TempBuffer); free(TempBuffer2); return(-1); } else { free(TempBuffer); free(TempBuffer2); #ifdef _WIN32_WCE // Not Supported on PPC return(0); #else if(errno!=ERANGE) { if(memcmp(TestValue,"-",1)==0) { return(-1); } return(0); } else { return(-1); } #endif } } */ // // Determines if a buffer offset is a delimiter // int ILibIsDelimiter(char* buffer, int offset, int buffersize, char* Delimiter, int DelimiterLength) { // // For simplicity sake, we'll assume a match unless proven otherwise // int i=0; int RetVal = 1; if(DelimiterLength>buffersize) { // // If the offset plus delimiter length is greater than the buffersize // There can't possible be a match, so don't bother looking // return(0); } for(i=0;iFirstResult = NULL; RetVal->NumResults = 0; // // By default we will always return at least one token, which will be the // entire string if the delimiter is not found. // // Iterate through the string to find delimiters // Token = buffer + offset; for(i=offset;i<(length+offset);++i) { if(StringDelimiter==0) { if(buffer[i]=='"') { // // Ignore everything inside double quotes // StringDelimiter='"'; Ignore=1; } else { if(buffer[i]=='\'') { // // Ignore everything inside single quotes // StringDelimiter='\''; Ignore=1; } } } else { // // Once we isolated everything inside double or single quotes, we can get // on with the real parsing // if(buffer[i]==StringDelimiter) { Ignore=((Ignore==0)?1:0); } } if(Ignore==0 && ILibIsDelimiter(buffer,i,length,Delimiter,DelimiterLength)) { // // We found a delimiter in the string // p_resultfield = (struct parser_result_field*)malloc(sizeof(struct parser_result_field)); p_resultfield->data = Token; p_resultfield->datalength = TokenLength; p_resultfield->NextResult = NULL; if(RetVal->FirstResult != NULL) { RetVal->LastResult->NextResult = p_resultfield; RetVal->LastResult = p_resultfield; } else { RetVal->FirstResult = p_resultfield; RetVal->LastResult = p_resultfield; } // // After we populate the values, we advance the token to after the delimiter // to prep for the next token // ++RetVal->NumResults; i = i + DelimiterLength -1; Token = Token + TokenLength + DelimiterLength; TokenLength = 0; } else { // // No match yet, so just increment this counter // ++TokenLength; } } // // Create a result for the last token, since it won't be caught in the above loop // because if there are no more delimiters, than the entire last portion of the string since the // last delimiter is the token // p_resultfield = (struct parser_result_field*)malloc(sizeof(struct parser_result_field)); p_resultfield->data = Token; p_resultfield->datalength = TokenLength; p_resultfield->NextResult = NULL; if(RetVal->FirstResult != NULL) { RetVal->LastResult->NextResult = p_resultfield; RetVal->LastResult = p_resultfield; } else { RetVal->FirstResult = p_resultfield; RetVal->LastResult = p_resultfield; } ++RetVal->NumResults; return(RetVal); } */ /*! \fn ILibTrimString(char **theString, int length) \brief Trims leading and trailing whitespace characters \param theString The string to trim \param length Length of \a theString \returns Length of the trimmed string */ /* int ILibTrimString(char **theString, int length) { int i; int flag1=0,flag2=0; for(i=0;iFirstResult = NULL; RetVal->NumResults = 0; // // By default we will always return at least one token, which will be the // entire string if the delimiter is not found. // // Iterate through the string to find delimiters // Token = buffer + offset; for(i=offset;idata = Token; p_resultfield->datalength = TokenLength; p_resultfield->NextResult = NULL; if(RetVal->FirstResult != NULL) { RetVal->LastResult->NextResult = p_resultfield; RetVal->LastResult = p_resultfield; } else { RetVal->FirstResult = p_resultfield; RetVal->LastResult = p_resultfield; } // // After we populate the values, we advance the token to after the delimiter // to prep for the next token // ++RetVal->NumResults; i = i + DelimiterLength -1; Token = Token + TokenLength + DelimiterLength; TokenLength = 0; } else { // // No match yet, so just increment this counter // ++TokenLength; } } // // Create a result for the last token, since it won't be caught in the above loop // because if there are no more delimiters, than the entire last portion of the string since the // last delimiter is the token // p_resultfield = (struct parser_result_field*)malloc(sizeof(struct parser_result_field)); p_resultfield->data = Token; p_resultfield->datalength = TokenLength; p_resultfield->NextResult = NULL; if(RetVal->FirstResult != NULL) { RetVal->LastResult->NextResult = p_resultfield; RetVal->LastResult = p_resultfield; } else { RetVal->FirstResult = p_resultfield; RetVal->LastResult = p_resultfield; } ++RetVal->NumResults; return(RetVal); } /*! \fn ILibDestructParserResults(struct parser_result *result) \brief Frees resources associated with the list of tokens returned from ILibParseString and ILibParseStringAdv. \param result The list of tokens to free */ void ILibDestructParserResults(struct parser_result *result) { // // All of these nodes only contain pointers // so we just need to iterate through all the nodes and free them // struct parser_result_field *node = result->FirstResult; struct parser_result_field *temp = NULL; while(node!=NULL) { temp = node->NextResult; free(node); node = temp; } free(result); } /*! \fn ILibDestructPacket(struct packetheader *packet) \brief Frees resources associated with a Packet that was created either by \a ILibCreateEmptyPacket or \a ILibParsePacket \param packet The packet to free */ /* void ILibDestructPacket(struct packetheader *packet) { struct packetheader_field_node *node = packet->FirstField; struct packetheader_field_node *nextnode; // // Iterate through all the headers // while(node!=NULL) { nextnode = node->NextField; if(node->UserAllocStrings!=0) { // // If the user allocated the string, then we need to free it. // Otherwise these are just pointers into others strings, in which // case we don't want to free them // free(node->Field); free(node->FieldData); } free(node); node = nextnode; } if(packet->UserAllocStrings!=0) { // // If this flag was set, it means the used ILibCreateEmptyPacket, // and set these fields manually, which means the string was copied. // In which case, we need to free the strings // if(packet->StatusData!=NULL) {free(packet->StatusData);} if(packet->Directive!=NULL) {free(packet->Directive);} if(packet->Reserved==NULL && packet->DirectiveObj!=NULL) {free(packet->DirectiveObj);} if(packet->Reserved!=NULL) {free(packet->Reserved);} if(packet->Body!=NULL) free(packet->Body); } if(packet->UserAllocVersion!=0) { free(packet->Version); } free(packet); } */ /*! \fn ILibHTTPEscape(char* outdata, const char* data) \brief Escapes a string according to HTTP Specifications. \para The string you would want to escape would typically be the string used in the Path portion of an HTTP request. eg:
GET foo/bar.txt HTTP/1.1

\b Note: It should be noted that the output buffer needs to be allocated prior to calling this method. The required space can be determined by calling \a ILibHTTPEscapeLength. \param outdata The escaped string \param data The string to escape \returns The length of the escaped string */ /* int ILibHTTPEscape(char* outdata, const char* data) { int i=0; int x=0; char hex[4]; int hexLen; while(data[x]!=0) { if( (data[x]>=63 && data[x]<=90) || (data[x]>=97 && data[x]<=122) || (data[x]>=47 && data[x]<=57) \ || data[x]==59 || data[x]==47 || data[x]==63 || data[x]==58 || data[x]==64 || data[x]==61 \ || data[x]==43 || data[x]==36 || data[x]==45 || data[x]==95 || data[x]==46 || data[x]==42) { // // These are all the allowed values for HTTP. If it's one of these characters, we're ok // outdata[i] = data[x]; ++i; } else { // // If it wasn't one of these characters, then we need to escape it // hexLen = sprintf(hex,"%02X",(unsigned char)data[x]); outdata[i] = '%'; outdata[i+1] = hex[0]; outdata[i+2] = hex[1]; i+=3; } ++x; } outdata[i]=0; return(i+1); } */ /*! \fn ILibHTTPEscapeLength(const char* data) \brief Determines the buffer space required to HTTP escape a particular string. \param data Calculates the length requirements as if \a\b data was escaped \returns The minimum required length */ /* int ILibHTTPEscapeLength(const char* data) { int i=0; int x=0; while(data[x]!=0) { if( (data[x]>=63 && data[x]<=90) || (data[x]>=97 && data[x]<=122) || (data[x]>=47 && data[x]<=57) \ || data[x]==59 || data[x]==47 || data[x]==63 || data[x]==58 || data[x]==64 || data[x]==61 \ || data[x]==43 || data[x]==36 || data[x]==45 || data[x]==95 || data[x]==46 || data[x]==42) { // No need to escape ++i; } else { // Need to escape i+=3; } ++x; } return(i+1); } */ /*! \fn ILibInPlaceHTTPUnEscape(char* data) \brief Unescapes a given string according to HTTP encoding rules \para The escaped representation of a string is always longer than the unescaped version so this method will overwrite the escaped string, with the unescaped result. \param data The buffer to unescape \returns The length of the unescaped string */ /* int ILibInPlaceHTTPUnEscape(char* data) { char hex[3]; char *stp; int src_x=0; int dst_x=0; int length = (int)strlen(data); hex[2]=0; while(src_xpacketheader structure */ /* struct packetheader* ILibParsePacketHeader(char* buffer, int offset, int length) { struct packetheader *RetVal = (struct packetheader*)malloc(sizeof(struct packetheader)); struct parser_result *_packet = NULL; struct parser_result *p = NULL; struct parser_result *StartLine = NULL; struct parser_result_field *HeaderLine = NULL; struct parser_result_field *f = NULL; char* tempbuffer = NULL; struct packetheader_field_node *node = NULL; int i=0; memset(RetVal,0,sizeof(struct packetheader)); // // All the headers are delineated with a CRLF, so we parse on that // p = (struct parser_result*)ILibParseString(buffer,offset,length,"\r\n",2); _packet = p; f = p->FirstResult; // // The first token is where we can figure out the Method, Path, Version, etc. // StartLine = (struct parser_result*)ILibParseString(f->data,0,f->datalength," ",1); HeaderLine = f->NextResult; if(memcmp(StartLine->FirstResult->data, "HTTP/", 5)==0) { // // If the StartLine starts with HTTP/, then we know this is a response packet. // We parse on the '/' character to determine the Version, as it follows. // eg: HTTP/1.1 200 OK // p = (struct parser_result*)ILibParseString(StartLine->FirstResult->data, 0, StartLine->FirstResult->datalength, "/",1); RetVal->Version = p->LastResult->data; RetVal->VersionLength = p->LastResult->datalength; RetVal->Version[RetVal->VersionLength]=0; ILibDestructParserResults(p); tempbuffer = (char*)malloc(1+sizeof(char)*(StartLine->FirstResult->NextResult->datalength)); memcpy(tempbuffer,StartLine->FirstResult->NextResult->data, StartLine->FirstResult->NextResult->datalength); //MEMCHECK(assert(StartLine->FirstResult->NextResult->datalength <= 1+(int)sizeof(char)*(StartLine->FirstResult->NextResult->datalength));) // // The other tokens contain the Status code and data // tempbuffer[StartLine->FirstResult->NextResult->datalength] = '\0'; RetVal->StatusCode = (int)atoi(tempbuffer); free(tempbuffer); RetVal->StatusData = StartLine->FirstResult->NextResult->NextResult->data; RetVal->StatusDataLength = StartLine->FirstResult->NextResult->NextResult->datalength; } else { // // If the packet didn't start with HTTP/ then we know it's a request packet // eg: GET /index.html HTTP/1.1 // The method (or directive), is the first token, and the Path // (or DirectiveObj) is the second, and version in the 3rd. // RetVal->Directive = StartLine->FirstResult->data; RetVal->DirectiveLength = StartLine->FirstResult->datalength; RetVal->DirectiveObj = StartLine->FirstResult->NextResult->data; RetVal->DirectiveObjLength = StartLine->FirstResult->NextResult->datalength; RetVal->StatusCode = -1; // // We parse the last token on '/' to find the version // p = (struct parser_result*)ILibParseString(StartLine->LastResult->data, 0, StartLine->LastResult->datalength, "/",1); RetVal->Version = p->LastResult->data; RetVal->VersionLength = p->LastResult->datalength; RetVal->Version[RetVal->VersionLength]=0; ILibDestructParserResults(p); RetVal->Directive[RetVal->DirectiveLength] = '\0'; RetVal->DirectiveObj[RetVal->DirectiveObjLength] = '\0'; } // // Headerline starts with the second token. Then we iterate through the rest of the tokens // while(HeaderLine!=NULL) { if(HeaderLine->datalength==0) { // // An empty line signals the end of the headers // break; } // Arthur, 050721, DLNA CTT 1.00.07 case 7.8.10.3 #ifdef ASUS_DLNA_CTT if(node!=NULL && (HeaderLine->data[0] == 0x09 || HeaderLine->data[0] == 0x20)) #else if(node!=NULL && HeaderLine->data[0]==' ') #endif { // // This is a multi-line continuation // if(node->UserAllocStrings==0) { tempbuffer = node->FieldData; node->FieldData = (char*)malloc(node->FieldDataLength + HeaderLine->datalength); memcpy(node->FieldData,tempbuffer,node->FieldDataLength); tempbuffer = node->Field; node->Field = (char*)malloc(node->FieldLength+1); memcpy(node->Field,tempbuffer,node->FieldLength); node->UserAllocStrings = -1; } else { node->FieldData = (char*)realloc(node->FieldData,node->FieldDataLength + HeaderLine->datalength); } memcpy(node->FieldData+node->FieldDataLength,HeaderLine->data+1,HeaderLine->datalength-1); node->FieldDataLength += (HeaderLine->datalength-1); } else { // // Instantiate a new header entry for each new token // node = (struct packetheader_field_node*)malloc(sizeof(struct packetheader_field_node)); memset(node,0,sizeof(struct packetheader_field_node)); for(i=0;idatalength;++i) { if(*((HeaderLine->data)+i)==':') { node->Field = HeaderLine->data; node->FieldLength = i; node->FieldData = HeaderLine->data + i + 1; node->FieldDataLength = (HeaderLine->datalength)-i-1; break; } } if(node->Field==NULL) { free(RetVal); RetVal = NULL; break; } // // We need to do white space processing, because we need to ignore them in the // headers // So do a 'trim' operation // node->FieldDataLength = ILibTrimString(&(node->FieldData),node->FieldDataLength); node->Field[node->FieldLength] = '\0'; node->FieldData[node->FieldDataLength] = '\0'; // // Since we are parsing an existing string, we set this flag to zero, so that it doesn't // get freed // node->UserAllocStrings = 0; node->NextField = NULL; if(RetVal->FirstField==NULL) { // // If there aren't any headers yet, this will be the first // RetVal->FirstField = node; RetVal->LastField = node; } else { // // There are already headers, so link this in the tail // RetVal->LastField->NextField = node; } RetVal->LastField = node; } HeaderLine = HeaderLine->NextResult; } ILibDestructParserResults(_packet); ILibDestructParserResults(StartLine); return(RetVal); } */ /*! \fn ILibFragmentTextLength(char *text, int textLength, char *delimiter, int delimiterLength, int tokenLength) \brief Determines the buffer size required to fragment a string \param text The string to fragment \param textLength Length of \a text \param delimiter Line delimiter \param delimiterLength Length of \a delimiter \param tokenLength The maximum size of each fragment or token \returns The length of the buffer required to call \a ILibFragmentText */ /* int ILibFragmentTextLength(char *text, int textLength, char *delimiter, int delimiterLength, int tokenLength) { int RetVal = textLength + (((textLength/tokenLength)==1?0:(textLength/tokenLength))*delimiterLength); return(RetVal); } */ /*! \fn ILibFragmentText(char *text, int textLength, char *delimiter, int delimiterLength, int tokenLength, char **RetVal) \brief Fragments a string into multiple tokens \param text The string to fragment \param textLength Length of \a text \param delimiter Line delimiter \param delimiterLength Length of \a delimiter \param tokenLength The maximum size of each fragment or token \param RetVal The buffer to store the resultant string \returns The length of the written string */ /* int ILibFragmentText(char *text, int textLength, char *delimiter, int delimiterLength, int tokenLength, char **RetVal) { char *Buffer; int i=0,i2=0; int BufferSize = 0; *RetVal = (char*)malloc(ILibFragmentTextLength(text,textLength,delimiter,delimiterLength,tokenLength)); Buffer = *RetVal; i2 = textLength; while(i2!=0) { if(i2!=textLength) { memcpy(Buffer+i,delimiter,delimiterLength); i+=delimiterLength; BufferSize += delimiterLength; } memcpy(Buffer+i,text + (textLength-i2),i2>tokenLength?tokenLength:i2); i+=i2>tokenLength?tokenLength:i2; BufferSize += i2>tokenLength?tokenLength:i2; i2 -= i2>tokenLength?tokenLength:i2; } return(BufferSize); } */ /*! \fn ILibGetRawPacket(struct packetheader* packet,char **RetVal) \brief Converts a packetheader structure into a raw char* buffer \para \b Note: The returned buffer must be freed \param packet The packetheader struture to convert \param RetVal The output char* buffer \returns The length of the output buffer */ /* int ILibGetRawPacket(struct packetheader* packet,char **RetVal) { int i,i2; int BufferSize = 0; char* Buffer, *temp; struct packetheader_field_node *node; if(packet->StatusCode!=-1) { BufferSize = 12 + packet->VersionLength + packet->StatusDataLength; // // HTTP/1.1 200 OK\r\n // 12 is the total number of literal characters. Just add Version and StatusData // HTTP/ OK \r\n // } else { BufferSize = packet->DirectiveLength + packet->DirectiveObjLength + 12; // // GET / HTTP/1.1\r\n // This is calculating the length for a request packet. // ToDo: This isn't completely correct // But it will work as long as the version is not > 9.9 // It should also add the length of the Version, but it's not critical. } node = packet->FirstField; while(node!=NULL) { // // A conservative estimate adding the lengths of the header name and value, plus // 4 characters for the ':' and CRLF // BufferSize += node->FieldLength + node->FieldDataLength + 4; // // If the header is longer than MAX_HEADER_LENGTH, we need to break it up // into multiple lines, so we need to calculate the space needed for the // delimiters. // if(node->FieldDataLength>MAX_HEADER_LENGTH) { BufferSize += ILibFragmentTextLength(node->FieldData,node->FieldDataLength,"\r\n ",3,MAX_HEADER_LENGTH); } node = node->NextField; } // // Another conservative estimate adding in the packet body length plus a padding of 3 // for the empty line // BufferSize += (3+packet->BodyLength); // // Allocate the buffer // *RetVal = (char*)malloc(BufferSize); Buffer = *RetVal; if(packet->StatusCode!=-1) { // // Write the response // memcpy(Buffer,"HTTP/",5); memcpy(Buffer+5,packet->Version,packet->VersionLength); i = 5+packet->VersionLength; i+=sprintf(Buffer+i," %d ",packet->StatusCode); memcpy(Buffer+i,packet->StatusData,packet->StatusDataLength); i+=packet->StatusDataLength; memcpy(Buffer+i,"\r\n",2); i+=2; // HTTP/1.1 200 OK\r\n } else { // // Write the Request // memcpy(Buffer,packet->Directive,packet->DirectiveLength); i = packet->DirectiveLength; memcpy(Buffer+i," ",1); i+=1; memcpy(Buffer+i,packet->DirectiveObj,packet->DirectiveObjLength); i+=packet->DirectiveObjLength; memcpy(Buffer+i," HTTP/",6); i+=6; memcpy(Buffer+i,packet->Version,packet->VersionLength); i+=packet->VersionLength; memcpy(Buffer+i,"\r\n",2); i+=2; // GET / HTTP/1.1\r\n } node = packet->FirstField; while(node!=NULL) { // // Write each header // memcpy(Buffer+i,node->Field,node->FieldLength); i+=node->FieldLength; memcpy(Buffer+i,": ",2); i+=2; BufferSize += (node->FieldLength + 2); if(ILibFragmentTextLength(node->FieldData,node->FieldDataLength,"\r\n ",3, MAX_HEADER_LENGTH)>node->FieldDataLength) { // Fragment this i2 = ILibFragmentText(node->FieldData,node->FieldDataLength,"\r\n ",3, MAX_HEADER_LENGTH,&temp); memcpy(Buffer+i,temp,i2); i += i2; BufferSize += i2; free(temp); } else { // No need to fragment this memcpy(Buffer+i,node->FieldData,node->FieldDataLength); i += node->FieldDataLength; BufferSize += node->FieldDataLength; } memcpy(Buffer+i,"\r\n",2); i+=2; BufferSize += 2; node = node->NextField; } // // Write the empty line // memcpy(Buffer+i,"\r\n",2); i+=2; // // Write the body // memcpy(Buffer+i,packet->Body,packet->BodyLength); i+=packet->BodyLength; Buffer[i] = '\0'; return(i); } */ /*! \fn unsigned short ILibGetDGramSocket(int local, int *TheSocket) \brief Allocates a UDP socket for a given interface, choosing a random port number from 50000 to 65535 \para \b Note: Storage type of \a TheSocket is platform dependent.
Windows Winsock2 = HANDLE*
Windows Winsock1 = SOCKET*
Linux/Posix = int*
\param local The interface to bind to \param TheSocket The created UDP socket \returns The port number that was bound */ /* #ifdef WINSOCK2 unsigned short ILibGetDGramSocket(int local, HANDLE *TheSocket) #elif WINSOCK1 unsigned short ILibGetDGramSocket(int local, SOCKET *TheSocket) #else unsigned short ILibGetDGramSocket(int local, int *TheSocket) #endif { unsigned short PortNum = -1; struct sockaddr_in addr; memset((char *)&(addr), 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = local; #ifdef WINSOCK2 *TheSocket = (HANDLE)socket(AF_INET, SOCK_DGRAM, 0); #elif WINSOCK1 *TheSocket = (SOCKET)socket(AF_INET, SOCK_DGRAM, 0); #else *TheSocket = (int)socket(AF_INET, SOCK_DGRAM, 0); #endif // // Keep looping until we find a port number that isn't in use. Since // we're using random numbers, the first try should usually do it. // We can't just bind to 0, because we need to be IANA compliant. // do { // // Choose a random port from 50000 to 65500, which is what IANA says to use // for non standard ports // PortNum = (unsigned short)(50000 + ((unsigned short)rand() % 15000)); addr.sin_port = htons(PortNum); } #ifdef WIN32 while(bind((SOCKET)*TheSocket, (struct sockaddr *) &(addr), sizeof(addr)) < 0); #else while(bind((int)*TheSocket, (struct sockaddr *) &(addr), sizeof(addr)) < 0); #endif return(PortNum); } */ /*! \fn unsigned short ILibGetStreamSocket(int local, unsigned short PortNumber, int *TheSocket) \brief Allocates a TCP socket for a given interface, choosing a random port number from 50000 to 65535 \para \b Note: Storage type of \a TheSocket is platform dependent.
Windows Winsock2 = HANDLE*
Windows Winsock1 = SOCKET*
Linux/Posix = int*
\param local The interface to bind to \param TheSocket The created TCP socket \returns The port number that was bound */ /* #ifdef WINSOCK2 unsigned short ILibGetStreamSocket(int local, unsigned short PortNumber, HANDLE *TheSocket) #elif WINSOCK1 unsigned short ILibGetStreamSocket(int local, unsigned short PortNumber, SOCKET *TheSocket) #else unsigned short ILibGetStreamSocket(int local, unsigned short PortNumber, int *TheSocket) #endif { int ra=1; unsigned short PortNum = -1; struct sockaddr_in addr; memset((char *)&(addr), 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = local; #ifdef WINSOCK2 *TheSocket = (HANDLE)socket(AF_INET, SOCK_STREAM, 0); #elif WINSOCK1 *TheSocket = (SOCKET)socket(AF_INET, SOCK_STREAM, 0); #else *TheSocket = (int)socket(AF_INET, SOCK_STREAM, 0); #endif if(PortNumber==0) { // // If PortNumber is 0, we need to choose a random port from MINPORTNUMBER to // MINPORTNUMBER + PORTNUMBERRANGE. // By default this is 50000 + 15000, which gives us the IANA defined range to use // do { PortNum = (unsigned short)(MINPORTNUMBER + ((unsigned short)rand() % PORTNUMBERRANGE)); addr.sin_port = htons(PortNum); } #ifdef WIN32 while(bind((SOCKET)*TheSocket, (struct sockaddr *) &(addr), sizeof(addr)) < 0); #else while(bind((int)*TheSocket, (struct sockaddr *) &(addr), sizeof(addr)) < 0); #endif } else { // // If a specific port was specified, try to use that // addr.sin_port = htons(PortNumber); #ifdef WIN32 if (setsockopt((SOCKET)*TheSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&ra, sizeof(ra)) < 0) #else if (setsockopt((int)*TheSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&ra, sizeof(ra)) < 0) #endif { } #ifdef WIN32 PortNum = bind((SOCKET)*TheSocket, (struct sockaddr *) &(addr), sizeof(addr))<0?0:PortNumber; #else PortNum = bind((int)*TheSocket, (struct sockaddr *) &(addr), sizeof(addr))<0?0:PortNumber; #endif } return(PortNum); } */ /*! \fn ILibParseUri(char* URI, char** IP, unsigned short* Port, char** Path) \brief Parses a URI string, into its IP Address, Port Number, and Path components \para \b Note: The IP and Path components must be freed \param URI The URI to parse \param IP The IP Address component in dotted quad format \param Port The Port component. Default is 80 \param Path The Path component */ /* void ILibParseUri(char* URI, char** IP, unsigned short* Port, char** Path) { struct parser_result *result,*result2,*result3; char *TempString,*TempString2; int TempStringLength,TempStringLength2; // // A scheme has the format xxx://yyy , so if we parse on ://, we can extract the path info // result = ILibParseString(URI, 0, (int)strlen(URI), "://", 3); TempString = result->LastResult->data; TempStringLength = result->LastResult->datalength; // // Parse Path // The first '/' will occur after the IPAddress:Port combination // result2 = ILibParseString(TempString,0,TempStringLength,"/",1); TempStringLength2 = TempStringLength-result2->FirstResult->datalength; *Path = (char*)malloc(TempStringLength2+1); memcpy(*Path,TempString+(result2->FirstResult->datalength),TempStringLength2); (*Path)[TempStringLength2] = '\0'; // Parse Port Number result3 = ILibParseString(result2->FirstResult->data,0,result2->FirstResult->datalength,":",1); if(result3->NumResults==1) { // // The default port is 80, if non is specified, because we are assuming // an HTTP scheme // *Port = 80; } else { // // If a port was specified, use that // TempString2 = (char*)malloc(result3->LastResult->datalength+1); memcpy(TempString2,result3->LastResult->data,result3->LastResult->datalength); TempString2[result3->LastResult->datalength] = '\0'; *Port = (unsigned short)atoi(TempString2); free(TempString2); } // Parse IP Address TempStringLength2 = result3->FirstResult->datalength; *IP = (char*)malloc(TempStringLength2+1); memcpy(*IP,result3->FirstResult->data,TempStringLength2); (*IP)[TempStringLength2] = '\0'; ILibDestructParserResults(result3); ILibDestructParserResults(result2); ILibDestructParserResults(result); } */ /*! \fn ILibCreateEmptyPacket() \brief Creates an empty packetheader structure \returns An empty packet */ /* struct packetheader *ILibCreateEmptyPacket() { struct packetheader *RetVal = (struct packetheader*)malloc(sizeof(struct packetheader)); memset(RetVal,0,sizeof(struct packetheader)); RetVal->UserAllocStrings = -1; RetVal->StatusCode = -1; RetVal->Version = "1.0"; RetVal->VersionLength = 3; return(RetVal); } */ /*! \fn ILibClonePacket(struct packetheader *packet) \brief Creates a Deep Copy of a packet structure \para Because ILibParsePacketHeader does not copy any data, the data will become invalid once the data is flushed. This method is used to preserve the data. \param packet The packet to clone \returns A cloned packet structure */ /* struct packetheader* ILibClonePacket(struct packetheader *packet) { struct packetheader *RetVal = ILibCreateEmptyPacket(); struct packetheader_field_node *n; RetVal->ClonedPacket=1; RetVal->ReceivingAddress = packet->ReceivingAddress; // // These three calls will result in the fields being copied // ILibSetDirective( RetVal, packet->Directive, packet->DirectiveLength, packet->DirectiveObj, packet->DirectiveObjLength); ILibSetStatusCode( RetVal, packet->StatusCode, packet->StatusData, packet->StatusDataLength); ILibSetVersion(RetVal,packet->Version,packet->VersionLength); // // Iterate through each header, and copy them // n = packet->FirstField; while(n!=NULL) { ILibAddHeaderLine( RetVal, n->Field, n->FieldLength, n->FieldData, n->FieldDataLength); n = n->NextField; } return(RetVal); } */ /*! \fn ILibSetVersion(struct packetheader *packet, char* Version, int VersionLength) \brief Sets the version of a packetheader structure. The Default version is 1.0 \param packet The packet to modify \param Version The version string to write. eg: 1.1 \param VersionLength The length of the \a Version */ /* void ILibSetVersion(struct packetheader *packet, char* Version, int VersionLength) { if(packet->UserAllocVersion!=0) {free(packet->Version);} packet->UserAllocVersion=1; packet->Version = (char*)malloc(1+VersionLength); memcpy(packet->Version,Version,VersionLength); packet->Version[VersionLength] = '\0'; } */ /*! \fn ILibSetStatusCode(struct packetheader *packet, int StatusCode, char *StatusData, int StatusDataLength) \brief Sets the status code of a packetheader structure \param packet The packet to modify \param StatusCode The status code, eg: 200 \param StatusData The status string, eg: OK \param StatusDataLength The length of \a StatusData */ /* void ILibSetStatusCode(struct packetheader *packet, int StatusCode, char *StatusData, int StatusDataLength) { packet->StatusCode = StatusCode; packet->StatusData = (char*)malloc(StatusDataLength+1); memcpy(packet->StatusData,StatusData,StatusDataLength); packet->StatusData[StatusDataLength] = '\0'; packet->StatusDataLength = StatusDataLength; } */ /*! \fn ILibSetDirective(struct packetheader *packet, char* Directive, int DirectiveLength, char* DirectiveObj, int DirectiveObjLength) \brief Sets the /a Method and /a Path of a packetheader structure \param packet The packet to modify \param Directive The Method to write, eg: \b GET \param DirectiveLength The length of \a Directive \param DirectiveObj The path component of the method, eg: \b /index.html \param DirectiveObjLength The length of \a DirectiveObj */ /* void ILibSetDirective(struct packetheader *packet, char* Directive, int DirectiveLength, char* DirectiveObj, int DirectiveObjLength) { packet->Directive = (char*)malloc(DirectiveLength+1); memcpy(packet->Directive,Directive,DirectiveLength); packet->Directive[DirectiveLength] = '\0'; packet->DirectiveLength = DirectiveLength; packet->DirectiveObj = (char*)malloc(DirectiveObjLength+1); memcpy(packet->DirectiveObj,DirectiveObj,DirectiveObjLength); packet->DirectiveObj[DirectiveObjLength] = '\0'; packet->DirectiveObjLength = DirectiveObjLength; packet->UserAllocStrings = -1; } */ /*! \fn ILibAddHeaderLine(struct packetheader *packet, char* FieldName, int FieldNameLength, char* FieldData, int FieldDataLength) \brief Adds an HTTP header entry into a packetheader structure \param packet The packet to modify \param FieldName The header name, eg: \b CONTENT-TYPE \param FieldNameLength The length of the \a FieldName \param FieldData The header value, eg: \b text/xml \param FieldDataLength The length of the \a FieldData */ /* void ILibAddHeaderLine(struct packetheader *packet, char* FieldName, int FieldNameLength, char* FieldData, int FieldDataLength) { struct packetheader_field_node *node; // // Create the Header Node // node = (struct packetheader_field_node*)malloc(sizeof(struct packetheader_field_node)); node->UserAllocStrings = -1; node->Field = (char*)malloc(FieldNameLength+1); memcpy(node->Field,FieldName,FieldNameLength); node->Field[FieldNameLength] = '\0'; node->FieldLength = FieldNameLength; node->FieldData = (char*)malloc(FieldDataLength+1); memcpy(node->FieldData,FieldData,FieldDataLength); node->FieldData[FieldDataLength] = '\0'; node->FieldDataLength = FieldDataLength; node->NextField = NULL; // // And attach it to the linked list // if(packet->LastField!=NULL) { packet->LastField->NextField = node; packet->LastField = node; } else { packet->LastField = node; packet->FirstField = node; } } */ /*! \fn ILibGetHeaderLine(struct packetheader *packet, char* FieldName, int FieldNameLength) \brief Retrieves an HTTP header value from a packet structure \para \b Note: The result must be freed \param packet The packet to introspect \param FieldName The header name to lookup \param FieldNameLength">The length of \a FieldName \returns The header value. NULL if not found */ /* char* ILibGetHeaderLine(struct packetheader *packet, char* FieldName, int FieldNameLength) { char* RetVal = NULL; struct packetheader_field_node *node = packet->FirstField; int i; // // Iterate through the headers, until we find the one we're interested in // while(node!=NULL) { if(strncasecmp(FieldName,node->Field,FieldNameLength)==0) { // // Copy the value, and return it // RetVal = (char*)malloc(node->FieldDataLength+1); for(i=0;iFieldDataLength;++i) { if(node->FieldData[i]!=' ') {break;} } if(i==node->FieldDataLength-1) {i = 0;} memcpy(RetVal,node->FieldData+i,node->FieldDataLength-i); RetVal[node->FieldDataLength-i] = '\0'; break; } node = node->NextField; } return(RetVal); } */ /* static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; // encode 3 8-bit binary bytes as 4 '6-bit' characters void ILibencodeblock( unsigned char in[3], unsigned char out[4], int len ) { out[0] = cb64[ in[0] >> 2 ]; out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='); out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '='); } */ /*! \fn ILibBase64Encode(unsigned char* input, const int inputlen, unsigned char** output) \brief Base64 encode a stream adding padding and line breaks as per spec. \para \b Note: The encoded stream must be freed \param input The stream to encode \param inputlen The length of \a input \param output The encoded stream \returns The length of the encoded stream */ /* int ILibBase64Encode(unsigned char* input, const int inputlen, unsigned char** output) { unsigned char* out; unsigned char* in; *output = (unsigned char*)malloc(((inputlen * 4) / 3) + 5); out = *output; in = input; if (input == NULL || inputlen == 0) { *output = NULL; return 0; } while ((in+3) <= (input+inputlen)) { ILibencodeblock(in, out, 3); in += 3; out += 4; } if ((input+inputlen)-in == 1) { ILibencodeblock(in, out, 1); out += 4; } else if ((input+inputlen)-in == 2) { ILibencodeblock(in, out, 2); out += 4; } *out = 0; return (int)(out-*output); } */ /* Decode 4 '6-bit' characters into 3 8-bit binary bytes */ /* void ILibdecodeblock( unsigned char in[4], unsigned char out[3] ) { out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4); out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2); out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]); } */ /*! \fn ILibBase64Decode(unsigned char* input, const int inputlen, unsigned char** output) \brief Decode a base64 encoded stream discarding padding, line breaks and noise \para \b Note: The decoded stream must be freed \param input The stream to decode \param inputlen The length of \a input \param output The decoded stream \returns The length of the decoded stream */ /* int ILibBase64Decode(unsigned char* input, const int inputlen, unsigned char** output) { unsigned char* inptr; unsigned char* out; unsigned char v; unsigned char in[4]; int i, len; if (input == NULL || inputlen == 0) { *output = NULL; return 0; } *output = (unsigned char*)malloc(((inputlen * 3) / 4) + 4); out = *output; inptr = input; while( inptr <= (input+inputlen) ) { for( len = 0, i = 0; i < 4 && inptr <= (input+inputlen); i++ ) { v = 0; while( inptr <= (input+inputlen) && v == 0 ) { v = (unsigned char) *inptr; inptr++; v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]); if( v ) { v = (unsigned char) ((v == '$') ? 0 : v - 61); } } if( inptr <= (input+inputlen) ) { len++; if( v ) { in[ i ] = (unsigned char) (v - 1); } } else { in[i] = 0; } } if( len ) { ILibdecodeblock( in, out ); out += len-1; } } *out = 0; return (int)(out-*output); } */ /*! \fn ILibInPlaceXmlUnEscape(char* data) \brief Unescapes a string according to XML parsing rules \para Since an escaped XML string is always larger than its unescaped form, this method will overwrite the escaped string with the unescaped string, while decoding. \param data The XML string to unescape \returns The length of the unescaped XML string */ /* int ILibInPlaceXmlUnEscape(char* data) { char* end = NULL; char* i = NULL; // src char* j = NULL; // dest if(data == NULL) return 0; end = data + strlen(data); i = data; j = data; // // Iterate through the string to find escaped sequences // while (j < end) { if (j[0] == '&' && j[1] == 'q' && j[2] == 'u' && j[3] == 'o' && j[4] == 't' && j[5] == ';') // " { // Double Quote i[0] = '"'; j += 5; } else if (j[0] == '&' && j[1] == 'a' && j[2] == 'p' && j[3] == 'o' && j[4] == 's' && j[5] == ';') // ' { // Single Quote (apostrophe) i[0] = '\''; j += 5; } else if (j[0] == '&' && j[1] == 'a' && j[2] == 'm' && j[3] == 'p' && j[4] == ';') // & { // Ampersand i[0] = '&'; j += 4; } else if (j[0] == '&' && j[1] == 'l' && j[2] == 't' && j[3] == ';') // < { // Less Than i[0] = '<'; j += 3; } else if (j[0] == '&' && j[1] == 'g' && j[2] == 't' && j[3] == ';') // > { // Greater Than i[0] = '>'; j += 3; } else { i[0] = j[0]; } i++; j++; } i[0] = '\0'; return (int)(i - data); } */ /*! \fn ILibXmlEscapeLength(const char* data) \brief Calculates the minimum required buffer space, to escape an xml string \para \b Note: This calculation does not include space for a null terminator \param data The XML string to calculate buffer requirments with \returns The minimum required buffer size */ /* int ILibXmlEscapeLength(const char* data) { int i = 0, j = 0; while (data[i] != 0) { switch (data[i]) { case '"': j += 6; break; case '\'': j += 6; break; case '<': j += 4; break; case '>': j += 4; break; case '&': j += 5; break; default: j++; } i++; } return j; } */ /*! \fn ILibXmlEscape(char* outdata, const char* indata) \brief Escapes a string according to XML parsing rules \b Note: /a outdata must be pre-allocated and freed \param outdata The escaped XML string \param indata The string to escape \returns The length of the escaped string */ /* int ILibXmlEscape(char* outdata, const char* indata) { int i=0; int inlen; char* out; out = outdata; inlen = (int)strlen(indata); for (i=0; i < inlen; i++) { if (indata[i] == '"') { memcpy(out, """, 6); out = out + 6; } else if (indata[i] == '\'') { memcpy(out, "'", 6); out = out + 6; } else if (indata[i] == '<') { memcpy(out, "<", 4); out = out + 4; } else if (indata[i] == '>') { memcpy(out, ">", 4); out = out + 4; } else if (indata[i] == '&') { memcpy(out, "&", 5); out = out + 5; } else { out[0] = indata[i]; out++; } } out[0] = 0; return (int)(out - outdata); } */ /*! \fn ILibLifeTime_AddEx(void *LifetimeMonitorObject,void *data, int ms, void* Callback, void* Destroy) \brief Registers a timed callback with millisecond granularity \param LifetimeMonitorObject The \a ILibLifeTime object to add the timed callback to \param data The data object to associate with the timed callback \param ms The number of milliseconds for the timed callback \param Callback The callback function pointer to trigger when the specified time elapses \param Destroy The abort function pointer, which triggers all non-triggered timed callbacks, upon shutdown */ /* void ILibLifeTime_AddEx(void *LifetimeMonitorObject,void *data, int ms, void* Callback, void* Destroy) { int NeedUnBlock = 0; struct timeval tv; struct LifeTimeMonitorData *temp; struct LifeTimeMonitorData *ltms = (struct LifeTimeMonitorData*)malloc(sizeof(struct LifeTimeMonitorData)); struct ILibLifeTime *UPnPLifeTime = (struct ILibLifeTime*)LifetimeMonitorObject; // // Get the current time for reference // gettimeofday(&tv,NULL); // // Set the trigger time // ltms->data = data; ltms->ExpirationTick = (tv.tv_sec*1000) + (tv.tv_usec/1000) + ms; // // Set the callback handlers // ltms->CallbackPtr = Callback; ltms->DestroyPtr = Destroy; ltms->Next = NULL; ltms->Prev = NULL; sem_wait(&(UPnPLifeTime->SyncLock)); if(UPnPLifeTime->LM==NULL) { // // There are no current triggers, so this is the first, // which also means, the Select timeout may not be short enough, so we need // to force an unblock, which will then reset the timeout appropriately // UPnPLifeTime->LM = ltms; NeedUnBlock = 1; } else { // // There are already triggers, so we just insert this one in sorted order // temp = UPnPLifeTime->LM; while(temp!=NULL) { if(ltms->ExpirationTick<=temp->ExpirationTick) { ltms->Next = temp; if(temp->Prev==NULL) { // // This is the shortest trigger, so again, the select timeout // may not be short enough, so we need to force unblock, to // recalculate the timeout for the select // UPnPLifeTime->LM=ltms; temp->Prev = ltms; NeedUnBlock = 1; } else { // // This isn't the shortest trigger, so we are gauranteed that the // MicroStack thread will unblock in time to reset the timeouts // ltms->Prev = temp->Prev; temp->Prev->Next = ltms; temp->Prev = ltms; } break; } else if(temp->Next == NULL) { // // If there aren't any more triggers left, this means we have the largest // trigger, so just tack it on the end // ltms->Next = NULL; ltms->Prev = temp; temp->Next = ltms; break; } temp = temp->Next; } } if(NeedUnBlock!=0) {ILibForceUnBlockChain(UPnPLifeTime->Chain);} sem_post(&(UPnPLifeTime->SyncLock)); } */ // // An internal method used by the ILibLifeTime methods // /* void ILibLifeTime_Check(void *LifeTimeMonitorObject,fd_set *readset, fd_set *writeset, fd_set *errorset, int* blocktime) { struct timeval tv; unsigned long CurrentTick; struct LifeTimeMonitorData *Temp, *Temp2, *Temp3, *EVT,*Last=NULL; struct ILibLifeTime *UPnPLifeTime = (struct ILibLifeTime*)LifeTimeMonitorObject; int nexttick; void *TempObject; EVT = NULL; sem_wait(&(UPnPLifeTime->SyncLock)); if(UPnPLifeTime->LM!=NULL) { // // Get the current tick count for reference // gettimeofday(&tv,NULL); CurrentTick = (tv.tv_sec*1000) + (tv.tv_usec/1000); Temp = UPnPLifeTime->LM; // // Keep looping until we find a node that doesn't need to be triggered // while(Temp!=NULL && Temp->ExpirationTick<=CurrentTick) { // // Since these are in sorted order, EVT will always point to the first // node that needs to be triggered. Last will point to the last node that // needs to be triggered. Temp will point to the first node that doesn't // need to be triggered. // EVT = UPnPLifeTime->LM; Last = Temp; Temp = Temp->Next; } if(EVT != NULL) { if(Temp!=NULL) { // // There are still nodes that will need to be triggered later, so reset it. // UPnPLifeTime->LM = Temp; if(UPnPLifeTime->LM!=NULL) { UPnPLifeTime->LM->Prev = NULL; } Last->Next = NULL; } else { // // There are no more nodes that will need to be triggered later. // UPnPLifeTime->LM = NULL; } } if(EVT!=NULL) { // // We need to create this queue, because it's possible that someone may try to remove // this particular node, while we are trying to remove it, which could get tricky. So // by creating this queue, we can track it. // UPnPLifeTime->Reserved = ILibQueue_Create(); } sem_post(&(UPnPLifeTime->SyncLock)); // // Iterate through all the triggers that we need to fire // while(EVT!=NULL) { //ToDo: We may want to check the table below first, before we start triggering EVT->CallbackPtr(EVT->data); Temp = EVT; EVT = EVT->Next; free(Temp); // // After we trigger, we check to see if any that are queued are already going to be // fired. Lots of times, a trigger may cause a removal, which may already be happening. // if(UPnPLifeTime->Reserved!=NULL) { ILibQueue_Lock(UPnPLifeTime->Reserved); Temp3 = NULL; // // TempObject is a node that was removed while we are triggering events // Iterate through all of these // TempObject = ILibQueue_DeQueue(UPnPLifeTime->Reserved); while(TempObject != NULL) { // // We need to iterate through our list of event triggers to see if // there is a match. If there is we need to remove it. // Save the root at Temp2, so when we're done, we can set EVT back // up so we can continue with the event triggers. // Temp2 = EVT; while(EVT!=NULL) { if(EVT->data==TempObject) { // Found Match, Remove it instead of triggering it if(EVT->Next!=NULL) { EVT->Next->Prev = EVT->Prev; } if(EVT->Prev!=NULL) { EVT->Prev->Next = EVT->Next; } if(Temp2 == EVT) { // // If we removed the root of the event triggers, we need to // change Temp2, so that when the list is reset, it is set correctly // Temp2 = EVT->Next; } EVT->Prev = NULL; EVT->Next = NULL; // // ToDo: Temp3 is initialized to NULL, so it looks like dead // code to me... Need to remove it later. // if(Temp3!=NULL) { EVT->Next = Temp3; Temp3 = EVT; } break; } EVT = EVT->Next; } EVT = Temp2; TempObject = (struct LifeTimeMonitorData*)ILibQueue_DeQueue(UPnPLifeTime->Reserved); } ILibQueue_UnLock(UPnPLifeTime->Reserved); // // Since none of the queued items were up to be triggered, we can go ahead and // trigger the Destroy event, because they won't be triggered. I noticed // that in the ILibLifeTime_Remove, it already triggers the Destroy. However // since Temp3 was preinitialized to NULL, I don't think this loop will enter // anyways, because I think it's dead code. // ToDo: Remove this // while(Temp3!=NULL) { Temp2 = Temp3->Next; if(Temp3->DestroyPtr!=NULL) {Temp3->DestroyPtr(Temp3->data);} free(Temp3); Temp3 = Temp2; } } } // // If there are more triggers that need to be fired later, we need to // recalculate what the max block time for our select should be // if(UPnPLifeTime->LM!=NULL) { nexttick = UPnPLifeTime->LM->ExpirationTick-CurrentTick; if(nexttick<*blocktime) {*blocktime=nexttick;} } if(UPnPLifeTime->Reserved!=NULL) { // // Since we already triggered a remove, we can throw away the queue, since // it's useless now // ILibQueue_Lock(UPnPLifeTime->Reserved); while(ILibQueue_DeQueue(UPnPLifeTime->Reserved)!=NULL); TempObject = UPnPLifeTime->Reserved; UPnPLifeTime->Reserved = NULL; ILibQueue_UnLock(TempObject); ILibQueue_Destroy(TempObject); } } else { sem_post(&(UPnPLifeTime->SyncLock)); } } */ /*! \fn ILibLifeTime_Remove(void *LifeTimeToken, void *data) \brief Removes a timed callback from an \a ILibLifeTime module \param LifeTimeToken The \a ILibLifeTime object to remove the callback from \param data The data object to remove */ /* void ILibLifeTime_Remove(void *LifeTimeToken, void *data) { struct ILibLifeTime *UPnPLifeTime = (struct ILibLifeTime*)LifeTimeToken; struct LifeTimeMonitorData *first,*last,*evt,*temp; evt = last = NULL; sem_wait(&(UPnPLifeTime->SyncLock)); first = UPnPLifeTime->LM; while(first!=NULL) { if(first->data==data) { // // Save the next pointer for use at end of loop // temp = first->Next; // // Found a match, now remove it from the list // if(first->Prev==NULL) { UPnPLifeTime->LM = first->Next; if(UPnPLifeTime->LM!=NULL) { UPnPLifeTime->LM->Prev = NULL; } } else { first->Prev->Next = first->Next; if(first->Next!=NULL) { first->Next->Prev = first->Prev; } } if(evt==NULL) { // // If this is the first match, create a new list // evt = last = first; evt->Prev = evt->Next = NULL; } else { // // Attach this match to the end of the list of matches // last->Next = first; first->Prev = last; first->Next = NULL; last = first; } first = temp; } else { first = first->Next; } } if(UPnPLifeTime->Reserved!=NULL) { // // If this queue exists, that means a bunch of nodes are being triggered. // If we are trying to remove one that is about to be triggered, we need to // stop it from being triggered. // ILibQueue_Lock(UPnPLifeTime->Reserved); ILibQueue_EnQueue(UPnPLifeTime->Reserved,data); ILibQueue_UnLock(UPnPLifeTime->Reserved); } // // Iterate through each node that is to be removed // sem_post(&(UPnPLifeTime->SyncLock)); while(evt!=NULL) { first = evt->Next; if(evt->DestroyPtr!=NULL) {evt->DestroyPtr(evt->data);} free(evt); evt = first; } } */ /*! \fn ILibLifeTime_Flush(void *LifeTimeToken) \brief Flushes all timed callbacks from an ILibLifeTime module \param LifeTimeToken The \a ILibLifeTime object to flush items from */ /* void ILibLifeTime_Flush(void *LifeTimeToken) { struct ILibLifeTime *UPnPLifeTime = (struct ILibLifeTime*)LifeTimeToken; struct LifeTimeMonitorData *temp,*temp2; sem_wait(&(UPnPLifeTime->SyncLock)); temp = UPnPLifeTime->LM; UPnPLifeTime->LM = NULL; sem_post(&(UPnPLifeTime->SyncLock)); while(temp!=NULL) { temp2 = temp->Next; if(temp->DestroyPtr!=NULL) {temp->DestroyPtr(temp->data);} free(temp); temp = temp2; } } */ // // An internal method used by the ILibLifeTime methods // /* void ILibLifeTime_Destroy(void *LifeTimeToken) { struct ILibLifeTime *UPnPLifeTime = (struct ILibLifeTime*)LifeTimeToken; ILibLifeTime_Flush(LifeTimeToken); sem_destroy(&(UPnPLifeTime->SyncLock)); } */ /*! \fn ILibCreateLifeTime(void *Chain) \brief Creates an empty ILibLifeTime container for Timed Callbacks. \para \b Note: All events are triggered on the MicroStack thread. Developers must \b NEVER block this thread! \param Chain The chain to add the \aILibLifeTime to \returns An \a ILibLifeTime token, which is used to add/remove callbacks */ /* void *ILibCreateLifeTime(void *Chain) { struct ILibLifeTime *RetVal = (struct ILibLifeTime*)malloc(sizeof(struct ILibLifeTime)); RetVal->LM = NULL; RetVal->PreSelect = &ILibLifeTime_Check; RetVal->PostSelect = NULL; RetVal->Destroy = &ILibLifeTime_Destroy; RetVal->Chain = Chain; RetVal->Reserved = NULL; sem_init(&(RetVal->SyncLock),0,1); ILibAddToChain(Chain,RetVal); return((void*)RetVal); } */ /*! \fn ILibFindEntryInTable(char *Entry, char **Table) \param Entry The text to search for \param Table The Array of strings to search \return The index into the array */ /* int ILibFindEntryInTable(char *Entry, char **Table) { int i = 0; while(Table[i]!=NULL) { if(strcmp(Entry,Table[i])==0) { return(i); } ++i; } return(-1); } */ /*! \fn ILibLinkedList_Create() \brief Create an empty Linked List Data Structure \returns Empty Linked List */ /* void* ILibLinkedList_Create() { struct ILibLinkedListNode_Root *root = (struct ILibLinkedListNode_Root*)malloc(sizeof(struct ILibLinkedListNode_Root)); root->Head = NULL; root->Tail = NULL; root->count=0; sem_init(&(root->LOCK),0,1); return(root); } */ /*! \fn ILibLinkedList_ShallowCopy(void *LinkedList) \brief Create a shallow copy of a linked list \param LinkedList The linked list to copy \returns The copy of the supplied linked list */ /* void* ILibLinkedList_ShallowCopy(void *LinkedList) { void *RetVal = ILibLinkedList_Create(); void *node = ILibLinkedList_GetNode_Head(LinkedList); while(node!=NULL) { ILibLinkedList_AddTail(RetVal,ILibLinkedList_GetDataFromNode(node)); node = ILibLinkedList_GetNextNode(node); } return(RetVal); } */ /*! \fn ILibLinkedList_GetNode_Head(void *LinkedList) \brief Returns the Head node of a linked list data structure \param LinkedList The linked list \returns The first node of the linked list */ /* void* ILibLinkedList_GetNode_Head(void *LinkedList) { return(((struct ILibLinkedListNode_Root*)LinkedList)->Head); } */ /*! \fn ILibLinkedList_GetNode_Tail(void *LinkedList) \brief Returns the Tail node of a linked list data structure \param LinkedList The linked list \returns The last node of the linked list */ /* void* ILibLinkedList_GetNode_Tail(void *LinkedList) { return(((struct ILibLinkedListNode_Root*)LinkedList)->Tail); } */ /*! \fn ILibLinkedList_GetNextNode(void *LinkedList_Node) \brief Returns the next node, from the specified linked list node \param LinkedList_Node The current linked list node \returns The next adjacent node of the current one */ /* void* ILibLinkedList_GetNextNode(void *LinkedList_Node) { return(((struct ILibLinkedListNode*)LinkedList_Node)->Next); } */ /*! \fn ILibLinkedList_GetPreviousNode(void *LinkedList_Node) \brief Returns the previous node, from the specified linked list node \param LinkedList_Node The current linked list node \returns The previous adjacent node of the current one */ /* void* ILibLinkedList_GetPreviousNode(void *LinkedList_Node) { return(((struct ILibLinkedListNode*)LinkedList_Node)->Previous); } */ /*! \fn ILibLinkedList_GetDataFromNode(void *LinkedList_Node) \brief Returns the data pointed to by a linked list node \param LinkedList_Node The current linked list node \returns The data pointer */ /* void *ILibLinkedList_GetDataFromNode(void *LinkedList_Node) { return(((struct ILibLinkedListNode*)LinkedList_Node)->Data); } */ /*! \fn ILibLinkedList_InsertBefore(void *LinkedList_Node, void *data) \brief Creates a new element, and inserts it before the given node \param LinkedList_Node The linked list node \param data The data pointer to be referenced */ /* void ILibLinkedList_InsertBefore(void *LinkedList_Node, void *data) { struct ILibLinkedListNode_Root *r = ((struct ILibLinkedListNode*)LinkedList_Node)->Root; struct ILibLinkedListNode *n = (struct ILibLinkedListNode*) LinkedList_Node; struct ILibLinkedListNode *newNode = (struct ILibLinkedListNode*)malloc(sizeof(struct ILibLinkedListNode)); newNode->Data = data; newNode->Root = r; // // Attach ourselved before the specified node // newNode->Next = n; newNode->Previous = n->Previous; if(newNode->Previous!=NULL) { newNode->Previous->Next = newNode; } n->Previous = newNode; // // If we are the first node, we need to adjust the head // if(r->Head==n) { r->Head = newNode; } ++r->count; } */ /*! \fn ILibLinkedList_InsertAfter(void *LinkedList_Node, void *data) \brief Creates a new element, and appends it after the given node \param LinkedList_Node The linked list node \param data The data pointer to be referenced */ /* void ILibLinkedList_InsertAfter(void *LinkedList_Node, void *data) { struct ILibLinkedListNode_Root *r = ((struct ILibLinkedListNode*)LinkedList_Node)->Root; struct ILibLinkedListNode *n = (struct ILibLinkedListNode*) LinkedList_Node; struct ILibLinkedListNode *newNode = (struct ILibLinkedListNode*)malloc(sizeof(struct ILibLinkedListNode)); newNode->Data = data; newNode->Root = r; // // Attach ourselved after the specified node // newNode->Next = n->Next; n->Next = newNode; newNode->Previous = n; if(newNode->Next!=NULL) { newNode->Next->Previous = newNode; } // // If we are the last node, we need to adjust the tail // if(r->Tail==n) { r->Tail = newNode; } ++r->count; } */ /*! \fn ILibLinkedList_Remove(void *LinkedList_Node) \brief Removes the given node from a linked list data structure \param LinkedList_Node The linked list node to remove */ /* void ILibLinkedList_Remove(void *LinkedList_Node) { struct ILibLinkedListNode_Root *r = ((struct ILibLinkedListNode*)LinkedList_Node)->Root; struct ILibLinkedListNode *n = (struct ILibLinkedListNode*) LinkedList_Node; if(n->Previous!=NULL) { n->Previous->Next = n->Next; } if(n->Next!=NULL) { n->Next->Previous = n->Previous; } if(r->Head==n) { r->Head = n->Next; } if(r->Tail==n) { r->Tail = n->Next; } --r->count; free(n); } */ /*! \fn ILibLinkedList_Remove_ByData(void *LinkedList, void *data) \brief Removes a node from the Linked list, via comparison \para Given a data pointer, will traverse the linked list data structure, deleting elements that point to this data pointer. \param LinkedList_Node The linked list to traverse \param data The data pointer to compare */ /* void ILibLinkedList_Remove_ByData(void *LinkedList, void *data) { struct ILibLinkedListNode_Root *r = (struct ILibLinkedListNode_Root*)LinkedList; struct ILibLinkedListNode *n,*t; n = r->Head; while(n!=NULL) { if(n->Data==data) { --r->count; if(n->Previous!=NULL) { n->Previous->Next = n->Next; } if(n->Next!=NULL) { n->Next->Previous = n->Previous; } if(r->Head==n) { r->Head = n->Next; } if(r->Tail==n) { r->Tail = n->Next; } t = n->Next; free(n); n = t; } else { n = n->Next; } } } */ /*! \fn ILibLinkedList_AddHead(void *LinkedList, void *data) \brief Creates a new element, and inserts it at the top of the linked list. \param LinkedList The linked list \param data The data pointer to reference */ /* void ILibLinkedList_AddHead(void *LinkedList, void *data) { struct ILibLinkedListNode_Root *r = (struct ILibLinkedListNode_Root*)LinkedList; struct ILibLinkedListNode *newNode = (struct ILibLinkedListNode*)malloc(sizeof(struct ILibLinkedListNode)); newNode->Data = data; newNode->Root = r; newNode->Previous = NULL; newNode->Next = r->Head; if(r->Head!=NULL) { r->Head->Previous = newNode; } r->Head = newNode; if(r->Tail==NULL) { r->Tail = newNode; } ++r->count; } */ /*! \fn ILibLinkedList_AddTail(void *LinkedList, void *data) \brief Creates a new element, and appends it to the end of the linked list \param LinkedList The linked list \param data The data pointer to reference */ /* void ILibLinkedList_AddTail(void *LinkedList, void *data) { struct ILibLinkedListNode_Root *r = (struct ILibLinkedListNode_Root*)LinkedList; struct ILibLinkedListNode *newNode = (struct ILibLinkedListNode*)malloc(sizeof(struct ILibLinkedListNode)); newNode->Data = data; newNode->Root = r; newNode->Next = NULL; newNode->Previous = r->Tail; if(r->Tail!=NULL) { r->Tail->Next = newNode; } r->Tail = newNode; if(r->Head==NULL) { r->Head = newNode; } ++r->count; } */ /*! \fn ILibLinkedList_Lock(void *LinkedList) \brief Locks the linked list with a non-recursive lock \param LinkedList The linked list */ /* void ILibLinkedList_Lock(void *LinkedList) { struct ILibLinkedListNode_Root *r = (struct ILibLinkedListNode_Root*)LinkedList; sem_wait(&(r->LOCK)); } */ /*! \fn ILibLinkedList_Lock(void *LinkedList) \brief Unlocks the linked list's non-recursive lock \param LinkedList The linked list */ /* void ILibLinkedList_UnLock(void *LinkedList) { struct ILibLinkedListNode_Root *r = (struct ILibLinkedListNode_Root*)LinkedList; sem_post(&(r->LOCK)); } */ /*! \fn ILibLinkedList_Destroy(void *LinkedList) \brief Frees the resources used by the linked list \b Note: The data pointer referenced needs to be freed by the user if required \param LinkedList The linked list */ /* void ILibLinkedList_Destroy(void *LinkedList) { struct ILibLinkedListNode_Root *r = (struct ILibLinkedListNode_Root*)LinkedList; while(r->Head!=NULL) { ILibLinkedList_Remove(ILibLinkedList_GetNode_Head(LinkedList)); } sem_destroy(&(r->LOCK)); free(r); } */ /*! \fn ILibLinkedList_GetCount(void *LinkedList) \brief Returns the number of nodes in the linked list \param LinkedList The linked list \returns Number of elements in the linked list */ /* long ILibLinkedList_GetCount(void *LinkedList) { return(((struct ILibLinkedListNode_Root*)LinkedList)->count); } */ /*! \fn ILibReadFileFromDiskEx(char **Target, char *FileName) \brief Reads a file into a char * \para \b Note: \a Target must be freed \param Target Pointer to char* that will contain the data \param FileName Filename of the file to read \returns length of the data read */ int ILibReadFileFromDiskEx(char **Target, char *FileName) { char *buffer; int SourceFileLength; FILE *SourceFile = fopen(FileName,"rb"); if(SourceFile==NULL) { return(0); } fseek(SourceFile,0,SEEK_END); SourceFileLength = (int)ftell(SourceFile); fseek(SourceFile,0,SEEK_SET); buffer = (char*)malloc(SourceFileLength); fread(buffer,sizeof(char),SourceFileLength,SourceFile); fclose(SourceFile); *Target = buffer; return(SourceFileLength); } /*! \fn ILibReadFileFromDisk(char *FileName) \brief Reads a file into a char * \para \b Note: Data must be null terminated \param FileName Filename of the file to read \returns data read */ char *ILibReadFileFromDisk(char *FileName, int *FileLen) { char *RetVal; *FileLen = ILibReadFileFromDiskEx(&RetVal,FileName); return(RetVal); } /*! \fn ILibWriteStringToDisk(char *FileName, char *data) \brief Writes a null terminated string to disk \para \b Note: Files that already exist will be overwritten \param FileName Filename of the file to write \param data data to write */ /* void ILibWriteStringToDisk(char *FileName, char *data) { FILE *SourceFile = fopen(FileName,"wb"); if(SourceFile!=NULL) { fwrite(data,sizeof(char),(int)strlen(data),SourceFile); fclose(SourceFile); } } */ #endif