]> err.no Git - sope/blob - libFoundation/Foundation/NSConcreteString.m
Drop apache 1 build-dependency
[sope] / libFoundation / Foundation / NSConcreteString.m
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 = (unsigned char *)[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 = (unsigned char *)[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 = (unsigned char *)[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 = (unsigned char *)[self __compact8BitBytes] + aRange.location;
275     abytes = (unsigned char *)[(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 = (unsigned char *)[self __compact8BitBytes] + aRange.location;
436     abytes = (unsigned char *)[(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 = (unsigned char *)[self __compact8BitBytes];
525     abytes = (unsigned char *)[(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  = (unsigned char *)[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:(char *)chars length:length
571                            copy:NO]);
572 }
573
574 - (NSString *)lowercaseString
575 {
576     // ENCODINGS - this code applies to the system's default encoding
577     int i;
578     int length = [self cStringLength];
579     unsigned char *bytes = (unsigned char *)[self __compact8BitBytes];
580     unsigned char *chars = (unsigned char *)MallocAtomic(sizeof(unichar)*(length+1));
581
582     for (i = 0; i < length; i++) {
583         register unsigned char c = bytes[i];
584         chars[i] = isupper(c) ? tolower(c) : c;
585     }
586     chars[i] = 0;
587
588     return AUTORELEASE([[NSOwned8BitString alloc]
589                            initWithCString:(char *)chars length:length copy:NO]);
590 }
591
592 - (NSString *)uppercaseString
593 {
594     // ENCODINGS - this code applies to the system's default encoding
595     int i;
596     int length = [self cStringLength];
597     unsigned char *bytes = (unsigned char *)[self __compact8BitBytes];
598     unsigned char *chars = (unsigned char *)MallocAtomic(sizeof(unichar)*(length+1));
599
600     for (i = 0; i < length; i++) {
601         register unsigned char c = bytes[i];
602         chars[i] = islower(c) ? toupper(c) : c;
603     }
604     
605     chars[i] = 0;
606     
607     return AUTORELEASE([[NSOwned8BitString alloc]
608                            initWithCString:(char *)chars length:length copy:NO]);
609 }
610
611 /* Working with C strings */
612
613 - (void)getCString:(char *)buffer maxLength:(unsigned int)maxLength
614   range:(NSRange)aRange remainingRange:(NSRange*)leftoverRange
615 {
616     unsigned char* bytes = (unsigned char *)[self __compact8BitBytes];
617     unsigned int toMove = MIN(maxLength, aRange.length);
618     unsigned int cLength = [self cStringLength];
619     
620     if (aRange.location + aRange.length > cLength) {
621         [[[IndexOutOfRangeException alloc] 
622             initWithFormat:@"range (%d,%d) in string %x of length %d",
623                 aRange.location, aRange.length, self, cLength] raise];
624     }
625
626     if (leftoverRange) {
627         leftoverRange->location = aRange.location + toMove;
628         leftoverRange->length = cLength - leftoverRange->location;
629     }
630     memcpy(buffer, bytes + aRange.location, toMove);
631     if (toMove < maxLength)
632         buffer[toMove] = '\0';
633 }
634
635 - (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
636 {
637     // UNICODE - remove this
638     NSData *data;
639     data = [self dataUsingEncoding:[NSString defaultCStringEncoding]];
640     return writeToFile(path, data, flag);
641 }
642
643 - (Class)classForCoder
644 {
645     return NS8BitStringClass;
646 }
647
648 - (void)encodeWithCoder:(NSCoder*)aCoder
649 {
650     const unsigned char* bytes = (unsigned char *)[self __compact8BitBytes];
651     int length = [self cStringLength];
652     
653     [aCoder encodeValueOfObjCType:@encode(int) at:&length];
654     [aCoder encodeArrayOfObjCType:@encode(char) count:length at:bytes];
655 }
656
657 - (id)initWithCoder:(NSCoder*)aDecoder
658 {
659     unsigned char *bytes;
660     int length;
661
662     RELEASE(self); self = nil;
663
664     [aDecoder decodeValueOfObjCType:@encode(int) at:&length];
665     bytes = MallocAtomic (length + 1);
666     [aDecoder decodeArrayOfObjCType:@encode(char) count:length at:bytes];
667     bytes[length] = '\0';
668     return [[NSOwned8BitString alloc] 
669                initWithCString:(char *)bytes length:length copy:NO];
670 }
671
672 - (NSString *)stringRepresentation
673 {
674     const unsigned char *cString;
675     int i, length;
676
677     cString = (unsigned char *)[self __compact8BitBytes];
678     length  = [self cStringLength];
679     
680     if (cString == NULL)    return @"\"\"";
681     if (length  == 0)       return @"\"\"";
682     if (cString[0] == '\0') return @"\"\"";
683     
684     /* Check if the string can be parsed as a STRING token by the property list
685        parser. Otherwise we must enclose it in double quotes. */
686     if (lf_isPlistBreakChar(cString[0])) {
687         return lf_quoteString((char *)cString, length);
688     }
689
690     for(i = 1; i < length; i++) {
691         if (lf_isPlistBreakChar(cString[i]))
692             return lf_quoteString((char *)cString, length);
693     }
694
695     return self;
696 }
697
698 - (id)copyWithZone:(NSZone*)zone
699 {
700     register Class clazz;
701     int length;
702     
703     if (NSShouldRetainWithZone(self, zone))
704         return RETAIN(self);
705
706     length = [self cStringLength];
707     
708     clazz = length < 255
709         ? NSShtInline8BitStringClass
710         : NSInline8BitStringClass;
711     
712     return [[clazz allocForCapacity:length zone:zone]
713                    initWithCString:[self __compact8BitBytes] length:length];
714 }
715
716 - (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
717   allowLossyConversion:(BOOL)flag;
718 {
719     /* NS8BitString */
720     if (encoding == [NSStringClass defaultCStringEncoding]) {
721         unsigned      len;
722         unsigned char *buf = NULL;
723         
724         len  = [self cStringLength];
725         buf = NSZoneMalloc(NULL, sizeof(unsigned char) * len + 1);
726         [self getCString:(char *)buf];
727         buf[len] = '\0';
728         return [NSDataClass dataWithBytesNoCopy:(char *)buf
729                             length:strlen((char *)buf)];
730     }
731     if (encoding == NSASCIIStringEncoding) {
732         register unsigned len = [self cStringLength];
733         register unsigned i;
734         register unsigned char *buf;
735             
736         buf = NSZoneMalloc(NULL, sizeof(char) * len + 1);
737         buf[len] = '\0';
738             
739         [self getCString:(char *)buf];            
740         if (!flag) {
741             /* check for strict ASCII */
742             for (i = 0; i < len; i++)
743                 if (buf[i] > 127) return nil;
744         }
745         return [NSDataClass dataWithBytesNoCopy:buf length:len];
746     }
747
748     return [super dataUsingEncoding:encoding allowLossyConversion:flag];
749 }
750
751 - (id)mutableCopyWithZone:(NSZone*)zone
752 {
753     return [[NSMutableSimple8BitString allocWithZone:zone]
754         initWithCString:[self __compact8BitBytes]
755         length:[self cStringLength] copy:YES];
756 }
757
758 @end /* NS8BitString */
759
760 /*
761  * Null terminated CString containing characters inline
762  */
763  
764 @implementation NSInline8BitString /* final */
765
766 + (id)allocForCapacity:(unsigned int)capacity zone:(NSZone *)zone
767 {
768     NSInline8BitString *str = (NSInline8BitString *)
769         NSAllocateObject(self, capacity, zone);
770     str->cLength = -1;
771     return str;
772 }
773
774 - (id)init
775 {
776     if (self->cLength != -1) {
777         [[[InvalidUseOfMethodException alloc] initWithFormat:
778             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
779             raise];
780     }
781     self->cLength = 0;
782     self->cString[0] = 0;
783     return self;
784 }
785
786 - (id)initWithCString:(const char*)byteString length:(unsigned int)length
787 {
788     if (self->cLength != -1) {
789         [[[InvalidUseOfMethodException alloc] initWithFormat:
790             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
791             raise];
792     }
793     self->cLength = length;
794     memcpy(self->cString, byteString, length);
795     self->cString[length] = 0;
796     return self;
797 }
798 - (id)initWithCharacters:(const unichar *)chars length:(unsigned int)length
799 {
800     /* it must be ensured that char values are below 256 by the cluster ! */
801     register unsigned i;
802     if (self->cLength != -1) {
803         [[[InvalidUseOfMethodException alloc] initWithFormat:
804             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
805             raise];
806     }
807     
808     for (i = 0; i < length; i++)
809         self->cString[i] = chars[i];
810     self->cString[i] = '\0';
811     self->cLength = i;
812     return self;
813 }
814
815 #if COLLECT_STRING_CLUSTER_STATISTICS
816 - (void)dealloc
817 {
818     NSInline8BitString_dealloc_count++;
819     NSInline8BitString_total_len += self->cLength == -1 ? 0 : self->cLength;
820     [super dealloc];
821 }
822 #endif
823
824 - (const char *)cString
825 {
826     return (const char *)self->cString;
827 }
828
829 - (unsigned int)cStringLength
830 {
831     return (self->cLength == -1) ? 0 : self->cLength;
832 }
833
834 - (unsigned int)length
835 {
836     return (self->cLength == -1) ? 0 : self->cLength;
837 }
838
839 - (unichar)characterAtIndex:(unsigned int)index
840 {
841     if (self->cLength == -1 || (int)index >= self->cLength) {
842         [[[IndexOutOfRangeException alloc] 
843             initWithFormat:@"index %d out of range in string %x of length %d",
844                 index, self, self->cLength] raise];
845     }
846     // ENCODING
847     return self->cString[index];
848 }
849
850 - (NSString *)substringWithRange:(NSRange)aRange
851 {
852     if (aRange.location + aRange.length > (unsigned)self->cLength) {
853         [[[IndexOutOfRangeException alloc] 
854             initWithFormat:@"range (%d,%d) in string %x of length %d",
855                 aRange.location, aRange.length, self, cLength] raise];
856     }
857     if (aRange.length == 0)
858         return @"";
859
860     return AUTORELEASE([[NSRange8BitString alloc]
861                            initWithString:self
862                            bytes:((char *)self->cString + aRange.location)
863                            length:aRange.length]);
864 }
865
866 - (char *)__compact8BitBytes
867 {
868     return (char *)self->cString;
869 }
870
871 - (unsigned)hash
872 {
873     register unsigned char *bytes;
874     register unsigned      hash = 0, hash2;
875     int i, n;
876     
877     bytes = self->cString;
878     n     = (self->cLength == -1) ? 0 : self->cLength;
879     
880     for (i = 0; i < n; i++) {
881         hash <<= 4;
882         // UNICODE - must use a for independent of composed characters
883         hash += bytes[i];
884         if ((hash2 = hash & 0xf0000000))
885             hash ^= (hash2 >> 24) ^ hash2;
886     }
887     
888     return hash;
889 }
890
891 @end /* NSInline8BitString */
892
893 @implementation NSShortInline8BitString /* final */
894
895 + (id)allocForCapacity:(unsigned int)capacity zone:(NSZone*)zone
896 {
897     NSShortInline8BitString *str = (NSShortInline8BitString *)
898         NSAllocateObject(self, capacity, zone);
899     str->cLength = 255;
900     return str;
901 }
902
903 - (id)init
904 {
905     if (self->cLength != 255) {
906         [[[InvalidUseOfMethodException alloc] initWithFormat:
907             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
908             raise];
909     }
910     self->cLength = 0;
911     self->cString[0] = 0;
912     return self;
913 }
914
915 - (id)initWithCString:(const char*)byteString length:(unsigned int)length
916 {
917     if (self->cLength != 255) {
918         [[[InvalidUseOfMethodException alloc] initWithFormat:
919             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
920             raise];
921     }
922     self->cLength = length;
923     memcpy(self->cString, byteString, length);
924     self->cString[length] = 0;
925     return self;
926 }
927 - (id)initWithCharacters:(const unichar *)chars length:(unsigned int)length
928 {
929     /* it must be ensured that char values are below 256 by the cluster ! */
930     register unsigned i;
931     if (self->cLength != 255) {
932         [[[InvalidUseOfMethodException alloc] initWithFormat:
933             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
934             raise];
935     }
936     
937     for (i = 0; i < length; i++)
938         self->cString[i] = chars[i];
939     self->cString[i] = '\0';
940     self->cLength = i;
941     return self;
942 }
943
944 #if COLLECT_STRING_CLUSTER_STATISTICS
945 - (void)dealloc
946 {
947     NSShortInline8BitString_dealloc_count++;
948     NSShortInline8BitString_total_len +=
949         self->cLength == 255 ? 0 : self->cLength;
950     [super dealloc];
951 }
952 #endif
953
954 - (const char *)cString
955 {
956     return (const char *)self->cString;
957 }
958
959 - (unsigned int)cStringLength
960 {
961     return (self->cLength == 255) ? 0 : self->cLength;
962 }
963
964 - (unsigned int)length
965 {
966     return (self->cLength == 255) ? 0 : self->cLength;
967 }
968
969 - (unichar)characterAtIndex:(unsigned int)index
970 {
971     if ((self->cLength == 255) || (index >= self->cLength)) {
972         [[[IndexOutOfRangeException alloc] 
973             initWithFormat:@"index %d out of range in string %x of length %d",
974                 index, self, self->cLength] raise];
975     }
976     // ENCODING
977     return self->cString[index];
978 }
979
980 #if PERF_SHTIN_USE_OWN_GETCHARS
981 - (void)getCharacters:(unichar *)buffer
982 {
983     register signed short i;
984     
985     i = self->cLength;
986     if ((i == 255) || (i == 0)) /* empty string */
987         return;
988     
989     for (i--; i >= 0; i--)
990         buffer[i] = (unichar)(self->cString[i]);
991 }
992 - (void)getCharacters:(unichar *)buffer range:(NSRange)aRange
993 {
994     register unsigned int i = 0, l;
995     
996     i = aRange.location;
997     l = i + aRange.length;
998     if (l > ((self->cLength == 255) ? 0 : self->cLength)) {
999         [[[IndexOutOfRangeException alloc] 
1000             initWithFormat:@"range (%d,%d) in string %x of length %d",
1001                 aRange.location, aRange.length, self, [self length]] raise];
1002     }
1003     
1004     for (; i < l; i++)
1005         buffer[i] = (unichar)(self->cString[i]);
1006 }
1007 #endif
1008
1009 - (NSString *)substringWithRange:(NSRange)aRange
1010 {
1011     if (aRange.location + aRange.length > self->cLength)
1012         [[[IndexOutOfRangeException alloc] 
1013             initWithFormat:@"range (%d,%d) in string %x of length %d",
1014                 aRange.location, aRange.length, self, cLength] raise];
1015
1016     if (aRange.length == 0)
1017         return @"";
1018
1019     return AUTORELEASE([[NSRange8BitString alloc]
1020                            initWithString:self
1021                            bytes:((char *)self->cString + aRange.location)
1022                            length:aRange.length]);
1023 }
1024
1025 - (char *)__compact8BitBytes
1026 {
1027     return (char *)self->cString;
1028 }
1029
1030 - (NSComparisonResult)compare:(NSString *)aString
1031   options:(unsigned int)mask range:(NSRange)aRange
1032 {
1033     // ENCODINGS - this code applies to the system's default encoding
1034     register unsigned char *mbytes, *abytes;
1035     register Class clazz;
1036     unsigned int   i, n, a;
1037     
1038 #if 1 /* optimized */
1039     if (aString == nil) /* TODO: hh: AFAIK nil is not allowed in Cocoa? */
1040         return NSOrderedDescending;
1041     else if (aString == self)
1042         return NSOrderedSame;
1043     i = 0;
1044     for (clazz = *(id *)aString; clazz; clazz = class_get_super_class(clazz)) {
1045         if (clazz == NS8BitStringClass || clazz == NSMutable8BitStringClass) {
1046             i = 1;
1047             break;
1048         }
1049     }
1050     if (i == 0)
1051         return [super compare:aString options:mask range:aRange];
1052 #else
1053     if (![aString isKindOfClass:NS8BitStringClass] &&
1054         ![aString isKindOfClass:NSMutable8BitStringClass]) {
1055         return [super compare:aString options:mask range:aRange];
1056     }
1057 #endif
1058     
1059     if ((aRange.location + aRange.length) > 
1060         ((self->cLength == 255) ? 0 : self->cLength)) {
1061         [[[IndexOutOfRangeException alloc] 
1062             initWithFormat:@"range (%d,%d) in string %x of length %d",
1063                 aRange.location, aRange.length, self, [self cStringLength]]
1064             raise];
1065     }
1066
1067     mbytes = self->cString + aRange.location;
1068     abytes = (unsigned char *)[(id)aString __compact8BitBytes];
1069     
1070     a = [aString cStringLength];
1071     n = MIN(a, aRange.length);
1072     
1073     if (mask & NSCaseInsensitiveSearch) {
1074         for (i = 0; i < n; i++) {
1075             register unsigned char cm = 
1076                 islower(mbytes[i]) ? toupper(mbytes[i]):mbytes[i];
1077             register unsigned char ca = 
1078                 islower(abytes[i]) ? toupper(abytes[i]):abytes[i];
1079
1080             if (cm < ca)
1081                 return NSOrderedAscending;
1082             if (cm > ca)
1083                 return NSOrderedDescending;
1084         }
1085     }
1086     else {
1087         for (i = 0; i < n; i++) {
1088             if (mbytes[i] < abytes[i])
1089                 return NSOrderedAscending;
1090             if (mbytes[i] > abytes[i])
1091                 return NSOrderedDescending;
1092         }
1093     }
1094     
1095     if (aRange.length < a)
1096         return NSOrderedAscending;
1097     if (aRange.length > a)
1098         return NSOrderedDescending;
1099
1100     return NSOrderedSame;
1101 }
1102
1103 #if PERF_SHTIN_USE_OWN_HASH
1104 - (unsigned)hash
1105 {
1106     /* 
1107        according to Valgrind this takes 3.13% of the runtime, can this be 
1108        further optimized without breaking dictionary performance due to
1109        broken hash values?
1110     */
1111     register unsigned char *bytes;
1112     register unsigned      hash = 0, hash2;
1113     register int i, n;
1114     
1115     bytes = self->cString;
1116     n     = (self->cLength == 255) ? 0 : self->cLength;
1117     
1118     for (i = 0; i < n; i++) {
1119         hash <<= 4;
1120         // UNICODE - must use a for independent of composed characters
1121         hash += bytes[i];
1122         if ((hash2 = hash & 0xf0000000))
1123             hash ^= (hash2 >> 24) ^ hash2;
1124     }
1125     
1126     return hash;
1127 }
1128 #endif
1129
1130 #if PERF_SHTIN_USE_OWN_EQUAL
1131 - (BOOL)isEqual:(id)aString
1132 {
1133     register unsigned char *mbytes, *abytes;
1134     register Class clazz;
1135     unsigned int   i, n, a;
1136     NSRange range;
1137     
1138     if (self == aString)
1139         return YES;
1140     else if (aString == nil)
1141         return NO;
1142     
1143     i = 0; n = 0;
1144     if (*(id *)aString == *(id *)self) { /* exactly the same class */
1145         i = 1; /* is NSString subclass             */
1146         n = 1; /* is 8-bit string subclass         */
1147         a = 1; /* is exactly the same string class */
1148     }
1149     else {
1150         a = 0;
1151         for (clazz=*(id *)aString; clazz; clazz=class_get_super_class(clazz)) {
1152             if (clazz==NS8BitStringClass || clazz==NSMutable8BitStringClass) {
1153                 i = 1; // is NSString subclass
1154                 n = 1; // is 8-bit string subclass
1155                 break;
1156             }
1157             if (clazz == NSStringClass) {
1158                 i = 1; // is NSString subclass 
1159                 n = 0; // is not an 8-bit string subclass
1160                 break;
1161             }
1162         }
1163         if (i == 0) // not a NSString subclass
1164             return NO;
1165     }
1166     range.length = (self->cLength == 255) ? 0 : self->cLength;
1167     if (n == 0) { // is not an 8-bit string subclass, use compare
1168         range.location = 0;
1169         return [self compare:aString options:0 range:range] == NSOrderedSame;
1170     }
1171     
1172     /* other string is 8 bit */
1173     
1174     if (a == 1) { /* exact string class, do not call method */
1175         a = (((NSShortInline8BitString *)aString)->cLength == 255) 
1176             ? 0 
1177             : ((NSShortInline8BitString *)aString)->cLength;
1178         if (a != range.length)
1179             /* strings differ in length */
1180             return NO;
1181     }
1182     else if ((a = [aString cStringLength]) != range.length)
1183         /* strings differ in length */
1184         return NO;
1185     
1186     /* same length */
1187     
1188     mbytes = self->cString;
1189     abytes = (unsigned char *)[(id)aString __compact8BitBytes];
1190     
1191     /* using memcmp is probably faster than looping on our own */
1192     return memcmp(self->cString, abytes, a) == 0 ? YES : NO;
1193 }
1194 #endif
1195
1196 @end /* NSShortInline8BitString */
1197
1198 @implementation NSCharacter8BitString /* final */
1199
1200 - (id)init
1201 {
1202     self->c[0] = '\0';
1203     self->c[1] = '\0';
1204     return self;
1205 }
1206
1207 - (id)initWithCString:(const char*)byteString length:(unsigned int)_length
1208 {
1209     if (_length != 1) {
1210         [[[InvalidUseOfMethodException alloc] initWithFormat:
1211             @"%@ can only handle a singe char", [self class]] raise];
1212     }
1213     self->c[0] = byteString[0];
1214     self->c[1] = '\0';
1215     
1216     return self;
1217 }
1218 - (id)initWithCharacters:(const unichar *)chars length:(unsigned int)_length
1219 {
1220     if (_length != 1) {
1221         [[[InvalidUseOfMethodException alloc] initWithFormat:
1222             @"%@ can only handle a singe char", [self class]] raise];
1223     }
1224     self->c[0] = (char)chars[0];
1225     self->c[1] = '\0';
1226     
1227     return self;
1228 }
1229
1230 - (const char *)cString
1231 {
1232     return (const char *)&(self->c[0]);
1233 }
1234
1235 - (unsigned int)cStringLength
1236 {
1237   return 1;
1238 }
1239
1240 - (unsigned int)length
1241 {
1242   return 1;
1243 }
1244
1245 - (unichar)characterAtIndex:(unsigned int)index
1246 {
1247     if (index != 0) {
1248         [[[IndexOutOfRangeException alloc] 
1249             initWithFormat:@"index %d out of range in string %x of length 1",
1250                 index, self] raise];
1251     }
1252     // ENCODING
1253     return self->c[0];
1254 }
1255
1256 - (NSString *)substringWithRange:(NSRange)aRange
1257 {
1258   if (aRange.location == 0 && aRange.length == 1)
1259     return self;
1260   if (aRange.length == 0)
1261     return @"";
1262
1263   [[[IndexOutOfRangeException alloc] 
1264           initWithFormat:@"range (%d,%d) in string %x of length 1",
1265           aRange.location, aRange.length, self] raise];
1266   return nil;
1267 }
1268
1269 - (char *)__compact8BitBytes
1270 {
1271     return (char *)&(self->c[0]);
1272 }
1273
1274 - (unsigned)hash
1275 {
1276     register unsigned hash = 0, hash2;
1277     
1278     hash <<= 4;
1279     // UNICODE - must use a for independent of composed characters
1280     hash += self->c[0];
1281     if ((hash2 = hash & 0xf0000000))
1282         hash ^= (hash2 >> 24) ^ hash2;
1283     
1284     return hash;
1285 }
1286
1287 @end /* NSCharacter8BitString */
1288
1289
1290 /*
1291  * String containing non-owned, zero termintated c-string
1292  */
1293
1294 @implementation NSNonOwned8BitString
1295
1296 - (id)init
1297 {
1298     if (self->cLength || self->cString) {
1299         [[[InvalidUseOfMethodException alloc] initWithFormat:
1300             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1301             raise];
1302     }
1303     self->cLength = 0;
1304     self->cString = (unsigned char *)"";
1305     return self;
1306 }
1307
1308 - (id)initWithCString:(char *)byteString
1309   length:(unsigned int)length copy:(BOOL)flag
1310 {
1311     if (self->cLength || self->cString) {
1312         [[[InvalidUseOfMethodException alloc] initWithFormat:
1313             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1314             raise];
1315     }
1316     if (flag) {
1317         [[[InvalidUseOfMethodException alloc] initWithFormat:
1318             @"cannot send %s with flag set to YES to %@ to instance", 
1319             sel_get_name(_cmd), NSStringFromClass([self class])] raise];
1320     }
1321     cLength = length;
1322     cString = (unsigned char *)byteString;
1323     return self;
1324 }
1325
1326 #if COLLECT_STRING_CLUSTER_STATISTICS
1327 - (void)dealloc
1328 {
1329     NSNonOwned8BitString_dealloc_count++;
1330     NSNonOwned8BitString_total_len += self->cLength;
1331     [super dealloc];
1332 }
1333 #endif
1334
1335 - (const char *)cString
1336 {
1337     return (const char *)self->cString;
1338 }
1339
1340 - (unsigned int)cStringLength
1341 {
1342     return self->cLength;
1343 }
1344
1345 - (unsigned int)length
1346 {
1347     return self->cLength;
1348 }
1349
1350 - (unichar)characterAtIndex:(unsigned int)index
1351 {
1352     if ((int)self->cLength == -1 || (index >= (unsigned)self->cLength)) {
1353         [[[IndexOutOfRangeException alloc] 
1354             initWithFormat:@"index %d out of range in string %x of length %d",
1355                 index, self, cLength] raise];
1356     }
1357     // ENCODING
1358     return self->cString[index];
1359 }
1360
1361 - (NSString *)substringWithRange:(NSRange)aRange
1362 {
1363     if (aRange.location + aRange.length > cLength) {
1364         [[[IndexOutOfRangeException alloc] 
1365                   initWithFormat:@"range (%d,%d) in string %x of length %d",
1366                   aRange.location, aRange.length, self, cLength] raise];
1367     }
1368     
1369     if (aRange.length == 0)
1370         return @"";
1371
1372     return AUTORELEASE([[NSRange8BitString alloc]
1373                            initWithString:self
1374                            bytes:(char *)cString + aRange.location
1375                            length:aRange.length]);
1376 }
1377
1378 - (char *)__compact8BitBytes
1379 {
1380     return (char *)self->cString;
1381 }
1382
1383 @end /* NSNonOwned8BitString */
1384
1385 @implementation NSOwned8BitString
1386
1387 - (id)init
1388 {
1389     if (self->cLength || self->cString) {
1390         [[[InvalidUseOfMethodException alloc] initWithFormat:
1391             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
1392             raise];
1393     }
1394
1395     self->cLength = 0;
1396     self->cString = NSZoneMallocAtomic([self zone], sizeof(char));
1397     self->cString[0] = 0;
1398     return self;
1399 }
1400
1401 - (id)initWithCString:(char*)byteString
1402   length:(unsigned int)length
1403   copy:(BOOL)flag
1404 {
1405     if (self->cLength != 0 || self->cString != NULL) {
1406         [[[InvalidUseOfMethodException alloc] initWithFormat:
1407             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1408             raise];
1409     }
1410
1411     self->cLength = length;
1412     if (flag) {
1413         self->cString = NSZoneMallocAtomic([self zone], sizeof(char)*(length+1));
1414         memcpy(self->cString, byteString, length);
1415         self->cString[self->cLength] = 0;
1416     }
1417     else
1418         self->cString = (unsigned char *)byteString;
1419     return self;
1420 }
1421
1422 - (void)dealloc
1423 {
1424 #if COLLECT_STRING_CLUSTER_STATISTICS
1425     NSOwned8BitString_dealloc_count++;
1426     NSOwned8BitString_total_len += self->cLength;
1427 #endif
1428     lfFree(self->cString);
1429     [super dealloc];
1430 }
1431
1432 @end /* NSOwned8BitString */
1433
1434
1435 #define USE_LIB_FOUNDATION_CUSTOM_CONSTSTR 1
1436 #define USE_LIB_FOUNDATION_CONSTSTR 1
1437
1438 #if USE_LIB_FOUNDATION_CONSTSTR
1439
1440 #if USE_LIB_FOUNDATION_CUSTOM_CONSTSTR
1441 #  define NXConstantString NSConstantString
1442 #endif
1443
1444 /* this requires that we use the special libFoundation libobjc */
1445 @implementation NXConstantString
1446
1447 - (oneway void)release
1448 {
1449 }
1450
1451 - (id)retain
1452 {
1453     return self;
1454 }
1455
1456 - (unsigned)retainCount
1457 {
1458     return 1;
1459 }
1460
1461 - (id)autorelease
1462 {
1463     return self;
1464 }
1465
1466 - (void)dealloc
1467 {
1468     [self shouldNotImplement:_cmd];
1469
1470     /* this is to please gcc 4.1 which otherwise issues a warning (and we
1471        don't know the -W option to disable it, let me know if you do ;-)*/
1472     if (0) [super dealloc];
1473 }
1474
1475 @end /* NXConstantString */
1476
1477 #if USE_LIB_FOUNDATION_CUSTOM_CONSTSTR
1478 #  undef NXConstantString
1479 #endif
1480
1481 #else
1482
1483 #warning NOT USING BUILTIN NXConstantString
1484
1485 @interface DummyNXConstantString : NSNonOwned8BitString
1486 @end
1487
1488 @implementation DummyNXConstantString
1489 - (oneway void)release
1490 {
1491 }
1492
1493 - (id)retain
1494 {
1495     return self;
1496 }
1497
1498 - (unsigned)retainCount
1499 {
1500     return 1;
1501 }
1502
1503 - (id)autorelease
1504 {
1505     return self;
1506 }
1507
1508 - (void)dealloc
1509 {
1510     [self shouldNotImplement:_cmd];
1511 }
1512
1513 + (void)load
1514 {
1515     static BOOL didLoad = NO;
1516
1517 #warning DEBUG LOG
1518     printf("LOAD DUMMY\n");
1519
1520     if (!didLoad) {
1521         Class metaClass;
1522         Class constantStringClass;
1523         Class constantStringMetaClass;
1524
1525         didLoad = YES;
1526         
1527         metaClass               = ((DummyNXConstantString*)self)->isa;
1528         constantStringClass     = objc_lookup_class ("NXConstantString");
1529         constantStringMetaClass = constantStringClass->class_pointer;
1530         
1531         memcpy(constantStringClass,     self,      sizeof (struct objc_class));
1532         memcpy(constantStringMetaClass, metaClass, sizeof (struct objc_class));
1533         
1534         constantStringClass->name
1535             = constantStringMetaClass->name
1536             = "NXConstantString";
1537         
1538         /* 
1539            Note: this doesn't work for dynamically loaded NSString categories,
1540                  that is categories either contained in bundles OR in libraries
1541                  which are loaded on-demand in case a bundle is loaded.
1542         */
1543         class_add_behavior(constantStringClass, self);
1544     }
1545 }
1546
1547 @end /* DummyNXConstantString */
1548 #endif
1549
1550 @implementation NSNonOwnedOpen8BitString
1551
1552 #if COLLECT_STRING_CLUSTER_STATISTICS
1553 - (void)dealloc
1554 {
1555     NSNonOwnedOpen8BitString_dealloc_count++;
1556     NSNonOwnedOpen8BitString_total_len += self->cLength;
1557     [super dealloc];
1558 }
1559 #endif
1560
1561 - (const char *)cString
1562 {
1563     unsigned char *str;
1564     
1565     str = NSZoneMallocAtomic([self zone], sizeof(char)*(self->cLength + 1));
1566     memcpy(str, self->cString, self->cLength);
1567     str[cLength] = 0;
1568 #if !LIB_FOUNDATION_BOEHM_GC
1569     [NSAutoreleasedPointer autoreleasePointer:str];
1570 #endif
1571     return (const char *)str;
1572 }
1573
1574 @end /* NSNonOwnedOpen8BitString */
1575
1576 @implementation NSOwnedOpen8BitString /* final */
1577
1578 #if COLLECT_STRING_CLUSTER_STATISTICS
1579 - (void)dealloc
1580 {
1581     NSOwnedOpen8BitString_dealloc_count++;
1582     NSOwnedOpen8BitString_total_len += self->cLength;
1583     [super dealloc];
1584 }
1585 #endif
1586
1587 - (id)initWithCString:(char *)byteString
1588   length:(unsigned int)length copy:(BOOL)flag
1589 {
1590     if (self->cLength || self->cString) {
1591         [[[InvalidUseOfMethodException alloc] initWithFormat:
1592             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)] 
1593             raise];
1594     }
1595     if (length != 0 && byteString == NULL) {
1596         [[[InvalidUseOfMethodException alloc] initWithFormat:
1597             @"passed NULL cstring to %s with a non-null length (%i)!", 
1598             sel_get_name(_cmd), length]
1599             raise];
1600     }
1601     
1602     if (strlen(byteString) < length) {
1603         printf("LENGTH DIFFERS: %ld vs %d\n", 
1604                (unsigned long)strlen(byteString), length);
1605         abort();
1606     }
1607     
1608     self->cLength = length;
1609     if (flag) {
1610         /* TODO: this is not tracked in dealloc? */
1611         self->cString = 
1612             NSZoneMallocAtomic([self zone], sizeof(char)*(length + 1));
1613         memcpy(cString, byteString, length);
1614         cString[length] = 0;
1615     }
1616     else
1617         self->cString = (unsigned char *)byteString;
1618     return self;
1619 }
1620
1621 - (const char *)cString
1622 {
1623     unsigned char *str = MallocAtomic(sizeof(char)*(self->cLength + 1));
1624     
1625     memcpy(str, self->cString, self->cLength);
1626     str[self->cLength] = 0;
1627 #if !LIB_FOUNDATION_BOEHM_GC
1628     [NSAutoreleasedPointer autoreleasePointer:str];
1629 #endif
1630     return (const char *)str;
1631 }
1632
1633 @end /* NSOwnedOpen8BitString */
1634
1635
1636 @implementation NSRange8BitString /* final */
1637
1638 - (id)initWithString:(NSString *)aParent 
1639   bytes:(char *)bytes length:(unsigned int)length
1640 {
1641     if (self->cLength != 0 || self->cString != NULL) {
1642         [[[InvalidUseOfMethodException alloc] initWithFormat:
1643             @"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1644             raise];
1645     }
1646     
1647     self->cString = (unsigned char *)bytes;
1648     self->cLength = length;
1649     self->parent  = RETAIN(aParent);
1650     return self;
1651 }
1652
1653 - (void)dealloc
1654 {
1655 #if COLLECT_STRING_CLUSTER_STATISTICS
1656     NSRange8BitString_dealloc_count++;
1657     NSRange8BitString_total_len += self->cLength;
1658 #endif
1659     RELEASE(self->parent);
1660     [super dealloc];
1661 }
1662
1663 - (NSString *)substringWithRange:(NSRange)aRange
1664 {
1665     if (aRange.location + aRange.length > cLength) {
1666         [[[IndexOutOfRangeException alloc] 
1667                   initWithFormat:@"range (%d,%d) in string %x of length %d",
1668                   aRange.location, aRange.length, self, cLength] raise];
1669     }
1670     
1671     if (aRange.length == 0)
1672         return @"";
1673
1674     return AUTORELEASE([[NSRange8BitString alloc] 
1675                            initWithString:parent
1676                            bytes:((char *)cString + aRange.location)
1677                            length:aRange.length]);
1678 }
1679
1680 - (unsigned)hash
1681 {
1682     register unsigned char *bytes;
1683     register unsigned      hash = 0, hash2;
1684     int i, n;
1685     
1686     bytes = self->cString;
1687     n     = self->cLength;
1688     
1689     for (i = 0; i < n; i++) {
1690         hash <<= 4;
1691         // UNICODE - must use a for independent of composed characters
1692         hash += bytes[i];
1693         if ((hash2 = hash & 0xf0000000))
1694             hash ^= (hash2 >> 24) ^ hash2;
1695     }
1696     
1697     return hash;
1698 }
1699
1700 @end /* NSRange8BitString */
1701
1702 /*
1703   Local Variables:
1704   c-basic-offset: 4
1705   tab-width: 8
1706   End:
1707 */