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
00101 @implementation CPKeyedArchiver : CPCoder
00102 {
00103 id _delegate;
00104 unsigned _delegateSelectors;
00105
00106 CPData _data;
00107
00108 CPArray _objects;
00109
00110 CPDictionary _UIDs;
00111 CPDictionary _conditionalUIDs;
00112
00113 CPDictionary _replacementObjects;
00114 CPDictionary _replacementClassNames;
00115
00116 id _plistObject;
00117 CPMutableArray _plistObjects;
00118
00119 CPPropertyListFormat _outputFormat;
00120
00121 }
00122
00123
00124
00125
00126 + (void)initialize
00127 {
00128 if (self != [CPKeyedArchiver class])
00129 return;
00130
00131 _CPKeyedArchiverStringClass = [CPString class];
00132 _CPKeyedArchiverNumberClass = [CPNumber class];
00133
00134 _CPKeyedArchiverNullReference = [CPDictionary dictionaryWithObject:0 forKey:_CPKeyedArchiverUIDKey];
00135 }
00136
00137 + (BOOL)allowsKeyedCoding
00138 {
00139 return YES;
00140 }
00141
00147 + (CPData)archivedDataWithRootObject:(id)anObject
00148 {
00149 var data = [CPData dataWithPlistObject:nil],
00150 archiver = [[self alloc] initForWritingWithMutableData:data];
00151
00152 [archiver encodeObject:anObject forKey:@"root"];
00153 [archiver finishEncoding];
00154
00155 return data;
00156 }
00157
00158
00164 - (id)initForWritingWithMutableData:(CPMutableData)data
00165 {
00166 self = [super init];
00167
00168 if (self)
00169 {
00170 _data = data;
00171
00172 _objects = [];
00173
00174 _UIDs = [CPDictionary dictionary];
00175 _conditionalUIDs = [CPDictionary dictionary];
00176
00177 _replacementObjects = [CPDictionary dictionary];
00178
00179 _data = data;
00180
00181 _plistObject = [CPDictionary dictionary];
00182 _plistObjects = [CPArray arrayWithObject:_CPKeyedArchiverNullString];
00183 }
00184
00185 return self;
00186 }
00187
00188
00193 - (void)finishEncoding
00194 {
00195 if (_delegate && _delegateSelectors & _CPKeyedArchiverWillFinishSelector)
00196 [_delegate archiverWillFinish:self];
00197
00198 var i = 0,
00199 topObject = _plistObject,
00200 classes = [];
00201
00202 for (; i < _objects.length; ++i)
00203 {
00204 var object = _objects[i],
00205 theClass = [object classForKeyedArchiver];
00206
00207
00208
00209
00210 _plistObject = _plistObjects[[_UIDs objectForKey:[object hash]]];
00211 [object encodeWithCoder:self];
00212
00213 if (_delegate && _delegateSelectors & _CPKeyedArchiverDidEncodeObjectSelector)
00214 [_delegate archiver:self didEncodeObject:object];
00215 }
00216
00217 _plistObject = [CPDictionary dictionary];
00218
00219 [_plistObject setObject:topObject forKey:_CPKeyedArchiverTopKey];
00220 [_plistObject setObject:_plistObjects forKey:_CPKeyedArchiverObjectsKey];
00221 [_plistObject setObject:[self className] forKey:_CPKeyedArchiverArchiverKey];
00222 [_plistObject setObject:@"100000" forKey:_CPKeyedArchiverVersionKey];
00223
00224 [_data setPlistObject:_plistObject];
00225
00226 if (_delegate && _delegateSelectors & _CPKeyedArchiverDidFinishSelector)
00227 [_delegate archiverDidFinish:self];
00228 }
00229
00233 - (CPPropertyListFormat)outputFormat
00234 {
00235 return _outputFormat;
00236 }
00237
00242 - (void)setOutputFormat:(CPPropertyListFormat)aPropertyListFormat
00243 {
00244 _outputFormat = aPropertyListFormat;
00245 }
00246
00252 - (void)encodeBool:(BOOL)aBOOL forKey:(CPString)aKey
00253 {
00254 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, aBOOL, NO) forKey:aKey];
00255 }
00256
00262 - (void)encodeDouble:(double)aDouble forKey:(CPString)aKey
00263 {
00264 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, aDouble, NO) forKey:aKey];
00265 }
00266
00272 - (void)encodeFloat:(float)aFloat forKey:(CPString)aKey
00273 {
00274 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, aFloat, NO) forKey:aKey];
00275 }
00276
00282 - (void)encodeInt:(float)anInt forKey:(CPString)aKey
00283 {
00284 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, anInt, NO) forKey:aKey];
00285 }
00286
00287
00291 - (void)setDelegate:(id)aDelegate
00292 {
00293 _delegate = aDelegate;
00294
00295 if ([_delegate respondsToSelector:@selector(archiver:didEncodeObject:)])
00296 _delegateSelectors |= _CPKeyedArchiverDidEncodeObjectSelector;
00297
00298 if ([_delegate respondsToSelector:@selector(archiver:willEncodeObject:)])
00299 _delegateSelectors |= _CPKeyedArchiverWillEncodeObjectSelector;
00300
00301 if ([_delegate respondsToSelector:@selector(archiver:willReplaceObject:withObject:)])
00302 _delegateSelectors |= _CPKeyedArchiverWillReplaceObjectWithObjectSelector;
00303
00304 if ([_delegate respondsToSelector:@selector(archiver:didFinishEncoding:)])
00305 _delegateSelectors |= _CPKeyedArchiverDidFinishEncodingSelector;
00306
00307 if ([_delegate respondsToSelector:@selector(archiver:willFinishEncoding:)])
00308 _delegateSelectors |= _CPKeyedArchiverWillFinishEncodingSelector;
00309
00310 }
00311
00315 - (id)delegate
00316 {
00317 return _delegate;
00318 }
00319
00325 - (void)encodePoint:(CGPoint)aPoint forKey:(CPString)aKey
00326 {
00327 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, CPStringFromPoint(aPoint), NO) forKey:aKey];
00328 }
00329
00335 - (void)encodeRect:(CGRect)aRect forKey:(CPString)aKey
00336 {
00337 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, CPStringFromRect(aRect), NO) forKey:aKey];
00338 }
00339
00345 - (void)encodeSize:(CGSize)aSize forKey:(CPString)aKey
00346 {
00347 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, CPStringFromSize(aSize), NO) forKey:aKey];
00348 }
00349
00357 - (void)encodeConditionalObject:(id)anObject forKey:(CPString)aKey
00358 {
00359 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, anObject, YES) forKey:aKey];
00360 }
00361
00367 - (void)encodeNumber:(CPNumber)aNumber forKey:(CPString)aKey
00368 {
00369 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, aNumber, NO) forKey:aKey];
00370 }
00371
00377 - (void)encodeObject:(id)anObject forKey:(CPString)aKey
00378 {
00379 [_plistObject setObject:_CPKeyedArchiverEncodeObject(self, anObject, NO) forKey:aKey];
00380 }
00381
00382
00383 - (void)_encodeArrayOfObjects:(CPArray)objects forKey:(CPString)aKey
00384 {
00385 var i = 0,
00386 count = objects.length,
00387 references = [CPArray arrayWithCapacity:count];
00388
00389 for (; i < count; ++i)
00390 [references addObject:_CPKeyedArchiverEncodeObject(self, objects[i], NO)];
00391
00392 [_plistObject setObject:references forKey:aKey];
00393 }
00394
00395
00396 - (void)_encodeDictionaryOfObjects:(CPDictionary)aDictionary forKey:(CPString)aKey
00397 {
00398 var key,
00399 keys = [aDictionary keyEnumerator],
00400 references = [CPDictionary dictionary];
00401
00402 while (key = [keys nextObject])
00403 [references setObject:_CPKeyedArchiverEncodeObject(self, [aDictionary objectForKey:key], NO) forKey:key];
00404
00405 [_plistObject setObject:references forKey:aKey];
00406 }
00407
00408
00416 + (void)setClassName:(CPString)aClassName forClass:(Class)aClass
00417 {
00418 if (!CPArchiverReplacementClassNames)
00419 CPArchiverReplacementClassNames = [CPDictionary dictionary];
00420
00421 [CPArchiverReplacementClassNames setObject:aClassName forKey:CPStringFromClass(aClass)];
00422 }
00423
00431 + (CPString)classNameForClass:(Class)aClass
00432 {
00433 if (!CPArchiverReplacementClassNames)
00434 return aClass.name;
00435
00436 var className = [CPArchiverReplacementClassNames objectForKey:CPStringFromClass(aClassName)];
00437
00438 return className ? className : aClass.name;
00439 }
00440
00448 - (void)setClassName:(CPString)aClassName forClass:(Class)aClass
00449 {
00450 if (!_replacementClassNames)
00451 _replacementClassNames = [CPDictionary dictionary];
00452
00453 [_replacementClassNames setObject:aClassName forKey:CPStringFromClass(aClass)];
00454 }
00455
00461 - (CPString)classNameForClass:(Class)aClass
00462 {
00463 if (!_replacementClassNames)
00464 return aClass.name;
00465
00466 var className = [_replacementClassNames objectForKey:CPStringFromClass(aClassName)];
00467
00468 return className ? className : aClass.name;
00469 }
00470
00471 @end
00472
00473 var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
00474 {
00475
00476
00477
00478 if (anObject !== nil && !anObject.isa)
00479 anObject = [_CPKeyedArchiverValue valueWithJSObject:anObject];
00480
00481
00482 var hash = [anObject hash],
00483 object = [self._replacementObjects objectForKey:hash];
00484
00485
00486
00487 if (object === nil)
00488 {
00489 object = [anObject replacementObjectForKeyedArchiver:self];
00490
00491
00492 if (self._delegate)
00493 {
00494 if (object !== anObject && self._delegateSelectors & _CPKeyedArchiverWillReplaceObjectWithObjectSelector)
00495 [self._delegate archiver:self willReplaceObject:anObject withObject:object];
00496
00497 if (self._delegateSelectors & _CPKeyedArchiverWillEncodeObjectSelector)
00498 {
00499 anObject = [self._delegate archiver:self willEncodeObject:object];
00500
00501 if (anObject !== object && self._delegateSelectors & _CPKeyedArchiverWillReplaceObjectWithObjectSelector)
00502 [self._delegate archiver:self willReplaceObject:object withObject:anObject];
00503
00504 object = anObject;
00505 }
00506 }
00507
00508 [self._replacementObjects setObject:object forKey:hash];
00509 }
00510
00511
00512
00513
00514 if (object === nil)
00515 return _CPKeyedArchiverNullReference;
00516
00517
00518 var UID = [self._UIDs objectForKey:hash = [object hash]];
00519
00520
00521
00522
00523 if (UID === nil)
00524 {
00525
00526 if (isConditional)
00527 {
00528
00529 if ((UID = [self._conditionalUIDs objectForKey:hash]) === nil)
00530 {
00531
00532 [self._conditionalUIDs setObject:UID = [self._plistObjects count] forKey:hash];
00533 [self._plistObjects addObject:_CPKeyedArchiverNullString];
00534 }
00535 }
00536 else
00537 {
00538 var theClass = [object classForKeyedArchiver],
00539 plistObject = nil;
00540
00541 if ((theClass === _CPKeyedArchiverStringClass) || (theClass === _CPKeyedArchiverNumberClass))
00542 plistObject = object;
00543 else
00544 {
00545
00546 plistObject = [CPDictionary dictionary];
00547
00548 [self._objects addObject:object];
00549
00550 var className = [self classNameForClass:theClass];
00551
00552 if (!className)
00553 className = [[self class] classNameForClass:theClass];
00554
00555 if (!className)
00556 className = theClass.name;
00557 else
00558 theClass = window[className];
00559
00560 var classUID = [self._UIDs objectForKey:className];
00561
00562 if (!classUID)
00563 {
00564 var plistClass = [CPDictionary dictionary],
00565 hierarchy = [];
00566
00567 [plistClass setObject:className forKey:_CPKeyedArchiverClassNameKey];
00568
00569 do
00570 {
00571 [hierarchy addObject:CPStringFromClass(theClass)];
00572 } while (theClass = [theClass superclass]);
00573
00574 [plistClass setObject:hierarchy forKey:_CPKeyedArchiverClassesKey];
00575
00576 classUID = [self._plistObjects count];
00577 [self._plistObjects addObject:plistClass];
00578 [self._UIDs setObject:classUID forKey:className];
00579 }
00580
00581 [plistObject setObject:[CPDictionary dictionaryWithObject:classUID forKey:_CPKeyedArchiverUIDKey] forKey:_CPKeyedArchiverClassKey];
00582 }
00583
00584 UID = [self._conditionalUIDs objectForKey:hash];
00585
00586
00587 if (UID !== nil)
00588 {
00589 [self._UIDs setObject:UID forKey:hash];
00590 [self._plistObjects replaceObjectAtIndex:UID withObject:plistObject];
00591 }
00592 else
00593 {
00594 [self._UIDs setObject:UID = [self._plistObjects count] forKey:hash];
00595 [self._plistObjects addObject:plistObject];
00596 }
00597 }
00598 }
00599
00600 return [CPDictionary dictionaryWithObject:UID forKey:_CPKeyedArchiverUIDKey];
00601 }