Index: src/OFConstantString.m ================================================================== --- src/OFConstantString.m +++ src/OFConstantString.m @@ -547,10 +547,17 @@ { [self finishInitialization]; return [self hexadecimalValue]; } + +- (uintmax_t)octalValue +{ + [self finishInitialization]; + + return [self octalValue]; +} - (float)floatValue { [self finishInitialization]; Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -950,38 +950,53 @@ * @return The URL path with relative sub paths resolved */ - (OFString*)stringByStandardizingURLPath; /*! - * @brief Returns the decimal value of the string as an intmax_t. + * @brief Returns the decimal value of the string as an `intmax_t`. * * Leading and trailing whitespaces are ignored. * * If the string contains any non-number characters, an - * OFInvalidEncodingException is thrown. + * @ref OFInvalidEncodingException is thrown. * - * If the number is too big to fit into an intmax_t, an OFOutOfRangeException - * is thrown. + * If the number is too big to fit into an `intmax_t`, an + * @ref OFOutOfRangeException is thrown. * - * @return An intmax_t with the value of the string + * @return An `intmax_t` with the value of the string */ - (intmax_t)decimalValue; /*! - * @brief Returns the hexadecimal value of the string as an uintmax_t. + * @brief Returns the hexadecimal value of the string as an `uintmax_t`. + * + * Leading and trailing whitespaces are ignored. + * + * If the string contains any non-number characters, an + * @ref OFInvalidEncodingException is thrown. + * + * If the number is too big to fit into an `uintmax_t`, an + * @ref OFOutOfRangeException is thrown. + * + * @return A `uintmax_t` with the value of the string + */ +- (uintmax_t)hexadecimalValue; + +/*! + * @brief Returns the octal value of the string as an `uintmax_t`. * * Leading and trailing whitespaces are ignored. * * If the string contains any non-number characters, an - * OFInvalidEncodingException is thrown. + * @ref OFInvalidEncodingException is thrown. * - * If the number is too big to fit into an uintmax_t, an OFOutOfRangeException - * is thrown. + * If the number is too big to fit into an `uintmax_t`, an + * @ref OFOutOfRangeException is thrown. * - * @return A uintmax_t with the value of the string + * @return A `uintmax_t` with the value of the string */ -- (uintmax_t)hexadecimalValue; +- (uintmax_t)octalValue; /*! * @brief Returns the float value of the string as a float. * * If the string contains any non-number characters, an Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -2258,10 +2258,62 @@ value = newValue; } if (!foundValue) @throw [OFInvalidFormatException exception]; + + objc_autoreleasePoolPop(pool); + + return value; +} + +- (uintmax_t)octalValue +{ + void *pool = objc_autoreleasePoolPush(); + const of_unichar_t *characters = [self characters]; + size_t i = 0, length = [self length]; + uintmax_t value = 0; + bool expectWhitespace = false; + + while (length > 0 && (*characters == ' ' || *characters == '\t' || + *characters == '\n' || *characters == '\r' || + *characters == '\f')) { + characters++; + length--; + } + + if (length == 0) { + objc_autoreleasePoolPop(pool); + return 0; + } + + for (; i < length; i++) { + uintmax_t newValue; + + if (expectWhitespace) { + if (characters[i] != ' ' && characters[i] != '\t' && + characters[i] != '\n' && characters[i] != '\r' && + characters[i] != '\f') + @throw [OFInvalidFormatException exception]; + continue; + } + + if (characters[i] >= '0' && characters[i] <= '7') + newValue = (value << 3) | (characters[i] - '0'); + else if (characters[i] == ' ' || characters[i] == '\t' || + characters[i] == '\n' || characters[i] == '\r' || + characters[i] == '\f') { + expectWhitespace = true; + continue; + } else + @throw [OFInvalidFormatException exception]; + + if (newValue < value) + @throw [OFOutOfRangeException exception]; + + value = newValue; + } objc_autoreleasePoolPop(pool); return value; } Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -442,10 +442,16 @@ [@" xbCDE" hexadecimalValue] == 0xBCDE && [@"$CdEf" hexadecimalValue] == 0xCDEF && [@"\rFeh " hexadecimalValue] == 0xFE && [@"\r\t" hexadecimalValue] == 0) + TEST(@"-[octalValue]", + [@"1234567" octalValue] == 01234567 && + [@"\r\n123" octalValue] == 0123 && + [@"765\t" octalValue] == 0765 && + [@"\t\t\r\n" octalValue] == 0) + /* * These test numbers can be generated without rounding if we have IEEE * floating point numbers, thus we can use == on them. */ TEST(@"-[floatValue]",