NSKeyedArchiver: Fix object replacement and reuse

This commit is contained in:
Ariel Abreu 2023-10-13 09:30:14 -04:00
parent f7c4c59b24
commit ffedc7bda0
No known key found for this signature in database
GPG Key ID: 5B88AAAF4280706F

View File

@ -146,7 +146,6 @@ static CFKeyedArchiverUIDRef _NSKeyedArchiverUIDCreateCached(NSKeyedArchiver *ar
#warning TODO find CFRelease point for UID cache #warning TODO find CFRelease point for UID cache
} }
static void _encodeObject(NSKeyedArchiver *archiver, id object, NSString *key) static void _encodeObject(NSKeyedArchiver *archiver, id object, NSString *key)
{ {
BOOL visited = NO; BOOL visited = NO;
@ -155,16 +154,22 @@ static void _encodeObject(NSKeyedArchiver *archiver, id object, NSString *key)
visited = YES; visited = YES;
} }
if (archiver->_replacementMap != nil && CFDictionaryContainsKey((CFDictionaryRef)archiver->_replacementMap, object)) id replacement = nil;
if (!CFDictionaryGetValueIfPresent(archiver->_replacementMap, object, &replacement))
{ {
// TODO replacement = [object replacementObjectForKeyedArchiver:archiver];
if (replacement)
{
[archiver replaceObject:object withObject:replacement];
}
} }
id old = [object replacementObjectForKeyedArchiver:archiver]; if (replacement)
if (old)
{ {
[archiver replaceObject:old withObject:object]; object = replacement;
} }
Class class = [object classForKeyedArchiver]; Class class = [object classForKeyedArchiver];
if ([archiver requiresSecureCoding]) if ([archiver requiresSecureCoding])
{ {
@ -186,6 +191,7 @@ static void _encodeObject(NSKeyedArchiver *archiver, id object, NSString *key)
{ {
// This object has already been encoded // This object has already been encoded
uidIndex = (int)mapObject; uidIndex = (int)mapObject;
visited = YES;
} }
else else
{ {
@ -561,8 +567,16 @@ static void _release(CFAllocatorRef allocator, const void *value)
NULL, NULL,
NULL NULL
}; };
CFDictionaryValueCallBacks valueCallbacks = {
0,
&_retain,
&_release,
NULL,
NULL,
};
_objRefMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &callbacks, NULL); _objRefMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &callbacks, NULL);
_conditionals = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &callbacks, NULL); _conditionals = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &callbacks, NULL);
_replacementMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &callbacks, &valueCallbacks);
_containers = [NSMutableArray new]; _containers = [NSMutableArray new];
NSMutableDictionary *dict = [NSMutableDictionary new]; NSMutableDictionary *dict = [NSMutableDictionary new];
@ -1032,6 +1046,11 @@ static size_t _encodeValueOfObjCType(NSKeyedArchiver *self, const char *type, co
{ {
index--; index--;
id obj = CFArrayGetValueAtIndex((CFArrayRef)_containers, index); id obj = CFArrayGetValueAtIndex((CFArrayRef)_containers, index);
if (obj != copyOfObjects)
{
// this should be impossible
DEBUG_BREAK();
}
CFRetain(obj); CFRetain(obj);
[_containers removeObjectAtIndex:index]; [_containers removeObjectAtIndex:index];
encodeFinalValue(self, obj, escapeKey(key)); encodeFinalValue(self, obj, escapeKey(key));
@ -1082,14 +1101,14 @@ static size_t _encodeValueOfObjCType(NSKeyedArchiver *self, const char *type, co
[_delegate archiver:self willReplaceObject:object withObject:replacement]; [_delegate archiver:self willReplaceObject:object withObject:replacement];
} }
id objectRef = [(NSMutableDictionary *)_objRefMap objectForKey:object]; id objectRef = nil;
if (objectRef != nil) if (CFDictionaryGetValueIfPresent(_objRefMap, object, &objectRef))
{ {
[(NSMutableDictionary *)_objRefMap removeObjectForKey:object]; CFDictionaryRemoveValue(_objRefMap, object);
[(NSMutableDictionary *)_objRefMap setObject:objectRef forKey:replacement]; CFDictionarySetValue(_objRefMap, replacement, objectRef);
} }
[(NSMutableDictionary *)_objRefMap setObject:replacement forKey:object]; CFDictionarySetValue(_replacementMap, object, replacement);
} }
- (void)finishEncoding - (void)finishEncoding