~ubuntu-branches/ubuntu/edgy/sope/edgy

« back to all changes in this revision

Viewing changes to libFoundation/Foundation/NSConcreteString.m

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Ley
  • Date: 2005-08-19 16:53:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050819165331-hs683wz1osm708pw
Tags: upstream-4.4rc.2
ImportĀ upstreamĀ versionĀ 4.4rc.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   NSConcreteString.m
 
3
 
 
4
   Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
 
5
   All rights reserved.
 
6
 
 
7
   Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
 
8
 
 
9
   This file is part of libFoundation.
 
10
 
 
11
   Permission to use, copy, modify, and distribute this software and its
 
12
   documentation for any purpose and without fee is hereby granted, provided
 
13
   that the above copyright notice appear in all copies and that both that
 
14
   copyright notice and this permission notice appear in supporting
 
15
   documentation.
 
16
 
 
17
   We disclaim all warranties with regard to this software, including all
 
18
   implied warranties of merchantability and fitness, in no event shall
 
19
   we be liable for any special, indirect or consequential damages or any
 
20
   damages whatsoever resulting from loss of use, data or profits, whether in
 
21
   an action of contract, negligence or other tortious action, arising out of
 
22
   or in connection with the use or performance of this software.
 
23
*/
 
24
 
 
25
#include <config.h>
 
26
 
 
27
#include <ctype.h>
 
28
 
 
29
#include <Foundation/common.h>
 
30
#include <Foundation/NSArray.h>
 
31
#include <Foundation/NSDictionary.h>
 
32
#include <Foundation/NSData.h>
 
33
#include <Foundation/NSCoder.h>
 
34
#include <Foundation/NSAutoreleasePool.h>
 
35
#include <Foundation/NSException.h>
 
36
#include <Foundation/exceptions/StringExceptions.h>
 
37
#include <Foundation/exceptions/GeneralExceptions.h>
 
38
 
 
39
#include <Foundation/NSCharacterSet.h>
 
40
#include <Foundation/NSString.h>
 
41
#include <Foundation/NSConcreteString.h>
 
42
 
 
43
#include <extensions/objc-runtime.h>
 
44
 
 
45
#define COLLECT_STRING_CLUSTER_STATISTICS 0
 
46
#define PERF_8BIT_USE_OPT_COMPARE   1
 
47
#define PERF_SHTIN_USE_OWN_HASH     1
 
48
#define PERF_SHTIN_USE_OWN_EQUAL    1
 
49
#define PERF_SHTIN_USE_OWN_GETCHARS 1
 
50
 
 
51
static Class NS8BitStringClass          = Nil;
 
52
static Class NSMutable8BitStringClass   = Nil;
 
53
static Class NSShtInline8BitStringClass = Nil;
 
54
static Class NSInline8BitStringClass    = Nil;
 
55
static Class NSDataClass                = Nil;
 
56
static Class NSStringClass              = Nil;
 
57
 
 
58
#if COLLECT_STRING_CLUSTER_STATISTICS
 
59
static unsigned int NS8BitString_dealloc_count             = 0;
 
60
static unsigned int NSInline8BitString_dealloc_count       = 0;
 
61
static unsigned int NSInline8BitString_total_len           = 0;
 
62
static unsigned int NSShortInline8BitString_dealloc_count  = 0;
 
63
static unsigned int NSShortInline8BitString_total_len      = 0;
 
64
static unsigned int NSNonOwned8BitString_dealloc_count     = 0;
 
65
static unsigned int NSNonOwned8BitString_total_len         = 0;
 
66
static unsigned int NSOwned8BitString_dealloc_count        = 0;
 
67
static unsigned int NSOwned8BitString_total_len            = 0;
 
68
static unsigned int NSNonOwnedOpen8BitString_dealloc_count = 0;
 
69
static unsigned int NSNonOwnedOpen8BitString_total_len     = 0;
 
70
static unsigned int NSOwnedOpen8BitString_dealloc_count    = 0;
 
71
static unsigned int NSOwnedOpen8BitString_total_len        = 0;
 
72
static unsigned int NSRange8BitString_dealloc_count        = 0;
 
73
static unsigned int NSRange8BitString_total_len            = 0;
 
74
 
 
75
@implementation NSString(ClusterStatistics)
 
76
 
 
77
+ (void)printStatistics
 
78
{
 
79
    fprintf(stderr,
 
80
            "NSString class cluster statistics:\n"
 
81
            "  dealloc counts:\n"
 
82
            "    NS8BitString:                 %d\n"
 
83
            "      NSInline8BitString:         %d\n"
 
84
            "      NSShortInline8BitString:    %d\n"
 
85
            "      NSNonOwned8BitString:       %d\n"
 
86
            "        NSOwned8BitString:        %d\n"
 
87
            "          NSOwnedOpen8BitString:  %d\n"
 
88
            "        NSNonOwnedOpen8BitString: %d\n"
 
89
            "          NSRange8BitString:      %d\n"
 
90
            "  avg len (dealloc statistics):\n"
 
91
            "    NS8BitString:\n"
 
92
            "      NSInline8BitString:         %d\n"
 
93
            "      NSShortInline8BitString:    %d\n"
 
94
            "      NSNonOwned8BitString:       %d\n"
 
95
            "        NSOwned8BitString:        %d\n"
 
96
            "          NSOwnedOpen8BitString:  %d\n"
 
97
            "        NSNonOwnedOpen8BitString: %d\n"
 
98
            "          NSRange8BitString:      %d\n"
 
99
            ,
 
100
            NS8BitString_dealloc_count,
 
101
            NSInline8BitString_dealloc_count,
 
102
            NSShortInline8BitString_dealloc_count,
 
103
            NSNonOwned8BitString_dealloc_count,
 
104
            NSOwned8BitString_dealloc_count,
 
105
            NSOwnedOpen8BitString_dealloc_count,
 
106
            NSNonOwnedOpen8BitString_dealloc_count,
 
107
            NSRange8BitString_dealloc_count,
 
108
            NSInline8BitString_dealloc_count
 
109
              ? NSInline8BitString_total_len / NSInline8BitString_dealloc_count
 
110
              : 0,
 
111
            NSShortInline8BitString_dealloc_count
 
112
              ? NSShortInline8BitString_total_len /
 
113
                NSShortInline8BitString_dealloc_count
 
114
              : 0,
 
115
            NSNonOwned8BitString_dealloc_count
 
116
              ? NSNonOwned8BitString_total_len/NSNonOwned8BitString_dealloc_count
 
117
              : 0,
 
118
            NSOwned8BitString_dealloc_count
 
119
              ? NSOwned8BitString_total_len / NSOwned8BitString_dealloc_count
 
120
              : 0,
 
121
            NSOwnedOpen8BitString_dealloc_count
 
122
              ? NSOwnedOpen8BitString_total_len /
 
123
                NSOwnedOpen8BitString_dealloc_count
 
124
              : 0,
 
125
            NSNonOwnedOpen8BitString_dealloc_count
 
126
              ? NSNonOwnedOpen8BitString_total_len /
 
127
                NSNonOwnedOpen8BitString_dealloc_count
 
128
              : 0,
 
129
            NSRange8BitString_dealloc_count
 
130
              ? NSRange8BitString_total_len / NSRange8BitString_dealloc_count
 
131
              : 0
 
132
            );
 
133
}
 
134
- (void)printStatistics
 
135
{
 
136
    [NSString printStatistics];
 
137
}
 
138
 
 
139
@end
 
140
#endif /* COLLECT_STRING_CLUSTER_STATISTICS */
 
141
 
 
142
@implementation NS8BitString
 
143
 
 
144
+ (void)initialize 
 
145
{
 
146
    NS8BitStringClass          = [NS8BitString             class];
 
147
    NSMutable8BitStringClass   = [NSMutable8BitStringClass class];
 
148
    NSShtInline8BitStringClass = [NSShortInline8BitString  class];
 
149
    NSInline8BitStringClass    = [NSInline8BitStringClass  class];
 
150
    NSDataClass                = [NSData                   class];
 
151
    NSStringClass              = [NSString                 class];
 
152
}
 
153
 
 
154
#if COLLECT_STRING_CLUSTER_STATISTICS
 
155
- (void)dealloc
 
156
{
 
157
    NS8BitString_dealloc_count++;
 
158
    [super dealloc];
 
159
}
 
160
#endif
 
161
 
 
162
/* Accessing characters */
 
163
 
 
164
- (void)getCharacters:(unichar *)buffer
 
165
{
 
166
    register unsigned int i = 0, l;
 
167
    register unsigned char *bytes;
 
168
    
 
169
    if ((l = [self cStringLength]) == 0)
 
170
        return;
 
171
    
 
172
    bytes = [self __compact8BitBytes];
 
173
    for (i = 0; i < l; i++)
 
174
        buffer[i] = (unichar)bytes[i];
 
175
}
 
176
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange
 
177
{
 
178
    register unsigned int i = 0;
 
179
    unsigned char *bytes;
 
180
    
 
181
    if (aRange.location + aRange.length > [self cStringLength]) {
 
182
        [[[IndexOutOfRangeException alloc] 
 
183
            initWithFormat:@"range (%d,%d) in string %x of length %d",
 
184
                aRange.location, aRange.length, self, [self cStringLength]]
 
185
            raise];
 
186
    }
 
187
    
 
188
    bytes = [self __compact8BitBytes];
 
189
    for (i = 0; i < aRange.length; i++)
 
190
        buffer[i] = bytes[i];
 
191
}
 
192
 
 
193
/* Dividing strings */
 
194
 
 
195
- (NSString *)substringWithRange:(NSRange)aRange
 
196
{
 
197
    [self subclassResponsibility:_cmd];
 
198
    return nil;
 
199
}
 
200
 
 
201
/* Finding characters and substrings */
 
202
 
 
203
- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet*)aSet
 
204
  options:(unsigned int)mask range:(NSRange)aRange
 
205
{
 
206
    // ENCODINGS - this code applies to the system's default encoding
 
207
    unsigned int i = 0;
 
208
 
 
209
    IMP imp = [aSet methodForSelector:@selector(characterIsMember:)];
 
210
    unsigned char *bytes = [self __compact8BitBytes];
 
211
 
 
212
    if (NSMaxRange(aRange) > [self cStringLength]) {
 
213
        [[[IndexOutOfRangeException alloc] 
 
214
            initWithFormat:@"range %@ not in string 0x%08x of length %d",
 
215
                NSStringFromRange(aRange), self, [self cStringLength]] 
 
216
            raise];
 
217
    }
 
218
 
 
219
    if (mask & NSBackwardsSearch) {
 
220
        for (i = aRange.length - 1; i >= aRange.location; i--) {
 
221
            unichar c = bytes[i];
 
222
            
 
223
            if ((*imp)(aSet, @selector(characterIsMember:), c) ||
 
224
                ((mask & NSCaseInsensitiveSearch) && 
 
225
                 ((islower(c) &&
 
226
                  (*imp)(aSet, @selector(characterIsMember:), toupper(c))) ||
 
227
                 (isupper(c) &&
 
228
                  (*imp)(aSet, @selector(characterIsMember:), tolower(c))))
 
229
                 )) {
 
230
                    return NSMakeRange(i, 1);
 
231
                }
 
232
        }
 
233
    } 
 
234
    else {
 
235
        unsigned max = NSMaxRange(aRange);
 
236
        for (i = aRange.location; i < max; i++) {
 
237
            unichar c = bytes[i];
 
238
 
 
239
            if ((*imp)(aSet, @selector(characterIsMember:), c) ||
 
240
                ((mask & NSCaseInsensitiveSearch) && 
 
241
                 ((islower(c) &&
 
242
                  (*imp)(aSet, @selector(characterIsMember:), toupper(c))) ||
 
243
                 (isupper(c) &&
 
244
                  (*imp)(aSet, @selector(characterIsMember:), tolower(c))))
 
245
                 )) {
 
246
          return NSMakeRange(i, 1);
 
247
                }
 
248
        }
 
249
    }
 
250
    
 
251
    return NSMakeRange(NSNotFound, 0);
 
252
}
 
253
 
 
254
- (NSRange)rangeOfString:(NSString*)aString
 
255
  options:(unsigned int)mask range:(NSRange)aRange
 
256
{
 
257
    // ENCODINGS - this code applies to the system's default encoding
 
258
    NSRange       range;
 
259
    unsigned char *mbytes;
 
260
    unsigned char *abytes;
 
261
    unsigned int  a;
 
262
    
 
263
    if (![aString isKindOfClass:NS8BitStringClass] &&
 
264
        ![aString isKindOfClass:NSMutable8BitStringClass])
 
265
            return [super rangeOfString:aString options:mask range:aRange];
 
266
    
 
267
    if ((aRange.location + aRange.length) > [self cStringLength]) {
 
268
        [[[IndexOutOfRangeException alloc] 
 
269
            initWithFormat:@"range (%d,%d) in string %x of length %d",
 
270
                aRange.location, aRange.length, self, [self cStringLength]] 
 
271
            raise];
 
272
    }
 
273
 
 
274
    mbytes = [self __compact8BitBytes] + aRange.location;
 
275
    abytes = [(id)aString __compact8BitBytes];
 
276
    a = [aString cStringLength];
 
277
    
 
278
    if ((a == 0) || (aRange.length < a))
 
279
        return NSMakeRange(0, 0);
 
280
    
 
281
    if (mask & NSAnchoredSearch)  {
 
282
        range.location = aRange.location + 
 
283
            ((mask & NSBackwardsSearch) ? aRange.length - a : 0);
 
284
        range.length = a;
 
285
        
 
286
        if ([self compare:aString options:mask range:range] == NSOrderedSame)
 
287
            return range;
 
288
        else
 
289
            return NSMakeRange(0,0);
 
290
    }
 
291
    
 
292
    if (mask & NSBackwardsSearch) {     
 
293
        if (mask & NSCaseInsensitiveSearch) {
 
294
            /* Backward case insensitive */
 
295
            unsigned char cf;
 
296
            int n;
 
297
 
 
298
            cf = islower(abytes[0]) ? toupper(abytes[0]) : abytes[0];
 
299
            
 
300
            for (n = aRange.length-a; n >= 0; n--) {
 
301
                unsigned char cm =
 
302
                    islower(mbytes[n]) ? toupper(mbytes[n]) : mbytes[n];
 
303
                unsigned char ca = cf;
 
304
                unsigned int i;
 
305
                
 
306
                if (cm != ca)
 
307
                    continue;
 
308
                for (i = 1; i < a; i++) {
 
309
                    cm = islower(mbytes[n+i]) ? 
 
310
                        toupper(mbytes[n+i]) : mbytes[n+i];
 
311
                    ca = islower(abytes[i]) ? toupper(abytes[i]) : abytes[i];
 
312
                    if (cm != ca)
 
313
                        break;
 
314
                }
 
315
                if (i == a) {
 
316
                    range.location = aRange.location + n;
 
317
                    range.length = a;
 
318
                    return range;
 
319
                }
 
320
            }
 
321
        }
 
322
        else {
 
323
            /* Backward case sensitive */
 
324
            int n;
 
325
            for (n = (aRange.length - a); n >= 0; n--) {
 
326
                unsigned int i;
 
327
                
 
328
                if (mbytes[n] != abytes[0])
 
329
                    continue;
 
330
                for (i = 1; i < a; i++)
 
331
                    if (mbytes[n+i] != abytes[i])
 
332
                        break;
 
333
                if (i == a) {
 
334
                    range.location = aRange.location + n;
 
335
                    range.length = a;
 
336
                    return range;
 
337
                }
 
338
            }
 
339
        }
 
340
    }
 
341
    else {
 
342
        if (mask & NSCaseInsensitiveSearch) {
 
343
            /* Forward case insensitive */
 
344
            int n;
 
345
            unsigned char cf;
 
346
 
 
347
            cf = islower(abytes[0]) ? toupper(abytes[0]) : abytes[0];
 
348
 
 
349
            for (n = 0; n + a <= aRange.length; n++) {
 
350
                unsigned char cm, ca;
 
351
                unsigned int i;
 
352
                
 
353
                cm = islower(mbytes[n]) ? toupper(mbytes[n]) : mbytes[n];
 
354
                ca = cf;
 
355
                
 
356
                if (cm != ca)
 
357
                    continue;
 
358
                for (i = 1; i < a; i++) {
 
359
                    cm = islower(mbytes[n+i]) ? 
 
360
                        toupper(mbytes[n+i]) : mbytes[n+i];
 
361
                    ca = islower(abytes[i]) ? toupper(abytes[i]) : abytes[i];
 
362
                    if (cm != ca)
 
363
                        break;
 
364
                }
 
365
                if (i == a) {
 
366
                    range.location = aRange.location + n;
 
367
                    range.length = a;
 
368
                    return range;
 
369
                }
 
370
            }
 
371
        }
 
372
        else {
 
373
            /* Forward case sensitive */
 
374
            int n;
 
375
            
 
376
            for (n = 0; (n + a) <= aRange.length; n++) {
 
377
                unsigned int i;
 
378
                
 
379
                if (mbytes[n] != abytes[0])
 
380
                    continue;
 
381
                for (i = 1; i < a; i++)
 
382
                    if (mbytes[n+i] != abytes[i])
 
383
                        break;
 
384
                if (i == a) {
 
385
                    range.location = aRange.location + n;
 
386
                    range.length   = a;
 
387
                    return range;
 
388
                }
 
389
            }
 
390
        }
 
391
    }
 
392
    
 
393
    range.location = range.length = 0;
 
394
    return range;
 
395
}
 
396
 
 
397
- (NSComparisonResult)compare:(NSString *)aString
 
398
  options:(unsigned int)mask range:(NSRange)aRange
 
399
{
 
400
    // ENCODINGS - this code applies to the system's default encoding
 
401
    register unsigned char *mbytes;
 
402
    register unsigned char *abytes;
 
403
    unsigned int   i, n, a;
 
404
    
 
405
#if PERF_8BIT_USE_OPT_COMPARE /* optimized */
 
406
    register Class clazz;
 
407
    
 
408
    if (aString == nil) /* TODO: hh: AFAIK nil is not allowed in Cocoa? */
 
409
        return NSOrderedDescending;
 
410
    else if (aString == self)
 
411
        return NSOrderedSame;
 
412
    i = 0;
 
413
    for (clazz = *(id *)aString; clazz; clazz = class_get_super_class(clazz)) {
 
414
        if (clazz == NS8BitStringClass || clazz == NSMutable8BitStringClass) {
 
415
            i = 1;
 
416
            break;
 
417
        }
 
418
    }
 
419
    if (i == 0)
 
420
        return [super compare:aString options:mask range:aRange];
 
421
#else
 
422
    if (![aString isKindOfClass:NS8BitStringClass] &&
 
423
        ![aString isKindOfClass:NSMutable8BitStringClass]) {
 
424
        return [super compare:aString options:mask range:aRange];
 
425
    }
 
426
#endif
 
427
    
 
428
    if (aRange.location + aRange.length > [self cStringLength]) {
 
429
        [[[IndexOutOfRangeException alloc] 
 
430
            initWithFormat:@"range (%d,%d) in string %x of length %d",
 
431
                aRange.location, aRange.length, self, [self cStringLength]]
 
432
            raise];
 
433
    }
 
434
 
 
435
    mbytes = [self __compact8BitBytes] + aRange.location;
 
436
    abytes = [(id)aString __compact8BitBytes];
 
437
    
 
438
    a = [aString cStringLength];
 
439
    n = MIN(a, aRange.length);
 
440
    
 
441
    if (mask & NSCaseInsensitiveSearch) {
 
442
        for (i = 0; i < n; i++) {
 
443
            register unsigned char cm = 
 
444
                islower(mbytes[i]) ? toupper(mbytes[i]):mbytes[i];
 
445
            register unsigned char ca = 
 
446
                islower(abytes[i]) ? toupper(abytes[i]):abytes[i];
 
447
 
 
448
            if (cm < ca)
 
449
                return NSOrderedAscending;
 
450
            if (cm > ca)
 
451
                return NSOrderedDescending;
 
452
        }
 
453
    }
 
454
    else {
 
455
        for (i = 0; i < n; i++) {
 
456
            if (mbytes[i] < abytes[i])
 
457
                return NSOrderedAscending;
 
458
            if (mbytes[i] > abytes[i])
 
459
                return NSOrderedDescending;
 
460
        }
 
461
    }
 
462
    
 
463
    if (aRange.length < a)
 
464
        return NSOrderedAscending;
 
465
    if (aRange.length > a)
 
466
        return NSOrderedDescending;
 
467
 
 
468
    return NSOrderedSame;
 
469
}
 
470
 
 
471
- (unsigned)hash
 
472
{
 
473
    static Class LastClass = Nil;
 
474
    static unsigned char *(*compact)(id, SEL) = NULL;
 
475
    static unsigned int  (*cstrlen)(id, SEL)  = NULL;
 
476
    register unsigned char *bytes;
 
477
    register unsigned      hash = 0, hash2;
 
478
    int i, n;
 
479
    
 
480
#if GNU_RUNTIME /* selector caching */
 
481
    if (LastClass != *(id *)self) {
 
482
        LastClass = *(id *)self;
 
483
        compact = (void *)method_get_imp(class_get_instance_method(LastClass, 
 
484
          @selector(__compact8BitBytes)));
 
485
        cstrlen = (void *)method_get_imp(class_get_instance_method(LastClass, 
 
486
          @selector(cStringLength)));
 
487
    }
 
488
    bytes = compact(self, NULL /* dangerous? */);
 
489
    n     = cstrlen(self, NULL /* dangerous? */);
 
490
#else
 
491
    bytes = [self __compact8BitBytes];
 
492
    n     = [self cStringLength];
 
493
#endif
 
494
    
 
495
    for (i = 0; i < n; i++) {
 
496
        hash <<= 4;
 
497
        // UNICODE - must use a for independent of composed characters
 
498
        hash += bytes[i];
 
499
        if ((hash2 = hash & 0xf0000000))
 
500
            hash ^= (hash2 >> 24) ^ hash2;
 
501
    }
 
502
    
 
503
    return hash;
 
504
}
 
505
 
 
506
/* Getting a shared prefix */
 
507
 
 
508
- (NSString *)commonPrefixWithString:(NSString*)aString
 
509
  options:(unsigned int)mask
 
510
{
 
511
    // ENCODINGS - this code applies to the system's default encoding
 
512
    NSRange range = {0, 0};
 
513
    unsigned char *mbytes;
 
514
    unsigned char *abytes;
 
515
    int           mLen, aLen, i;
 
516
    
 
517
    if (![aString isKindOfClass:NS8BitStringClass] &&
 
518
        ![aString isKindOfClass:NSMutable8BitStringClass]) {
 
519
            return [super commonPrefixWithString:aString options:mask];
 
520
    }
 
521
    
 
522
    mLen   = [self cStringLength];
 
523
    aLen   = [aString length];
 
524
    mbytes = [self __compact8BitBytes];
 
525
    abytes = [(NS8BitString *)aString __compact8BitBytes];
 
526
 
 
527
    for (i = 0; (i < mLen) && (i < aLen); i++) {
 
528
        unsigned char c1 = mbytes[i];
 
529
        unsigned char c2 = abytes[i];
 
530
        
 
531
        if (mask & NSCaseInsensitiveSearch) {
 
532
            c1 = tolower(c1);
 
533
            c2 = tolower(c2);
 
534
        }
 
535
        if (c1 != c2)
 
536
            break;
 
537
    }
 
538
    
 
539
    range.length = i;
 
540
    return [self substringWithRange:range];
 
541
}
 
542
 
 
543
/* Changing case */
 
544
 
 
545
- (NSString *)capitalizedString
 
546
{
 
547
    // ENCODINGS - this code applies to the system's default encoding
 
548
    int            i;
 
549
    BOOL           f      = YES;
 
550
    int            length = [self cStringLength];
 
551
    unsigned char* bytes  = [self __compact8BitBytes];
 
552
    unsigned char* chars  = MallocAtomic(sizeof(unichar)*(length+1));
 
553
 
 
554
    for (i = 0; i < length; i++) {
 
555
        unsigned char c = bytes[i];
 
556
        
 
557
        if (isspace(c))
 
558
            f = YES;
 
559
        
 
560
        if (f) {
 
561
            chars[i] = islower(c) ? toupper(c) : c;
 
562
            f = NO;
 
563
        }
 
564
        else
 
565
            chars[i] = isupper(c) ? tolower(c) : c;
 
566
    }
 
567
    chars[i] = 0;
 
568
    
 
569
    return AUTORELEASE([[NSOwned8BitString alloc]
 
570
                           initWithCString:chars length:length copy:NO]);
 
571
}
 
572
 
 
573
- (NSString *)lowercaseString
 
574
{
 
575
    // ENCODINGS - this code applies to the system's default encoding
 
576
    int i;
 
577
    int length = [self cStringLength];
 
578
    unsigned char *bytes = [self __compact8BitBytes];
 
579
    unsigned char *chars = MallocAtomic(sizeof(unichar)*(length+1));
 
580
 
 
581
    for (i = 0; i < length; i++) {
 
582
        register unsigned char c = bytes[i];
 
583
        chars[i] = isupper(c) ? tolower(c) : c;
 
584
    }
 
585
    chars[i] = 0;
 
586
 
 
587
    return AUTORELEASE([[NSOwned8BitString alloc]
 
588
                           initWithCString:chars length:length copy:NO]);
 
589
}
 
590
 
 
591
- (NSString *)uppercaseString
 
592
{
 
593
    // ENCODINGS - this code applies to the system's default encoding
 
594
    int i;
 
595
    int length = [self cStringLength];
 
596
    unsigned char *bytes = [self __compact8BitBytes];
 
597
    unsigned char *chars = MallocAtomic(sizeof(unichar)*(length+1));
 
598
 
 
599
    for (i = 0; i < length; i++) {
 
600
        register unsigned char c = bytes[i];
 
601
        chars[i] = islower(c) ? toupper(c) : c;
 
602
    }
 
603
    
 
604
    chars[i] = 0;
 
605
    
 
606
    return AUTORELEASE([[NSOwned8BitString alloc]
 
607
                           initWithCString:chars length:length copy:NO]);
 
608
}
 
609
 
 
610
/* Working with C strings */
 
611
 
 
612
- (void)getCString:(char *)buffer maxLength:(unsigned int)maxLength
 
613
  range:(NSRange)aRange remainingRange:(NSRange*)leftoverRange
 
614
{
 
615
    unsigned char* bytes = [self __compact8BitBytes];
 
616
    unsigned int toMove = MIN(maxLength, aRange.length);
 
617
    unsigned int cLength = [self cStringLength];
 
618
    
 
619
    if (aRange.location + aRange.length > cLength) {
 
620
        [[[IndexOutOfRangeException alloc] 
 
621
            initWithFormat:@"range (%d,%d) in string %x of length %d",
 
622
                aRange.location, aRange.length, self, cLength] raise];
 
623
    }
 
624
 
 
625
    if (leftoverRange) {
 
626
        leftoverRange->location = aRange.location + toMove;
 
627
        leftoverRange->length = cLength - leftoverRange->location;
 
628
    }
 
629
    memcpy(buffer, bytes + aRange.location, toMove);
 
630
    if (toMove < maxLength)
 
631
        buffer[toMove] = '\0';
 
632
}
 
633
 
 
634
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
 
635
{
 
636
    // UNICODE - remove this
 
637
    NSData *data;
 
638
    data = [self dataUsingEncoding:[NSString defaultCStringEncoding]];
 
639
    return writeToFile(path, data, flag);
 
640
}
 
641
 
 
642
- (Class)classForCoder
 
643
{
 
644
    return NS8BitStringClass;
 
645
}
 
646
 
 
647
- (void)encodeWithCoder:(NSCoder*)aCoder
 
648
{
 
649
    const unsigned char* bytes = [self __compact8BitBytes];
 
650
    int length = [self cStringLength];
 
651
    
 
652
    [aCoder encodeValueOfObjCType:@encode(int) at:&length];
 
653
    [aCoder encodeArrayOfObjCType:@encode(char) count:length at:bytes];
 
654
}
 
655
 
 
656
- (id)initWithCoder:(NSCoder*)aDecoder
 
657
{
 
658
    unsigned char *bytes;
 
659
    int length;
 
660
 
 
661
    RELEASE(self); self = nil;
 
662
 
 
663
    [aDecoder decodeValueOfObjCType:@encode(int) at:&length];
 
664
    bytes = MallocAtomic (length + 1);
 
665
    [aDecoder decodeArrayOfObjCType:@encode(char) count:length at:bytes];
 
666
    bytes[length] = '\0';
 
667
    return [[NSOwned8BitString alloc] initWithCString:bytes length:length copy:NO];
 
668
}
 
669
 
 
670
- (NSString *)stringRepresentation
 
671
{
 
672
    const unsigned char *cString;
 
673
    int i, length;
 
674
 
 
675
    cString = [self __compact8BitBytes];
 
676
    length = [self cStringLength];
 
677
    
 
678
    if (cString == NULL)    return @"\"\"";
 
679
    if (length  == 0)       return @"\"\"";
 
680
    if (cString[0] == '\0') return @"\"\"";
 
681
    
 
682
    /* Check if the string can be parsed as a STRING token by the property list
 
683
       parser. Otherwise we must enclose it in double quotes. */
 
684
    if (lf_isPlistBreakChar(cString[0])) {
 
685
        return lf_quoteString(cString, length);
 
686
    }
 
687
 
 
688
    for(i = 1; i < length; i++) {
 
689
        if (lf_isPlistBreakChar(cString[i]))
 
690
            return lf_quoteString(cString, length);
 
691
    }
 
692
 
 
693
    return self;
 
694
}
 
695
 
 
696
- (id)copyWithZone:(NSZone*)zone
 
697
{
 
698
    register Class clazz;
 
699
    int length;
 
700
    
 
701
    if (NSShouldRetainWithZone(self, zone))
 
702
        return RETAIN(self);
 
703
 
 
704
    length = [self cStringLength];
 
705
    
 
706
    clazz = length < 255
 
707
        ? NSShtInline8BitStringClass
 
708
        : NSInline8BitStringClass;
 
709
    
 
710
    return [[clazz allocForCapacity:length zone:zone]
 
711
                   initWithCString:[self __compact8BitBytes] length:length];
 
712
}
 
713
 
 
714
- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
 
715
  allowLossyConversion:(BOOL)flag;
 
716
{
 
717
    /* NS8BitString */
 
718
    if (encoding == [NSStringClass defaultCStringEncoding]) {
 
719
        unsigned      len;
 
720
        unsigned char *buf = NULL;
 
721
        
 
722
        len  = [self cStringLength];
 
723
        buf = NSZoneMalloc(NULL, sizeof(unsigned char) * len + 1);
 
724
        [self getCString:buf];
 
725
        buf[len] = '\0';
 
726
        return [NSDataClass dataWithBytesNoCopy:buf length:strlen(buf)];
 
727
    }
 
728
    if (encoding == NSASCIIStringEncoding) {
 
729
        register unsigned len = [self cStringLength];
 
730
        register unsigned i;
 
731
        register unsigned char *buf;
 
732
            
 
733
        buf = NSZoneMalloc(NULL, sizeof(char) * len + 1);
 
734
        buf[len] = '\0';
 
735
            
 
736
        [self getCString:buf];            
 
737
        if (!flag) {
 
738
            /* check for strict ASCII */
 
739
            for (i = 0; i < len; i++)
 
740
                if (buf[i] > 127) return nil;
 
741
        }
 
742
        return [NSDataClass dataWithBytesNoCopy:buf length:len];
 
743
    }
 
744
 
 
745
    return [super dataUsingEncoding:encoding allowLossyConversion:flag];
 
746
}
 
747
 
 
748
- (id)mutableCopyWithZone:(NSZone*)zone
 
749
{
 
750
    return [[NSMutableSimple8BitString allocWithZone:zone]
 
751
        initWithCString:[self __compact8BitBytes]
 
752
        length:[self cStringLength] copy:YES];
 
753
}
 
754
 
 
755
@end /* NS8BitString */
 
756
 
 
757
/*
 
758
 * Null terminated CString containing characters inline
 
759
 */
 
760
 
 
761
@implementation NSInline8BitString /* final */
 
762
 
 
763
+ (id)allocForCapacity:(unsigned int)capacity zone:(NSZone *)zone
 
764
{
 
765
    NSInline8BitString *str = NSAllocateObject(self, capacity, zone);
 
766
    str->cLength = -1;
 
767
    return str;
 
768
}
 
769
 
 
770
- (id)init
 
771
{
 
772
    if (self->cLength != -1) {
 
773
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
774
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
 
775
            raise];
 
776
    }
 
777
    self->cLength = 0;
 
778
    self->cString[0] = 0;
 
779
    return self;
 
780
}
 
781
 
 
782
- (id)initWithCString:(const char*)byteString length:(unsigned int)length
 
783
{
 
784
    if (self->cLength != -1) {
 
785
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
786
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
 
787
            raise];
 
788
    }
 
789
    self->cLength = length;
 
790
    memcpy(self->cString, byteString, length);
 
791
    self->cString[length] = 0;
 
792
    return self;
 
793
}
 
794
- (id)initWithCharacters:(const unichar *)chars length:(unsigned int)length
 
795
{
 
796
    /* it must be ensured that char values are below 256 by the cluster ! */
 
797
    register unsigned i;
 
798
    if (self->cLength != -1) {
 
799
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
800
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
 
801
            raise];
 
802
    }
 
803
    
 
804
    for (i = 0; i < length; i++)
 
805
        self->cString[i] = chars[i];
 
806
    self->cString[i] = '\0';
 
807
    self->cLength = i;
 
808
    return self;
 
809
}
 
810
 
 
811
#if COLLECT_STRING_CLUSTER_STATISTICS
 
812
- (void)dealloc
 
813
{
 
814
    NSInline8BitString_dealloc_count++;
 
815
    NSInline8BitString_total_len += self->cLength == -1 ? 0 : self->cLength;
 
816
    [super dealloc];
 
817
}
 
818
#endif
 
819
 
 
820
- (const char *)cString
 
821
{
 
822
    return self->cString;
 
823
}
 
824
 
 
825
- (unsigned int)cStringLength
 
826
{
 
827
    return (self->cLength == -1) ? 0 : self->cLength;
 
828
}
 
829
 
 
830
- (unsigned int)length
 
831
{
 
832
    return (self->cLength == -1) ? 0 : self->cLength;
 
833
}
 
834
 
 
835
- (unichar)characterAtIndex:(unsigned int)index
 
836
{
 
837
    if (self->cLength == -1 || (int)index >= self->cLength) {
 
838
        [[[IndexOutOfRangeException alloc] 
 
839
            initWithFormat:@"index %d out of range in string %x of length %d",
 
840
                index, self, self->cLength] raise];
 
841
    }
 
842
    // ENCODING
 
843
    return self->cString[index];
 
844
}
 
845
 
 
846
- (NSString *)substringWithRange:(NSRange)aRange
 
847
{
 
848
    if (aRange.location + aRange.length > (unsigned)self->cLength) {
 
849
        [[[IndexOutOfRangeException alloc] 
 
850
            initWithFormat:@"range (%d,%d) in string %x of length %d",
 
851
                aRange.location, aRange.length, self, cLength] raise];
 
852
    }
 
853
    if (aRange.length == 0)
 
854
        return @"";
 
855
 
 
856
    return AUTORELEASE([[NSRange8BitString alloc]
 
857
                           initWithString:self
 
858
                           bytes:(self->cString + aRange.location)
 
859
                           length:aRange.length]);
 
860
}
 
861
 
 
862
- (char *)__compact8BitBytes
 
863
{
 
864
    return self->cString;
 
865
}
 
866
 
 
867
- (unsigned)hash
 
868
{
 
869
    register unsigned char *bytes;
 
870
    register unsigned      hash = 0, hash2;
 
871
    int i, n;
 
872
    
 
873
    bytes = self->cString;
 
874
    n     = (self->cLength == -1) ? 0 : self->cLength;
 
875
    
 
876
    for (i = 0; i < n; i++) {
 
877
        hash <<= 4;
 
878
        // UNICODE - must use a for independent of composed characters
 
879
        hash += bytes[i];
 
880
        if ((hash2 = hash & 0xf0000000))
 
881
            hash ^= (hash2 >> 24) ^ hash2;
 
882
    }
 
883
    
 
884
    return hash;
 
885
}
 
886
 
 
887
@end /* NSInline8BitString */
 
888
 
 
889
@implementation NSShortInline8BitString /* final */
 
890
 
 
891
+ (id)allocForCapacity:(unsigned int)capacity zone:(NSZone*)zone
 
892
{
 
893
    NSShortInline8BitString *str = NSAllocateObject(self, capacity, zone);
 
894
    str->cLength = 255;
 
895
    return str;
 
896
}
 
897
 
 
898
- (id)init
 
899
{
 
900
    if (self->cLength != 255) {
 
901
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
902
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
 
903
            raise];
 
904
    }
 
905
    self->cLength = 0;
 
906
    self->cString[0] = 0;
 
907
    return self;
 
908
}
 
909
 
 
910
- (id)initWithCString:(const char*)byteString length:(unsigned int)length
 
911
{
 
912
    if (self->cLength != 255) {
 
913
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
914
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
 
915
            raise];
 
916
    }
 
917
    self->cLength = length;
 
918
    memcpy(self->cString, byteString, length);
 
919
    self->cString[length] = 0;
 
920
    return self;
 
921
}
 
922
- (id)initWithCharacters:(const unichar *)chars length:(unsigned int)length
 
923
{
 
924
    /* it must be ensured that char values are below 256 by the cluster ! */
 
925
    register unsigned i;
 
926
    if (self->cLength != 255) {
 
927
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
928
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
 
929
            raise];
 
930
    }
 
931
    
 
932
    for (i = 0; i < length; i++)
 
933
        self->cString[i] = chars[i];
 
934
    self->cString[i] = '\0';
 
935
    self->cLength = i;
 
936
    return self;
 
937
}
 
938
 
 
939
#if COLLECT_STRING_CLUSTER_STATISTICS
 
940
- (void)dealloc
 
941
{
 
942
    NSShortInline8BitString_dealloc_count++;
 
943
    NSShortInline8BitString_total_len +=
 
944
        self->cLength == 255 ? 0 : self->cLength;
 
945
    [super dealloc];
 
946
}
 
947
#endif
 
948
 
 
949
- (const char *)cString
 
950
{
 
951
    return self->cString;
 
952
}
 
953
 
 
954
- (unsigned int)cStringLength
 
955
{
 
956
    return (self->cLength == 255) ? 0 : self->cLength;
 
957
}
 
958
 
 
959
- (unsigned int)length
 
960
{
 
961
    return (self->cLength == 255) ? 0 : self->cLength;
 
962
}
 
963
 
 
964
- (unichar)characterAtIndex:(unsigned int)index
 
965
{
 
966
    if ((self->cLength == 255) || (index >= self->cLength)) {
 
967
        [[[IndexOutOfRangeException alloc] 
 
968
            initWithFormat:@"index %d out of range in string %x of length %d",
 
969
                index, self, self->cLength] raise];
 
970
    }
 
971
    // ENCODING
 
972
    return self->cString[index];
 
973
}
 
974
 
 
975
#if PERF_SHTIN_USE_OWN_GETCHARS
 
976
- (void)getCharacters:(unichar *)buffer
 
977
{
 
978
    register signed short i;
 
979
    
 
980
    i = self->cLength;
 
981
    if ((i == 255) || (i == 0)) /* empty string */
 
982
        return;
 
983
    
 
984
    for (i--; i >= 0; i--)
 
985
        buffer[i] = (unichar)(self->cString[i]);
 
986
}
 
987
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange
 
988
{
 
989
    register unsigned int i = 0, l;
 
990
    
 
991
    i = aRange.location;
 
992
    l = i + aRange.length;
 
993
    if (l > ((self->cLength == 255) ? 0 : self->cLength)) {
 
994
        [[[IndexOutOfRangeException alloc] 
 
995
            initWithFormat:@"range (%d,%d) in string %x of length %d",
 
996
                aRange.location, aRange.length, self, [self length]] raise];
 
997
    }
 
998
    
 
999
    for (; i < l; i++)
 
1000
        buffer[i] = (unichar)(self->cString[i]);
 
1001
}
 
1002
#endif
 
1003
 
 
1004
- (NSString *)substringWithRange:(NSRange)aRange
 
1005
{
 
1006
    if (aRange.location + aRange.length > self->cLength)
 
1007
        [[[IndexOutOfRangeException alloc] 
 
1008
            initWithFormat:@"range (%d,%d) in string %x of length %d",
 
1009
                aRange.location, aRange.length, self, cLength] raise];
 
1010
 
 
1011
    if (aRange.length == 0)
 
1012
        return @"";
 
1013
 
 
1014
    return AUTORELEASE([[NSRange8BitString alloc]
 
1015
                           initWithString:self
 
1016
                           bytes:(self->cString + aRange.location)
 
1017
                           length:aRange.length]);
 
1018
}
 
1019
 
 
1020
- (char *)__compact8BitBytes
 
1021
{
 
1022
    return self->cString;
 
1023
}
 
1024
 
 
1025
- (NSComparisonResult)compare:(NSString *)aString
 
1026
  options:(unsigned int)mask range:(NSRange)aRange
 
1027
{
 
1028
    // ENCODINGS - this code applies to the system's default encoding
 
1029
    register unsigned char *mbytes, *abytes;
 
1030
    register Class clazz;
 
1031
    unsigned int   i, n, a;
 
1032
    
 
1033
#if 1 /* optimized */
 
1034
    if (aString == nil) /* TODO: hh: AFAIK nil is not allowed in Cocoa? */
 
1035
        return NSOrderedDescending;
 
1036
    else if (aString == self)
 
1037
        return NSOrderedSame;
 
1038
    i = 0;
 
1039
    for (clazz = *(id *)aString; clazz; clazz = class_get_super_class(clazz)) {
 
1040
        if (clazz == NS8BitStringClass || clazz == NSMutable8BitStringClass) {
 
1041
            i = 1;
 
1042
            break;
 
1043
        }
 
1044
    }
 
1045
    if (i == 0)
 
1046
        return [super compare:aString options:mask range:aRange];
 
1047
#else
 
1048
    if (![aString isKindOfClass:NS8BitStringClass] &&
 
1049
        ![aString isKindOfClass:NSMutable8BitStringClass]) {
 
1050
        return [super compare:aString options:mask range:aRange];
 
1051
    }
 
1052
#endif
 
1053
    
 
1054
    if ((aRange.location + aRange.length) > 
 
1055
        ((self->cLength == 255) ? 0 : self->cLength)) {
 
1056
        [[[IndexOutOfRangeException alloc] 
 
1057
            initWithFormat:@"range (%d,%d) in string %x of length %d",
 
1058
                aRange.location, aRange.length, self, [self cStringLength]]
 
1059
            raise];
 
1060
    }
 
1061
 
 
1062
    mbytes = self->cString + aRange.location;
 
1063
    abytes = [(id)aString __compact8BitBytes];
 
1064
    
 
1065
    a = [aString cStringLength];
 
1066
    n = MIN(a, aRange.length);
 
1067
    
 
1068
    if (mask & NSCaseInsensitiveSearch) {
 
1069
        for (i = 0; i < n; i++) {
 
1070
            register unsigned char cm = 
 
1071
                islower(mbytes[i]) ? toupper(mbytes[i]):mbytes[i];
 
1072
            register unsigned char ca = 
 
1073
                islower(abytes[i]) ? toupper(abytes[i]):abytes[i];
 
1074
 
 
1075
            if (cm < ca)
 
1076
                return NSOrderedAscending;
 
1077
            if (cm > ca)
 
1078
                return NSOrderedDescending;
 
1079
        }
 
1080
    }
 
1081
    else {
 
1082
        for (i = 0; i < n; i++) {
 
1083
            if (mbytes[i] < abytes[i])
 
1084
                return NSOrderedAscending;
 
1085
            if (mbytes[i] > abytes[i])
 
1086
                return NSOrderedDescending;
 
1087
        }
 
1088
    }
 
1089
    
 
1090
    if (aRange.length < a)
 
1091
        return NSOrderedAscending;
 
1092
    if (aRange.length > a)
 
1093
        return NSOrderedDescending;
 
1094
 
 
1095
    return NSOrderedSame;
 
1096
}
 
1097
 
 
1098
#if PERF_SHTIN_USE_OWN_HASH
 
1099
- (unsigned)hash
 
1100
{
 
1101
    /* 
 
1102
       according to Valgrind this takes 3.13% of the runtime, can this be 
 
1103
       further optimized without breaking dictionary performance due to
 
1104
       broken hash values?
 
1105
    */
 
1106
    register unsigned char *bytes;
 
1107
    register unsigned      hash = 0, hash2;
 
1108
    register int i, n;
 
1109
    
 
1110
    bytes = self->cString;
 
1111
    n     = (self->cLength == 255) ? 0 : self->cLength;
 
1112
    
 
1113
    for (i = 0; i < n; i++) {
 
1114
        hash <<= 4;
 
1115
        // UNICODE - must use a for independent of composed characters
 
1116
        hash += bytes[i];
 
1117
        if ((hash2 = hash & 0xf0000000))
 
1118
            hash ^= (hash2 >> 24) ^ hash2;
 
1119
    }
 
1120
    
 
1121
    return hash;
 
1122
}
 
1123
#endif
 
1124
 
 
1125
#if PERF_SHTIN_USE_OWN_EQUAL
 
1126
- (BOOL)isEqual:(id)aString
 
1127
{
 
1128
    register unsigned char *mbytes, *abytes;
 
1129
    register Class clazz;
 
1130
    unsigned int   i, n, a;
 
1131
    NSRange range;
 
1132
    
 
1133
    if (self == aString)
 
1134
        return YES;
 
1135
    else if (aString == nil)
 
1136
        return NO;
 
1137
    
 
1138
    i = 0; n = 0;
 
1139
    if (*(id *)aString == *(id *)self) { /* exactly the same class */
 
1140
        i = 1; /* is NSString subclass             */
 
1141
        n = 1; /* is 8-bit string subclass         */
 
1142
        a = 1; /* is exactly the same string class */
 
1143
    }
 
1144
    else {
 
1145
        a = 0;
 
1146
        for (clazz=*(id *)aString; clazz; clazz=class_get_super_class(clazz)) {
 
1147
            if (clazz==NS8BitStringClass || clazz==NSMutable8BitStringClass) {
 
1148
                i = 1; // is NSString subclass
 
1149
                n = 1; // is 8-bit string subclass
 
1150
                break;
 
1151
            }
 
1152
            if (clazz == NSStringClass) {
 
1153
                i = 1; // is NSString subclass 
 
1154
                n = 0; // is not an 8-bit string subclass
 
1155
                break;
 
1156
            }
 
1157
        }
 
1158
        if (i == 0) // not a NSString subclass
 
1159
            return NO;
 
1160
    }
 
1161
    range.length = (self->cLength == 255) ? 0 : self->cLength;
 
1162
    if (n == 0) { // is not an 8-bit string subclass, use compare
 
1163
        range.location = 0;
 
1164
        return [self compare:aString options:0 range:range] == NSOrderedSame;
 
1165
    }
 
1166
    
 
1167
    /* other string is 8 bit */
 
1168
    
 
1169
    if (a == 1) { /* exact string class, do not call method */
 
1170
        a = (((NSShortInline8BitString *)aString)->cLength == 255) 
 
1171
            ? 0 
 
1172
            : ((NSShortInline8BitString *)aString)->cLength;
 
1173
        if (a != range.length)
 
1174
            /* strings differ in length */
 
1175
            return NO;
 
1176
    }
 
1177
    else if ((a = [aString cStringLength]) != range.length)
 
1178
        /* strings differ in length */
 
1179
        return NO;
 
1180
    
 
1181
    /* same length */
 
1182
    
 
1183
    mbytes = self->cString;
 
1184
    abytes = [(id)aString __compact8BitBytes];
 
1185
    
 
1186
    /* using memcmp is probably faster than looping on our own */
 
1187
    return memcmp(self->cString, abytes, a) == 0 ? YES : NO;
 
1188
}
 
1189
#endif
 
1190
 
 
1191
@end /* NSShortInline8BitString */
 
1192
 
 
1193
@implementation NSCharacter8BitString /* final */
 
1194
 
 
1195
- (id)init
 
1196
{
 
1197
    self->c[0] = '\0';
 
1198
    self->c[1] = '\0';
 
1199
    return self;
 
1200
}
 
1201
 
 
1202
- (id)initWithCString:(const char*)byteString length:(unsigned int)_length
 
1203
{
 
1204
    if (_length != 1) {
 
1205
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1206
            @"%@ can only handle a singe char", [self class]] raise];
 
1207
    }
 
1208
    self->c[0] = byteString[0];
 
1209
    self->c[1] = '\0';
 
1210
    
 
1211
    return self;
 
1212
}
 
1213
- (id)initWithCharacters:(const unichar *)chars length:(unsigned int)_length
 
1214
{
 
1215
    if (_length != 1) {
 
1216
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1217
            @"%@ can only handle a singe char", [self class]] raise];
 
1218
    }
 
1219
    self->c[0] = (char)chars[0];
 
1220
    self->c[1] = '\0';
 
1221
    
 
1222
    return self;
 
1223
}
 
1224
 
 
1225
- (const char *)cString
 
1226
{
 
1227
    return &(self->c[0]);
 
1228
}
 
1229
 
 
1230
- (unsigned int)cStringLength
 
1231
{
 
1232
  return 1;
 
1233
}
 
1234
 
 
1235
- (unsigned int)length
 
1236
{
 
1237
  return 1;
 
1238
}
 
1239
 
 
1240
- (unichar)characterAtIndex:(unsigned int)index
 
1241
{
 
1242
    if (index != 0) {
 
1243
        [[[IndexOutOfRangeException alloc] 
 
1244
            initWithFormat:@"index %d out of range in string %x of length 1",
 
1245
                index, self] raise];
 
1246
    }
 
1247
    // ENCODING
 
1248
    return self->c[0];
 
1249
}
 
1250
 
 
1251
- (NSString *)substringWithRange:(NSRange)aRange
 
1252
{
 
1253
  if (aRange.location == 0 && aRange.length == 1)
 
1254
    return self;
 
1255
  if (aRange.length == 0)
 
1256
    return @"";
 
1257
 
 
1258
  [[[IndexOutOfRangeException alloc] 
 
1259
          initWithFormat:@"range (%d,%d) in string %x of length 1",
 
1260
          aRange.location, aRange.length, self] raise];
 
1261
  return nil;
 
1262
}
 
1263
 
 
1264
- (char *)__compact8BitBytes
 
1265
{
 
1266
    return &(self->c[0]);
 
1267
}
 
1268
 
 
1269
- (unsigned)hash
 
1270
{
 
1271
    register unsigned hash = 0, hash2;
 
1272
    
 
1273
    hash <<= 4;
 
1274
    // UNICODE - must use a for independent of composed characters
 
1275
    hash += self->c[0];
 
1276
    if ((hash2 = hash & 0xf0000000))
 
1277
        hash ^= (hash2 >> 24) ^ hash2;
 
1278
    
 
1279
    return hash;
 
1280
}
 
1281
 
 
1282
@end /* NSCharacter8BitString */
 
1283
 
 
1284
 
 
1285
/*
 
1286
 * String containing non-owned, zero termintated c-string
 
1287
 */
 
1288
 
 
1289
@implementation NSNonOwned8BitString
 
1290
 
 
1291
- (id)init
 
1292
{
 
1293
    if (self->cLength || self->cString) {
 
1294
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1295
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
 
1296
            raise];
 
1297
    }
 
1298
    self->cLength = 0;
 
1299
    self->cString = "";
 
1300
    return self;
 
1301
}
 
1302
 
 
1303
- (id)initWithCString:(char *)byteString
 
1304
  length:(unsigned int)length copy:(BOOL)flag
 
1305
{
 
1306
    if (self->cLength || self->cString) {
 
1307
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1308
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
 
1309
            raise];
 
1310
    }
 
1311
    if (flag) {
 
1312
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1313
            @"cannot send %s with flag set to YES to %@ to instance", 
 
1314
            sel_get_name(_cmd), NSStringFromClass([self class])] raise];
 
1315
    }
 
1316
    cLength = length;
 
1317
    cString = byteString;
 
1318
    return self;
 
1319
}
 
1320
 
 
1321
#if COLLECT_STRING_CLUSTER_STATISTICS
 
1322
- (void)dealloc
 
1323
{
 
1324
    NSNonOwned8BitString_dealloc_count++;
 
1325
    NSNonOwned8BitString_total_len += self->cLength;
 
1326
    [super dealloc];
 
1327
}
 
1328
#endif
 
1329
 
 
1330
- (const char *)cString
 
1331
{
 
1332
    return self->cString;
 
1333
}
 
1334
 
 
1335
- (unsigned int)cStringLength
 
1336
{
 
1337
    return self->cLength;
 
1338
}
 
1339
 
 
1340
- (unsigned int)length
 
1341
{
 
1342
    return self->cLength;
 
1343
}
 
1344
 
 
1345
- (unichar)characterAtIndex:(unsigned int)index
 
1346
{
 
1347
    if ((int)self->cLength == -1 || (index >= (unsigned)self->cLength)) {
 
1348
        [[[IndexOutOfRangeException alloc] 
 
1349
            initWithFormat:@"index %d out of range in string %x of length %d",
 
1350
                index, self, cLength] raise];
 
1351
    }
 
1352
    // ENCODING
 
1353
    return self->cString[index];
 
1354
}
 
1355
 
 
1356
- (NSString *)substringWithRange:(NSRange)aRange
 
1357
{
 
1358
    if (aRange.location + aRange.length > cLength) {
 
1359
        [[[IndexOutOfRangeException alloc] 
 
1360
                  initWithFormat:@"range (%d,%d) in string %x of length %d",
 
1361
                  aRange.location, aRange.length, self, cLength] raise];
 
1362
    }
 
1363
    
 
1364
    if (aRange.length == 0)
 
1365
        return @"";
 
1366
 
 
1367
    return AUTORELEASE([[NSRange8BitString alloc]
 
1368
                           initWithString:self
 
1369
                           bytes:cString + aRange.location
 
1370
                           length:aRange.length]);
 
1371
}
 
1372
 
 
1373
- (char*)__compact8BitBytes
 
1374
{
 
1375
    return self->cString;
 
1376
}
 
1377
 
 
1378
@end /* NSNonOwned8BitString */
 
1379
 
 
1380
@implementation NSOwned8BitString
 
1381
 
 
1382
- (id)init
 
1383
{
 
1384
    if (self->cLength || self->cString) {
 
1385
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1386
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
 
1387
            raise];
 
1388
    }
 
1389
 
 
1390
    self->cLength = 0;
 
1391
    self->cString = NSZoneMallocAtomic([self zone], sizeof(char));
 
1392
    self->cString[0] = 0;
 
1393
    return self;
 
1394
}
 
1395
 
 
1396
- (id)initWithCString:(char*)byteString
 
1397
  length:(unsigned int)length
 
1398
  copy:(BOOL)flag
 
1399
{
 
1400
    if (self->cLength != 0 || self->cString != NULL) {
 
1401
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1402
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
 
1403
            raise];
 
1404
    }
 
1405
 
 
1406
    self->cLength = length;
 
1407
    if (flag) {
 
1408
        self->cString = NSZoneMallocAtomic([self zone], sizeof(char)*(length+1));
 
1409
        memcpy(self->cString, byteString, length);
 
1410
        self->cString[self->cLength] = 0;
 
1411
    }
 
1412
    else
 
1413
        self->cString = byteString;
 
1414
    return self;
 
1415
}
 
1416
 
 
1417
- (void)dealloc
 
1418
{
 
1419
#if COLLECT_STRING_CLUSTER_STATISTICS
 
1420
    NSOwned8BitString_dealloc_count++;
 
1421
    NSOwned8BitString_total_len += self->cLength;
 
1422
#endif
 
1423
    lfFree(self->cString);
 
1424
    [super dealloc];
 
1425
}
 
1426
 
 
1427
@end /* NSOwned8BitString */
 
1428
 
 
1429
#if 1
 
1430
@implementation NXConstantString
 
1431
 
 
1432
- (oneway void)release
 
1433
{
 
1434
}
 
1435
 
 
1436
- (id)retain
 
1437
{
 
1438
    return self;
 
1439
}
 
1440
 
 
1441
- (unsigned)retainCount
 
1442
{
 
1443
    return 1;
 
1444
}
 
1445
 
 
1446
- (id)autorelease
 
1447
{
 
1448
    return self;
 
1449
}
 
1450
 
 
1451
- (void)dealloc
 
1452
{
 
1453
    [self shouldNotImplement:_cmd];
 
1454
}
 
1455
 
 
1456
@end /* NXConstantString */
 
1457
#else
 
1458
@interface DummyNXConstantString : NSNonOwned8BitString
 
1459
@end
 
1460
 
 
1461
@implementation DummyNXConstantString
 
1462
- (oneway void)release
 
1463
{
 
1464
}
 
1465
 
 
1466
- (id)retain
 
1467
{
 
1468
    return self;
 
1469
}
 
1470
 
 
1471
- (unsigned)retainCount
 
1472
{
 
1473
    return 1;
 
1474
}
 
1475
 
 
1476
- (id)autorelease
 
1477
{
 
1478
    return self;
 
1479
}
 
1480
 
 
1481
- (void)dealloc
 
1482
{
 
1483
    [self shouldNotImplement:_cmd];
 
1484
}
 
1485
 
 
1486
+ (void)load
 
1487
{
 
1488
    static BOOL didLoad = NO;
 
1489
 
 
1490
    if (!didLoad) {
 
1491
        Class metaClass;
 
1492
        Class constantStringClass;
 
1493
        Class constantStringMetaClass;
 
1494
 
 
1495
        didLoad = YES;
 
1496
 
 
1497
        metaClass               = ((DummyNXConstantString*)self)->isa;
 
1498
        constantStringClass     = objc_lookup_class ("NXConstantString");
 
1499
        constantStringMetaClass = constantStringClass->class_pointer;
 
1500
        
 
1501
        memcpy(constantStringClass,     self,      sizeof (struct objc_class));
 
1502
        memcpy(constantStringMetaClass, metaClass, sizeof (struct objc_class));
 
1503
        
 
1504
        constantStringClass->name
 
1505
            = constantStringMetaClass->name
 
1506
            = "NXConstantString";
 
1507
 
 
1508
        class_add_behavior(constantStringClass, self);
 
1509
    }
 
1510
}
 
1511
 
 
1512
@end /* DummyNXConstantString */
 
1513
#endif
 
1514
 
 
1515
@implementation NSNonOwnedOpen8BitString
 
1516
 
 
1517
#if COLLECT_STRING_CLUSTER_STATISTICS
 
1518
- (void)dealloc
 
1519
{
 
1520
    NSNonOwnedOpen8BitString_dealloc_count++;
 
1521
    NSNonOwnedOpen8BitString_total_len += self->cLength;
 
1522
    [super dealloc];
 
1523
}
 
1524
#endif
 
1525
 
 
1526
- (const char*)cString
 
1527
{
 
1528
    unsigned char *str;
 
1529
    
 
1530
    str = NSZoneMallocAtomic([self zone], sizeof(char)*(self->cLength + 1));
 
1531
    memcpy(str, self->cString, self->cLength);
 
1532
    str[cLength] = 0;
 
1533
#if !LIB_FOUNDATION_BOEHM_GC
 
1534
    [NSAutoreleasedPointer autoreleasePointer:str];
 
1535
#endif
 
1536
    return str;
 
1537
}
 
1538
 
 
1539
@end /* NSNonOwnedOpen8BitString */
 
1540
 
 
1541
@implementation NSOwnedOpen8BitString /* final */
 
1542
 
 
1543
#if COLLECT_STRING_CLUSTER_STATISTICS
 
1544
- (void)dealloc
 
1545
{
 
1546
    NSOwnedOpen8BitString_dealloc_count++;
 
1547
    NSOwnedOpen8BitString_total_len += self->cLength;
 
1548
    [super dealloc];
 
1549
}
 
1550
#endif
 
1551
 
 
1552
- (id)initWithCString:(char *)byteString
 
1553
  length:(unsigned int)length copy:(BOOL)flag
 
1554
{
 
1555
    if (self->cLength || self->cString) {
 
1556
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1557
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
 
1558
            raise];
 
1559
    }
 
1560
    if (length != 0 && byteString == NULL) {
 
1561
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1562
            @"passed NULL cstring to %s with a non-null length (%i)!", 
 
1563
            sel_get_name(_cmd), length]
 
1564
            raise];
 
1565
    }
 
1566
    
 
1567
    if (strlen(byteString) < length) {
 
1568
        printf("LENGTH DIFFERS: %i vs %i\n", strlen(byteString), length);
 
1569
        abort();
 
1570
    }
 
1571
    
 
1572
    self->cLength = length;
 
1573
    if (flag) {
 
1574
        /* TODO: this is not tracked in dealloc? */
 
1575
        self->cString = 
 
1576
            NSZoneMallocAtomic([self zone], sizeof(char)*(length + 1));
 
1577
        memcpy(cString, byteString, length);
 
1578
        cString[length] = 0;
 
1579
    }
 
1580
    else
 
1581
        self->cString = byteString;
 
1582
    return self;
 
1583
}
 
1584
 
 
1585
- (const char *)cString
 
1586
{
 
1587
    unsigned char *str = MallocAtomic(sizeof(char)*(self->cLength + 1));
 
1588
    
 
1589
    memcpy(str, self->cString, self->cLength);
 
1590
    str[self->cLength] = 0;
 
1591
#if !LIB_FOUNDATION_BOEHM_GC
 
1592
    [NSAutoreleasedPointer autoreleasePointer:str];
 
1593
#endif
 
1594
    return str;
 
1595
}
 
1596
 
 
1597
@end /* NSOwnedOpen8BitString */
 
1598
 
 
1599
@implementation NSRange8BitString /* final */
 
1600
 
 
1601
- (id)initWithString:(NSString *)aParent 
 
1602
  bytes:(char *)bytes length:(unsigned int)length
 
1603
{
 
1604
    if (self->cLength != 0 || self->cString != NULL) {
 
1605
        [[[InvalidUseOfMethodException alloc] initWithFormat:
 
1606
            @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
 
1607
            raise];
 
1608
    }
 
1609
    
 
1610
    self->cString = bytes;
 
1611
    self->cLength = length;
 
1612
    self->parent  = RETAIN(aParent);
 
1613
    return self;
 
1614
}
 
1615
 
 
1616
- (void)dealloc
 
1617
{
 
1618
#if COLLECT_STRING_CLUSTER_STATISTICS
 
1619
    NSRange8BitString_dealloc_count++;
 
1620
    NSRange8BitString_total_len += self->cLength;
 
1621
#endif
 
1622
    RELEASE(self->parent);
 
1623
    [super dealloc];
 
1624
}
 
1625
 
 
1626
- (NSString *)substringWithRange:(NSRange)aRange
 
1627
{
 
1628
    if (aRange.location + aRange.length > cLength) {
 
1629
        [[[IndexOutOfRangeException alloc] 
 
1630
                  initWithFormat:@"range (%d,%d) in string %x of length %d",
 
1631
                  aRange.location, aRange.length, self, cLength] raise];
 
1632
    }
 
1633
    
 
1634
    if (aRange.length == 0)
 
1635
        return @"";
 
1636
 
 
1637
    return AUTORELEASE([[NSRange8BitString alloc] 
 
1638
                           initWithString:parent
 
1639
                           bytes:cString+aRange.location 
 
1640
                           length:aRange.length]);
 
1641
}
 
1642
 
 
1643
- (unsigned)hash
 
1644
{
 
1645
    register unsigned char *bytes;
 
1646
    register unsigned      hash = 0, hash2;
 
1647
    int i, n;
 
1648
    
 
1649
    bytes = self->cString;
 
1650
    n     = self->cLength;
 
1651
    
 
1652
    for (i = 0; i < n; i++) {
 
1653
        hash <<= 4;
 
1654
        // UNICODE - must use a for independent of composed characters
 
1655
        hash += bytes[i];
 
1656
        if ((hash2 = hash & 0xf0000000))
 
1657
            hash ^= (hash2 >> 24) ^ hash2;
 
1658
    }
 
1659
    
 
1660
    return hash;
 
1661
}
 
1662
 
 
1663
@end /* NSRange8BitString */
 
1664
 
 
1665
/*
 
1666
  Local Variables:
 
1667
  c-basic-offset: 4
 
1668
  tab-width: 8
 
1669
  End:
 
1670
*/