~ubuntu-branches/ubuntu/karmic/gnustep-base/karmic

« back to all changes in this revision

Viewing changes to Source/NSKeyedArchiver.m

  • Committer: Bazaar Package Importer
  • Author(s): Eric Heintzmann
  • Date: 2005-04-17 00:14:38 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050417001438-enf0y07c9tku85z1
Tags: 1.10.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** Implementation for NSKeyedArchiver for GNUstep
 
2
   Copyright (C) 2004 Free Software Foundation, Inc.
 
3
 
 
4
   Written by:  Richard Frith-Macdonald <rfm@gnu.org>
 
5
   Date: January 2004
 
6
 
 
7
   This file is part of the GNUstep Base Library.
 
8
 
 
9
   This library is free software; you can redistribute it and/or
 
10
   modify it under the terms of the GNU Library General Public
 
11
   License as published by the Free Software Foundation; either
 
12
   version 2 of the License, or (at your option) any later version.
 
13
 
 
14
   This library is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
   Library General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU Library General Public
 
20
   License along with this library; if not, write to the Free
 
21
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
 
22
 
 
23
   */
 
24
 
 
25
#include <Foundation/NSAutoreleasePool.h>
 
26
#include <Foundation/NSObject.h>
 
27
#include <Foundation/NSData.h>
 
28
#include <Foundation/NSException.h>
 
29
#include <Foundation/NSScanner.h>
 
30
#include <Foundation/NSValue.h>
 
31
 
 
32
#include "GSPrivate.h"
 
33
 
 
34
@class  GSString;
 
35
 
 
36
/*
 
37
 *      Setup for inline operation of pointer map tables.
 
38
 */
 
39
#define GSI_MAP_RETAIN_KEY(M, X)        RETAIN(X.obj)   
 
40
#define GSI_MAP_RELEASE_KEY(M, X)       RELEASE(X.obj)
 
41
#define GSI_MAP_RETAIN_VAL(M, X)        
 
42
#define GSI_MAP_RELEASE_VAL(M, X)       
 
43
#define GSI_MAP_HASH(M, X)      ((X).uint)
 
44
#define GSI_MAP_EQUAL(M, X,Y)   ((X).uint == (Y).uint)
 
45
#undef  GSI_MAP_NOCLEAN
 
46
 
 
47
#include "GNUstepBase/GSIMap.h"
 
48
 
 
49
 
 
50
#define _IN_NSKEYEDARCHIVER_M   1
 
51
#include <Foundation/NSKeyedArchiver.h>
 
52
#undef  _IN_NSKEYEDARCHIVER_M
 
53
 
 
54
/* Exceptions */
 
55
 
 
56
/**
 
57
 * An archiving error has occurred.
 
58
 */
 
59
NSString * const NSInvalidArchiveOperationException
 
60
= @"NSInvalidArchiveOperationException";
 
61
 
 
62
static NSMapTable       *globalClassMap = 0;
 
63
 
 
64
static Class    NSStringClass = 0;
 
65
static Class    NSScannerClass = 0;
 
66
static SEL      scanFloatSel;
 
67
static SEL      scanStringSel;
 
68
static SEL      scannerSel;
 
69
static BOOL     (*scanFloatImp)(NSScanner*, SEL, float*);
 
70
static BOOL     (*scanStringImp)(NSScanner*, SEL, NSString*, NSString**);
 
71
static id       (*scannerImp)(Class, SEL, NSString*);
 
72
 
 
73
static inline void
 
74
setupCache(void)
 
75
{
 
76
  if (NSStringClass == 0)
 
77
    {
 
78
      NSStringClass = [NSString class];
 
79
      NSScannerClass = [NSScanner class];
 
80
      scanFloatSel = @selector(scanFloat:);
 
81
      scanStringSel = @selector(scanString:intoString:);
 
82
      scannerSel = @selector(scannerWithString:);
 
83
      scanFloatImp = (BOOL (*)(NSScanner*, SEL, float*))
 
84
        [NSScannerClass instanceMethodForSelector: scanFloatSel];
 
85
      scanStringImp = (BOOL (*)(NSScanner*, SEL, NSString*, NSString**))
 
86
        [NSScannerClass instanceMethodForSelector: scanStringSel];
 
87
      scannerImp = (id (*)(Class, SEL, NSString*))
 
88
        [NSScannerClass methodForSelector: scannerSel];
 
89
    }
 
90
}
 
91
 
 
92
#define CHECKKEY \
 
93
  if ([aKey isKindOfClass: [NSString class]] == NO) \
 
94
    { \
 
95
      [NSException raise: NSInvalidArgumentException \
 
96
                  format: @"%@, bad key '%@' in %@", \
 
97
        NSStringFromClass([self class]), aKey, NSStringFromSelector(_cmd)]; \
 
98
    } \
 
99
  if ([aKey hasPrefix: @"$"] == YES) \
 
100
    { \
 
101
      aKey = [@"$" stringByAppendingString: aKey]; \
 
102
    } \
 
103
  if ([_enc objectForKey: aKey] != nil) \
 
104
    { \
 
105
      [NSException raise: NSInvalidArgumentException \
 
106
                  format: @"%@, duplicate key '%@' in %@", \
 
107
        NSStringFromClass([self class]), aKey, NSStringFromSelector(_cmd)]; \
 
108
    }
 
109
 
 
110
/*
 
111
 * Make a dictionary referring to the object at ref in the array of all objects.
 
112
 */
 
113
static NSDictionary *makeReference(unsigned ref)
 
114
{
 
115
  NSNumber      *n;
 
116
  NSDictionary  *d;
 
117
 
 
118
  n = [NSNumber numberWithUnsignedInt: ref];
 
119
  d = [NSDictionary dictionaryWithObject: n forKey:  @"CF$UID"];
 
120
  return d;
 
121
}
 
122
 
 
123
@interface      NSKeyedArchiver (Private)
 
124
- (id) _encodeObject: (id)anObject conditional: (BOOL)conditional;
 
125
@end
 
126
 
 
127
@implementation NSKeyedArchiver (Internal)
 
128
/**
 
129
 * Internal method used to encode an array relatively efficiently.<br />
 
130
 * Some MacOS-X library classes seem to use this.
 
131
 */
 
132
- (void) _encodeArrayOfObjects: (NSArray*)anArray forKey: (NSString*)aKey
 
133
{
 
134
  id            o;
 
135
  CHECKKEY
 
136
 
 
137
  if (anArray == nil)
 
138
    {
 
139
      o = makeReference(0);
 
140
    }
 
141
  else
 
142
    {
 
143
      NSMutableArray    *m;
 
144
      unsigned          c;
 
145
      unsigned          i;
 
146
 
 
147
      c = [anArray count];
 
148
      m = [NSMutableArray arrayWithCapacity: c];
 
149
      for (i = 0; i < c; i++)
 
150
        {
 
151
          o = [self _encodeObject: [anArray objectAtIndex: i] conditional: NO];
 
152
          [m addObject: o];
 
153
        }
 
154
      o = m;
 
155
    }
 
156
  [_enc setObject: o forKey: aKey];
 
157
}
 
158
 
 
159
- (void) _encodePropertyList: (id)anObject forKey: (NSString*)aKey
 
160
{
 
161
  CHECKKEY
 
162
  [_enc setObject: anObject forKey: aKey];
 
163
}
 
164
@end
 
165
 
 
166
@implementation NSKeyedArchiver (Private)
 
167
/*
 
168
 * The real workhorse of the archiving process ... this deals with all
 
169
 * archiving of objects. It returns the object to be stored in the
 
170
 * mapping dictionary (_enc).
 
171
 */
 
172
- (id) _encodeObject: (id)anObject conditional: (BOOL)conditional
 
173
{
 
174
  id                    original = anObject;
 
175
  GSIMapNode            node;
 
176
  id                    objectInfo = nil;       // Encoded object
 
177
  NSMutableDictionary   *m = nil;
 
178
  NSDictionary          *refObject;
 
179
  unsigned              ref = 0;                // Reference to nil
 
180
 
 
181
  if (anObject != nil)
 
182
    {
 
183
      /*
 
184
       * Obtain replacement object for the value being encoded.
 
185
       * Notify delegate of progress and set up new mapping if necessary.
 
186
       */
 
187
      node = GSIMapNodeForKey(_repMap, (GSIMapKey)anObject);
 
188
      if (node == 0)
 
189
        {
 
190
          anObject = [original replacementObjectForKeyedArchiver: self];
 
191
          if (_delegate != nil)
 
192
            {
 
193
              if (anObject != nil)
 
194
                {
 
195
                  anObject = [_delegate archiver: self
 
196
                                willEncodeObject: anObject];
 
197
                }
 
198
              if (original != anObject)
 
199
                {
 
200
                  [_delegate archiver: self
 
201
                    willReplaceObject: original
 
202
                           withObject: anObject];
 
203
                }
 
204
            }
 
205
          GSIMapAddPair(_repMap, (GSIMapKey)original, (GSIMapVal)anObject);
 
206
        }
 
207
    }
 
208
 
 
209
  if (anObject != nil)
 
210
    {
 
211
      node = GSIMapNodeForKey(_uIdMap, (GSIMapKey)anObject);
 
212
      if (node == 0)
 
213
        {
 
214
          if (conditional == YES)
 
215
            {
 
216
              node = GSIMapNodeForKey(_cIdMap, (GSIMapKey)anObject);
 
217
              if (node == 0)
 
218
                {
 
219
                  ref = [_obj count];
 
220
                  GSIMapAddPair(_cIdMap, (GSIMapKey)anObject, (GSIMapVal)ref);
 
221
                  /*
 
222
                   * Use the null object as a placeholder for a conditionally
 
223
                   * encoded object.
 
224
                   */
 
225
                  [_obj addObject: [_obj objectAtIndex: 0]];
 
226
                }
 
227
              else
 
228
                {
 
229
                  /*
 
230
                   * This object has already been conditionally encoded.
 
231
                   */
 
232
                  ref = node->value.uint;
 
233
                }
 
234
            }
 
235
          else
 
236
            {
 
237
              Class     c = [anObject class];
 
238
 
 
239
// FIXME ... exactly what classes are stored directly???
 
240
              if ([anObject isKindOfClass: [GSString class]] == YES
 
241
                || c == [@"literal" class])
 
242
                {
 
243
                  // We will store the string object directly.
 
244
                  objectInfo = anObject;
 
245
                }
 
246
              else
 
247
                {
 
248
                  // We store a dictionary describing the object.
 
249
                  m = [NSMutableDictionary new];
 
250
                  objectInfo = m;
 
251
                }
 
252
 
 
253
              node = GSIMapNodeForKey(_cIdMap, (GSIMapKey)anObject);
 
254
              if (node == 0)
 
255
                {
 
256
                  /*
 
257
                   * Not encoded ... create dictionary for it.
 
258
                   */
 
259
                  ref = [_obj count];
 
260
                  GSIMapAddPair(_uIdMap, (GSIMapKey)anObject, (GSIMapVal)ref);
 
261
                  [_obj addObject: objectInfo];
 
262
                }
 
263
              else
 
264
                {
 
265
                  /*
 
266
                   * Conditionally encoded ... replace with actual value.
 
267
                   */
 
268
                  ref = node->value.uint;
 
269
                  GSIMapAddPair(_uIdMap, (GSIMapKey)anObject, (GSIMapVal)ref);
 
270
                  GSIMapRemoveKey(_cIdMap, (GSIMapKey)anObject);
 
271
                  [_obj replaceObjectAtIndex: ref withObject: objectInfo];
 
272
                }
 
273
              RELEASE(m);
 
274
            }
 
275
        }
 
276
      else
 
277
        {
 
278
          ref = node->value.uint;
 
279
        }
 
280
    }
 
281
 
 
282
  /*
 
283
   * Build an object to reference the encoded value of anObject
 
284
   */
 
285
  refObject = makeReference(ref);
 
286
 
 
287
  /*
 
288
   * objectInfo is a dictionary describing the object.
 
289
   */
 
290
  if (objectInfo != nil && m == objectInfo)
 
291
    {
 
292
      NSMutableDictionary       *savedEnc = _enc;
 
293
      unsigned                  savedKeyNum = _keyNum;
 
294
      Class                     c = [anObject class];
 
295
      NSString                  *classname;
 
296
      Class                     mapped;
 
297
 
 
298
      /*
 
299
       * Map the class of the object to the actual class it is encoded as.
 
300
       * First ask the object, then apply any name mappings to that value.
 
301
       */
 
302
      mapped = [anObject classForKeyedArchiver];
 
303
      if (mapped != nil)
 
304
        {
 
305
          c = mapped;
 
306
        }
 
307
 
 
308
      classname = [self classNameForClass: c];
 
309
      if (classname == nil)
 
310
        {
 
311
          classname = [[self class] classNameForClass: c];
 
312
        }
 
313
      if (classname == nil)
 
314
        {
 
315
          classname = NSStringFromClass(c);
 
316
        }
 
317
      else
 
318
        {
 
319
          c = NSClassFromString(classname);
 
320
        }
 
321
 
 
322
      /*
 
323
       * At last, get the object to encode itself.  Save and restore the
 
324
       * current object scope of course.
 
325
       */
 
326
      _enc = m;
 
327
      _keyNum = 0;
 
328
      [anObject encodeWithCoder: self];
 
329
      _keyNum = savedKeyNum;
 
330
      _enc = savedEnc;
 
331
 
 
332
      /*
 
333
       * This is ugly, but it seems to be the way MacOS-X does it ...
 
334
       * We create class information by storing it directly into the
 
335
       * table of all objects, and making a reference so we can look
 
336
       * up the table entry by class pointer.
 
337
       * A much cleaner way to do it would be by encoding the class
 
338
       * normally, but we are trying to be compatible.
 
339
       *
 
340
       * Also ... we encode the class *after* encoding the instance,
 
341
       * simply because that seems to be the way MacOS-X does it and
 
342
       * we want to maximise compatibility (perhaps they had good reason?)
 
343
       */
 
344
      node = GSIMapNodeForKey(_uIdMap, (GSIMapKey)c);
 
345
      if (node == 0)
 
346
        {
 
347
          NSMutableDictionary   *cDict;
 
348
          NSMutableArray        *hierarchy;
 
349
 
 
350
          ref = [_obj count];
 
351
          GSIMapAddPair(_uIdMap, (GSIMapKey)c, (GSIMapVal)ref);
 
352
          cDict = [[NSMutableDictionary alloc] initWithCapacity: 2];
 
353
 
 
354
          /*
 
355
           * record class name
 
356
           */
 
357
          [cDict setObject: classname forKey: @"$classname"];
 
358
 
 
359
          /*
 
360
           * Record the class hierarchy for this object.
 
361
           */
 
362
          hierarchy = [NSMutableArray new];
 
363
          while (c != 0)
 
364
            {
 
365
              Class     next = [c superClass];
 
366
 
 
367
              [hierarchy addObject: NSStringFromClass(c)];
 
368
              if (next == c)
 
369
                {
 
370
                  break;
 
371
                }
 
372
              c = next;
 
373
            }
 
374
          [cDict setObject: hierarchy forKey: @"$classes"];
 
375
          RELEASE(hierarchy);
 
376
          [_obj addObject: cDict];
 
377
          RELEASE(cDict);
 
378
        }
 
379
      else
 
380
        {
 
381
          ref = node->value.uint;
 
382
        }
 
383
 
 
384
      /*
 
385
       * Now create a reference to the class information and store it
 
386
       * in the object description dictionary for the object we just encoded.
 
387
       */
 
388
      [m setObject: makeReference(ref) forKey: @"$class"];
 
389
    }
 
390
 
 
391
  /*
 
392
   * If we have encoded the object information, tell the delegaate.
 
393
   */
 
394
  if (objectInfo != nil && _delegate != nil)
 
395
    {
 
396
      [_delegate archiver: self didEncodeObject: anObject];
 
397
    }
 
398
 
 
399
  /*
 
400
   * Return the dictionary identifying the encoded object.
 
401
   */
 
402
  return refObject;
 
403
}
 
404
@end
 
405
 
 
406
@implementation NSKeyedArchiver
 
407
 
 
408
/*
 
409
 * When I tried this on MacOS 10.3 it encoded the object with the key 'root',
 
410
 * so this implementation does the same.
 
411
 */
 
412
+ (NSData*) archivedDataWithRootObject: (id)anObject
 
413
{
 
414
  NSMutableData         *m = nil;
 
415
  NSKeyedArchiver       *a = nil;
 
416
  NSData                *d = nil;
 
417
 
 
418
  NS_DURING
 
419
    {
 
420
      m = [[NSMutableData alloc] initWithCapacity: 10240];
 
421
      a = [[NSKeyedArchiver alloc] initForWritingWithMutableData: m];
 
422
      [a encodeObject: anObject forKey: @"root"];
 
423
      [a finishEncoding];
 
424
      d = [m copy];
 
425
      DESTROY(m);
 
426
      DESTROY(a);
 
427
    }
 
428
  NS_HANDLER
 
429
    {
 
430
      DESTROY(m);
 
431
      DESTROY(a);
 
432
      [localException raise];
 
433
    }
 
434
  NS_ENDHANDLER
 
435
  return AUTORELEASE(d);
 
436
}
 
437
 
 
438
+ (BOOL) archiveRootObject: (id)anObject toFile: (NSString*)aPath
 
439
{
 
440
  CREATE_AUTORELEASE_POOL(pool);
 
441
  NSData        *d;
 
442
  BOOL          result;
 
443
 
 
444
  d = [self archivedDataWithRootObject: anObject];
 
445
  result = [d writeToFile: aPath atomically: YES];
 
446
  RELEASE(pool);
 
447
  return result;
 
448
}
 
449
 
 
450
+ (NSString*) classNameForClass: (Class)aClass
 
451
{
 
452
  return (NSString*)NSMapGet(globalClassMap, (void*)aClass);
 
453
}
 
454
 
 
455
+ (void) initialize
 
456
{
 
457
  if (globalClassMap == 0)
 
458
    {
 
459
      globalClassMap =
 
460
        NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
 
461
                          NSObjectMapValueCallBacks, 0);
 
462
    }
 
463
}
 
464
 
 
465
+ (void) setClassName: (NSString*)aString forClass: (Class)aClass
 
466
{
 
467
  if (aString == nil)
 
468
    {
 
469
      NSMapRemove(globalClassMap, (void*)aClass);
 
470
    }
 
471
  else
 
472
    {
 
473
      NSMapInsert(globalClassMap, (void*)aClass, aString);
 
474
    }
 
475
}
 
476
 
 
477
- (BOOL) allowsKeyedCoding
 
478
{
 
479
  return YES;
 
480
}
 
481
 
 
482
- (NSString*) classNameForClass: (Class)aClass
 
483
{
 
484
  return (NSString*)NSMapGet(_clsMap, (void*)aClass);
 
485
}
 
486
 
 
487
- (void) dealloc
 
488
{
 
489
  RELEASE(_enc);
 
490
  RELEASE(_obj);
 
491
  RELEASE(_data);
 
492
  if (_clsMap != 0)
 
493
    {
 
494
      NSFreeMapTable(_clsMap);
 
495
      _clsMap = 0;
 
496
    }
 
497
  if (_cIdMap)
 
498
    {
 
499
      GSIMapEmptyMap(_cIdMap);
 
500
      if (_uIdMap)
 
501
        {
 
502
          GSIMapEmptyMap(_uIdMap);
 
503
        }
 
504
      if (_repMap)
 
505
        {
 
506
          GSIMapEmptyMap(_repMap);
 
507
        }
 
508
      NSZoneFree(_cIdMap->zone, (void*)_cIdMap);
 
509
    }
 
510
  [super dealloc];
 
511
}
 
512
 
 
513
- (id) delegate
 
514
{
 
515
  return _delegate;
 
516
}
 
517
 
 
518
- (void) encodeArrayOfObjCType: (const char*)aType
 
519
                         count: (unsigned)aCount
 
520
                            at: (const void*)address
 
521
{
 
522
  id    o;
 
523
 
 
524
  o = [[_NSKeyedCoderOldStyleArray alloc] initWithObjCType: aType
 
525
                                                     count: aCount
 
526
                                                        at: address];
 
527
  [self encodeObject: o];
 
528
  RELEASE(o);
 
529
}
 
530
 
 
531
- (void) encodeBool: (BOOL)aBool forKey: (NSString*)aKey
 
532
{
 
533
  CHECKKEY
 
534
 
 
535
  [_enc setObject: [NSNumber  numberWithBool: aBool] forKey: aKey];
 
536
}
 
537
 
 
538
- (void) encodeBytes: (const uint8_t*)aPointer length: (unsigned)length forKey: (NSString*)aKey
 
539
{
 
540
  CHECKKEY
 
541
 
 
542
  [_enc setObject: [NSData dataWithBytes: aPointer length: length]
 
543
           forKey: aKey];
 
544
}
 
545
 
 
546
- (void) encodeConditionalObject: (id)anObject
 
547
{
 
548
  NSString      *aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
 
549
 
 
550
  anObject = [self _encodeObject: anObject conditional: YES];
 
551
  [_enc setObject: anObject forKey: aKey];
 
552
}
 
553
 
 
554
- (void) encodeConditionalObject: (id)anObject forKey: (NSString*)aKey
 
555
{
 
556
  CHECKKEY
 
557
 
 
558
  anObject = [self _encodeObject: anObject conditional: YES];
 
559
  [_enc setObject: anObject forKey: aKey];
 
560
}
 
561
 
 
562
- (void) encodeDouble: (double)aDouble forKey: (NSString*)aKey
 
563
{
 
564
  CHECKKEY
 
565
 
 
566
  [_enc setObject: [NSNumber  numberWithDouble: aDouble] forKey: aKey];
 
567
}
 
568
 
 
569
- (void) encodeFloat: (float)aFloat forKey: (NSString*)aKey
 
570
{
 
571
  CHECKKEY
 
572
 
 
573
  [_enc setObject: [NSNumber  numberWithFloat: aFloat] forKey: aKey];
 
574
}
 
575
 
 
576
- (void) encodeInt: (int)anInteger forKey: (NSString*)aKey
 
577
{
 
578
  CHECKKEY
 
579
 
 
580
  [_enc setObject: [NSNumber  numberWithInt: anInteger] forKey: aKey];
 
581
}
 
582
 
 
583
- (void) encodeInt32: (int32_t)anInteger forKey: (NSString*)aKey
 
584
{
 
585
  CHECKKEY
 
586
 
 
587
  [_enc setObject: [NSNumber  numberWithLong: anInteger] forKey: aKey];
 
588
}
 
589
 
 
590
- (void) encodeInt64: (int64_t)anInteger forKey: (NSString*)aKey
 
591
{
 
592
  CHECKKEY
 
593
 
 
594
  [_enc setObject: [NSNumber  numberWithLongLong: anInteger] forKey: aKey];
 
595
}
 
596
 
 
597
- (void) encodeObject: (id)anObject
 
598
{
 
599
  NSString      *aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
 
600
 
 
601
  anObject = [self _encodeObject: anObject conditional: NO];
 
602
  [_enc setObject: anObject forKey: aKey];
 
603
}
 
604
 
 
605
- (void) encodeObject: (id)anObject forKey: (NSString*)aKey
 
606
{
 
607
  CHECKKEY
 
608
 
 
609
  anObject = [self _encodeObject: anObject conditional: NO];
 
610
  [_enc setObject: anObject forKey: aKey];
 
611
}
 
612
 
 
613
- (void) encodePoint: (NSPoint)p
 
614
{
 
615
  [self encodeValueOfObjCType: @encode(float) at: &p.x];
 
616
  [self encodeValueOfObjCType: @encode(float) at: &p.y];
 
617
}
 
618
 
 
619
- (void) encodeRect: (NSRect)r
 
620
{
 
621
  [self encodeValueOfObjCType: @encode(float) at: &r.origin.x];
 
622
  [self encodeValueOfObjCType: @encode(float) at: &r.origin.y];
 
623
  [self encodeValueOfObjCType: @encode(float) at: &r.size.width];
 
624
  [self encodeValueOfObjCType: @encode(float) at: &r.size.height];
 
625
}
 
626
 
 
627
- (void) encodeSize: (NSSize)s
 
628
{
 
629
  [self encodeValueOfObjCType: @encode(float) at: &s.width];
 
630
  [self encodeValueOfObjCType: @encode(float) at: &s.height];
 
631
}
 
632
 
 
633
- (void) encodeValueOfObjCType: (const char*)type
 
634
                            at: (const void*)address
 
635
{
 
636
  NSString      *aKey;
 
637
  id            o;
 
638
 
 
639
  if (*type == _C_ID || *type == _C_CLASS)
 
640
    {
 
641
      [self encodeObject: *(id*)address];
 
642
      return;
 
643
    }
 
644
 
 
645
  aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
 
646
  switch (*type)
 
647
    {
 
648
      case _C_SEL:
 
649
        {
 
650
          // Selectors are encoded by name as strings.
 
651
          o = NSStringFromSelector(*(SEL*)address);
 
652
          [self encodeObject: o];
 
653
        }
 
654
        return;
 
655
 
 
656
      case _C_CHARPTR:
 
657
        {
 
658
          /*
 
659
           * Bizzarely MacOS-X seems to encode char* values by creating
 
660
           * string objects and encoding those objects!
 
661
           */
 
662
          o = [NSString stringWithCString: (char*)address];
 
663
          [self encodeObject: o];
 
664
        }
 
665
        return;
 
666
 
 
667
      case _C_CHR:
 
668
        o = [NSNumber numberWithInt: (int)*(char*)address];
 
669
        [_enc setObject: o forKey: aKey];
 
670
        return;
 
671
 
 
672
      case _C_UCHR:
 
673
        o = [NSNumber numberWithInt: (int)*(unsigned char*)address];
 
674
        [_enc setObject: o forKey: aKey];
 
675
        return;
 
676
 
 
677
      case _C_SHT:
 
678
        o = [NSNumber numberWithInt: (int)*(short*)address];
 
679
        [_enc setObject: o forKey: aKey];
 
680
        return;
 
681
 
 
682
      case _C_USHT:
 
683
        o = [NSNumber numberWithLong: (long)*(unsigned short*)address];
 
684
        [_enc setObject: o forKey: aKey];
 
685
        return;
 
686
 
 
687
      case _C_INT:
 
688
        o = [NSNumber numberWithInt: *(int*)address];
 
689
        [_enc setObject: o forKey: aKey];
 
690
        return;
 
691
 
 
692
      case _C_UINT:
 
693
        o = [NSNumber numberWithUnsignedInt: *(unsigned int*)address];
 
694
        [_enc setObject: o forKey: aKey];
 
695
        return;
 
696
 
 
697
      case _C_LNG:
 
698
        o = [NSNumber numberWithLong: *(long*)address];
 
699
        [_enc setObject: o forKey: aKey];
 
700
        return;
 
701
 
 
702
      case _C_ULNG:
 
703
        o = [NSNumber numberWithUnsignedLong: *(unsigned long*)address];
 
704
        [_enc setObject: o forKey: aKey];
 
705
        return;
 
706
 
 
707
      case _C_LNG_LNG:
 
708
        o = [NSNumber numberWithLongLong: *(long long*)address];
 
709
        [_enc setObject: o forKey: aKey];
 
710
        return;
 
711
 
 
712
      case _C_ULNG_LNG:
 
713
        o = [NSNumber numberWithUnsignedLongLong:
 
714
          *(unsigned long long*)address];
 
715
        [_enc setObject: o forKey: aKey];
 
716
        return;
 
717
 
 
718
      case _C_FLT:
 
719
        o = [NSNumber numberWithFloat: *(float*)address];
 
720
        [_enc setObject: o forKey: aKey];
 
721
        return;
 
722
 
 
723
      case _C_DBL:
 
724
        o = [NSNumber numberWithDouble: *(double*)address];
 
725
        [_enc setObject: o forKey: aKey];
 
726
        return;
 
727
 
 
728
      case _C_STRUCT_B:
 
729
        [NSException raise: NSInvalidArgumentException
 
730
                    format: @"-[%@ %@]: this archiver cannote encode structs",
 
731
          NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
 
732
        return;
 
733
 
 
734
      default:  /* Types that can be ignored in first pass.     */
 
735
        [NSException raise: NSInvalidArgumentException
 
736
                    format: @"-[%@ %@]: unknown type encoding ('%c')",
 
737
          NSStringFromClass([self class]), NSStringFromSelector(_cmd), *type];
 
738
        break;
 
739
    }
 
740
}
 
741
 
 
742
- (void) finishEncoding
 
743
{
 
744
  NSMutableDictionary   *final;
 
745
  NSData                *data;
 
746
  NSString              *error;
 
747
 
 
748
  [_delegate archiverWillFinish: self];
 
749
 
 
750
  final = [NSMutableDictionary new];
 
751
  [final setObject: NSStringFromClass([self class]) forKey: @"$archiver"];
 
752
  [final setObject: [NSNumber numberWithInt: 100000] forKey: @"$version"];
 
753
  [final setObject: _enc forKey: @"$top"];
 
754
  [final setObject: _obj forKey: @"$objects"];
 
755
  data = [NSPropertyListSerialization dataFromPropertyList: final
 
756
                                                    format: _format
 
757
                                          errorDescription: &error];
 
758
  RELEASE(final);
 
759
  [_data setData: data];
 
760
  [_delegate archiverDidFinish: self];
 
761
}
 
762
 
 
763
- (id) initForWritingWithMutableData: (NSMutableData*)data
 
764
{
 
765
  self = [super init];
 
766
  if (self)
 
767
    {
 
768
      NSZone    *zone = [self zone];
 
769
 
 
770
      _keyNum = 0;
 
771
      _data = RETAIN(data);
 
772
 
 
773
      _clsMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
 
774
                          NSObjectMapValueCallBacks, 0);
 
775
      /*
 
776
       *        Set up map tables.
 
777
       */
 
778
      _cIdMap = (GSIMapTable)NSZoneMalloc(zone, sizeof(GSIMapTable_t)*5);
 
779
      _uIdMap = &_cIdMap[1];
 
780
      _repMap = &_cIdMap[2];
 
781
      GSIMapInitWithZoneAndCapacity(_cIdMap, zone, 10);
 
782
      GSIMapInitWithZoneAndCapacity(_uIdMap, zone, 200);
 
783
      GSIMapInitWithZoneAndCapacity(_repMap, zone, 1);
 
784
 
 
785
      _enc = [NSMutableDictionary new];         // Top level mapping dict
 
786
      _obj = [NSMutableArray new];              // Array of objects.
 
787
      [_obj addObject: @"$null"];               // Placeholder.
 
788
 
 
789
      _format = NSPropertyListXMLFormat_v1_0;   // FIXME ... should be binary.
 
790
    }
 
791
  return self;
 
792
}
 
793
 
 
794
- (NSPropertyListFormat) outputFormat
 
795
{
 
796
  return _format;
 
797
}
 
798
 
 
799
- (void) setClassName: (NSString*)aString forClass: (Class)aClass
 
800
{
 
801
  if (aString == nil)
 
802
    {
 
803
      NSMapRemove(_clsMap, (void*)aClass);
 
804
    }
 
805
  else
 
806
    {
 
807
      NSMapInsert(_clsMap, (void*)aClass, aString);
 
808
    }
 
809
}
 
810
 
 
811
- (void) setDelegate: (id)anObject
 
812
{
 
813
  _delegate = anObject;         // Not retained.
 
814
}
 
815
 
 
816
- (void) setOutputFormat: (NSPropertyListFormat)format
 
817
{
 
818
  _format = format;
 
819
}
 
820
 
 
821
@end
 
822
 
 
823
@implementation NSObject (NSKeyedArchiverDelegate)
 
824
- (void) archiver: (NSKeyedArchiver*)anArchiver didEncodeObject: (id)anObject
 
825
{
 
826
}
 
827
- (id) archiver: (NSKeyedArchiver*)anArchiver willEncodeObject: (id)anObject
 
828
{
 
829
  return anObject;
 
830
}
 
831
- (void) archiverDidFinish: (NSKeyedArchiver*)anArchiver
 
832
{
 
833
}
 
834
- (void) archiverWillFinish: (NSKeyedArchiver*)anArchiver
 
835
{
 
836
}
 
837
- (void) archiver: (NSKeyedArchiver*)anArchiver
 
838
willReplaceObject: (id)anObject
 
839
       withObject: (id)newObject
 
840
{
 
841
}
 
842
@end
 
843
 
 
844
@implementation NSObject (NSKeyedArchiverObjectSubstitution)
 
845
- (Class) classForKeyedArchiver
 
846
{
 
847
  return [self classForArchiver];
 
848
}
 
849
- (id) replacementObjectForKeyedArchiver: (NSKeyedArchiver*)archiver
 
850
{
 
851
  return [self replacementObjectForArchiver: nil];
 
852
}
 
853
@end
 
854
 
 
855
 
 
856
 
 
857
@implementation NSCoder (NSGeometryKeyedCoding)
 
858
- (void) encodePoint: (NSPoint)aPoint forKey: (NSString*)aKey
 
859
{
 
860
  NSString      *val;
 
861
 
 
862
  val = [NSString stringWithFormat: @"{%g, %g}", aPoint.x, aPoint.y];
 
863
  [self encodeObject: val forKey: aKey];
 
864
}
 
865
 
 
866
- (void) encodeRect: (NSRect)aRect forKey: (NSString*)aKey
 
867
{
 
868
  NSString      *val;
 
869
 
 
870
  val = [NSString stringWithFormat: @"{{%g, %g}, {%g, %g}}",
 
871
    aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height];
 
872
  [self encodeObject: val forKey: aKey];
 
873
}
 
874
 
 
875
- (void) encodeSize: (NSSize)aSize forKey: (NSString*)aKey
 
876
{
 
877
  NSString      *val;
 
878
 
 
879
  val = [NSString stringWithFormat: @"{%g, %g}", aSize.width, aSize.height];
 
880
  [self encodeObject: val forKey: aKey];
 
881
}
 
882
 
 
883
- (NSPoint) decodePointForKey: (NSString*)aKey
 
884
{
 
885
  NSString      *val = [self decodeObjectForKey: aKey];
 
886
  NSPoint       aPoint;
 
887
 
 
888
  if (val == 0)
 
889
    {
 
890
      aPoint = NSMakePoint(0, 0);
 
891
    }
 
892
  else
 
893
    {
 
894
      NSScanner *scanner;
 
895
 
 
896
      setupCache();
 
897
      scanner = (*scannerImp)(NSScannerClass, scannerSel, val);
 
898
      if (!(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
 
899
        || !(*scanFloatImp)(scanner, scanFloatSel, &aPoint.x)
 
900
        || !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
 
901
        || !(*scanFloatImp)(scanner, scanFloatSel, &aPoint.y)
 
902
        || !(*scanStringImp)(scanner, scanStringSel, @"}", NULL))
 
903
        {
 
904
          [NSException raise: NSInvalidArgumentException
 
905
                      format: @"[%@ -%@]: bad value - '%@'",
 
906
            NSStringFromClass([self class]), NSStringFromSelector(_cmd), val];
 
907
        }
 
908
    }
 
909
  return aPoint;
 
910
}
 
911
 
 
912
- (NSRect) decodeRectForKey: (NSString*)aKey
 
913
{
 
914
  NSString      *val = [self decodeObjectForKey: aKey];
 
915
  NSRect        aRect;
 
916
 
 
917
  if (val == 0)
 
918
    {
 
919
      aRect = NSMakeRect(0, 0, 0, 0);
 
920
    }
 
921
  else
 
922
    {
 
923
      NSScanner *scanner;
 
924
 
 
925
      setupCache();
 
926
      scanner = (*scannerImp)(NSScannerClass, scannerSel, val);
 
927
      if (!(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
 
928
        || !(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
 
929
        || !(*scanFloatImp)(scanner, scanFloatSel, &aRect.origin.x)
 
930
        || !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
 
931
        || !(*scanFloatImp)(scanner, scanFloatSel, &aRect.origin.y)
 
932
        || !(*scanStringImp)(scanner, scanStringSel, @"}", NULL)
 
933
        || !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
 
934
        || !(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
 
935
        || !(*scanFloatImp)(scanner, scanFloatSel, &aRect.size.width)
 
936
        || !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
 
937
        || !(*scanFloatImp)(scanner, scanFloatSel, &aRect.size.height)
 
938
        || !(*scanStringImp)(scanner, scanStringSel, @"}", NULL)
 
939
        || !(*scanStringImp)(scanner, scanStringSel, @"}", NULL))
 
940
        {
 
941
          [NSException raise: NSInvalidArgumentException
 
942
                      format: @"[%@ -%@]: bad value - '%@'",
 
943
            NSStringFromClass([self class]), NSStringFromSelector(_cmd), val];
 
944
        }
 
945
    }
 
946
  return aRect;
 
947
}
 
948
 
 
949
- (NSSize) decodeSizeForKey: (NSString*)aKey
 
950
{
 
951
  NSString      *val = [self decodeObjectForKey: aKey];
 
952
  NSSize        aSize;
 
953
 
 
954
  if (val == 0)
 
955
    {
 
956
      aSize = NSMakeSize(0, 0);
 
957
    }
 
958
  else
 
959
    {
 
960
      NSScanner *scanner;
 
961
 
 
962
      setupCache();
 
963
      scanner = (*scannerImp)(NSScannerClass, scannerSel, val);
 
964
      if (!(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
 
965
        || !(*scanFloatImp)(scanner, scanFloatSel, &aSize.width)
 
966
        || !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
 
967
        || !(*scanFloatImp)(scanner, scanFloatSel, &aSize.height)
 
968
        || !(*scanStringImp)(scanner, scanStringSel, @"}", NULL))
 
969
        {
 
970
          [NSException raise: NSInvalidArgumentException
 
971
                      format: @"[%@ -%@]: bad value - '%@'",
 
972
            NSStringFromClass([self class]), NSStringFromSelector(_cmd), val];
 
973
        }
 
974
    }
 
975
  return aSize;
 
976
}
 
977
@end
 
978