Skip to content

Commit

Permalink
Fixes IOS-4383 - null value in CFDictionarySetValue
Browse files Browse the repository at this point in the history
Due to testing for _nullObject parameter it is possible for the code to
try and pass a null value to CFDictionarySetValue - this patch fixes
that and cleans up the handling of _nullObject.


JIRA: IOS-4383
  • Loading branch information
schwa committed Jul 11, 2013
1 parent efc891a commit 925e8b7
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 39 deletions.
94 changes: 57 additions & 37 deletions Source/CJSONDeserializer.m
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,13 @@ - (id)deserialize:(NSData *)inData error:(NSError **)outError
}
}
}

else
{
if (theObject == [NSNull null])
{
theObject = _nullObject;
}
}
}

return (theObject);
Expand Down Expand Up @@ -138,7 +144,7 @@ - (BOOL)_setData:(NSData *)inData error:(NSError **)outError;
{
if (outError)
{
*outError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:kJSONDeserializerErrorCode_NothingToScan userInfo:NULL];
*outError = [self _error:kJSONDeserializerErrorCode_NothingToScan underlyingError:NULL description:@"Have no data to scan."];
}
return(NO);
}
Expand Down Expand Up @@ -217,7 +223,7 @@ - (BOOL)_setData:(NSData *)inData error:(NSError **)outError;

- (BOOL)_scanJSONObject:(id *)outObject error:(NSError **)outError
{
BOOL theResult = YES;
BOOL theResult;

_current = _SkipWhiteSpace(_current, _end);

Expand All @@ -236,26 +242,28 @@ - (BOOL)_scanJSONObject:(id *)outObject error:(NSError **)outError
switch (C)
{
case 't':
if (_ScanUTF8String(self, "true", 4))
{
theObject = (__bridge id) kCFBooleanTrue;
}
{
theResult = _ScanUTF8String(self, "true", 4);
theObject = (__bridge id) kCFBooleanTrue;
break;
}
case 'f':
if (_ScanUTF8String(self, "false", 5))
{
theObject = (__bridge id) kCFBooleanFalse;
}
{
theResult = _ScanUTF8String(self, "false", 5);
theObject = (__bridge id) kCFBooleanFalse;
}
break;
case 'n':
if (_ScanUTF8String(self, "null", 4))
{
theObject = _nullObject;
}
{
theResult = _ScanUTF8String(self, "null", 4);
theObject = _nullObject ?: [NSNull null];
}
break;
case '\"':
case '\'':
{
theResult = [self _scanJSONStringConstant:&theObject key:NO error:outError];
}
break;
case '0':
case '1':
Expand All @@ -268,24 +276,28 @@ - (BOOL)_scanJSONObject:(id *)outObject error:(NSError **)outError
case '8':
case '9':
case '-':
{
theResult = [self _scanJSONNumberConstant:&theObject error:outError];
}
break;
case '{':
{
theResult = [self _scanJSONDictionary:&theObject error:outError];
}
break;
case '[':
{
theResult = [self _scanJSONArray:&theObject error:outError];
}
break;
default:
theResult = NO;
{
if (outError)
{
NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@"Could not scan object. Character not a valid JSON character.", NSLocalizedDescriptionKey,
NULL];
[theUserInfo addEntriesFromDictionary:self._userInfoForScanLocation];
*outError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:kJSONDeserializerErrorCode_CouldNotScanObject userInfo:theUserInfo];
*outError = [self _error:kJSONDeserializerErrorCode_CouldNotScanObject description:@"Could not scan object. Character not a valid JSON character."];
}
return(NO);
}
break;
}

Expand All @@ -294,7 +306,7 @@ - (BOOL)_scanJSONObject:(id *)outObject error:(NSError **)outError
*outObject = theObject;
}

return (theResult);
return(theResult);
}

- (BOOL)_scanJSONDictionary:(NSDictionary **)outDictionary error:(NSError **)outError
Expand Down Expand Up @@ -358,19 +370,22 @@ - (BOOL)_scanJSONDictionary:(NSDictionary **)outDictionary error:(NSError **)out
return (NO);
}

if (theValue == NULL && _nullObject == NULL)
if (_nullObject == NULL && theValue == [NSNull null])
{
// If the value is a null and nullObject is also null then we're skipping this key/value pair.
continue;
}
else

if (theKey == NULL)
{
if (theKey == NULL)
{
*outError = [self _error:kJSONDeserializerErrorCode_DictionaryKeyScanFailed description:@"Could not scan dictionary. Failed to scan a key."];
return(NO);
}
CFDictionarySetValue((__bridge CFMutableDictionaryRef) theDictionary, (__bridge void *) theKey, (__bridge void *) theValue);
*outError = [self _error:kJSONDeserializerErrorCode_DictionaryKeyScanFailed description:@"Could not scan dictionary. Failed to scan a key."];
return(NO);
}
if (theValue == NULL)
{
*outError = [self _error:kJSONDeserializerErrorCode_DictionaryValueScanFailed description:@"Could not scan dictionary. Failed to scan a value."];
return(NO);
}
CFDictionarySetValue((__bridge CFMutableDictionaryRef)theDictionary, (__bridge void *)theKey, (__bridge void *)theValue);

_current = _SkipWhiteSpace(_current, _end);

Expand Down Expand Up @@ -450,11 +465,7 @@ - (BOOL)_scanJSONArray:(NSArray **)outArray error:(NSError **)outError
_current = _start + theScanLocation;
if (outError)
{
NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@"Could not scan array. Could not scan a value.", NSLocalizedDescriptionKey,
NULL];
[theUserInfo addEntriesFromDictionary:self._userInfoForScanLocation];
*outError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:kJSONDeserializerErrorCode_ArrayValueScanFailed userInfo:theUserInfo];
*outError = [self _error:kJSONDeserializerErrorCode_ArrayValueScanFailed underlyingError:NULL description:@"Could not scan array. Could not scan a value."];
}
return (NO);
}
Expand Down Expand Up @@ -798,16 +809,25 @@ - (NSDictionary *)_userInfoForScanLocation
return (theUserInfo);
}

- (NSError *)_error:(NSInteger)inCode description:(NSString *)inDescription
- (NSError *)_error:(NSInteger)inCode underlyingError:(NSError *)inUnderlyingError description:(NSString *)inDescription
{
NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
inDescription, NSLocalizedDescriptionKey,
NULL];
[theUserInfo addEntriesFromDictionary:self._userInfoForScanLocation];
if (inUnderlyingError)
{
theUserInfo[NSUnderlyingErrorKey] = inUnderlyingError;
}
NSError *theError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:inCode userInfo:theUserInfo];
return (theError);
}

- (NSError *)_error:(NSInteger)inCode description:(NSString *)inDescription
{
return ([self _error:inCode underlyingError:NULL description:inDescription]);
}

#pragma mark -

inline static BOOL _PtrRangeContainsCharacter(PtrRange inPtrRange, char C)
Expand Down
4 changes: 2 additions & 2 deletions Support/UnitTests/CJSONDeserializer_UnitTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -822,13 +822,13 @@ -(void)testCheckForErrorWithNilJSONAndIgnoringError_Deprecated
STAssertNil(dictionary, @"Dictionary will be nil when there is an error deserializing", nil);
}

-(void)testSkipNullValueInArray
-(void)testNullValueInArray
{
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.nullObject = NULL;
NSData *theData = [@"[null]" dataUsingEncoding:NSUTF8StringEncoding];
NSArray *theArray = [theDeserializer deserialize:theData error:nil];
STAssertEqualObjects(theArray, [NSArray array], @"Skipping null did not produce empty array");
STAssertEqualObjects(theArray, @[ [NSNull null] ], @"Array mismatch");
}

-(void)testAlternativeNullValueInArray
Expand Down

0 comments on commit 925e8b7

Please sign in to comment.