/***************************************************************************/ /* */ /* Project: OpenSLP - OpenSource implementation of Service Location */ /* Protocol */ /* */ /* File: slp_string.c */ /* */ /* Abstract: Various functions that deal with SLP strings and */ /* string-lists */ /* */ /*-------------------------------------------------------------------------*/ /* */ /* Please submit patches to http://www.openslp.org */ /* */ /*-------------------------------------------------------------------------*/ /* */ /* Copyright (C) 2000 Caldera Systems, Inc */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions are */ /* met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the */ /* distribution. */ /* */ /* Neither the name of Caldera Systems nor the names of its */ /* contributors may be used to endorse or promote products derived */ /* from this software without specific prior written permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA */ /* SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /***************************************************************************/ #include #include #include "slp_compare.h" #ifndef _WIN32 # ifndef HAVE_STRNCASECMP int strncasecmp(const char *s1, const char *s2, size_t len) { while ( *s1 && (*s1 == *s2 || tolower(*s1) == tolower(*s2)) ) { len--; if(len == 0) return 0; s1++; s2++; } return(int) *(unsigned char *)s1 - (int) *(unsigned char *)s2; } # endif # ifndef HAVE_STRCASECMP int strcasecmp(const char *s1, const char *s2) { while ( *s1 && (*s1 == *s2 || tolower(*s1) == tolower(*s2)) ) { s1++; s2++; } return(int) *(unsigned char *)s1 - (int) *(unsigned char *)s2; } # endif #endif /*=========================================================================*/ int SLPCompareString(int str1len, const char* str1, int str2len, const char* str2) /* Does a lexical string compare as described in RFC 2608 section 6.4. */ /* */ /* TODO: Handle the whole utf8 spec */ /* */ /* str1 - pointer to string to be compared */ /* */ /* str1len - length of str1 in bytes */ /* */ /* str2 - pointer to string to be compared */ /* */ /* str2len - length of str2 in bytes */ /* */ /* Returns - zero if strings are equal. >0 if str1 is greater than str2 */ /* <0 if s1 is less than str2 */ /*=========================================================================*/ { /* TODO: fold whitespace and handle escapes*/ if(str1len == str2len) { if (str1len <= 0) return(0); return strncasecmp(str1,str2,str1len); } else if(str1len > str2len) { return -1; } return 1; } /*=========================================================================*/ int SLPCompareNamingAuth(int srvtypelen, const char* srvtype, int namingauthlen, const char* namingauth) /* Does srvtype match namingauth */ /* */ /* TODO: Handle the whole utf8 spec */ /* */ /* srvtype - pointer to service type to be compared */ /* */ /* srvtypelen - length of srvtype in bytes */ /* */ /* namingauth - pointer to naming authority to be matched */ /* */ /* namingauthlen - length of naming authority in bytes */ /* */ /* Returns - zero if srvtype matches the naming authority. Nonzero if */ /* it doesn't */ /*=========================================================================*/ { const char *dot; if(namingauthlen == 0xffff) /* match all naming authorities */ return 0; /* Skip "service:" */ if ((srvtypelen > 8) && (strncasecmp(srvtype,"service:",8) == 0)) { srvtypelen -= 8; srvtype += 8; } /* stop search at colon after naming authority (if there is one) */ dot = memchr(srvtype,':',srvtypelen); if (dot) srvtypelen = dot - srvtype; dot = memchr(srvtype,'.',srvtypelen); if(!namingauthlen) /* IANA naming authority */ return dot ? 1 : 0; if (dot) { int srvtypenalen = srvtypelen - (dot + 1 - srvtype); if(srvtypenalen != namingauthlen) return 1; if(strncasecmp(dot + 1, namingauth, namingauthlen) == 0) return 0; } return 1; } /*=========================================================================*/ int SLPCompareSrvType(int lsrvtypelen, const char* lsrvtype, int rsrvtypelen, const char* rsrvtype) /* Does lsrvtype = rsrvtype? */ /* */ /* TODO: Handle the whole utf8 spec */ /* */ /* lsrvtype - pointer to string to be compared */ /* */ /* lsrvtypelen - length of str1 in bytes */ /* */ /* rsrvtype - pointer to string to be compared */ /* */ /* rsrvtypelen - length of str2 in bytes */ /* */ /* Returns - zero if srvtypes are equal. Nonzero if they are not */ /*=========================================================================*/ { char* colon; /* Skip "service:" */ if(strncasecmp(lsrvtype,"service:",lsrvtypelen > 8 ? 8 : lsrvtypelen) == 0) { lsrvtypelen = lsrvtypelen - 8; lsrvtype = lsrvtype + 8; } if(strncasecmp(rsrvtype,"service:",rsrvtypelen > 8 ? 8 : rsrvtypelen) == 0) { rsrvtypelen = rsrvtypelen - 8; rsrvtype = rsrvtype + 8; } if(memchr(lsrvtype,':',lsrvtypelen)) { /* lsrvtype is uses concrete type so strings must be identical */ if(lsrvtypelen == rsrvtypelen) { return strncasecmp(lsrvtype,rsrvtype,lsrvtypelen); } return 1; } colon = memchr(rsrvtype,':',rsrvtypelen); if(colon) { /* lsrvtype is abstract only and rsrvtype is concrete */ if(lsrvtypelen == (colon - rsrvtype)) { return strncasecmp(lsrvtype,rsrvtype,lsrvtypelen); } return 1; } /* lsrvtype and rsrvtype are abstract only */ if(lsrvtypelen == rsrvtypelen) { return strncasecmp(lsrvtype,rsrvtype,lsrvtypelen); } return 1; } /*=========================================================================*/ int SLPContainsStringList(int listlen, const char* list, int stringlen, const char* string) /* Checks a string-list for the occurence of a string */ /* */ /* list - pointer to the string-list to be checked */ /* */ /* listlen - length in bytes of the list to be checked */ /* */ /* string - pointer to a string to find in the string-list */ /* */ /* stringlen - the length of the string in bytes */ /* */ /* Returns - zero if string is NOT contained in the list. non-zero if it*/ /* is. */ /*=========================================================================*/ { char* listend = (char*)list + listlen; char* itembegin = (char*)list; char* itemend = itembegin; while(itemend < listend) { itembegin = itemend; /* seek to the end of the next list item */ while(1) { if(itemend == listend || *itemend == ',') { if(*(itemend - 1) != '\\') { break; } } itemend ++; } if(SLPCompareString(itemend - itembegin, itembegin, stringlen, string) == 0) { return 1; } itemend ++; } return 0; } /*=========================================================================*/ int SLPIntersectStringList(int list1len, const char* list1, int list2len, const char* list2) /* Calculates the number of common entries between two string-lists */ /* */ /* list1 - pointer to the string-list to be checked */ /* */ /* list1len - length in bytes of the list to be checked */ /* */ /* list2 - pointer to the string-list to be checked */ /* */ /* list2len - length in bytes of the list to be checked */ /* */ /* Returns - The number of common entries. */ /*=========================================================================*/ { int result = 0; char* listend = (char*)list1 + list1len; char* itembegin = (char*)list1; char* itemend = itembegin; while(itemend < listend) { itembegin = itemend; /* seek to the end of the next list item */ while(1) { if(itemend == listend || *itemend == ',') { if(*(itemend - 1) != '\\') { break; } } itemend ++; } if(SLPContainsStringList(list2len, list2, itemend - itembegin, itembegin)) { result ++; } itemend ++; } return result; } /*=========================================================================*/ int SLPUnionStringList(int list1len, const char* list1, int list2len, const char* list2, int* unionlistlen, char * unionlist) /* Generate a string list that is a union of two string lists */ /* */ /* list1len - length in bytes of list1 */ /* */ /* list1 - pointer to a string-list */ /* */ /* list2len - length in bytes of list2 */ /* */ /* list2 - pointer to a string-list */ /* */ /* unionlistlen - pointer to the size in bytes of the unionlist buffer. */ /* also receives the size in bytes of the unionlist buffer */ /* on successful return. */ /* */ /* unionlist - pointer to the buffer that will receive the union list. */ /* */ /* */ /* Returns - Length of the resulting union list or negative if */ /* unionlist is not big enough. If negative is returned */ /* *unionlist will be changed indicate the size of unionlist */ /* buffer needed */ /* */ /* Important: In order ensure that unionlist does not contain any */ /* duplicates, at least list1 must not have any duplicates. */ /* Also, for speed optimization if list1 and list2 are both */ /* with out duplicates, the larger list should be passed in */ /* as list1. */ /* */ /* Note: A good size for unionlist (so that non-zero will never be */ /* returned) is list1len + list2len + 1 */ /*=========================================================================*/ { char* listend = (char*)list2 + list2len; char* itembegin = (char*)list2; char* itemend = itembegin; int itemlen; int copiedlen; if(unionlist == 0 || *unionlistlen == 0 || *unionlistlen < list1len) { *unionlistlen = list1len + list2len + 1; return -1; } /* Copy list1 into the unionlist since it should not have any duplicates */ memcpy(unionlist,list1,list1len); copiedlen = list1len; while(itemend < listend) { itembegin = itemend; /* seek to the end of the next list item */ while(1) { if(itemend == listend || *itemend == ',') { if(*(itemend - 1) != '\\') { break; } } itemend ++; } itemlen = itemend - itembegin; if(SLPContainsStringList(list1len, list1, itemlen, itembegin) == 0) { if(copiedlen + itemlen + 1 > *unionlistlen) { *unionlistlen = list1len + list2len + 1; return -1; } /* append a comma if not the first entry*/ if(copiedlen) { unionlist[copiedlen] = ','; copiedlen++; } memcpy(unionlist + copiedlen, itembegin, itemlen); copiedlen += itemlen; } itemend ++; } *unionlistlen = copiedlen; return copiedlen; } /*=========================================================================*/ int SLPSubsetStringList(int listlen, const char* list, int sublistlen, const char* sublist) /* Test if sublist is a set of list */ /* */ /* list - pointer to the string-list to be checked */ /* */ /* listlen - length in bytes of the list to be checked */ /* */ /* sublistlistlen - pointer to the string-list to be checked */ /* */ /* sublist - length in bytes of the list to be checked */ /* */ /* Returns - non-zero is sublist is a subset of list. Zero otherwise */ /*=========================================================================*/ { /* count the items in sublist */ int curpos; int sublistcount; if(sublistlen ==0 || listlen == 0) { return 0; } curpos = 0; sublistcount = 1; while(curpos < sublistlen) { if(sublist[curpos] == ',') { sublistcount ++; } curpos ++; } if(SLPIntersectStringList(listlen, list, sublistlen, sublist) == sublistcount) { return sublistcount; } return 0; } /*=========================================================================*/ int SLPCheckServiceUrlSyntax(const char* srvurl, int srvurllen) /* Test if a service url conforms to accepted syntax * * srvurl - (IN) service url string to check * * srvurllen - (IN) length of srvurl in bytes * * Returns - zero if srvurl has acceptable syntax, non-zero on failure * *=========================================================================*/ { /* TODO: Do we actually need to do something here to ensure correct * service-url syntax, or should we expect that it will be used * by smart developers who know that ambiguities could be encountered * if they don't? if(srvurllen < 8) { return 1; } if(strncasecmp(srvurl,"service:",8)) { return 1; } return 0; */ return 0; } /*=========================================================================*/ int SLPCheckAttributeListSyntax(const char* attrlist, int attrlistlen) /* Test if a service url conforms to accepted syntax * * attrlist - (IN) attribute list string to check * * attrlistlen - (IN) length of attrlist in bytes * * Returns - zero if srvurl has acceptable syntax, non-zero on failure * *=========================================================================*/ { const char* slider; const char* end; if(attrlistlen) { slider = attrlist; end = attrlist + attrlistlen; while(slider != end) { if(*slider == '(') { while(slider != end) { if(*slider == '=') { return 0; } slider++; } return 1; } slider++; } } return 0; }