Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -632,10 +632,23 @@ * OF_INVALID_INDEX as start position if it was not found */ - (of_range_t)rangeOfString: (OFString*)string options: (of_string_search_options_t)options; +/** + * \brief Returns the range of the string in the specified range. + * + * \param string The string to search + * \param options Options modifying search behaviour + * \param range The range in which to search + * \return The range of the first occurrence of the string or a range with + * OF_INVALID_INDEX as start position if it was not found + */ +- (of_range_t)rangeOfString: (OFString*)string + options: (of_string_search_options_t)options + range: (of_range_t)range; + /** * \brief Returns whether the string contains the specified string. * * \param string The string to search * \return Whether the string contains the specified string Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -1156,51 +1156,79 @@ } - (of_range_t)rangeOfString: (OFString*)string { return [self rangeOfString: string - options: 0]; + options: 0 + range: of_range(0, [self length])]; +} + +- (of_range_t)rangeOfString: (OFString*)string + options: (of_string_search_options_t)options +{ + return [self rangeOfString: string + options: options + range: of_range(0, [self length])]; } - (of_range_t)rangeOfString: (OFString*)string options: (of_string_search_options_t)options + range: (of_range_t)range { void *pool; - const of_unichar_t *unicodeString, *searchString; - size_t i, length, searchLength; + const of_unichar_t *searchString; + of_unichar_t *unicodeString; + size_t i, searchLength; if ((searchLength = [string length]) == 0) return of_range(0, 0); - if (searchLength > (length = [self length])) + if (searchLength > range.length) return of_range(OF_INVALID_INDEX, 0); - pool = objc_autoreleasePoolPush(); - - unicodeString = [self unicodeString]; - searchString = [string unicodeString]; - - if (options & OF_STRING_SEARCH_BACKWARDS) { - for (i = length - searchLength;; i--) { - if (!memcmp(unicodeString + i, searchString, - searchLength * sizeof(of_unichar_t))) { - objc_autoreleasePoolPop(pool); - return of_range(i, searchLength); - } - - /* Did not match and we're at the last character */ - if (i == 0) - break; - } - } else { - for (i = 0; i <= length - searchLength; i++) { - if (!memcmp(unicodeString + i, searchString, - searchLength * sizeof(of_unichar_t))) { - objc_autoreleasePoolPop(pool); - return of_range(i, searchLength); - } - } + if (range.length > SIZE_MAX / sizeof(of_unichar_t)) + @throw [OFOutOfRangeException exceptionWithClass: [self class]]; + + pool = objc_autoreleasePoolPush(); + + searchString = [string unicodeString]; + unicodeString = malloc(range.length * sizeof(of_unichar_t)); + + if (unicodeString == NULL) + @throw [OFOutOfMemoryException + exceptionWithClass: [self class] + requestedSize: range.length * sizeof(of_unichar_t)]; + + @try { + [self getCharacters: unicodeString + inRange: range]; + + if (options & OF_STRING_SEARCH_BACKWARDS) { + for (i = range.length - searchLength;; i--) { + if (!memcmp(unicodeString + i, searchString, + searchLength * sizeof(of_unichar_t))) { + objc_autoreleasePoolPop(pool); + return of_range(range.start + i, + searchLength); + } + + /* No match and we're at the last character */ + if (i == 0) + break; + } + } else { + for (i = 0; i <= range.length - searchLength; i++) { + if (!memcmp(unicodeString + i, searchString, + searchLength * sizeof(of_unichar_t))) { + objc_autoreleasePoolPop(pool); + return of_range(range.start + i, + searchLength); + } + } + } + } @finally { + free(unicodeString); } objc_autoreleasePoolPop(pool); return of_range(OF_INVALID_INDEX, 0); Index: src/OFString_UTF8.m ================================================================== --- src/OFString_UTF8.m +++ src/OFString_UTF8.m @@ -1037,37 +1037,60 @@ objc_autoreleasePoolPop(pool); } - (of_range_t)rangeOfString: (OFString*)string options: (of_string_search_options_t)options + range: (of_range_t)range { const char *cString = [string UTF8String]; size_t i, cStringLength = [string UTF8StringLength]; + size_t rangeStart, rangeLength; + + if (s->isUTF8) { + rangeStart = of_string_utf8_get_position( + s->cString, range.start, s->cStringLength); + rangeLength = of_string_utf8_get_position( + s->cString + rangeStart, range.length, + s->cStringLength - rangeStart); + } else { + rangeStart = range.start; + rangeLength = range.length; + } if (cStringLength == 0) return of_range(0, 0); - if (cStringLength > s->cStringLength) + if (cStringLength > rangeLength || + rangeStart + rangeLength > s->cStringLength) return of_range(OF_INVALID_INDEX, 0); if (options & OF_STRING_SEARCH_BACKWARDS) { - for (i = s->cStringLength - cStringLength;; i--) { - if (!memcmp(s->cString + i, cString, cStringLength)) - return of_range( - of_string_utf8_get_index(s->cString, i), - [string length]); + for (i = rangeLength - cStringLength;; i--) { + if (!memcmp(s->cString + rangeStart + i, cString, + cStringLength)) { + range.start += of_string_utf8_get_index( + s->cString + rangeStart, i); + range.length = [string length]; + + return range; + } /* Did not match and we're at the last char */ if (i == 0) return of_range(OF_INVALID_INDEX, 0); } } else { - for (i = 0; i <= s->cStringLength - cStringLength; i++) - if (!memcmp(s->cString + i, cString, cStringLength)) - return of_range( - of_string_utf8_get_index(s->cString, i), - [string length]); + for (i = 0; i <= rangeLength - cStringLength; i++) { + if (!memcmp(s->cString + rangeStart + i, cString, + cStringLength)) { + range.start += of_string_utf8_get_index( + s->cString + rangeStart, i); + range.length = [string length]; + + return range; + } + } } return of_range(OF_INVALID_INDEX, 0); }