You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

588 lines
22 KiB

/***************************************************************************/
/* */
/* 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 <string.h>
#include <ctype.h>
#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;
}