|
|
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.