|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.0 (the 'License'). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License."
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /*
25: NXReadWriteString.m
26: Copyright 1991, NeXT, Inc.
27: Responsibility:
28: */
29:
30: #ifndef KERNEL
31: #ifdef SHLIB
32: #import "shlib.h"
33: #endif SHLIB
34:
35: #import "NXStringPrivate.h"
36:
37: @implementation NXReadWriteString
38:
39: #define actStr ((struct {@defs(NXReadOnlyString);} *)actualString)
40:
41: - initFromCharactersNoCopy:(unichar *)chars length:(unsigned)len
42: {
43: return [self initFromCharactersNoCopy:chars length:len freeWhenDone:YES];
44: }
45:
46: // To allow for cheap creation of empty read/write strings (with init, say),
47: // we keep around an empty readonly string and hand out copies of it whenever
48: // necessary. A mutex could be used in the code below to prevent the one-time leak
49: // of one or more NXReadOnlyStrings. However, the chances of the leak are so small
50: // it's not clear we should bother.
51:
52: - initFromCharactersNoCopy:(unichar *)chars length:(unsigned)len freeWhenDone:(BOOL)flag
53: {
54: static NXReadOnlyString *emptyReadOnlyString = nil;
55: [super initFromCharactersNoCopy:chars length:len];
56: if (len == 0 && emptyReadOnlyString) {
57: actualString = [emptyReadOnlyString copy];
58: } else {
59: actualString = [[NXReadOnlyString allocFromZone:[self zone]] initFromCharactersNoCopy:len ? chars : NULL length:len freeWhenDone:flag];
60: if (len == 0 && !emptyReadOnlyString) { // ??? mutex could be used to prevent possible leak
61: emptyReadOnlyString = [actualString copy];
62: }
63: }
64: return self;
65: }
66:
67: - (unsigned)length
68: {
69: return actStr->_length;
70: }
71:
72: - (unichar)characterAt:(unsigned)loc
73: {
74: if (loc >= actStr->_length) BOUNDSERROR;
75: return actStr->characters[loc];
76: }
77:
78: - (unichar *)allocateCharacterBuffer:(unsigned)nChars
79: {
80: return NX_CHARALLOC(stringZone, nChars);
81: }
82:
83: - (void)getCharacters:(unichar *)buffer range:(NXRange)range
84: {
85: if (RNGLOC(range) + RNGLEN(range) > actStr->_length) BOUNDSERROR;
86: NX_CHARCOPY(actStr->characters + RNGLOC(range), buffer, RNGLEN(range));
87: }
88:
89: - (void)getCString:(char *)buffer maxLength:(unsigned)bytes range:(NXRange)range remainingRange:(NXRange *)leftover
90: {
91: #if CHARS_ARE_EIGHT_BIT
92: NXRange desiredRange = range;
93: unsigned cnt;
94: if (RNGLOC(range) + RNGLEN(range) > actStr->_length) BOUNDSERROR;
95: if (RNGLEN(range) > bytes) RNGLEN(range) = bytes;
96: for (cnt = 0; cnt < RNGLEN(range); cnt++) {
97: unichar ch = actStr->characters[RNGLOC(range) + cnt];
98: buffer[cnt] = (ch > 0x0ff) ? NX_UNREPRESENTABLE_CHARACTER : ch;
99: }
100: buffer[RNGLEN(range)] = 0;
101: if (leftover) {
102: RNGLOC(*leftover) = RNGLOC(desiredRange) + RNGLEN(range);
103: RNGLEN(*leftover) = RNGLEN(desiredRange) - RNGLEN(range);
104: }
105: #else
106: #warning getCString:maxLength:range:remainingRange: not implemented for Unicode
107: _NXStringErrorRaise (NXStringInternalError, "getCString:maxLength:range:remainingRange: not implemented for Unicode");
108: #endif
109: }
110:
111: // ??? Most of these methods simply forward the message onto the actualString, so we
112: // might just want to use forwarding here...
113:
114: - (NXComparisonResult)compare:string mask:(unsigned int)options table:(void *)table
115: {
116: return [actualString compare:string mask:options table:table];
117: }
118:
119: - (NXRange)findString:(NXString *)findStr range:(NXRange)fRange mask:(unsigned int)options table:(void *)table
120: {
121: return [actualString findString:findStr range:fRange mask:options table:table];
122: }
123:
124: - (unsigned)findCharacter:(unichar)ch range:(NXRange)fRange mask:(unsigned int)options table:(void *)table
125: {
126: return [actualString findCharacter:ch range:fRange mask:options table:NULL];
127: }
128:
129: - (unsigned)findOneOf:(NXCharacterSet *)set range:(NXRange)fRange mask:(unsigned int)options table:(void *)table
130: {
131: return [actualString findOneOf:set range:fRange mask:options table:table];
132: }
133:
134: - (unsigned)hash
135: {
136: return [actualString hash];
137: }
138:
139: - (void)replaceCharactersInRange:(NXRange)range withString:(NXString *)string
140: {
141: unsigned int newLength, len = [self length], otherLength = [string length];
142: unichar *newBuffer;
143: NXRange strRange = {0, otherLength};
144:
145: if (RNGLOC(range) + RNGLEN(range) > len) BOUNDSERROR;
146:
147: newLength = len + otherLength - RNGLEN(range);
148: newBuffer = [self allocateCharacterBuffer:newLength];
149:
150: // Copy the three chunks into the new buffer
151:
152: NX_CHARCOPY (actStr->characters, newBuffer, RNGLOC(range));
153: [string getCharacters:(newBuffer + RNGLOC(range)) range:strRange];
154: NX_CHARCOPY (actStr->characters + (RNGLOC(range) + RNGLEN(range)), newBuffer + RNGLOC(range) + otherLength, (len - (RNGLOC(range) + RNGLEN(range))));
155:
156: // Now the new buffer is created. See what we do with the old one...
157:
158: if (actStr->_flags.refs > 1) {
159: actStr->_flags.refs -= 1;
160: actualString = [[NXReadOnlyString allocFromZone:[self zone]] initFromCharactersNoCopy:newBuffer length:newLength freeWhenDone:YES];
161: } else {
162: if (!actStr->_flags.notCopied) {
163: free (actStr->characters);
164: }
165: actStr->_length = newLength;
166: actStr->characters = newBuffer;
167: }
168: }
169:
170: - copyFromZone:(NXZone *)zone
171: {
172: NXReadWriteString *newInstance = [super copyFromZone:zone];
173: newInstance->actualString = [actualString copy];
174: return newInstance;
175: }
176:
177: - immutableCopyFromZone:(NXZone *)zone
178: {
179: return [actualString copyFromZone:zone];
180: }
181:
182: - free
183: {
184: [actualString free];
185: return [super free];
186: }
187:
188: - write:(NXTypedStream *)s
189: {
190: [super write:s];
191: NXWriteObject (s, actualString);
192: return self;
193: }
194:
195: - read:(NXTypedStream *)s
196: {
197: [super read:s];
198: actualString = NXReadObject (s);
199: return self;
200: }
201:
202: // We want to make sure the object itself comes out of the string zone
203: // and not some random area which might be deallocated later...
204:
205: - finishUnarchiving
206: {
207: id actual = nil;
208: if ([self zone] != stringZone) {
209: actual = object_copyFromZone (self, 0, stringZone);
210: object_dispose(self);
211: }
212: return actual;
213: }
214:
215:
216: @end
217: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.