@@ -323,7 +323,7 @@ The code in isValidCodePoint() is derived from the ICU code in
323323static void jk_managedBuffer_setToStackBuffer (JKManagedBuffer *managedBuffer, unsigned char *ptr, size_t length);
324324static unsigned char *jk_managedBuffer_resize (JKManagedBuffer *managedBuffer, size_t newSize);
325325static void jk_objectStack_release (JKObjectStack *objectStack);
326- static void jk_objectStack_setToStackBuffer (JKObjectStack *objectStack, void **objects, void **keys, size_t count);
326+ static void jk_objectStack_setToStackBuffer (JKObjectStack *objectStack, void **objects, void **keys, JKHash *hashes, size_t *sizes, size_t count);
327327static int jk_objectStack_resize (JKObjectStack *objectStack, size_t newCount);
328328
329329static void jk_error (JKParseState *parseState, NSString *format, ...);
@@ -334,6 +334,7 @@ The code in isValidCodePoint() is derived from the ICU code in
334334static int jk_parse_next_token (JKParseState *parseState);
335335static void jk_set_parsed_token (JKParseState *parseState, const unsigned char *ptr, size_t length, JKTokenType type, size_t advanceBy);
336336static void jk_error_parse_accept_or3 (JKParseState *parseState, int state, NSString *or1String, NSString *or2String, NSString *or3String);
337+ static void *jk_create_dictionary (JKParseState *parseState, size_t startingObjectIndex);
337338static void *jk_parse_dictionary (JKParseState *parseState);
338339static void *jk_parse_array (JKParseState *parseState);
339340static void *jk_object_for_token (JKParseState *parseState);
@@ -472,11 +473,13 @@ static void jk_objectStack_release(JKObjectStack *objectStack) {
472473 objectStack->flags &= ~JKObjectStackLocationMask;
473474}
474475
475- static void jk_objectStack_setToStackBuffer (JKObjectStack *objectStack, void **objects, void **keys, size_t count) {
476- NSCParameterAssert ((objectStack != NULL ) && (objects != NULL ) && (keys != NULL ) && (count > 0UL ));
476+ static void jk_objectStack_setToStackBuffer (JKObjectStack *objectStack, void **objects, void **keys, JKHash *hashes, size_t *sizes, size_t count) {
477+ NSCParameterAssert ((objectStack != NULL ) && (objects != NULL ) && (keys != NULL ) && (hashes != NULL ) && (sizes != NULL ) && ( count > 0UL ));
477478 jk_objectStack_release (objectStack);
478479 objectStack->objects = objects;
479480 objectStack->keys = keys;
481+ objectStack->hashes = hashes;
482+ objectStack->sizes = sizes;
480483 objectStack->count = count;
481484 objectStack->flags = (objectStack->flags & ~JKObjectStackLocationMask) | JKObjectStackOnStack;
482485#ifndef NS_BLOCK_ASSERTIONS
@@ -487,28 +490,42 @@ static void jk_objectStack_setToStackBuffer(JKObjectStack *objectStack, void **o
487490
488491static int jk_objectStack_resize (JKObjectStack *objectStack, size_t newCount) {
489492 size_t roundedUpNewCount = newCount;
493+ int returnCode = 0 ;
494+
495+ void **newObjects = NULL , **newKeys = NULL ;
496+ JKHash *newHashes = NULL ;
497+ size_t *newSizes = NULL ;
490498
491499 if (objectStack->roundSizeUpToMultipleOf > 0UL ) { roundedUpNewCount = newCount + ((objectStack->roundSizeUpToMultipleOf - (newCount % objectStack->roundSizeUpToMultipleOf )) % objectStack->roundSizeUpToMultipleOf ); }
492500
493501 if ((roundedUpNewCount != objectStack->count ) && (roundedUpNewCount > objectStack->count )) {
494502 if ((objectStack->flags & JKObjectStackLocationMask) == JKObjectStackOnStack) {
495503 NSCParameterAssert ((objectStack->flags & JKObjectStackMustFree) == 0);
496- void **newObjects = NULL , **newKeys = NULL ;
497-
498- if ((newObjects = (void **)calloc (1 , roundedUpNewCount * sizeof (void *))) == NULL ) { return (1 ); }
504+
505+ if ((newObjects = (void **)calloc (1 , roundedUpNewCount * sizeof (void *))) == NULL ) { returnCode = 1 ; goto errorExit; }
499506 memcpy (newObjects, objectStack->objects , jk_min (objectStack->count , roundedUpNewCount) * sizeof (void *));
500- if ((newKeys = (void **)calloc (1 , roundedUpNewCount * sizeof (void *))) == NULL ) { free (newObjects); return ( 1 ) ; }
507+ if ((newKeys = (void **)calloc (1 , roundedUpNewCount * sizeof (void *))) == NULL ) { returnCode = 1 ; goto errorExit ; }
501508 memcpy (newKeys, objectStack->keys , jk_min (objectStack->count , roundedUpNewCount) * sizeof (void *));
502509
510+ if ((newHashes = (JKHash *)calloc (1 , roundedUpNewCount * sizeof (JKHash))) == NULL ) { returnCode = 1 ; goto errorExit; }
511+ memcpy (newHashes, objectStack->hashes , jk_min (objectStack->count , roundedUpNewCount) * sizeof (JKHash));
512+ if ((newSizes = (size_t *)calloc (1 , roundedUpNewCount * sizeof (size_t ))) == NULL ) { returnCode = 1 ; goto errorExit; }
513+ memcpy (newSizes, objectStack->sizes , jk_min (objectStack->count , roundedUpNewCount) * sizeof (size_t ));
514+
503515 objectStack->flags = (objectStack->flags & ~JKObjectStackLocationMask) | (JKObjectStackOnHeap | JKObjectStackMustFree);
504- objectStack->objects = newObjects;
505- objectStack->keys = newKeys;
516+ objectStack->objects = newObjects; newObjects = NULL ;
517+ objectStack->keys = newKeys; newKeys = NULL ;
518+ objectStack->hashes = newHashes; newHashes = NULL ;
519+ objectStack->sizes = newSizes; newSizes = NULL ;
506520 objectStack->count = roundedUpNewCount;
507521 } else {
508522 NSCParameterAssert (((objectStack->flags & JKObjectStackMustFree) != 0) && ((objectStack->flags & JKObjectStackLocationMask) == JKObjectStackOnHeap));
509- void **newObjects = NULL , **newKeys = NULL ;
510- if ((newObjects = (void **)realloc (objectStack->objects , roundedUpNewCount * sizeof (void *))) != NULL ) { objectStack->objects = newObjects; } else { return (1 ); }
511- if ((newKeys = (void **)realloc (objectStack->keys , roundedUpNewCount * sizeof (void *))) != NULL ) { objectStack->keys = newKeys; } else { return (1 ); }
523+ if ((newObjects = (void **)realloc (objectStack->objects , roundedUpNewCount * sizeof (void *))) != NULL ) { objectStack->objects = newObjects; newObjects = NULL ; } else { returnCode = 1 ; goto errorExit; }
524+ if ((newKeys = (void **)realloc (objectStack->keys , roundedUpNewCount * sizeof (void *))) != NULL ) { objectStack->keys = newKeys; newKeys = NULL ; } else { returnCode = 1 ; goto errorExit; }
525+
526+ if ((newHashes = (JKHash *)realloc (objectStack->hashes , roundedUpNewCount * sizeof (JKHash))) != NULL ) { objectStack->hashes = newHashes; newHashes = NULL ; } else { returnCode = 1 ; goto errorExit; }
527+ if ((newSizes = (size_t *)realloc (objectStack->sizes , roundedUpNewCount * sizeof (size_t ))) != NULL ) { objectStack->sizes = newSizes; newSizes = NULL ; } else { returnCode = 1 ; goto errorExit; }
528+
512529#ifndef NS_BLOCK_ASSERTIONS
513530 size_t idx;
514531 for (idx = objectStack->count ; idx < roundedUpNewCount; idx++) { objectStack->objects [idx] = NULL ; objectStack->keys [idx] = NULL ; }
@@ -517,7 +534,13 @@ static int jk_objectStack_resize(JKObjectStack *objectStack, size_t newCount) {
517534 }
518535 }
519536
520- return (0 );
537+ errorExit:
538+ if (newObjects != NULL ) { free (newObjects); newObjects = NULL ; }
539+ if (newKeys != NULL ) { free (newKeys); newKeys = NULL ; }
540+ if (newHashes != NULL ) { free (newHashes); newHashes = NULL ; }
541+ if (newSizes != NULL ) { free (newSizes); newSizes = NULL ; }
542+
543+ return (returnCode);
521544}
522545
523546
@@ -896,6 +919,9 @@ static int jk_parse_number(JKParseState *parseState) {
896919 numberTempBuf[parseState->token.tokenPtrRange.length] = 0 ;
897920
898921 errno = 0 ;
922+
923+ // Treat "-0" as a floating point number, which is capable of representing negative zeros.
924+ if (isNegative && (parseState->token .tokenPtrRange .length == 2 ) && (numberTempBuf[1 ] == ' 0' )) { isFloatingPoint = 1 ; }
899925
900926 if (isFloatingPoint) {
901927 parseState->token .value .number .doubleValue = strtod ((const char *)numberTempBuf, (char **)&endOfNumber);
@@ -1070,7 +1096,10 @@ JK_STATIC_INLINE void jk_cache_age(JKParseState *parseState) {
10701096 switch (parseState->token .value .type ) {
10711097 case JKValueTypeString: parsedAtom = (void *)CFStringCreateWithBytes (NULL , parseState->token .value .ptrRange .ptr , parseState->token .value .ptrRange .length , kCFStringEncodingUTF8 , 0 ); break ;
10721098 case JKValueTypeLongLong: parsedAtom = (void *)CFNumberCreate (NULL , kCFNumberLongLongType , &parseState->token .value .number .longLongValue ); break ;
1073- case JKValueTypeUnsignedLongLong: parsedAtom = (void *)CFNumberCreate (NULL , kCFNumberLongLongType , &parseState->token .value .number .unsignedLongLongValue ); break ;
1099+ case JKValueTypeUnsignedLongLong:
1100+ if (parseState->token .value .number .unsignedLongLongValue <= LLONG_MAX) { parsedAtom = (void *)CFNumberCreate (NULL , kCFNumberLongLongType , &parseState->token .value .number .unsignedLongLongValue ); }
1101+ else { parsedAtom = (void *)parseState->objCImpCache .NSNumberInitWithUnsignedLongLong(parseState->objCImpCache .NSNumberAlloc(parseState->objCImpCache .NSNumberClass , @selector (alloc )), @selector (initWithUnsignedLongLong: ), parseState->token .value .number .unsignedLongLongValue ); }
1102+ break ;
10741103 case JKValueTypeDouble: parsedAtom = (void *)CFNumberCreate (NULL , kCFNumberDoubleType , &parseState->token .value .number .doubleValue ); break ;
10751104 default : jk_error (parseState, @" Internal error: Unknown token value type. line #%ld " , (long )__LINE__); break ;
10761105 }
@@ -1162,6 +1191,38 @@ static void jk_error_parse_accept_or3(JKParseState *parseState, int state, NSStr
11621191 return (parsedArray);
11631192}
11641193
1194+ static void * jk_create_dictionary (JKParseState *parseState, size_t startingObjectIndex) {
1195+ void *parsedDictionary = NULL ;
1196+
1197+ parseState->objectStack .index --;
1198+
1199+ ssize_t numberOfDuplicateKeys = 0L , atIndex = 0L , cmpIndex = 0L ;
1200+ for (atIndex = parseState->objectStack .index ; atIndex >= (ssize_t )startingObjectIndex; atIndex--) {
1201+ for (cmpIndex = atIndex - 1L ; cmpIndex >= (ssize_t )startingObjectIndex; cmpIndex--) {
1202+ if ((parseState->objectStack .keys [atIndex] != NULL ) && (parseState->objectStack .keys [cmpIndex] != NULL ) && (parseState->objectStack .hashes [atIndex] == parseState->objectStack .hashes [cmpIndex]) && (parseState->objectStack .sizes [atIndex] == parseState->objectStack .sizes [cmpIndex]) && ((parseState->objectStack .keys [atIndex] == parseState->objectStack .keys [cmpIndex]) || CFEqual (parseState->objectStack .keys [atIndex], parseState->objectStack .keys [cmpIndex]))) {
1203+ numberOfDuplicateKeys++;
1204+ CFRelease (parseState->objectStack .keys [cmpIndex]); parseState->objectStack .keys [cmpIndex] = NULL ;
1205+ CFRelease (parseState->objectStack .objects [cmpIndex]); parseState->objectStack .objects [cmpIndex] = NULL ;
1206+ }
1207+ }
1208+ }
1209+
1210+ if (numberOfDuplicateKeys) {
1211+ atIndex = startingObjectIndex;
1212+ for (cmpIndex = startingObjectIndex; cmpIndex < (ssize_t )parseState->objectStack .index ; cmpIndex++) {
1213+ if ((parseState->objectStack .keys [cmpIndex] != NULL ) && (cmpIndex != atIndex)) {
1214+ parseState->objectStack .keys [atIndex] = parseState->objectStack .keys [cmpIndex];
1215+ parseState->objectStack .objects [atIndex] = parseState->objectStack .objects [cmpIndex];
1216+ }
1217+ }
1218+
1219+ parseState->objectStack .index -= numberOfDuplicateKeys;
1220+ }
1221+
1222+ parsedDictionary = (void *)CFDictionaryCreate (NULL , (const void **)&parseState->objectStack .keys [startingObjectIndex], (const void **)&parseState->objectStack .objects [startingObjectIndex], (parseState->objectStack .index ) - startingObjectIndex, &jk_transferOwnershipDictionaryKeyCallBacks, &jk_transferOwnershipDictionaryValueCallBacks);
1223+
1224+ return (parsedDictionary);
1225+ }
11651226
11661227static void *jk_parse_dictionary (JKParseState *parseState) {
11671228 size_t startingObjectIndex = parseState->objectStack .index ;
@@ -1180,10 +1241,10 @@ static void jk_error_parse_accept_or3(JKParseState *parseState, int state, NSStr
11801241 switch (parseState->token .type ) {
11811242 case JKTokenTypeString:
11821243 if (JK_EXPECTED ((dictState & JKParseAcceptValue) == 0 , 0U )) { parseState->errorIsPrev = 1 ; jk_error (parseState, @" Unexpected string." ); stopParsing = 1 ; break ; }
1183- if (JK_EXPECTED ((key = jk_object_for_token (parseState)) == NULL , 0U )) { jk_error (parseState, @" Internal error: Key == NULL." ); stopParsing = 1 ; break ; } else { parseState->objectStack .keys [objectStackIndex] = key; }
1244+ if (JK_EXPECTED ((key = jk_object_for_token (parseState)) == NULL , 0U )) { jk_error (parseState, @" Internal error: Key == NULL." ); stopParsing = 1 ; break ; } else { parseState->objectStack .keys [objectStackIndex] = key; parseState-> objectStack . hashes [objectStackIndex] = parseState-> token . value . hash ; parseState-> objectStack . sizes [objectStackIndex] = parseState-> token . value . ptrRange . length ; }
11841245 break ;
11851246
1186- case JKTokenTypeObjectEnd: if ((JK_EXPECTED (dictState & JKParseAcceptEnd, 1U ))) { NSCParameterAssert(parseState->objectStack .index >= startingObjectIndex); parsedDictionary = ( void *) CFDictionaryCreate ( NULL , ( const void **)& parseState-> objectStack . keys [startingObjectIndex], ( const void **)&parseState-> objectStack . objects [ startingObjectIndex], (--parseState-> objectStack . index ) - startingObjectIndex, &jk_transferOwnershipDictionaryKeyCallBacks, &jk_transferOwnershipDictionaryValueCallBacks ); } else { parseState->errorIsPrev = 1 ; jk_error (parseState, @" Unexpected '}'." ); } stopParsing = 1 ; break ;
1247+ case JKTokenTypeObjectEnd: if ((JK_EXPECTED (dictState & JKParseAcceptEnd, 1U ))) { NSCParameterAssert(parseState->objectStack .index >= startingObjectIndex); parsedDictionary = jk_create_dictionary ( parseState, startingObjectIndex); } else { parseState->errorIsPrev = 1 ; jk_error (parseState, @" Unexpected '}'." ); } stopParsing = 1 ; break ;
11871248 case JKTokenTypeComma: if ((JK_EXPECTED (dictState & JKParseAcceptComma, 1U ))) { dictState = JKParseAcceptValue; parseState->objectStack .index --; continue ; } else { parseState->errorIsPrev = 1 ; jk_error (parseState, @" Unexpected ','." ); stopParsing = 1 ; } break ;
11881249
11891250 default : parseState->errorIsPrev = 1 ; jk_error_parse_accept_or3 (parseState, dictState, @" a \" STRING\" " , @" a comma" , @" a '}'" ); stopParsing = 1 ; break ;
@@ -1277,6 +1338,15 @@ - (id)initWithParseOptions:(JKParseOptionFlags)parseOptionFlags
12771338 parseState.token .tokenBuffer .roundSizeUpToMultipleOf = 4096UL ;
12781339 parseState.objectStack .roundSizeUpToMultipleOf = 2048UL ;
12791340
1341+ parseState.objCImpCache .NSNumberClass = [NSNumber class ];
1342+ parseState.objCImpCache .NSNumberAlloc = (NSNumberAllocImp)[NSNumber methodForSelector: @selector (alloc )];
1343+
1344+ // Hacktacular. Need to do it this way due to the nature of class clusters.
1345+ id temp_NSNumber = [NSNumber alloc ];
1346+ parseState.objCImpCache .NSNumberInitWithUnsignedLongLong = (NSNumberInitWithUnsignedLongLongImp)[temp_NSNumber methodForSelector: @selector (initWithUnsignedLongLong: )];
1347+ [[temp_NSNumber init ] release ];
1348+ temp_NSNumber = NULL ;
1349+
12801350 parseState.cache .count = JK_CACHE_SLOTS;
12811351 if ((parseState.cache .items = (JKTokenCacheItem *)calloc (1 , sizeof (JKTokenCacheItem) * parseState.cache .count )) == NULL ) { goto errorExit; }
12821352
@@ -1337,10 +1407,11 @@ - (id)parseUTF8String:(const unsigned char *)string length:(size_t)length error:
13371407 unsigned char stackTokenBuffer[JK_TOKENBUFFER_SIZE] JK_ALIGNED (64 );
13381408 jk_managedBuffer_setToStackBuffer (&parseState.token .tokenBuffer , stackTokenBuffer, sizeof (stackTokenBuffer));
13391409
1340- void *stackObjects[JK_STACK_OBJS] JK_ALIGNED (64 );
1341- void *stackKeys [JK_STACK_OBJS] JK_ALIGNED (64 );
1342-
1343- jk_objectStack_setToStackBuffer (&parseState.objectStack , stackObjects, stackKeys, JK_STACK_OBJS);
1410+ void *stackObjects[JK_STACK_OBJS] JK_ALIGNED (64 );
1411+ void *stackKeys [JK_STACK_OBJS] JK_ALIGNED (64 );
1412+ JKHash stackHashes [JK_STACK_OBJS] JK_ALIGNED (64 );
1413+ size_t stackSizes [JK_STACK_OBJS] JK_ALIGNED (64 );
1414+ jk_objectStack_setToStackBuffer (&parseState.objectStack , stackObjects, stackKeys, stackHashes, stackSizes, JK_STACK_OBJS);
13441415
13451416 id parsedJSON = json_parse_it (&parseState);
13461417
0 commit comments