00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import "CPData.j"
00024 @import "CPCoder.j"
00025 @import "CPArray.j"
00026 @import "CPString.j"
00027 @import "CPNumber.j"
00028 @import "CPDictionary.j"
00029 @import "CPValue.j"
00030
00031
00032 var CPArchiverReplacementClassNames = nil;
00033
00034 var _CPKeyedArchiverDidEncodeObjectSelector = 1,
00035 _CPKeyedArchiverWillEncodeObjectSelector = 2,
00036 _CPKeyedArchiverWillReplaceObjectWithObjectSelector = 4,
00037 _CPKeyedArchiverDidFinishSelector = 8,
00038 _CPKeyedArchiverWillFinishSelector = 16;
00039
00040 var _CPKeyedArchiverNullString = "$null",
00041 _CPKeyedArchiverNullReference = nil,
00042
00043 _CPKeyedArchiverUIDKey = "CP$UID",
00044
00045 _CPKeyedArchiverTopKey = "$top",
00046 _CPKeyedArchiverObjectsKey = "$objects",
00047 _CPKeyedArchiverArchiverKey = "$archiver",
00048 _CPKeyedArchiverVersionKey = "$version",
00049
00050 _CPKeyedArchiverClassNameKey = "$classname",
00051 _CPKeyedArchiverClassesKey = "$classes",
00052 _CPKeyedArchiverClassKey = "$class";
00053
00054 var _CPKeyedArchiverStringClass = Nil,
00055 _CPKeyedArchiverNumberClass = Nil;
00056
00057
00058 @implementation _CPKeyedArchiverValue : CPValue
00059 {
00060 }
00061 @end
00062
00098 @implementation CPKeyedArchiver : CPCoder
00099 {
00100 id _delegate;
00101 unsigned _delegateSelectors;
00102
00103 CPData _data;
00104
00105 CPArray _objects;
00106
00107 CPDictionary _UIDs;
00108 CPDictionary _conditionalUIDs;
00109
00110 CPDictionary _replacementObjects;
00111 CPDictionary _replacementClassNames;
00112
00113 id _plistObject;
00114 CPMutableArray _plistObjects;
00115
00116 CPPropertyListFormat _outputFormat;
00117
00118 }
00119
00120
00121
00122
00123 + (void)initialize
00124 {
00125 if (self != [CPKeyedArchiver class])
00126 return;
00127
00128 _CPKeyedArchiverStringClass = [CPString class];
00129 _CPKeyedArchiverNumberClass = [CPNumber class];
00130
00131 _CPKeyedArchiverNullReference = [CPDictionary dictionaryWithObject:0 forKey:_CPKeyedArchiverUIDKey];
00132 }
00133
00134 + (BOOL)allowsKeyedCoding
00135 {
00136 return YES;
00137 }
00138
00144 + (CPData)archivedDataWithRootObject:(id)anObject
00145 {
00146 var data = [CPData dataWithPlistObject:nil],
00147 archiver = [[self alloc] initForWritingWithMutableData:data];
00148
00149 [archiver encodeObject:anObject forKey:@"root"];
00150 [archiver finishEncoding];
00151
00152 return data;
00153 }
00154
00155
00161 - (id)initForWritingWithMutableData:(CPMutableData)data
00162 {
00163 self = [super init];
00164
00165 if (self)
00166 {
00167 _data = data;
00168
00169 _objects = [];
00170
00171 _UIDs = [CPDictionary dictionary];
00172 _conditionalUIDs = [CPDictionary dictionary];
00173
00174 _replacementObjects = [CPDictionary dictionary];
00175
00176 _data = data;
00177
00178 _plistObject = [CPDictionary dictionary];
00179 _plistObjects = [CPArray arrayWithObject:_CPKeyedArchiverNullString];
00180 }
00181
00182 return self;
00183 }
00184
00185
00190 - (void)finishEncoding
00191 {
00192 if (_delegate && _delegateSelectors & _CPKeyedArchiverWillFinishSelector)
00193 [_delegate archiverWillFinish:self];
00194
00195 var i = 0,
00196 topObject = _plistObject,
00197 classes = [];
00198
00199 for (; i < _objects.length; ++i)
00200 {
00201 var object = _objects[i],
00202 theClass = [object classForKeyedArchiver];
00203
00204
00205
00206
00207 _plistObject = _plistObjects[[_UIDs objectForKey:[object hash]]];
00208 [object encodeWithCoder:self];
00209
00210 if (_delegate && _delegateSelectors & _CPKeyedArchiverDidEncodeObjectSelector)
00211 [_delegate archiver:self didEncodeObject:object];
00212 }
00213
00214 _plistObject = [CPDictionary dictionary];
00215
00216 [_plistObject setObject:topObject forKey:_CPKeyedArchiverTopKey];
00217 [_plistObject setObject:_plistObjects forKey:_CPKeyedArchiverObjectsKey];
00218 [_plistObject setObject:[self className] forKey:_CPKeyedArchiverArchiverKey];
00219 [_plistObject setObject:@"100000" forKey:_CPKeyedArchiverVersionKey];
00220
00221 [_data setPlistObject:_plistObject];
00222
00223 if (_delegate && _delegateSelectors & _CPKeyedArchiverDidFinishSelector)
00224 [_delegate archiverDidFinish:self];
00225 }
00226
00230 - (CPPropertyListFormat)outputFormat
00231 {
00232 return _outputFormat;
00233 }
00234
00239 - (void)setOutputFormat:(CPPropertyListFormat)aPropertyListFormat
00240 {
00241 _outputFormat = aPropertyListFormat;
00242 }
00243
00249 - (void)encodeBool:(BOOL)aBOOL forKey:(CPString)aKey
00250 {
00251 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, aBOOL, NO) forKey:aKey];
00252 }
00253
00259 - (void)encodeDouble:(double)aDouble forKey:(CPString)aKey
00260 {
00261 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, aDouble, NO) forKey:aKey];
00262 }
00263
00269 - (void)encodeFloat:(float)aFloat forKey:(CPString)aKey
00270 {
00271 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, aFloat, NO) forKey:aKey];
00272 }
00273
00279 - (void)encodeInt:(float)anInt forKey:(CPString)aKey
00280 {
00281 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, anInt, NO) forKey:aKey];
00282 }
00283
00284
00288 - (void)setDelegate:(id)aDelegate
00289 {
00290 _delegate = aDelegate;
00291
00292 if ([_delegate respondsToSelector:@selector(archiver:didEncodeObject:)])
00293 _delegateSelectors |= _CPKeyedArchiverDidEncodeObjectSelector;
00294
00295 if ([_delegate respondsToSelector:@selector(archiver:willEncodeObject:)])
00296 _delegateSelectors |= _CPKeyedArchiverWillEncodeObjectSelector;
00297
00298 if ([_delegate respondsToSelector:@selector(archiver:willReplaceObject:withObject:)])
00299 _delegateSelectors |= _CPKeyedArchiverWillReplaceObjectWithObjectSelector;
00300
00301 if ([_delegate respondsToSelector:@selector(archiver:didFinishEncoding:)])
00302 _delegateSelectors |= _CPKeyedArchiverDidFinishEncodingSelector;
00303
00304 if ([_delegate respondsToSelector:@selector(archiver:willFinishEncoding:)])
00305 _delegateSelectors |= _CPKeyedArchiverWillFinishEncodingSelector;
00306
00307 }
00308
00312 - (id)delegate
00313 {
00314 return _delegate;
00315 }
00316
00322 - (void)encodePoint:(CGPoint)aPoint forKey:(CPString)aKey
00323 {
00324 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, CPStringFromPoint(aPoint), NO) forKey:aKey];
00325 }
00326
00332 - (void)encodeRect:(CGRect)aRect forKey:(CPString)aKey
00333 {
00334 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, CPStringFromRect(aRect), NO) forKey:aKey];
00335 }
00336
00342 - (void)encodeSize:(CGSize)aSize forKey:(CPString)aKey
00343 {
00344 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, CPStringFromSize(aSize), NO) forKey:aKey];
00345 }
00346
00354 - (void)encodeConditionalObject:(id)anObject forKey:(CPString)aKey
00355 {
00356 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, anObject, YES) forKey:aKey];
00357 }
00358
00364 - (void)encodeNumber:(CPNumber)aNumber forKey:(CPString)aKey
00365 {
00366 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, aNumber, NO) forKey:aKey];
00367 }
00368
00374 - (void)encodeObject:(id)anObject forKey:(CPString)aKey
00375 {
00376 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, anObject, NO) forKey:aKey];
00377 }
00378
00379
00380 - (void)_encodeArrayOfObjects:(CPArray)objects forKey:(CPString)aKey
00381 {
00382 var i = 0,
00383 count = objects.length,
00384 references = [CPArray arrayWithCapacity:count];
00385
00386 for (; i < count; ++i)
00387 [references addObject:_CPKeyedArchiverEncodeObject(self, objects[i], NO)];
00388
00389 [_plistObject setObject:references forKey:aKey];
00390 }
00391
00392
00393 - (void)_encodeDictionaryOfObjects:(CPDictionary)aDictionary forKey:(CPString)aKey
00394 {
00395 var key,
00396 keys = [aDictionary keyEnumerator],
00397 references = [CPDictionary dictionary];
00398
00399 while (key = [keys nextObject])
00400 [references setObject:_CPKeyedArchiverEncodeObject(self, [aDictionary objectForKey:key], NO) forKey:key];
00401
00402 [_plistObject setObject:references forKey:aKey];
00403 }
00404
00405
00413 + (void)setClassName:(CPString)aClassName forClass:(Class)aClass
00414 {
00415 if (!CPArchiverReplacementClassNames)
00416 CPArchiverReplacementClassNames = [CPDictionary dictionary];
00417
00418 [CPArchiverReplacementClassNames setObject:aClassName forKey:CPStringFromClass(aClass)];
00419 }
00420
00428 + (CPString)classNameForClass:(Class)aClass
00429 {
00430 if (!CPArchiverReplacementClassNames)
00431 return aClass.name;
00432
00433 var className = [CPArchiverReplacementClassNames objectForKey:CPStringFromClass(aClassName)];
00434
00435 return className ? className : aClass.name;
00436 }
00437
00445 - (void)setClassName:(CPString)aClassName forClass:(Class)aClass
00446 {
00447 if (!_replacementClassNames)
00448 _replacementClassNames = [CPDictionary dictionary];
00449
00450 [_replacementClassNames setObject:aClassName forKey:CPStringFromClass(aClass)];
00451 }
00452
00458 - (CPString)classNameForClass:(Class)aClass
00459 {
00460 if (!_replacementClassNames)
00461 return aClass.name;
00462
00463 var className = [_replacementClassNames objectForKey:CPStringFromClass(aClassName)];
00464
00465 return className ? className : aClass.name;
00466 }
00467
00468 @end
00469
00470 var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
00471 {
00472
00473
00474
00475 if (anObject != nil && !anObject.isa)
00476 anObject = [_CPKeyedArchiverValue valueWithJSObject:anObject];
00477
00478
00479 var hash = [anObject hash],
00480 object = [self._replacementObjects objectForKey:hash];
00481
00482
00483
00484 if (object == nil)
00485 {
00486 object = [anObject replacementObjectForKeyedArchiver:self];
00487
00488
00489 if (self._delegate)
00490 {
00491 if (object != anObject && self._delegateSelectors & _CPKeyedArchiverWillReplaceObjectWithObjectSelector)
00492 [self._delegate archiver:self willReplaceObject:anObject withObject:object];
00493
00494 if (self._delegateSelectors & _CPKeyedArchiverWillEncodeObjectSelector)
00495 {
00496 anObject = [self._delegate archiver:self willEncodeObject:object];
00497
00498 if (anObject != object && self._delegateSelectors & _CPKeyedArchiverWillReplaceObjectWithObjectSelector)
00499 [self._delegate archiver:self willReplaceObject:object withObject:anObject];
00500
00501 object = anObject;
00502 }
00503 }
00504
00505 [self._replacementObjects setObject:object forKey:hash];
00506 }
00507
00508
00509
00510
00511 if (object == nil)
00512 return _CPKeyedArchiverNullReference;
00513
00514
00515 var UID = [self._UIDs objectForKey:hash = [object hash]];
00516
00517
00518
00519
00520 if (UID == nil)
00521 {
00522
00523 if (isConditional)
00524 {
00525
00526 if ((UID = [self._conditionalUIDs objectForKey:hash]) == nil)
00527 {
00528
00529 [self._conditionalUIDs setObject:UID = [self._plistObjects count] forKey:hash];
00530 [self._plistObjects addObject:_CPKeyedArchiverNullString];
00531 }
00532 }
00533 else
00534 {
00535 var theClass = [anObject classForKeyedArchiver],
00536 plistObject = nil,
00537 shouldEncodeObject = NO;
00538
00539 if (theClass == _CPKeyedArchiverStringClass || theClass == _CPKeyedArchiverNumberClass)
00540 plistObject = object;
00541 else
00542 {
00543 shouldEncodeObject = YES;
00544 plistObject = [CPDictionary dictionary];
00545 }
00546
00547
00548 if ((UID = [self._conditionalUIDs objectForKey:hash]) == nil)
00549 {
00550 [self._UIDs setObject:UID = [self._plistObjects count] forKey:hash];
00551 [self._plistObjects addObject:plistObject];
00552
00553
00554 if (shouldEncodeObject)
00555 {
00556 [self._objects addObject:object];
00557
00558 var className = [self classNameForClass:theClass];
00559
00560 if (!className)
00561 className = [[self class] classNameForClass:theClass];
00562
00563 if (!className)
00564 className = theClass.name;
00565 else
00566 theClass = window[className];
00567
00568 var classUID = [self._UIDs objectForKey:className];
00569
00570 if (!classUID)
00571 {
00572 var plistClass = [CPDictionary dictionary],
00573 hierarchy = [];
00574
00575 [plistClass setObject:className forKey:_CPKeyedArchiverClassNameKey];
00576
00577 do
00578 {
00579 [hierarchy addObject:CPStringFromClass(theClass)];
00580 } while (theClass = [theClass superclass]);
00581
00582 [plistClass setObject:hierarchy forKey:_CPKeyedArchiverClassesKey];
00583
00584 classUID = [self._plistObjects count];
00585 [self._plistObjects addObject:plistClass];
00586 [self._UIDs setObject:classUID forKey:className];
00587 }
00588
00589 [plistObject setObject:[CPDictionary dictionaryWithObject:classUID forKey:_CPKeyedArchiverUIDKey] forKey:_CPKeyedArchiverClassKey];
00590 }
00591 }
00592 else
00593 {
00594 [self._UIDs setObject:object forKey:UID];
00595 [self._plistObjects replaceObjectAtIndex:UID withObject:plistObject];
00596 }
00597 }
00598 }
00599
00600 return [CPDictionary dictionaryWithObject:UID forKey:_CPKeyedArchiverUIDKey];
00601 }