1 /*-------------------------------------------------------------------------
2 * Copyright (C) 2000 Caldera Systems, Inc
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of Caldera Systems nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA
24 * SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *-------------------------------------------------------------------------*/
32
33 /** Utility functions that deal with SLP strings and string-lists.
34 *
35 * These functions provide "case" and "no-case" versions of string matching
36 * routines.
37 *
38 * @file slp_compare.c
39 * @author Matthew Peterson, John Calcote (jcalcote@novell.com)
40 * @attention Please submit patches to http://www.openslp.org
41 * @ingroup CommonCodeStrings
42 */
43
44 #include "slp_types.h"
45 #include "slp_xmalloc.h"
46 #include "slp_compare.h"
47 #include "slp_net.h"
48 #include "slp_iface.h"
49
50 #ifdef HAVE_ICU
51 /* --- ICU header stuff - so we don't have to include their headers. --- */
52 #define u_strFromUTF8 u_strFromUTF8_3_2
53 #define u_strncasecmp u_strncasecmp_3_2
54
55 typedef int UErrorCode;
56 typedef uint16_t UChar;
57
58 UChar * u_strFromUTF8(UChar * dest, int32_t destCapacity,
59 int32_t * pDestLength, const char * src, int32_t srcLength,
60 UErrorCode * pErrorCode);
61
62 int32_t u_strncasecmp(const UChar * s1, const UChar * s2,
63 int32_t n, uint32_t options);
64 /* --- End of ICU header stuff --- */
65 #endif /* HAVE_ICU */
66
67 #ifndef _WIN32
68 # ifndef HAVE_STRNCASECMP
69 /** Case-insensitive, size-constrained, lexical comparison.
70 *
71 * Compares a specified maximum number of characters of two strings for
72 * lexical equivalence in a case-insensitive manner.
73 *
74 * @param[in] s1 - The first string to be compared.
75 * @param[in] s2 - The second string to be compared.
76 * @param[in] len - The maximum number of characters to compare.
77 *
78 * @return Zero if at least @p len characters of @p s1 are the same as
79 * the corresponding characters in @p s2 within the ASCII printable
80 * range; a value less than zero if @p s1 is lexically less than
81 * @p s2; or a value greater than zero if @p s1 is lexically greater
82 * than @p s2.
83 *
84 * @internal
85 */
strncasecmp(const char * s1,const char * s2,size_t len)86 int strncasecmp(const char * s1, const char * s2, size_t len)
87 {
88 while (*s1 && (*s1 == *s2 || tolower(*s1) == tolower(*s2)))
89 {
90 len--;
91 if (len == 0)
92 return 0;
93 s1++;
94 s2++;
95 }
96 return len? (int)(*(unsigned char *)s1 - (int)*(unsigned char *)s2): 0;
97 }
98 # endif
99
100 # ifndef HAVE_STRCASECMP
101 /** Case-insensitive lexical comparison.
102 *
103 * Compares two strings for lexical equivalence in a case-insensitive
104 * manner.
105 *
106 * @param[in] s1 - The first string to be compared.
107 * @param[in] s2 - The second string to be compared.
108 *
109 * @return Zero if @p s1 is the same as @p s2 within the ASCII printable
110 * range; a value less than zero if @p s1 is lexically less than @p s2;
111 * or a value greater than zero if @p s1 is lexically greater than
112 * @p s2.
113 *
114 * @internal
115 */
strcasecmp(const char * s1,const char * s2)116 int strcasecmp(const char * s1, const char * s2)
117 {
118 while (*s1 && (*s1 == *s2 || tolower(*s1) == tolower(*s2)))
119 s1++, s2++;
120 return (int)(*(unsigned char *)s1 - (int)*(unsigned char *)s2);
121 }
122 # endif
123 #endif
124
125 /** Convert a character to upper case using US ASCII rules. */
126 #define usaupr(c) (((c) & 0xC0) == 0x40? (c) & ~0x20: (c))
127
128 /** Determines if a specified character is a valid hexadecimal character.
129 *
130 * @param[in] c - The character to examine.
131 *
132 * @returns 1 if @p c is a valid hexadecimal character; 0 if not.
133 */
ishex(int c)134 static int ishex(int c)
135 {
136 c = usaupr(c);
137 return (c >= '0' && c <= '9') || ((c >= 'A' && c <= 'F')? 1: 0);
138 }
139
140 /** Converts a valid hexadecimal character into its binary equivalent.
141 *
142 * @param[in] c - The character to be converted.
143 *
144 * @returns The binary value of @p c.
145 */
hex2bin(int c)146 static int hex2bin(int c)
147 {
148 c = usaupr(c);
149 return c - (c <= '9'? '0': 'A' - 10);
150 }
151
152 /** Unescape an SLP string in place.
153 *
154 * Replace escape sequences with corresponding character codes in a
155 * specified string.
156 *
157 * @param[in] len - The length in bytes of @p str.
158 * @param[in,out] str - The string in which escape sequences should be
159 * replaced with corresponding characters.
160 *
161 * @returns The new (shorter) length of @p str.
162 *
163 * @note Since only valid escapeable characters may be escaped, we will
164 * assume that escaped characters are sequences of bytes within the
165 * 0x00 - 0x7F range (ascii subset of utf-8).
166 */
SLPUnescapeInPlace(size_t len,char * str)167 static int SLPUnescapeInPlace(size_t len, char * str)
168 {
169 char * fp = str, * tp = str, * ep = str + len;
170 while (fp < ep - 2)
171 {
172 char c = *fp++;
173 if (c == '\\' && *fp && ishex(fp[0]) && ishex(fp[1]))
174 {
175 c = (char)(hex2bin(fp[0]) * 16 + hex2bin(fp[1]));
176 fp += 2;
177 len -= 2;
178 }
179 *tp++ = c;
180 }
181 return (int)len;
182 }
183
184 /** Fold internal white space within a string.
185 *
186 * Folds all internal white space to a single space character within a
187 * specified string. Modified the @p str parameter with the result and
188 * returns the new length of the string.
189 *
190 * @param[in] len - The length in bytes of @p str.
191 * @param[in,out] str - The string from which extraneous white space
192 * should be removed.
193 *
194 * @return The new (shorter) length of @p str.
195 *
196 * @note This routine assumes that leading and trailing white space have
197 * already been removed from @p str.
198 */
SLPFoldWhiteSpace(size_t len,char * str)199 static int SLPFoldWhiteSpace(size_t len, char * str)
200 {
201 char * p = str, * ep = str + len;
202 while (p < ep)
203 {
204 if (isspace(*p))
205 {
206 char * ws2p = ++p; /* Point ws2p to the second ws char. */
207 while (isspace(*p)) /* Scan till we hit a non-ws char. */
208 p++;
209 len -= p - ws2p; /* Reduce the length by extra ws. */
210 memmove(ws2p, p, ep - p); /* Overwrite the extra white space. */
211 }
212 p++;
213 }
214 return (int)len;
215 }
216
217 /** Lexical compare routine.
218 *
219 * Performs a lexical string compare on two normalized UTF-8 strings as
220 * described in RFC 2608, section 6.4.
221 *
222 * @param[in] str1 - A pointer to string to be compared.
223 * @param[in] str2 - A pointer to string to be compared.
224 * @param[in] length - The maximum length to compare in bytes.
225 *
226 * @return Zero if @p str1 is equal to @p str2, less than zero if @p str1
227 * is greater than @p str2, greater than zero if @p str1 is less than
228 * @p str2.
229 */
SLPCompareNormalizedString(const char * str1,const char * str2,size_t length)230 static int SLPCompareNormalizedString(const char * str1,
231 const char * str2, size_t length)
232 {
233 #ifdef HAVE_ICU
234 int result;
235 UErrorCode uerr = 0;
236 UChar * ustr1 = xmalloc((length + 1) * sizeof(UChar));
237 UChar * ustr2 = xmalloc((length + 1) * sizeof(UChar));
238 if (ustr1 && ustr2)
239 {
240 u_strFromUTF8(ustr1, (int32_t)length + 1, 0, str1,
241 (int32_t)length, &uerr);
242 u_strFromUTF8(ustr2, (int32_t)length + 1, 0, str2,
243 (int32_t)length, &uerr);
244 }
245 if (ustr1 != 0 && ustr2 != 0 && uerr == 0)
246 result = (int)u_strncasecmp(ustr1, ustr2, (int32_t)length, 0);
247 else
248 result = strncasecmp(str1, str2, length);
249 xfree(ustr1);
250 xfree(ustr2);
251 return result;
252 #else
253 return strncasecmp(str1, str2, length);
254 #endif /* HAVE_ICU */
255 }
256
257 /** Normalizes a string
258 *
259 * Normalizes a string by (optionally) removing leading and trailing white space,
260 * folding internal white space, folding case (upper->lower), and unescaping
261 * the string.
262 *
263 * @param[in] len - The length of the string to be normalised, in bytes.
264 * @param[in] srcstr - A pointer to the string to be normalised.
265 * @param[in] dststr - A pointer to the buffer for the normalised string.
266 * @param[in] trim - A flag to specify whether to trim leading and trailing space
267 * completely (if non-zero) or just fold it (if zero).
268 *
269 * @return Size of normalised string in bytes.
270 *
271 * @remarks @p dststr may be the same as @p srcstr for "update in place".
272 */
SLPNormalizeString(size_t len,const char * srcstr,char * dststr,int trim)273 size_t SLPNormalizeString(size_t len, const char * srcstr, char * dststr, int trim)
274 {
275 char *upd = dststr;
276 while (len > 0 && *srcstr)
277 {
278 if (isspace(*srcstr))
279 {
280 while (isspace(*srcstr) && len > 0)
281 {
282 ++srcstr, --len;
283 }
284 if (!trim || (upd != dststr && len > 0))
285 /* Internal whitespace */
286 *upd++ = ' ';
287 }
288 else if (*srcstr == '\\')
289 {
290 if (len < 3)
291 {
292 /* This indicates incorrect escaping, but just copy verbatim */
293 *upd++ = *srcstr++;
294 --len;
295 }
296 else
297 {
298 if (ishex(srcstr[1]) && ishex(srcstr[2]))
299 {
300 *upd++ = (char)(hex2bin(srcstr[0]) * 16 + hex2bin(srcstr[1]));
301 len -= 3;
302 }
303 else
304 {
305 /* This indicates incorrect escaping, but just copy verbatim */
306 *upd++ = *srcstr++;
307 --len;
308 }
309 }
310 }
311 else
312 {
313 *upd++ = (char)tolower(*srcstr++);
314 --len;
315 }
316 }
317 return upd - dststr;
318 }
319
320 /** Compares two non-normalized strings.
321 *
322 * Normalizes two strings by removing leading and trailing white space,
323 * folding internal white space and unescaping the strings first, and then
324 * calling SLPCompareNormalizedString (as per RFC 2608, section 6.4).
325 *
326 * @param[in] str1 - A pointer to string to be compared.
327 * @param[in] str1len - The length of str1 in bytes.
328 * @param[in] str2 - A pointer to string to be compared.
329 * @param[in] str2len - The length of str2 in bytes.
330 *
331 * @return Zero if @p str1 is equal to @p str2, less than zero if @p str1
332 * is greater than @p str2, greater than zero if @p str1 is less than
333 * @p str2.
334 */
SLPCompareString(size_t str1len,const char * str1,size_t str2len,const char * str2)335 int SLPCompareString(size_t str1len, const char * str1,
336 size_t str2len, const char * str2)
337 {
338 int result;
339 char * cpy1, * cpy2;
340
341 /* Remove leading white space. */
342 while (str1len && isspace(*str1))
343 str1++, str1len--;
344 while (str2len && isspace(*str2))
345 str2++, str2len--;
346
347 /* Remove trailing white space. */
348 while (str1len && isspace(str1[str1len - 1]))
349 str1len--;
350 while (str2len && isspace(str2[str2len - 1]))
351 str2len--;
352
353 /*A quick check for empty strings before we start xmemduping and xfreeing*/
354 if (str1len == 0 || str2len == 0)
355 {
356 if(str1len == str2len)
357 return 0;
358 if(str1len < str2len)
359 return -1;
360 return 1;
361 }
362
363 /* Make modifiable copies. If either fails, compare original strings. */
364 cpy1 = xmemdup(str1, str1len);
365 cpy2 = xmemdup(str2, str2len);
366 if (cpy1 != 0 && cpy2 != 0)
367 {
368 /* Unescape copies in place. */
369 str1len = SLPUnescapeInPlace(str1len, cpy1);
370 str2len = SLPUnescapeInPlace(str2len, cpy2);
371
372 /* Fold white space in place. */
373 str1len = SLPFoldWhiteSpace(str1len, cpy1);
374 str2len = SLPFoldWhiteSpace(str2len, cpy2);
375
376 /* Reset original pointers to modified copies. */
377 str1 = cpy1;
378 str2 = cpy2;
379 }
380
381 /* Comparison logic. */
382 if (str1len == str2len)
383 result = SLPCompareNormalizedString(str1, str2, str1len);
384 else if (str1len > str2len)
385 result = -1;
386 else
387 result = 1;
388
389 xfree(cpy1);
390 xfree(cpy2);
391
392 return result;
393 }
394
395 /** Compare service type for matching naming authority.
396 *
397 * Compares a service type string with a naming authority to determine
398 * if they refer to the same naming authority, as described in RFC 2608,
399 * section ??.
400 *
401 * @param[in] srvtype - The service type to be compared.
402 * @param[in] srvtypelen - The length of @p srvtype in bytes.
403 * @param[in] namingauth - The naming authority to be matched.
404 * @param[in] namingauthlen - The length of @p namingauth in bytes.
405 *
406 * @return Zero if @p srvtype matches @p namingauth; non-zero if not.
407 */
SLPCompareNamingAuth(size_t srvtypelen,const char * srvtype,size_t namingauthlen,const char * namingauth)408 int SLPCompareNamingAuth(size_t srvtypelen, const char * srvtype,
409 size_t namingauthlen, const char * namingauth)
410 {
411 const char * dot;
412 size_t srvtypenalen;
413
414 if (namingauthlen == 0xffff)
415 return 0; /* match all naming authorities */
416
417 dot = memchr(srvtype, '.', srvtypelen);
418 if (!namingauthlen)
419 return dot? 1: 0; /* IANA naming authority */
420
421 srvtypenalen = srvtypelen - (dot + 1 - srvtype);
422 if (srvtypenalen != namingauthlen)
423 return 1;
424
425 if (SLPCompareNormalizedString(dot + 1, namingauth, namingauthlen) == 0)
426 return 0;
427
428 return 1;
429 }
430
431 /** Compare service types.
432 *
433 * Determine if two service type strings refer to the same service type.
434 *
435 * @param[in] lsrvtype - The first service type to be compared.
436 * @param[in] lsrvtypelen - The length of @p lsrvtype in bytes.
437 * @param[in] rsrvtype - The second service type to be compared.
438 * @param[in] rsrvtypelen - The length of @p rsrvtype in bytes.
439 *
440 * @return Zero if @p lsrvtype is the same as @p lsrvtype; non-zero
441 * if they are different.
442 */
SLPCompareSrvType(size_t lsrvtypelen,const char * lsrvtype,size_t rsrvtypelen,const char * rsrvtype)443 int SLPCompareSrvType(size_t lsrvtypelen, const char * lsrvtype,
444 size_t rsrvtypelen, const char * rsrvtype)
445 {
446 char * colon;
447
448 /* Skip "service:" */
449 if (strncasecmp(lsrvtype, "service:", lsrvtypelen > 8?
450 8: lsrvtypelen) == 0)
451 {
452 lsrvtypelen = lsrvtypelen - 8;
453 lsrvtype = lsrvtype + 8;
454 }
455 if (strncasecmp(rsrvtype, "service:", rsrvtypelen > 8?
456 8: rsrvtypelen) == 0)
457 {
458 rsrvtypelen = rsrvtypelen - 8;
459 rsrvtype = rsrvtype + 8;
460 }
461 if (memchr(lsrvtype, ':', lsrvtypelen))
462 {
463 /* lsrvtype is uses concrete type so strings must be identical. */
464 if (lsrvtypelen == rsrvtypelen)
465 return SLPCompareNormalizedString(lsrvtype, rsrvtype, lsrvtypelen);
466 return 1;
467 }
468 colon = memchr(rsrvtype, ':', rsrvtypelen);
469 if (colon)
470 {
471 /* lsrvtype is abstract only and rsrvtype is concrete. */
472 if (lsrvtypelen == (size_t)(colon - rsrvtype))
473 return SLPCompareNormalizedString(lsrvtype, rsrvtype, lsrvtypelen);
474 return 1;
475 }
476
477 /* lsrvtype and rsrvtype are abstract only. */
478 if (lsrvtypelen == rsrvtypelen)
479 return SLPCompareNormalizedString(lsrvtype, rsrvtype, lsrvtypelen);
480 return 1;
481 }
482
483 /** Scan a string list for a string.
484 *
485 * Determine if a specified string list contains a specified string.
486 *
487 * @param[in] list - A list of strings to search for @p string.
488 * @param[in] listlen - The length of @p list in bytes.
489 * @param[in] string - A string to locate in @p list.
490 * @param[in] stringlen - The length of @p string in bytes.
491 *
492 * @return 1-based index of position of @p string in @p list; zero if not in list.
493 *
494 * @remarks The @p list parameter is a zero-terminated string consisting
495 * of a comma-separated list of sub-strings. This routine actually
496 * determines if a specified sub-string (@p string) matches one of
497 * the sub-strings in this list.
498 */
SLPContainsStringList(size_t listlen,const char * list,size_t stringlen,const char * string)499 int SLPContainsStringList(size_t listlen, const char * list, size_t stringlen,
500 const char * string)
501 {
502 const char * listend = list + listlen;
503 const char * itembegin = list;
504 const char * itemend = itembegin;
505
506 while (itemend < listend)
507 {
508 itembegin = itemend;
509
510 /* Seek to the end of the next list item, break on commas. */
511 while (itemend != listend && itemend[0] != ',')
512 itemend++;
513
514 if (SLPCompareString(itemend - itembegin, itembegin,
515 stringlen, string) == 0)
516 return (int)(1 + (itembegin - list)); /* 1-based index of the position of the string in the list */
517
518 itemend++;
519 }
520 return 0;
521 }
522
523 /** Intersects two string lists.
524 *
525 * Calculates the number of common entries between two string-lists.
526 *
527 * @param[in] list1 - A pointer to the string-list to be checked
528 * @param[in] list1len - The length in bytes of the list to be checked
529 * @param[in] list2 - A pointer to the string-list to be checked
530 * @param[in] list2len - The length in bytes of the list to be checked
531 *
532 * @return The number of common entries between @p list1 and @p list2.
533 */
SLPIntersectStringList(size_t list1len,const char * list1,size_t list2len,const char * list2)534 int SLPIntersectStringList(size_t list1len, const char * list1,
535 size_t list2len, const char * list2)
536 {
537 int result = 0;
538 const char * listend = list1 + list1len;
539 const char * itembegin = list1;
540 const char * itemend = itembegin;
541
542 while (itemend < listend)
543 {
544 itembegin = itemend;
545
546 /* Seek to the end of the next list item, break on commas. */
547 while (itemend < listend && itemend[0] != ',')
548 itemend++;
549
550 if (SLPContainsStringList(list2len, list2,
551 itemend - itembegin, itembegin))
552 result++;
553
554 itemend++;
555 }
556 return result;
557 }
558
559 /** Intersects two string lists, and removes the common entries from
560 * the second list.
561 *
562 * @param[in] list1len - The length in bytes of the list to be checked
563 * @param[in] list1 - A pointer to the string-list to be checked
564 * @param[in] list2len - The length in bytes of the list to be checked
565 * and updated
566 * @param[in] list2 - A pointer to the string-list to be checked and
567 * updated
568 *
569 * @return The number of common entries between @p list1 and @p list2.
570 */
SLPIntersectRemoveStringList(int list1len,const char * list1,int * list2len,char * list2)571 int SLPIntersectRemoveStringList(int list1len,
572 const char* list1,
573 int* list2len,
574 char* list2)
575 {
576 int result = 0;
577 int pos;
578 char* listend = (char*)list1 + list1len;
579 char* itembegin = (char*)list1;
580 char* itemend = itembegin;
581 char* list2end = (char*)list2 + (*list2len);
582
583 while(itemend < listend)
584 {
585 itembegin = itemend;
586
587 /* seek to the end of the next list item */
588 while(1)
589 {
590 if(itemend == listend || *itemend == ',')
591 {
592 if(*(itemend - 1) != '\\')
593 {
594 break;
595 }
596 }
597
598 itemend++;
599 }
600
601 if ((pos = SLPContainsStringList(*list2len,
602 list2,
603 itemend - itembegin,
604 itembegin)) != 0)
605 {
606 /* String found in the list at position pos (1-based) */
607 /* Remove it from list2 */
608 char* dest = list2+(pos-1);
609 char* src = dest+(itemend-itembegin);
610
611 result++;
612
613 if (src < list2end)
614 {
615 if (*src == ',')
616 ++src;
617 }
618 while (src < list2end)
619 {
620 *dest++ = *src++;
621 }
622 list2end = dest;
623 }
624
625 itemend++;
626 }
627
628 *list2len = (int)(list2end - (char *)list2);
629
630 return result;
631 }
632
633 /** Take the union of two string lists.
634 *
635 * Generates a string list that contains all unique strings within
636 * two specified string lists.
637 *
638 * @param[in] list1 - A pointer to the first string-list.
639 * @param[in] list1len - The length in bytes of @p list1.
640 * @param[in] list2 - A pointer to the second string-list.
641 * @param[in] list2len - The length in bytes of @p list2.
642 * @param[out] unionlist - A pointer to a buffer that will receive
643 * the union of @p list1 and @p list2.
644 * @param[in,out] unionlistlen - A pointer to the size in bytes of the
645 * @p unionlist buffer on entry; also receives the number of bytes
646 * written to the @p unionlist buffer on success.
647 *
648 * @return The length of the resulting union list, or a negative value
649 * if @p unionlist is not large enough. If a negative value is returned
650 * @p *unionlist will return the required size of @p unionlist.
651 *
652 * @remarks In order ensure that @p unionlist does not contain duplicates,
653 * @p list1 must not have any duplicates. Also, as a speed optimization,
654 * if neither @p list1 nor @p list2 contain internal duplicates, the
655 * larger list should be passed in as @p list1.
656 *
657 * @remarks To avoid buffer overflow errors pass @p list1len +
658 * @p list2len + 1 as the value for @p unionlistlen.
659 */
SLPUnionStringList(size_t list1len,const char * list1,size_t list2len,const char * list2,size_t * unionlistlen,char * unionlist)660 int SLPUnionStringList(size_t list1len, const char * list1, size_t list2len,
661 const char * list2, size_t * unionlistlen, char * unionlist)
662 {
663 char * listend = (char *)list2 + list2len;
664 char * itembegin = (char *)list2;
665 char * itemend = itembegin;
666 size_t itemlen;
667 size_t copiedlen;
668
669 if (unionlist == 0 || *unionlistlen == 0 || *unionlistlen < list1len)
670 {
671 *unionlistlen = list1len + list2len + 1;
672 return -1;
673 }
674
675 /* Copy list1 into the unionlist since it should not have any duplicates */
676 memcpy(unionlist, list1, list1len);
677 copiedlen = list1len;
678
679 while (itemend < listend)
680 {
681 itembegin = itemend;
682
683 /* seek to the end of the next list item */
684 while (1)
685 {
686 if (itemend == listend || *itemend == ',')
687 if (*(itemend - 1) != '\\')
688 break;
689 itemend++;
690 }
691
692 itemlen = itemend - itembegin;
693 if (SLPContainsStringList(list1len, list1, itemlen, itembegin) == 0)
694 {
695 if (copiedlen + itemlen + 1 > *unionlistlen)
696 {
697 *unionlistlen = list1len + list2len + 1;
698 return -1;
699 }
700
701 /* append a comma if not the first entry*/
702 if (copiedlen)
703 {
704 unionlist[copiedlen] = ',';
705 copiedlen++;
706 }
707 memcpy(unionlist + copiedlen, itembegin, itemlen);
708 copiedlen += itemlen;
709 }
710 itemend++;
711 }
712 *unionlistlen = copiedlen;
713 return (int)copiedlen;
714 }
715
716 /** Test if a list is a proper sub-set of another list.
717 *
718 * Determines if @p sublist is a proper sub-set of @p list.
719 *
720 * @param[in] list - The list to compare @p sublist against.
721 * @param[in] listlen - The length of @p list in bytes.
722 * @param[in] sublist - The sub-list to be compared against @p list.
723 * @param[in] sublistlen - The length of @p sublist in bytes.
724 *
725 * @return A Boolean value; true if @p sublist is a proper subset of
726 * @p list; false if not.
727 */
SLPSubsetStringList(size_t listlen,const char * list,size_t sublistlen,const char * sublist)728 int SLPSubsetStringList(size_t listlen, const char * list,
729 size_t sublistlen, const char * sublist)
730 {
731 unsigned curpos;
732 int sublistcount;
733
734 /* Quick check for empty lists. Note that an empty sub-list is not
735 * considered a proper subset of any value of list.
736 */
737 if (sublistlen == 0 || listlen == 0)
738 return 0;
739
740 /* Count the items in sublist. */
741 curpos = 0;
742 sublistcount = 1;
743 while (curpos < sublistlen)
744 {
745 if (sublist[curpos] == ',')
746 sublistcount++;
747 curpos++;
748 }
749
750 /* Intersect the lists, return 1 if proper subset, 0 if not. */
751 return SLPIntersectStringList(listlen, list, sublistlen,
752 sublist) == sublistcount? 1 : 0;
753 }
754
755 /** Test URL conformance.
756 *
757 * Test if a service URL conforms to accepted syntax as described in
758 * RFC 2608, section ??.
759 *
760 * @param[in] srvurl The service url string to check.
761 * @param[in] srvurllen The length of @p srvurl in bytes.
762 *
763 * @return Zero if @p srvurl has acceptable syntax, non-zero on failure.
764 */
SLPCheckServiceUrlSyntax(const char * srvurl,size_t srvurllen)765 int SLPCheckServiceUrlSyntax(const char * srvurl, size_t srvurllen)
766 {
767 (void)srvurl;
768 (void)srvurllen;
769
770 /*!@todo Do we actually need to do something here to ensure correct
771 * service-url syntax, or should we expect that it will be used
772 * by smart developers who know that ambiguities could be encountered
773 * if they don't?
774
775 if (srvurllen < 8)
776 return 1;
777 if (strncasecmp(srvurl, "service:",8))
778 return 1;
779 return 0;
780
781 */
782 return 0;
783 }
784
785 /** Test URL conformance.
786 *
787 * Test if a service URL conforms to accepted syntax as described in
788 * RFC 2608, section ??.
789 *
790 * @param[in] attrlist - The attribute list string to check.
791 * @param[in] attrlistlen - The length of @p attrlist in bytes.
792 *
793 * @return Zero if @p srvurl has acceptable syntax, non-zero on failure.
794 */
SLPCheckAttributeListSyntax(const char * attrlist,size_t attrlistlen)795 int SLPCheckAttributeListSyntax(const char * attrlist, size_t attrlistlen)
796 {
797 const char * slider;
798 const char * end;
799
800 if (attrlistlen)
801 {
802 slider = attrlist;
803 end = attrlist + attrlistlen;
804 while (slider != end)
805 {
806 if (*slider == '(')
807 {
808 while (slider != end)
809 {
810 if (*slider == '=')
811 return 0;
812 slider++;
813 }
814 return 1;
815 }
816 slider++;
817 }
818 }
819 return 0;
820 }
821
822 #ifdef SLP_COMPARE_TEST
823
824 /* ---------------- Test main for the slp_compare.c module ----------------
825 *
826 * Compile with:
827 * gcc -g -Wall -I .. -o0 -D SLP_COMPARE_TEST -D DEBUG -D HAVE_CONFIG_H \
828 * -o slp-compare-test slp_compare.c slp_linkedlist.c slp_xmalloc.c
829 */
main(void)830 int main(void)
831 {
832 /* test data */
833 static char lst1[] = "item_a_1,item_aa_2,item_aaa_3, item_aaaa_4";
834 static char lst2[] = "item_a_1";
835 static char lst3[] = "item_aa_2, item_aaaaa_5";
836 static char lst4[] = "item_aaaaa_5,item_aaaaaa_6";
837 static char str1[] = "item_x";
838 static char str2[] = "item_a_1";
839 static char str3[] = "item_aa_2";
840
841 int count;
842
843 /* *** SLPContainsStringList ***
844 */
845 count = SLPContainsStringList(sizeof lst1 - 1, lst1, sizeof str1 - 1, str1);
846 if (count != 0)
847 return -1;
848
849 count = SLPContainsStringList(sizeof lst1 - 1, lst1, sizeof str2 - 1 , str2);
850 if (count != 1)
851 return -1;
852
853 count = SLPContainsStringList(sizeof lst1 - 1, lst1, sizeof str3 - 1, str3);
854 if (count != 10)
855 return -1;
856
857 /* *** SLPIntersectStringList ***
858 */
859 count = SLPIntersectStringList(sizeof lst1 - 1, lst1, sizeof lst2 - 1, lst2);
860 if (count != 1)
861 return -1;
862
863 count = SLPIntersectStringList(sizeof lst1 - 1, lst1, sizeof lst3 - 1, lst3);
864 if (count != 1)
865 return -1;
866
867 count = SLPIntersectStringList(sizeof lst1 - 1, lst1, sizeof lst4 - 1, lst4);
868 if (count != 0)
869 return -1;
870
871 return 0;
872 }
873
874 #endif /* SLP_COMPARE_TEST */
875
876 /*=========================================================================*/
877