#include "CFInternal.h"
#include <CoreFoundation/CFString.h>
#include <sys/types.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
CF_INLINE Boolean __CFCharacterIsADigit(UniChar ch) {
return (ch >= '0' && ch <= '9') ? true : false;
}
CF_INLINE SInt32 __CFCharacterNumericOrHexValue (UniChar ch) {
if (ch >= '0' && ch <= '9') {
return ch - '0';
} else if (ch >= 'A' && ch <= 'F') {
return ch + 10 - 'A';
} else if (ch >= 'a' && ch <= 'f') {
return ch + 10 - 'a';
} else {
return -1;
}
}
CF_INLINE SInt32 __CFCharacterNumericValue(UniChar ch) {
return (ch >= '0' && ch <= '9') ? (ch - '0') : -1;
}
CF_INLINE UniChar __CFStringGetFirstNonSpaceCharacterFromInlineBuffer(CFStringInlineBuffer *buf, SInt32 *indexPtr) {
UniChar ch;
while (__CFIsWhitespace(ch = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr))) (*indexPtr)++;
return ch;
}
__private_extern__ Boolean __CFStringScanInteger(CFStringInlineBuffer *buf, CFTypeRef locale, SInt32 *indexPtr, Boolean doLonglong, void *result) {
Boolean doingLonglong = false;
Boolean neg = false;
int intResult = 0;
register int64_t longlongResult = 0;
UniChar ch;
ch = __CFStringGetFirstNonSpaceCharacterFromInlineBuffer(buf, indexPtr);
if (ch == '-' || ch == '+') {
neg = (ch == '-');
(*indexPtr)++;
ch = __CFStringGetFirstNonSpaceCharacterFromInlineBuffer(buf, indexPtr);
}
if (! __CFCharacterIsADigit(ch)) return false;
do {
if (doingLonglong) {
if ((longlongResult >= LLONG_MAX / 10) && ((longlongResult > LLONG_MAX / 10) || (__CFCharacterNumericValue(ch) - (neg ? 1 : 0) >= LLONG_MAX - longlongResult * 10))) {
longlongResult = neg ? LLONG_MIN : LLONG_MAX;
neg = false;
while (__CFCharacterIsADigit(ch = __CFStringGetCharacterFromInlineBufferAux(buf, ++(*indexPtr))));
} else {
longlongResult = longlongResult * 10 + __CFCharacterNumericValue(ch);
ch = __CFStringGetCharacterFromInlineBufferAux(buf, ++(*indexPtr));
}
} else {
if ((intResult >= INT_MAX / 10) && ((intResult > INT_MAX / 10) || (__CFCharacterNumericValue(ch) - (neg ? 1 : 0) >= INT_MAX - intResult * 10))) {
if (doLonglong) {
longlongResult = intResult;
doingLonglong = true;
} else {
intResult = neg ? INT_MIN : INT_MAX;
neg = false;
while (__CFCharacterIsADigit(ch = __CFStringGetCharacterFromInlineBufferAux(buf, ++(*indexPtr))));
}
} else {
intResult = intResult * 10 + __CFCharacterNumericValue(ch);
ch = __CFStringGetCharacterFromInlineBufferAux(buf, ++(*indexPtr));
}
}
} while (__CFCharacterIsADigit(ch));
if (result) {
if (doLonglong) {
if (!doingLonglong) longlongResult = intResult;
*(int64_t *)result = neg ? -longlongResult : longlongResult;
} else {
*(int *)result = neg ? -intResult : intResult;
}
}
return true;
}
__private_extern__ Boolean __CFStringScanHex(CFStringInlineBuffer *buf, SInt32 *indexPtr, unsigned *result) {
UInt32 value = 0;
SInt32 curDigit;
UniChar ch;
ch = __CFStringGetFirstNonSpaceCharacterFromInlineBuffer(buf, indexPtr);
if (ch == '0') {
ch = __CFStringGetCharacterFromInlineBufferAux(buf, ++(*indexPtr));
if (ch == 'x' || ch == 'X') ch = __CFStringGetCharacterFromInlineBufferAux(buf, ++(*indexPtr));
curDigit = __CFCharacterNumericOrHexValue(ch);
if (curDigit == -1) {
(*indexPtr)--;
if (result) *result = 0;
return true;
}
} else {
curDigit = __CFCharacterNumericOrHexValue(ch);
if (curDigit == -1) return false;
}
do {
if (value > (UINT_MAX >> 4)) {
value = UINT_MAX;
} else {
value = (value << 4) + curDigit;
}
curDigit = __CFCharacterNumericOrHexValue(__CFStringGetCharacterFromInlineBufferAux(buf, ++(*indexPtr)));
} while (curDigit != -1);
if (result) *result = value;
return true;
}
static const unsigned char __CFNumberSet[16] = {
0X00, 0X00, 0X00, 0X00, 0X00, 0X68, 0xFF, 0X03, 0X20, 0X00, 0X00, 0X00, 0X20, 0X00, 0X00, 0X00, };
__private_extern__ Boolean __CFStringScanDouble(CFStringInlineBuffer *buf, CFTypeRef locale, SInt32 *indexPtr, double *resultPtr) {
#define STACK_BUFFER_SIZE 256
#define ALLOC_CHUNK_SIZE 256 char localCharBuffer[STACK_BUFFER_SIZE];
char *charPtr = localCharBuffer;
char *endCharPtr;
SInt32 numChars = 0;
SInt32 capacity = STACK_BUFFER_SIZE; double result;
UniChar ch;
CFAllocatorRef tmpAlloc = NULL;
ch = __CFStringGetFirstNonSpaceCharacterFromInlineBuffer(buf, indexPtr);
#if 0
#warning need to allow, case insensitively, all of: "nan", "inf", "-inf", "+inf", "-infinity", "+infinity", "infinity";
#warning -- strtod() will actually do most or all of that for us
#define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL)
#define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL)
#define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL)
if ('N' == ch || 'n' == ch) { UniChar next1 = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + 1);
UniChar next2 = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + 2);
if (('a' == next1 || 'A' == next1) &&
('N' == next2 || 'n' == next2)) {
*indexPtr += 3;
if (resultPtr) *(uint64_t *)resultPtr = BITSFORDOUBLENAN;
return true;
}
}
if ('I' == ch || 'i' == ch) { UniChar next1 = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + 1);
UniChar next2 = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + 2);
if (('n' == next1 || 'N' == next1) &&
('f' == next2 || 'F' == next2)) {
*indexPtr += 3;
if (resultPtr) *(uint64_t *)resultPtr = BITSFORDOUBLEPOSINF;
return true;
}
}
if ('+' == ch || '-' == ch) { UniChar next1 = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + 1);
UniChar next2 = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + 2);
UniChar next3 = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + 3);
if (('I' == next1 || 'i' == next1) &&
('n' == next2 || 'N' == next2) &&
('f' == next3 || 'F' == next3)) {
*indexPtr += 4;
if (resultPtr) *(uint64_t *)resultPtr = ('-' == ch) ? BITSFORDOUBLENEGINF : BITSFORDOUBLEPOSINF;
return true;
}
}
#endif // 0
while ((ch < 128) && (__CFNumberSet[ch >> 3] & (1 << (ch & 7)))) {
if (numChars >= capacity - 1) {
capacity += ALLOC_CHUNK_SIZE;
if (tmpAlloc == NULL) tmpAlloc = __CFGetDefaultAllocator();
if (charPtr == localCharBuffer) {
charPtr = (char *)CFAllocatorAllocate(tmpAlloc, capacity * sizeof(char), 0);
memmove(charPtr, localCharBuffer, numChars * sizeof(char));
} else {
charPtr = (char *)CFAllocatorReallocate(tmpAlloc, charPtr, capacity * sizeof(char), 0);
}
}
charPtr[numChars++] = (char)ch;
ch = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + numChars);
};
charPtr[numChars] = 0;
result = strtod_l(charPtr, &endCharPtr, NULL);
if (tmpAlloc) CFAllocatorDeallocate(tmpAlloc, charPtr);
if (charPtr == endCharPtr) return false;
*indexPtr += (endCharPtr - charPtr);
if (resultPtr) *resultPtr = result;
return true;
}
#undef STACK_BUFFER_SIZE
#undef ALLOC_CHUNK_SIZE