2001-12-17 14:31:42 +00:00
|
|
|
|
/** Implementation for GNUStep of NSString concrete subclasses
|
2000-10-09 05:32:50 +00:00
|
|
|
|
Copyright (C) 1997,1998,2000 Free Software Foundation, Inc.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
Base on code written by Stevo Crvenkovski <stevo@btinternet.com>
|
2000-10-09 05:32:50 +00:00
|
|
|
|
Date: February 1997
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
Based on NSGCString and NSString
|
|
|
|
|
Written by: Andrew Kachites McCallum
|
|
|
|
|
<mccallum@gnu.ai.mit.edu>
|
|
|
|
|
Date: March 1995
|
|
|
|
|
|
|
|
|
|
Optimised by Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
|
Date: October 1998
|
|
|
|
|
|
|
|
|
|
Redesign/rewrite by Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
|
Date: September 2000
|
|
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2000-10-09 05:32:50 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2019-12-09 23:36:00 +00:00
|
|
|
|
Lesser General Public License for more details.
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2000-10-09 05:32:50 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2006-05-22 10:09:34 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
2019-12-09 23:36:00 +00:00
|
|
|
|
Boston, MA 02110 USA.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
|
#import "common.h"
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "Foundation/NSArray.h"
|
2015-08-16 10:42:48 +00:00
|
|
|
|
#import "Foundation/NSCharacterSet.h"
|
|
|
|
|
#import "Foundation/NSCoder.h"
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "Foundation/NSData.h"
|
|
|
|
|
#import "Foundation/NSDictionary.h"
|
|
|
|
|
#import "Foundation/NSException.h"
|
2015-08-16 10:42:48 +00:00
|
|
|
|
#import "Foundation/NSHashTable.h"
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "Foundation/NSKeyedArchiver.h"
|
2015-08-16 10:42:48 +00:00
|
|
|
|
#import "Foundation/NSRange.h"
|
|
|
|
|
#import "Foundation/NSValue.h"
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "GNUstepBase/GSObjCRuntime.h"
|
2002-03-13 09:58:43 +00:00
|
|
|
|
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "GSPrivate.h"
|
2002-03-13 09:58:43 +00:00
|
|
|
|
|
2010-03-16 06:11:00 +00:00
|
|
|
|
#ifdef HAVE_MALLOC_H
|
2012-09-03 13:36:45 +00:00
|
|
|
|
#if !defined(__OpenBSD__)
|
2010-03-16 06:11:00 +00:00
|
|
|
|
#include <malloc.h>
|
|
|
|
|
#endif
|
2012-04-22 19:00:27 +00:00
|
|
|
|
#endif
|
2012-09-03 13:36:45 +00:00
|
|
|
|
|
2010-02-25 19:05:21 +00:00
|
|
|
|
#ifdef HAVE_ALLOCA_H
|
|
|
|
|
#include <alloca.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
/* memcpy(), strlen(), strcmp() are gcc builtin's */
|
|
|
|
|
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "GNUstepBase/Unicode.h"
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2011-11-01 09:43:25 +00:00
|
|
|
|
static NSStringEncoding externalEncoding = 0;
|
|
|
|
|
static NSStringEncoding internalEncoding = NSISOLatin1StringEncoding;
|
|
|
|
|
|
2006-10-09 14:00:01 +00:00
|
|
|
|
static BOOL isByteEncoding(NSStringEncoding enc)
|
|
|
|
|
{
|
2006-10-20 10:56:27 +00:00
|
|
|
|
return GSPrivateIsByteEncoding(enc);
|
2006-10-09 14:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-12 15:25:37 +00:00
|
|
|
|
#ifdef NeXT_RUNTIME
|
|
|
|
|
/* Used by the Darwin/NeXT ObjC Runtime
|
|
|
|
|
until Apple Radar 2870817 is fixed. */
|
2002-01-03 20:39:12 +00:00
|
|
|
|
struct objc_class _NSConstantStringClassReference;
|
2002-03-12 15:25:37 +00:00
|
|
|
|
#endif
|
2002-01-03 20:39:12 +00:00
|
|
|
|
|
2020-11-11 22:23:13 +00:00
|
|
|
|
/* Count the number of bytes that make up this UTF-8 code point.
|
|
|
|
|
This to keep in mind:
|
|
|
|
|
* This macro doesn't return anything larger than '4'
|
|
|
|
|
* Legal UTF-8 cannot be larger than 4 bytes long (0x10FFFF)
|
|
|
|
|
* It will return 0 for anything illegal
|
|
|
|
|
*/
|
|
|
|
|
#define UTF8_BYTE_COUNT(c) \
|
|
|
|
|
(((c) < 0xf8) ? 1 + ((c) >= 0xc0) + ((c) >= 0xe0) + ((c) >= 0xf0) : 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef GNUSTEP_NEW_STRING_ABI
|
2011-10-31 08:12:26 +00:00
|
|
|
|
/* Determine the length of the UTF-8 string as a unicode (UTF-16) string.
|
|
|
|
|
* sets the ascii flag according to the content found.
|
|
|
|
|
*/
|
|
|
|
|
static NSUInteger
|
|
|
|
|
lengthUTF8(const uint8_t *p, unsigned l, BOOL *ascii, BOOL *latin1)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t *e = p + l;
|
|
|
|
|
BOOL a = YES;
|
|
|
|
|
BOOL l1 = YES;
|
|
|
|
|
|
|
|
|
|
l = 0;
|
|
|
|
|
while (p < e)
|
|
|
|
|
{
|
|
|
|
|
uint8_t c = *p;
|
|
|
|
|
uint32_t u = c;
|
|
|
|
|
|
|
|
|
|
if (c > 0x7f)
|
|
|
|
|
{
|
|
|
|
|
int i, sle = 0;
|
|
|
|
|
|
|
|
|
|
a = NO;
|
|
|
|
|
/* calculated the expected sequence length */
|
|
|
|
|
while (c & 0x80)
|
|
|
|
|
{
|
|
|
|
|
c = c << 1;
|
|
|
|
|
sle++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* legal ? */
|
|
|
|
|
if ((sle < 2) || (sle > 6))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Bad sequence length in constant string"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p + sle > e)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Short data in constant string"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get the codepoint */
|
|
|
|
|
for (i = 1; i < sle; i++)
|
|
|
|
|
{
|
|
|
|
|
if (p[i] < 0x80 || p[i] >= 0xc0)
|
|
|
|
|
break;
|
|
|
|
|
u = (u << 6) | (p[i] & 0x3f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i < sle)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Codepoint out of range in constant string"];
|
|
|
|
|
}
|
|
|
|
|
u = u & ~(0xffffffff << ((5 * sle) + 1));
|
|
|
|
|
p += sle;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We check for invalid codepoints here.
|
|
|
|
|
*/
|
2016-10-05 17:44:00 +00:00
|
|
|
|
if (u > 0x10ffff)
|
2011-10-31 08:12:26 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Codepoint invalid in constant string"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((u >= 0xd800) && (u <= 0xdfff))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Bad surrogate pair in constant string"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Add codepoint as either a single unichar for BMP
|
|
|
|
|
* or as a pair of surrogates for codepoints over 16 bits.
|
|
|
|
|
*/
|
|
|
|
|
if (u < 0x10000)
|
|
|
|
|
{
|
|
|
|
|
l++;
|
|
|
|
|
if (u > 255)
|
|
|
|
|
{
|
|
|
|
|
l1 = NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
l += 2;
|
2017-07-10 08:16:27 +00:00
|
|
|
|
l1 = NO;
|
2011-10-31 08:12:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (0 != ascii)
|
|
|
|
|
{
|
|
|
|
|
*ascii = a;
|
|
|
|
|
}
|
|
|
|
|
if (0 != latin1)
|
|
|
|
|
{
|
|
|
|
|
*latin1 = l1;
|
|
|
|
|
}
|
|
|
|
|
return l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Sequentially extracts characters from UTF-8 string
|
|
|
|
|
* p = pointer to the utf-8 data
|
|
|
|
|
* l = length (bytes) of the utf-8 data
|
|
|
|
|
* o = pointer to current offset within the data
|
|
|
|
|
* n = pointer to either zero or the next pre-read part of a surrogate pair.
|
|
|
|
|
* The condition for having read the entire string is that the offset (*o)
|
|
|
|
|
* is the number of bytes in the string, and the unichar pointed to by *n
|
|
|
|
|
* is zero (meaning there is no second part of a surrogate pair remaining).
|
|
|
|
|
*/
|
|
|
|
|
static inline unichar
|
|
|
|
|
nextUTF8(const uint8_t *p, unsigned l, unsigned *o, unichar *n)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
/* If we still have the second part of a surrogate pair, return it.
|
|
|
|
|
*/
|
|
|
|
|
if (*n > 0)
|
|
|
|
|
{
|
|
|
|
|
unichar u = *n;
|
|
|
|
|
|
|
|
|
|
*n = 0;
|
|
|
|
|
return u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((i = *o) < l)
|
|
|
|
|
{
|
|
|
|
|
uint8_t c = p[i];
|
|
|
|
|
uint32_t u = c;
|
|
|
|
|
|
|
|
|
|
if (c > 0x7f)
|
|
|
|
|
{
|
|
|
|
|
int j, sle = 0;
|
|
|
|
|
|
|
|
|
|
/* calculated the expected sequence length */
|
2012-12-18 09:00:40 +00:00
|
|
|
|
sle = UTF8_BYTE_COUNT(c);
|
2011-10-31 08:12:26 +00:00
|
|
|
|
|
|
|
|
|
/* legal ? */
|
2012-12-18 09:00:40 +00:00
|
|
|
|
if (sle < 2)
|
2011-10-31 08:12:26 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"bad multibyte character length"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sle + i > l)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"multibyte character extends beyond data"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get the codepoint */
|
|
|
|
|
for (j = 1; j < sle; j++)
|
|
|
|
|
{
|
|
|
|
|
uint8_t b = p[i + j];
|
|
|
|
|
|
|
|
|
|
if (b < 0x80 || b >= 0xc0)
|
|
|
|
|
break;
|
|
|
|
|
u = (u << 6) | (b & 0x3f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (j < sle)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"bad data in multibyte character"];
|
|
|
|
|
}
|
|
|
|
|
u = u & ~(0xffffffff << ((5 * sle) + 1));
|
|
|
|
|
i += sle;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We discard invalid codepoints here.
|
|
|
|
|
*/
|
2016-10-05 17:44:00 +00:00
|
|
|
|
if (u > 0x10ffff)
|
2011-10-31 08:12:26 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"invalid unicode codepoint"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Add codepoint as either a single unichar for BMP
|
|
|
|
|
* or as a pair of surrogates for codepoints over 16 bits.
|
|
|
|
|
*/
|
|
|
|
|
if (u >= 0x10000)
|
|
|
|
|
{
|
|
|
|
|
unichar ul, uh;
|
|
|
|
|
|
|
|
|
|
u -= 0x10000;
|
|
|
|
|
ul = u & 0x3ff;
|
|
|
|
|
uh = (u >> 10) & 0x3ff;
|
|
|
|
|
|
|
|
|
|
*n = ul + 0xdc00; // record second part of pair
|
|
|
|
|
u = uh + 0xd800; // return first part.
|
|
|
|
|
}
|
|
|
|
|
*o = i; // Return new index
|
|
|
|
|
return (unichar)u;
|
|
|
|
|
}
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"no more data in UTF-8 string"];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-11-11 22:23:13 +00:00
|
|
|
|
#endif
|
2011-10-31 08:12:26 +00:00
|
|
|
|
|
2011-11-01 09:43:25 +00:00
|
|
|
|
static BOOL
|
|
|
|
|
literalIsEqualInternal(NXConstantString *s, GSStr o)
|
|
|
|
|
{
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifdef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
if (s->nxcslen != o->_count)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
size_t end = s->nxcslen;
|
|
|
|
|
static const int buffer_size = 64;
|
|
|
|
|
unichar buffer1[buffer_size];
|
|
|
|
|
unichar buffer2[buffer_size];
|
|
|
|
|
NSRange r = { 0, buffer_size };
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (r.location + r.length > end)
|
|
|
|
|
{
|
|
|
|
|
r.length = s->nxcslen - r.location;
|
|
|
|
|
}
|
|
|
|
|
[s getCharacters: buffer1 range: r];
|
|
|
|
|
[o getCharacters: buffer2 range: r];
|
|
|
|
|
if (memcmp(buffer1, buffer2, r.length * sizeof(unichar)) != 0)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
r.location += buffer_size;
|
|
|
|
|
} while (r.location < end);
|
|
|
|
|
return YES;
|
|
|
|
|
#else
|
2011-11-01 09:43:25 +00:00
|
|
|
|
unsigned len = o->_count;
|
|
|
|
|
|
|
|
|
|
/* Since UTF-8 is a multibyte character set, it must have at least
|
|
|
|
|
* as many bytes as another string of the same length. So if the
|
|
|
|
|
* UTF-8 string is shorter, the two cannot be equal.
|
|
|
|
|
* A check for this can quickly give us a result in half the cases
|
|
|
|
|
* where the two strings have different lengths.
|
|
|
|
|
*/
|
|
|
|
|
if (len > s->nxcslen)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSUInteger pos = 0;
|
|
|
|
|
unichar n = 0;
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
unichar u;
|
|
|
|
|
|
|
|
|
|
if (0 == o->_flags.wide)
|
|
|
|
|
{
|
2011-11-01 11:43:40 +00:00
|
|
|
|
/* If the other string is a buffer containing ascii characters,
|
|
|
|
|
* we can perform a bytewise comparison.
|
2011-11-01 09:43:25 +00:00
|
|
|
|
*/
|
2011-11-01 11:43:40 +00:00
|
|
|
|
if (internalEncoding == NSASCIIStringEncoding)
|
2011-11-01 09:43:25 +00:00
|
|
|
|
{
|
2011-11-01 11:43:40 +00:00
|
|
|
|
if (len == s->nxcslen
|
|
|
|
|
&& 0 == memcmp(o->_contents.c, s->nxcsptr, len))
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2011-11-01 09:43:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-01 11:43:40 +00:00
|
|
|
|
/* If the other string is a buffer containing latin1 characters,
|
2011-11-01 09:43:25 +00:00
|
|
|
|
* we can compare buffer contents with unichar values directly.
|
|
|
|
|
*/
|
2011-11-01 11:43:40 +00:00
|
|
|
|
if (internalEncoding == NSISOLatin1StringEncoding)
|
2011-11-01 09:43:25 +00:00
|
|
|
|
{
|
|
|
|
|
while (i < s->nxcslen || n > 0)
|
|
|
|
|
{
|
|
|
|
|
u = nextUTF8((const uint8_t *)s->nxcsptr, s->nxcslen, &i, &n);
|
|
|
|
|
if (pos >= len || (unichar)o->_contents.c[pos] != u)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
pos++;
|
|
|
|
|
}
|
|
|
|
|
if (pos != len)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2011-11-01 11:43:40 +00:00
|
|
|
|
|
|
|
|
|
/* For any other narrow internal string, we know that ascii is
|
|
|
|
|
* a subset of the encoding, so as long as characters are ascii
|
|
|
|
|
* (don't have the top bit set) we can do bytewise comparison.
|
|
|
|
|
*/
|
|
|
|
|
if (len == s->nxcslen)
|
|
|
|
|
{
|
|
|
|
|
unsigned index;
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < len; index++)
|
|
|
|
|
{
|
|
|
|
|
uint8_t c = s->nxcsptr[index];
|
|
|
|
|
|
|
|
|
|
if (c != o->_contents.c[index] || c >= 128)
|
|
|
|
|
{
|
|
|
|
|
/* Characters differ at this point.
|
|
|
|
|
*/
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (index == len)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
/* The characters were the same up to 'index', so we won't
|
|
|
|
|
* need to recheck those first few characters.
|
|
|
|
|
*/
|
|
|
|
|
pos = i = index;
|
|
|
|
|
}
|
2011-11-01 09:43:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For small strings, or ones where we already have an array of
|
|
|
|
|
* UTF-16 characters, we can do a UTF-16 comparison directly.
|
|
|
|
|
* For larger strings, we may do as well with a character by
|
|
|
|
|
* character comparison.
|
|
|
|
|
*/
|
2011-11-01 11:43:40 +00:00
|
|
|
|
if (1 == o->_flags.wide || (len < 200 && pos < len))
|
2011-11-01 09:43:25 +00:00
|
|
|
|
{
|
|
|
|
|
unichar *ptr;
|
|
|
|
|
|
|
|
|
|
if (1 == o->_flags.wide)
|
|
|
|
|
{
|
|
|
|
|
ptr = o->_contents.u;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ptr = alloca(sizeof(unichar) * len);
|
|
|
|
|
if (NO == GSToUnicode(&ptr, &len, o->_contents.c,
|
|
|
|
|
len, internalEncoding, 0, 0))
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now we have a UTF-16 buffer, so we can do a UTF-16 comparison.
|
|
|
|
|
*/
|
|
|
|
|
while (i < s->nxcslen || n > 0)
|
|
|
|
|
{
|
|
|
|
|
u = nextUTF8((const uint8_t *)s->nxcsptr, s->nxcslen, &i, &n);
|
|
|
|
|
if (pos >= len || ptr[pos] != u)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
pos++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unichar (*imp)(id, SEL, NSUInteger);
|
|
|
|
|
|
|
|
|
|
/* Do a character by character comparison using characterAtIndex:
|
|
|
|
|
* This will be relatively slow, but how often will we actually
|
|
|
|
|
* need to do this for a literal string? Most string literals will
|
|
|
|
|
* either be short or will differ from any other string we are
|
|
|
|
|
* doing a comparison with within the first few tens of characters.
|
|
|
|
|
*/
|
|
|
|
|
imp = (unichar(*)(id,SEL,NSUInteger))[(id)o methodForSelector:
|
|
|
|
|
@selector(characterAtIndex:)];
|
|
|
|
|
while (i < s->nxcslen || n > 0)
|
|
|
|
|
{
|
|
|
|
|
u = nextUTF8((const uint8_t *)s->nxcsptr, s->nxcslen, &i, &n);
|
|
|
|
|
if (pos >= len
|
|
|
|
|
|| (*imp)((id)o, @selector(characterAtIndex:), pos) != u)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
pos++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (pos != len)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif
|
2011-11-01 09:43:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* GSPlaceholderString - placeholder class for objects awaiting intialisation.
|
|
|
|
|
*/
|
|
|
|
|
@interface GSPlaceholderString : NSString
|
|
|
|
|
{
|
2015-05-25 11:47:13 +00:00
|
|
|
|
NSZone *myZone;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
/*
|
2003-11-05 02:11:49 +00:00
|
|
|
|
GSString is the root class of our hierarchy of string classes. All our
|
|
|
|
|
classes except GSPlaceholderString inherit from it. GSString provides
|
|
|
|
|
the common part of the ivar layout. It also has safe implementations
|
|
|
|
|
of all the memory management methods subclasses should override.
|
|
|
|
|
|
|
|
|
|
Concrete subclasses of GSString are identified by two properties:
|
|
|
|
|
how the string is encoded (its structure; 8-bit data or 16-bit unicode
|
|
|
|
|
data), and how the memory for the contents is handled (its memory
|
|
|
|
|
management).
|
|
|
|
|
|
|
|
|
|
Two direct subclasses of GSString provide the code for the two structures.
|
|
|
|
|
The memory management part of the concrete subclasses is abstracted to
|
|
|
|
|
a single flag for the structure classes: free. This is set only if the
|
|
|
|
|
_contents buffer is guaranteed to remain valid at least until the instance
|
|
|
|
|
has been deallocated.
|
|
|
|
|
|
|
|
|
|
Many optimizations, such as retaining instead of copying, and using pointers
|
|
|
|
|
to another strings _contents buffer, are valid only if this flag is set.
|
|
|
|
|
|
|
|
|
|
GSCString, an abstract class that stores the string as 8-bit data in the
|
2004-06-05 10:06:56 +00:00
|
|
|
|
internal encoding.
|
2003-11-05 02:11:49 +00:00
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
@interface GSCString : GSString
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
/*
|
2003-11-05 02:11:49 +00:00
|
|
|
|
And GSUnicodeString, an abstract class that stores the string as 16-bit
|
|
|
|
|
unicode characters.
|
|
|
|
|
*/
|
|
|
|
|
@interface GSUnicodeString : GSString
|
2000-10-29 14:52:33 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2000-10-29 14:52:33 +00:00
|
|
|
|
/*
|
2003-11-05 02:11:49 +00:00
|
|
|
|
For each memory management scheme, there is a pair of concrete subclasses
|
|
|
|
|
of the two abstract structure classes. Each subclass has a single -init...
|
|
|
|
|
method which can be used to initialize that specific subclass.
|
|
|
|
|
|
|
|
|
|
GS*BufferString, concrete subclasses that store the data in an external
|
|
|
|
|
(wrt. the instance itself) buffer. The buffer may or may not be owned
|
2009-04-10 08:25:03 +00:00
|
|
|
|
by the instance; the 'owned' flag indicates which. If it is set,
|
|
|
|
|
we may need to free the buffer when we are deallocated.
|
2003-11-05 02:11:49 +00:00
|
|
|
|
*/
|
|
|
|
|
@interface GSCBufferString : GSCString
|
2000-10-20 10:30:51 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2003-11-05 02:11:49 +00:00
|
|
|
|
@interface GSUnicodeBufferString : GSUnicodeString
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2000-10-29 14:52:33 +00:00
|
|
|
|
/*
|
2003-11-05 02:11:49 +00:00
|
|
|
|
GS*InlineString, concrete subclasses that store the data immediately after
|
|
|
|
|
the instance iself.
|
|
|
|
|
*/
|
|
|
|
|
@interface GSCInlineString : GSCString
|
2000-11-03 10:11:56 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
@interface GSUInlineString : GSUnicodeString
|
2000-10-29 14:52:33 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
/*
|
2003-11-05 02:11:49 +00:00
|
|
|
|
GS*SubString, concrete subclasses that use the data in another string
|
|
|
|
|
instance.
|
|
|
|
|
*/
|
|
|
|
|
@interface GSCSubString : GSCString
|
|
|
|
|
{
|
|
|
|
|
@public
|
2006-08-15 04:51:18 +00:00
|
|
|
|
GSString *_parent;
|
2003-11-05 02:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
@interface GSUnicodeSubString : GSUnicodeString
|
2000-10-20 10:30:51 +00:00
|
|
|
|
{
|
|
|
|
|
@public
|
2006-08-15 04:51:18 +00:00
|
|
|
|
GSString *_parent;
|
2000-10-20 10:30:51 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
/*
|
|
|
|
|
* Include sequence handling code with instructions to generate search
|
|
|
|
|
* and compare functions for NSString objects.
|
|
|
|
|
*/
|
|
|
|
|
#define GSEQ_STRCOMP strCompUsNs
|
|
|
|
|
#define GSEQ_STRRANGE strRangeUsNs
|
|
|
|
|
#define GSEQ_O GSEQ_NS
|
|
|
|
|
#define GSEQ_S GSEQ_US
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "GSeq.h"
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
#define GSEQ_STRCOMP strCompUsUs
|
|
|
|
|
#define GSEQ_STRRANGE strRangeUsUs
|
|
|
|
|
#define GSEQ_O GSEQ_US
|
|
|
|
|
#define GSEQ_S GSEQ_US
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "GSeq.h"
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
#define GSEQ_STRCOMP strCompUsCs
|
|
|
|
|
#define GSEQ_STRRANGE strRangeUsCs
|
|
|
|
|
#define GSEQ_O GSEQ_CS
|
|
|
|
|
#define GSEQ_S GSEQ_US
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "GSeq.h"
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
#define GSEQ_STRCOMP strCompCsNs
|
|
|
|
|
#define GSEQ_STRRANGE strRangeCsNs
|
|
|
|
|
#define GSEQ_O GSEQ_NS
|
|
|
|
|
#define GSEQ_S GSEQ_CS
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "GSeq.h"
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
#define GSEQ_STRCOMP strCompCsUs
|
|
|
|
|
#define GSEQ_STRRANGE strRangeCsUs
|
|
|
|
|
#define GSEQ_O GSEQ_US
|
|
|
|
|
#define GSEQ_S GSEQ_CS
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "GSeq.h"
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
#define GSEQ_STRCOMP strCompCsCs
|
|
|
|
|
#define GSEQ_STRRANGE strRangeCsCs
|
|
|
|
|
#define GSEQ_O GSEQ_CS
|
|
|
|
|
#define GSEQ_S GSEQ_CS
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "GSeq.h"
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2008-07-15 06:57:01 +00:00
|
|
|
|
#define GSEQ_STRRANGE strRangeNsNs
|
|
|
|
|
#define GSEQ_O GSEQ_NS
|
|
|
|
|
#define GSEQ_S GSEQ_NS
|
|
|
|
|
#include "GSeq.h"
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
static Class NSDataClass = 0;
|
|
|
|
|
static Class NSStringClass = 0;
|
2000-10-20 10:30:51 +00:00
|
|
|
|
static Class GSStringClass = 0;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
static Class GSCStringClass = 0;
|
2003-11-05 02:11:49 +00:00
|
|
|
|
static Class GSCBufferStringClass = 0;
|
2000-10-29 14:52:33 +00:00
|
|
|
|
static Class GSCInlineStringClass = 0;
|
2000-10-20 10:30:51 +00:00
|
|
|
|
static Class GSCSubStringClass = 0;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
static Class GSUnicodeStringClass = 0;
|
2003-11-05 02:11:49 +00:00
|
|
|
|
static Class GSUnicodeBufferStringClass = 0;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
static Class GSUnicodeSubStringClass = 0;
|
2012-08-08 09:46:08 +00:00
|
|
|
|
static Class GSUInlineStringClass = 0;
|
2020-11-22 14:55:39 +00:00
|
|
|
|
static Class GSImmutableStringClass = 0;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
static Class GSMutableStringClass = 0;
|
2001-06-06 15:18:28 +00:00
|
|
|
|
static Class NSConstantStringClass = 0;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2002-02-06 13:44:03 +00:00
|
|
|
|
static SEL cMemberSel;
|
2000-10-30 18:00:27 +00:00
|
|
|
|
static SEL convertSel;
|
|
|
|
|
static BOOL (*convertImp)(id, SEL, NSStringEncoding);
|
|
|
|
|
static SEL equalSel;
|
|
|
|
|
static BOOL (*equalImp)(id, SEL, id);
|
|
|
|
|
static SEL hashSel;
|
2010-09-12 17:05:30 +00:00
|
|
|
|
static NSUInteger (*hashImp)(id, SEL);
|
2020-11-22 14:55:39 +00:00
|
|
|
|
static Ivar immutableIvar;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* The setup() function is called when any concrete string class is
|
2002-02-06 13:44:03 +00:00
|
|
|
|
* initialized, and caches classes and some method implementations.
|
2000-10-20 10:30:51 +00:00
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
static void
|
2010-07-19 17:10:46 +00:00
|
|
|
|
setup(BOOL rerun)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
static BOOL beenHere = NO;
|
|
|
|
|
|
2010-07-19 17:10:46 +00:00
|
|
|
|
if (!beenHere || rerun)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
beenHere = YES;
|
|
|
|
|
|
2008-07-15 06:57:01 +00:00
|
|
|
|
caiSel = @selector(characterAtIndex:);
|
|
|
|
|
gcrSel = @selector(getCharacters:range:);
|
|
|
|
|
ranSel = @selector(rangeOfComposedCharacterSequenceAtIndex:);
|
|
|
|
|
|
2006-10-09 14:00:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* Cache the default string encoding, and set the internal encoding
|
|
|
|
|
* used by 8-bit character strings to match if possible.
|
|
|
|
|
*/
|
2006-10-20 10:56:27 +00:00
|
|
|
|
externalEncoding = GSPrivateDefaultCStringEncoding();
|
2006-10-09 14:00:01 +00:00
|
|
|
|
if (isByteEncoding(externalEncoding) == YES)
|
|
|
|
|
{
|
|
|
|
|
internalEncoding = externalEncoding;
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* Cache pointers to classes to work round misfeature in
|
|
|
|
|
* GNU compiler/runtime system where class lookup is very slow.
|
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
NSDataClass = [NSData class];
|
|
|
|
|
NSStringClass = [NSString class];
|
2000-10-20 10:30:51 +00:00
|
|
|
|
GSStringClass = [GSString class];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
GSCStringClass = [GSCString class];
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSUnicodeStringClass = [GSUnicodeString class];
|
2003-11-05 02:11:49 +00:00
|
|
|
|
GSCBufferStringClass = [GSCBufferString class];
|
|
|
|
|
GSUnicodeBufferStringClass = [GSUnicodeBufferString class];
|
2000-10-29 14:52:33 +00:00
|
|
|
|
GSCInlineStringClass = [GSCInlineString class];
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineStringClass = [GSUInlineString class];
|
2000-10-20 10:30:51 +00:00
|
|
|
|
GSCSubStringClass = [GSCSubString class];
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSUnicodeSubStringClass = [GSUnicodeSubString class];
|
|
|
|
|
GSMutableStringClass = [GSMutableString class];
|
2002-10-02 13:29:54 +00:00
|
|
|
|
NSConstantStringClass = [NXConstantString class];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2020-11-22 14:55:39 +00:00
|
|
|
|
/* This comes from the base additions library. The instance variable
|
|
|
|
|
* pointing to the original mutable string is not public, but we want
|
|
|
|
|
* to use it efficiently.
|
|
|
|
|
*/
|
|
|
|
|
GSImmutableStringClass = NSClassFromString(@"GSImmutableString");
|
|
|
|
|
immutableIvar
|
|
|
|
|
= class_getInstanceVariable(GSImmutableStringClass, "_parent");
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* Cache some selectors and method implementations for
|
|
|
|
|
* cases where we want to use the implementation
|
|
|
|
|
* provided in the abstract rolot cllass of the cluster.
|
|
|
|
|
*/
|
2002-02-06 13:44:03 +00:00
|
|
|
|
cMemberSel = @selector(characterIsMember:);
|
2000-10-30 18:00:27 +00:00
|
|
|
|
convertSel = @selector(canBeConvertedToEncoding:);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
convertImp = (BOOL (*)(id, SEL, NSStringEncoding))
|
|
|
|
|
[NSStringClass instanceMethodForSelector: convertSel];
|
2000-10-30 18:00:27 +00:00
|
|
|
|
equalSel = @selector(isEqualToString:);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
equalImp = (BOOL (*)(id, SEL, id))
|
|
|
|
|
[NSStringClass instanceMethodForSelector: equalSel];
|
2000-10-30 18:00:27 +00:00
|
|
|
|
hashSel = @selector(hash);
|
2010-10-01 11:24:19 +00:00
|
|
|
|
hashImp = (NSUInteger (*)(id, SEL))
|
2009-12-07 05:02:55 +00:00
|
|
|
|
[GSStringClass instanceMethodForSelector: hashSel];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2001-05-23 14:32:56 +00:00
|
|
|
|
caiSel = @selector(characterAtIndex:);
|
|
|
|
|
gcrSel = @selector(getCharacters:range:);
|
|
|
|
|
ranSel = @selector(rangeOfComposedCharacterSequenceAtIndex:);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
static GSCInlineString*
|
|
|
|
|
newCInline(unsigned length, NSZone *zone)
|
|
|
|
|
{
|
|
|
|
|
GSCInlineString *me;
|
|
|
|
|
|
|
|
|
|
me = (GSCInlineString*)
|
|
|
|
|
NSAllocateObject(GSCInlineStringClass, length, zone);
|
|
|
|
|
me->_contents.c = (unsigned char*)
|
|
|
|
|
(((void*)me)+class_getInstanceSize(GSCInlineStringClass));
|
|
|
|
|
me->_count = length;
|
|
|
|
|
me->_flags.wide = 0;
|
|
|
|
|
me->_flags.owned = 1; // Ignored on dealloc, but means we own buffer
|
|
|
|
|
return me;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GSUInlineString*
|
|
|
|
|
newUInline(unsigned length, NSZone *zone)
|
|
|
|
|
{
|
|
|
|
|
GSUInlineString *me;
|
|
|
|
|
|
|
|
|
|
me = (GSUInlineString*)
|
|
|
|
|
NSAllocateObject(GSUInlineStringClass, length*sizeof(unichar), zone);
|
|
|
|
|
me->_contents.u = (unichar*)
|
|
|
|
|
(((void*)me)+class_getInstanceSize(GSUInlineStringClass));
|
|
|
|
|
me->_count = length;
|
|
|
|
|
me->_flags.wide = 1;
|
|
|
|
|
me->_flags.owned = 1; // Ignored on dealloc, but means we own buffer
|
|
|
|
|
return me;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-02 13:20:58 +00:00
|
|
|
|
@implementation NSString (RegressionTesting)
|
|
|
|
|
/* This method is provided to enable regression tests to ensure they are
|
|
|
|
|
* using an object whose internal representation is wide (unicode) text,
|
|
|
|
|
* so that all the comparison operations between 8bit and 16bit strings
|
|
|
|
|
* can be tested.
|
|
|
|
|
*/
|
|
|
|
|
- (NSString*) _unicodeString
|
|
|
|
|
{
|
|
|
|
|
GSUInlineString *o;
|
|
|
|
|
unsigned i = [self length];
|
|
|
|
|
|
|
|
|
|
o = [newUInline(i, [self zone]) autorelease];
|
|
|
|
|
while (i-- > 0)
|
|
|
|
|
{
|
|
|
|
|
o->_contents.u[i] = [self characterAtIndex: i];
|
|
|
|
|
}
|
|
|
|
|
return o;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2006-08-12 04:55:36 +00:00
|
|
|
|
/* Predeclare a few functions
|
|
|
|
|
*/
|
|
|
|
|
static void GSStrWiden(GSStr s);
|
|
|
|
|
static void getCString_u(GSStr self, char *buffer, unsigned int maxLength,
|
|
|
|
|
NSRange aRange, NSRange *leftoverRange);
|
|
|
|
|
|
2011-11-16 20:48:50 +00:00
|
|
|
|
#if defined(OBJC_SMALL_OBJECT_SHIFT) && (OBJC_SMALL_OBJECT_SHIFT == 3)
|
|
|
|
|
#define TINY_STRING_MASK 4
|
2011-11-17 06:11:36 +00:00
|
|
|
|
static BOOL useTinyStrings;
|
2011-11-16 20:48:50 +00:00
|
|
|
|
/**
|
|
|
|
|
* A GSTinyString is used on 64-bit platforms to store up to 8 ASCII (7-bit)
|
|
|
|
|
* characters inside a pointer. Note that a mutable version of this class is
|
|
|
|
|
* not possible, because modifying the string changes the pointer value.
|
|
|
|
|
* The layout of a tiny string is as follows:
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
uintptr_t char0 :7;
|
|
|
|
|
uintptr_t char1 :7;
|
|
|
|
|
uintptr_t char2 :7;
|
|
|
|
|
uintptr_t char3 :7;
|
|
|
|
|
uintptr_t char4 :7;
|
|
|
|
|
uintptr_t char5 :7;
|
|
|
|
|
uintptr_t char6 :7;
|
|
|
|
|
uintptr_t char7 :7;
|
|
|
|
|
uintptr_t length :5;
|
|
|
|
|
uintptr_t tag :3;
|
|
|
|
|
};
|
|
|
|
|
*/
|
|
|
|
|
#define TINY_STRING_CHAR(s, x) ((s & (0xFE00000000000000 >> (x*7))) >> (57-(x*7)))
|
|
|
|
|
#define TINY_STRING_LENGTH_MASK 0x1f
|
|
|
|
|
#define TINY_STRING_LENGTH_SHIFT OBJC_SMALL_OBJECT_SHIFT
|
2015-05-22 16:24:27 +00:00
|
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
|
tinyEqualToString(uintptr_t s, NSString *aString)
|
|
|
|
|
{
|
|
|
|
|
NSUInteger l;
|
|
|
|
|
|
|
|
|
|
if ((NSString*)s == aString)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2020-06-23 06:03:55 +00:00
|
|
|
|
if (nil == aString)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2015-05-22 16:24:27 +00:00
|
|
|
|
|
|
|
|
|
l = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
|
|
|
|
if ([aString length] != l)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else if (l > 0)
|
|
|
|
|
{
|
|
|
|
|
unichar buf[8];
|
|
|
|
|
|
|
|
|
|
[aString getCharacters: buf range: NSMakeRange(0, l)];
|
|
|
|
|
while (l-- > 0)
|
|
|
|
|
{
|
|
|
|
|
if ((unichar)TINY_STRING_CHAR(s, l) != buf[l])
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-17 06:11:36 +00:00
|
|
|
|
@interface GSTinyString : NSString
|
|
|
|
|
@end
|
|
|
|
|
|
2012-08-25 14:01:56 +00:00
|
|
|
|
#ifdef GS_PROFILE_TINY_STRINGS
|
2012-08-25 12:15:11 +00:00
|
|
|
|
static int tinyStrings = 0;
|
|
|
|
|
static void logTinyStringCount(void)
|
|
|
|
|
{
|
2013-01-07 21:39:35 +00:00
|
|
|
|
fprintf(stderr, "%d tiny strings created\n", tinyStrings);
|
2012-08-25 12:15:11 +00:00
|
|
|
|
}
|
2012-08-25 14:01:56 +00:00
|
|
|
|
#endif
|
2015-05-05 11:54:14 +00:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
tsbytes(uintptr_t s, char *buf)
|
|
|
|
|
{
|
|
|
|
|
int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < length; index++)
|
|
|
|
|
{
|
|
|
|
|
buf[index] = (char)TINY_STRING_CHAR(s, index);
|
|
|
|
|
}
|
|
|
|
|
buf[index] = 0;
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-16 20:48:50 +00:00
|
|
|
|
@implementation GSTinyString
|
2015-05-05 11:54:14 +00:00
|
|
|
|
|
|
|
|
|
- (BOOL) boolValue
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
2015-05-05 11:54:14 +00:00
|
|
|
|
char buf[9];
|
|
|
|
|
int count = tsbytes((uintptr_t)self, buf);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
char c = buf[i];
|
|
|
|
|
|
|
|
|
|
if (strchr("123456789yYtT", c) != 0)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
if (!isspace(c) && c != '0' && c != '-' && c != '+')
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
2011-11-16 20:48:50 +00:00
|
|
|
|
}
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
|
|
|
|
- (unichar) characterAtIndex: (NSUInteger)anIndex
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
|
|
|
|
uintptr_t s = (uintptr_t)self;
|
|
|
|
|
NSUInteger length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
2011-11-16 20:48:50 +00:00
|
|
|
|
if (anIndex >= length)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-characterAtIndex: index out of range"];
|
|
|
|
|
}
|
|
|
|
|
// Implicit NULL terminator on slightly-too-long strings.
|
|
|
|
|
if (anIndex == 8)
|
|
|
|
|
{
|
|
|
|
|
return '\0';
|
|
|
|
|
}
|
|
|
|
|
return TINY_STRING_CHAR(s, anIndex);
|
|
|
|
|
}
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
- (void) getCharacters: (unichar*)buffer
|
|
|
|
|
{
|
|
|
|
|
uintptr_t s = (uintptr_t)self;
|
|
|
|
|
int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < length; index++)
|
|
|
|
|
{
|
|
|
|
|
buffer[index] = (unichar)TINY_STRING_CHAR(s, index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCharacters: (unichar*)buffer range: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
uintptr_t s = (uintptr_t)self;
|
|
|
|
|
int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
|
|
|
|
int index;
|
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
|
|
GS_RANGE_CHECK(aRange, length);
|
|
|
|
|
length = NSMaxRange(aRange);
|
|
|
|
|
offset = 0;
|
|
|
|
|
for (index = aRange.location; index < length; index++)
|
|
|
|
|
{
|
|
|
|
|
buffer[offset++] = (unichar)TINY_STRING_CHAR(s, index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) getCString: (char*)buffer
|
|
|
|
|
maxLength: (NSUInteger)maxLength
|
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
uintptr_t s = (uintptr_t)self;
|
|
|
|
|
int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
if (buffer == 0)
|
|
|
|
|
{
|
|
|
|
|
return NO; // Can't fit in here
|
|
|
|
|
}
|
|
|
|
|
if (NSUnicodeStringEncoding == encoding)
|
|
|
|
|
{
|
|
|
|
|
maxLength /= 2;
|
|
|
|
|
if (maxLength > 1)
|
|
|
|
|
{
|
2016-05-14 09:34:01 +00:00
|
|
|
|
unichar *buf = (unichar*)(void*)buffer;
|
2016-06-25 18:27:33 +00:00
|
|
|
|
BOOL result = (length < maxLength) ? YES : NO;
|
2015-05-05 11:54:14 +00:00
|
|
|
|
|
|
|
|
|
if (maxLength <= length)
|
|
|
|
|
{
|
|
|
|
|
length = maxLength - 1;
|
|
|
|
|
}
|
|
|
|
|
for (index = 0; index < length; index++)
|
|
|
|
|
{
|
|
|
|
|
buf[index] = (unichar)TINY_STRING_CHAR(s, index);
|
|
|
|
|
}
|
|
|
|
|
buf[index] = 0;
|
2016-06-25 18:27:33 +00:00
|
|
|
|
return result;
|
2015-05-05 11:54:14 +00:00
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else if (isByteEncoding(encoding))
|
|
|
|
|
{
|
|
|
|
|
if (maxLength > 0)
|
|
|
|
|
{
|
2016-06-25 18:27:33 +00:00
|
|
|
|
BOOL result = (length < maxLength) ? YES : NO;
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
if (maxLength <= length)
|
|
|
|
|
{
|
|
|
|
|
length = maxLength - 1;
|
|
|
|
|
}
|
|
|
|
|
for (index = 0; index < length; index++)
|
|
|
|
|
{
|
|
|
|
|
buffer[index] = (char)TINY_STRING_CHAR(s, index);
|
|
|
|
|
}
|
|
|
|
|
buffer[index] = 0;
|
2016-06-25 18:27:33 +00:00
|
|
|
|
return result;
|
2015-05-05 11:54:14 +00:00
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return [super getCString: buffer maxLength: maxLength encoding: encoding];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSUInteger) hash
|
|
|
|
|
{
|
|
|
|
|
uintptr_t s = (uintptr_t)self;
|
|
|
|
|
int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
|
|
|
|
uint32_t ret = 0;
|
|
|
|
|
|
|
|
|
|
if (length > 0)
|
|
|
|
|
{
|
|
|
|
|
unichar buf[10];
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < length; index++)
|
|
|
|
|
{
|
|
|
|
|
buf[index] = (char)TINY_STRING_CHAR(s, index);
|
|
|
|
|
}
|
|
|
|
|
ret = GSPrivateHash(0, buf, length * sizeof(unichar));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The hash caching in our concrete string classes uses zero to denote
|
|
|
|
|
* an empty cache value, so we MUST NOT return a hash of zero.
|
|
|
|
|
*/
|
|
|
|
|
ret &= 0x0fffffff;
|
|
|
|
|
if (ret == 0)
|
|
|
|
|
{
|
|
|
|
|
ret = 0x0fffffff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = 0x0ffffffe; /* Hash for an empty string. */
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) intValue
|
|
|
|
|
{
|
|
|
|
|
char buf[9];
|
|
|
|
|
|
|
|
|
|
tsbytes((uintptr_t)self, buf);
|
|
|
|
|
return strtol(buf, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSInteger) integerValue
|
|
|
|
|
{
|
|
|
|
|
char buf[9];
|
|
|
|
|
|
|
|
|
|
tsbytes((uintptr_t)self, buf);
|
|
|
|
|
#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG
|
|
|
|
|
return strtol(buf, 0, 10);
|
|
|
|
|
#else
|
|
|
|
|
return strtoll(buf, 0, 10);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-22 16:24:27 +00:00
|
|
|
|
- (BOOL) isEqualToString: (NSString*)aString
|
|
|
|
|
{
|
|
|
|
|
return tinyEqualToString((uintptr_t)self, aString);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
- (NSUInteger) length
|
|
|
|
|
{
|
|
|
|
|
uintptr_t s = (uintptr_t)self;
|
|
|
|
|
return (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (long long) longLongValue
|
|
|
|
|
{
|
|
|
|
|
char buf[9];
|
|
|
|
|
|
|
|
|
|
tsbytes((uintptr_t)self, buf);
|
|
|
|
|
return strtoll(buf, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-25 18:13:10 +00:00
|
|
|
|
- (id) mutableCopyWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
uintptr_t s = (uintptr_t)self;
|
|
|
|
|
NSUInteger i;
|
|
|
|
|
NSUInteger l;
|
|
|
|
|
GSMutableString *obj;
|
|
|
|
|
char bytes[8];
|
|
|
|
|
|
|
|
|
|
l = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
|
|
|
|
for (i = 0; i < l; i++)
|
|
|
|
|
{
|
|
|
|
|
bytes[i] = (unichar)TINY_STRING_CHAR(s, i);
|
|
|
|
|
}
|
|
|
|
|
obj = (GSMutableString*)NSAllocateObject(GSMutableStringClass, 0, z);
|
|
|
|
|
obj = [obj initWithBytes: bytes
|
|
|
|
|
length: l
|
|
|
|
|
encoding: internalEncoding];
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-22 14:28:08 +00:00
|
|
|
|
- (NSRange) rangeOfComposedCharacterSequenceAtIndex: (NSUInteger)anIndex
|
|
|
|
|
{
|
|
|
|
|
uintptr_t s = (uintptr_t)self;
|
|
|
|
|
NSUInteger l = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
|
|
|
|
|
|
|
|
|
if (anIndex >= l)
|
|
|
|
|
[NSException raise: NSRangeException format:@"Invalid location."];
|
|
|
|
|
return NSMakeRange(anIndex, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-08 16:20:25 +00:00
|
|
|
|
- (NSUInteger) sizeOfContentExcluding: (NSHashTable*)exclude
|
|
|
|
|
{
|
|
|
|
|
return 0; // Tiny string uses no heap
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSUInteger) sizeOfInstance
|
|
|
|
|
{
|
|
|
|
|
return 0; // Tiny string uses no heap
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
- (const char*) UTF8String
|
|
|
|
|
{
|
|
|
|
|
char *buf = GSAutoreleasedBuffer(9);
|
|
|
|
|
|
|
|
|
|
tsbytes((uintptr_t)self, buf);
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-17 06:11:36 +00:00
|
|
|
|
+ (void) load
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
|
|
|
|
useTinyStrings = objc_registerSmallObjectClass_np(self, TINY_STRING_MASK);
|
2012-08-25 14:01:56 +00:00
|
|
|
|
#ifdef GS_PROFILE_TINY_STRINGS
|
2012-08-25 12:15:11 +00:00
|
|
|
|
atexit(logTinyStringCount);
|
2012-08-25 14:01:56 +00:00
|
|
|
|
#endif
|
2011-11-16 20:48:50 +00:00
|
|
|
|
}
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
|
|
|
|
+ (id) alloc
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
|
|
|
|
return (id)TINY_STRING_MASK;
|
|
|
|
|
}
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)aZone
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
|
|
|
|
return (id)TINY_STRING_MASK;
|
|
|
|
|
}
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
|
|
|
|
- (id) copy
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone*)aZone
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2015-05-22 14:28:08 +00:00
|
|
|
|
|
2013-01-29 18:42:23 +00:00
|
|
|
|
- (NSUInteger) retainCount
|
|
|
|
|
{
|
|
|
|
|
return UINT_MAX;
|
|
|
|
|
}
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
|
|
|
|
- (id) autorelease
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (oneway void) release
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-15 14:14:21 +00:00
|
|
|
|
|
2015-07-16 08:44:15 +00:00
|
|
|
|
- (NSUInteger) sizeInBytesExcluding: (NSHashTable*)exclude
|
2015-07-15 14:14:21 +00:00
|
|
|
|
{
|
2015-07-15 15:26:29 +00:00
|
|
|
|
if (0 == NSHashGet(exclude, self))
|
2015-07-15 14:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 8;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-16 20:48:50 +00:00
|
|
|
|
@end
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
2011-11-16 20:48:50 +00:00
|
|
|
|
/**
|
|
|
|
|
* Constructs a tiny string.
|
|
|
|
|
*/
|
2015-05-25 17:55:51 +00:00
|
|
|
|
static inline id
|
2011-11-17 06:11:36 +00:00
|
|
|
|
createTinyString(const char *str, int length)
|
|
|
|
|
{
|
2011-12-19 23:04:04 +00:00
|
|
|
|
unsigned int i;
|
|
|
|
|
uintptr_t s = TINY_STRING_MASK;
|
|
|
|
|
|
2011-11-17 06:11:36 +00:00
|
|
|
|
/* No tiny string support detected at run time, give up
|
|
|
|
|
*/
|
|
|
|
|
if (!useTinyStrings)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* String too long to fit in a pointer, give up
|
|
|
|
|
*/
|
|
|
|
|
if (length > 9)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* String would fit if the last byte was an implicit 0, but it isn't.
|
|
|
|
|
*/
|
|
|
|
|
if ((length == 9) && str[8] != '\0')
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2011-12-19 23:04:04 +00:00
|
|
|
|
|
2011-11-16 20:48:50 +00:00
|
|
|
|
s |= length << TINY_STRING_LENGTH_SHIFT;
|
2011-12-19 23:04:04 +00:00
|
|
|
|
for (i = 0 ; i<length ; i++)
|
2011-11-17 06:11:36 +00:00
|
|
|
|
{
|
2012-08-25 12:15:11 +00:00
|
|
|
|
// If this is not a 7-bit character, we can't use it.
|
|
|
|
|
if (str[i] & 0x80) { return nil; }
|
2011-11-17 06:11:36 +00:00
|
|
|
|
s |= ((uintptr_t)str[i]) << (57 - (i*7));
|
|
|
|
|
}
|
2012-08-25 14:01:56 +00:00
|
|
|
|
#ifdef GS_PROFILE_TINY_STRINGS
|
2012-08-25 12:15:11 +00:00
|
|
|
|
__sync_fetch_and_add(&tinyStrings, 1);
|
2012-08-25 14:01:56 +00:00
|
|
|
|
#endif
|
2011-11-16 20:48:50 +00:00
|
|
|
|
return (id)s;
|
|
|
|
|
}
|
2012-08-25 12:31:41 +00:00
|
|
|
|
#else
|
2015-05-25 17:55:51 +00:00
|
|
|
|
static inline id
|
2012-08-25 12:31:41 +00:00
|
|
|
|
createTinyString(const char *str, int length)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2011-11-16 20:48:50 +00:00
|
|
|
|
#endif
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* The GSPlaceholderString class is used by the abstract cluster root
|
|
|
|
|
* class to provide temporary objects that will be replaced as soon
|
|
|
|
|
* as the objects are initialised. This object tries to replace
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* itself with an appropriate object whose type may vary depending
|
2000-11-03 10:11:56 +00:00
|
|
|
|
* on the initialisation method used.
|
|
|
|
|
*/
|
|
|
|
|
@implementation GSPlaceholderString
|
2015-05-25 11:47:13 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
GSPlaceholderString *o = NSAllocateObject(self, 0, z);
|
|
|
|
|
o->myZone = z;
|
|
|
|
|
return o;
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
2010-07-19 17:10:46 +00:00
|
|
|
|
setup(NO);
|
2000-11-03 10:11:56 +00:00
|
|
|
|
}
|
2001-01-08 16:45:36 +00:00
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
- (id) autorelease
|
|
|
|
|
{
|
2001-01-08 16:45:36 +00:00
|
|
|
|
NSWarnLog(@"-autorelease sent to uninitialised string");
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return self; // placeholders never get released.
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (unichar) characterAtIndex: (NSUInteger)index
|
2000-11-03 10:11:56 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"attempt to use uninitialised string"];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2009-10-10 08:16:17 +00:00
|
|
|
|
NSLog(@"Warning ... attempt to deallocate instance of %@ in zone %p",
|
|
|
|
|
NSStringFromClass([self class]), [self zone]);
|
2006-06-04 06:42:10 +00:00
|
|
|
|
GSNOSUPERDEALLOC; // Placeholders never get deallocated.
|
2000-11-03 10:11:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-09-09 10:39:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* Replace self with an empty inline unicode string.
|
|
|
|
|
*/
|
|
|
|
|
- (id) init
|
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return [self initWithBytes: 0 length: 0 encoding: internalEncoding];
|
2004-09-09 10:39:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
2006-05-14 18:01:13 +00:00
|
|
|
|
* Remove any BOM and perform byte swapping if required.
|
2000-11-03 10:11:56 +00:00
|
|
|
|
*/
|
2006-05-14 18:01:13 +00:00
|
|
|
|
static void
|
2009-04-10 08:25:03 +00:00
|
|
|
|
fixBOM(unsigned char **bytes, NSUInteger*length, BOOL *owned,
|
2006-05-14 18:01:13 +00:00
|
|
|
|
NSStringEncoding encoding)
|
2000-11-03 10:11:56 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
unsigned char *b = *bytes;
|
|
|
|
|
unsigned len = *length;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (encoding == NSUnicodeStringEncoding && *length >= 2
|
|
|
|
|
&& ((b[0] == 0xFE && b[1] == 0xFF) || (b[0] == 0xFF && b[1] == 0xFE)))
|
2006-03-26 10:59:57 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
// Got a byte order marker ... remove it.
|
|
|
|
|
if (len == sizeof(unichar))
|
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
if (*owned)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSZoneFromPointer(b), b);
|
2009-04-10 08:25:03 +00:00
|
|
|
|
*owned = NO;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
|
|
|
|
*length = 0;
|
|
|
|
|
*bytes = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned char *from = b;
|
|
|
|
|
unsigned char *to;
|
|
|
|
|
unichar u;
|
|
|
|
|
|
|
|
|
|
// Got a byte order marker ... remove it.
|
|
|
|
|
len -= sizeof(unichar);
|
|
|
|
|
memcpy(&u, from, sizeof(unichar));
|
|
|
|
|
from += sizeof(unichar);
|
2009-04-10 08:25:03 +00:00
|
|
|
|
to = NSAllocateCollectable(len, 0);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (u == 0xFEFF)
|
|
|
|
|
{
|
|
|
|
|
// Native byte order
|
|
|
|
|
memcpy(to, from, len);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < len; i += 2)
|
|
|
|
|
{
|
|
|
|
|
to[i] = from[i+1];
|
|
|
|
|
to[i+1] = from[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-04-10 08:25:03 +00:00
|
|
|
|
if (*owned == YES)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(b), b);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*owned = YES;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
|
|
|
|
*length = len;
|
|
|
|
|
*bytes = to;
|
|
|
|
|
}
|
2006-03-26 10:59:57 +00:00
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
else if (encoding == NSUTF8StringEncoding && len >= 3
|
|
|
|
|
&& b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF)
|
2006-03-26 10:59:57 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (len == 3)
|
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
if (*owned)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSZoneFromPointer(b), b);
|
2009-04-10 08:25:03 +00:00
|
|
|
|
*owned = NO;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
|
|
|
|
*length = 0;
|
|
|
|
|
*bytes = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned char *from = b;
|
|
|
|
|
unsigned char *to;
|
|
|
|
|
|
|
|
|
|
// Got a byte order marker ... remove it.
|
|
|
|
|
len -= 3;
|
|
|
|
|
from += 3;
|
2009-04-10 08:25:03 +00:00
|
|
|
|
to = NSAllocateCollectable(len, 0);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
memcpy(to, from, len);
|
2009-04-10 08:25:03 +00:00
|
|
|
|
if (*owned == YES)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(b), b);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*owned = YES;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
|
|
|
|
*length = len;
|
|
|
|
|
*bytes = to;
|
2006-03-26 10:59:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithBytes: (const void*)bytes
|
2009-02-23 20:42:32 +00:00
|
|
|
|
length: (NSUInteger)length
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
2015-05-22 14:28:08 +00:00
|
|
|
|
const void *original;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
void *chars = 0;
|
|
|
|
|
BOOL flag = NO;
|
|
|
|
|
|
2015-05-22 14:28:08 +00:00
|
|
|
|
if (0 == length)
|
2006-06-02 05:25:21 +00:00
|
|
|
|
{
|
2015-05-22 14:28:08 +00:00
|
|
|
|
return (id)@"";
|
2006-06-02 05:25:21 +00:00
|
|
|
|
}
|
2015-05-22 14:28:08 +00:00
|
|
|
|
|
|
|
|
|
if (0 == bytes)
|
2006-03-26 10:59:57 +00:00
|
|
|
|
{
|
2015-05-22 14:28:08 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-initWithBytes:lenth:encoding given nul bytes"];
|
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
|
2011-11-17 06:11:36 +00:00
|
|
|
|
#if defined(OBJC_SMALL_OBJECT_SHIFT) && (OBJC_SMALL_OBJECT_SHIFT == 3)
|
2015-05-22 14:28:08 +00:00
|
|
|
|
if (useTinyStrings)
|
|
|
|
|
{
|
|
|
|
|
if (NSASCIIStringEncoding == encoding)
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
2015-05-22 14:28:08 +00:00
|
|
|
|
id tinyString = createTinyString(bytes, length);
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
2015-05-22 14:28:08 +00:00
|
|
|
|
if (tinyString)
|
|
|
|
|
{
|
|
|
|
|
return tinyString;
|
2011-11-16 20:48:50 +00:00
|
|
|
|
}
|
2015-05-22 14:28:08 +00:00
|
|
|
|
}
|
|
|
|
|
if (length < 9)
|
|
|
|
|
{
|
|
|
|
|
if (NSUTF8StringEncoding == encoding
|
|
|
|
|
|| GSPrivateIsByteEncoding(encoding))
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
|
|
|
|
NSUInteger i;
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
2011-11-16 20:48:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (((const char*)bytes)[i] & 0x80)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (i == length)
|
|
|
|
|
{
|
|
|
|
|
id tinyString = createTinyString(bytes, length);
|
2011-11-17 06:11:36 +00:00
|
|
|
|
|
2011-11-16 20:48:50 +00:00
|
|
|
|
if (tinyString)
|
|
|
|
|
{
|
|
|
|
|
return tinyString;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-05-22 14:28:08 +00:00
|
|
|
|
}
|
2011-11-17 06:11:36 +00:00
|
|
|
|
#endif
|
2011-11-16 20:48:50 +00:00
|
|
|
|
|
2015-05-22 14:28:08 +00:00
|
|
|
|
original = bytes;
|
|
|
|
|
fixBOM((unsigned char**)&bytes, &length, &flag, encoding);
|
|
|
|
|
/*
|
|
|
|
|
* We need to copy the data if there is any, unless fixBOM()
|
|
|
|
|
* has already done it for us.
|
|
|
|
|
*/
|
|
|
|
|
if (original == bytes)
|
|
|
|
|
{
|
2015-05-25 11:47:13 +00:00
|
|
|
|
chars = NSZoneMalloc(myZone, length);
|
2015-05-22 14:28:08 +00:00
|
|
|
|
memcpy(chars, bytes, length);
|
2006-03-26 10:59:57 +00:00
|
|
|
|
}
|
2015-05-22 14:28:08 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The fixBOM() function has already copied the data and allocated
|
|
|
|
|
* new memory, so we can just pass that to the designated initialiser
|
|
|
|
|
*/
|
|
|
|
|
chars = (void*)bytes;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return [self initWithBytesNoCopy: chars
|
|
|
|
|
length: length
|
|
|
|
|
encoding: encoding
|
|
|
|
|
freeWhenDone: YES];
|
2000-11-03 10:11:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-05-20 14:52:38 +00:00
|
|
|
|
- (id) initWithBytesNoCopy: (void*)bytes
|
2009-02-23 20:42:32 +00:00
|
|
|
|
length: (NSUInteger)length
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
freeWhenDone: (BOOL)flag
|
2000-11-03 10:11:56 +00:00
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
GSCharPtr chars = { .u = 0 };
|
2006-05-14 18:01:13 +00:00
|
|
|
|
BOOL isASCII = NO;
|
|
|
|
|
BOOL isLatin1 = NO;
|
|
|
|
|
GSStr me;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
|
2015-05-22 14:28:08 +00:00
|
|
|
|
if (0 == length)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
2015-05-23 21:35:03 +00:00
|
|
|
|
if (YES == flag && 0 != bytes)
|
2015-05-22 14:28:08 +00:00
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSZoneFromPointer(bytes), bytes);
|
|
|
|
|
}
|
|
|
|
|
return (id)@"";
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
2018-01-31 14:24:46 +00:00
|
|
|
|
if (0 == bytes)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-%@ given NULL pointer",
|
|
|
|
|
NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
2015-05-22 14:28:08 +00:00
|
|
|
|
fixBOM((unsigned char**)&bytes, &length, &flag, encoding);
|
|
|
|
|
if (encoding == NSUnicodeStringEncoding)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
2015-05-22 14:28:08 +00:00
|
|
|
|
chars.u = bytes;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
2015-05-22 14:28:08 +00:00
|
|
|
|
else
|
2006-06-22 22:36:46 +00:00
|
|
|
|
{
|
2015-05-22 14:28:08 +00:00
|
|
|
|
chars.c = bytes;
|
2006-06-22 22:36:46 +00:00
|
|
|
|
}
|
2015-05-22 14:28:08 +00:00
|
|
|
|
|
|
|
|
|
if (encoding == NSUTF8StringEncoding
|
|
|
|
|
|| (encoding != internalEncoding && isByteEncoding(encoding) == YES))
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
if ((chars.c)[i] > 127)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
|
|
|
|
if (encoding == NSASCIIStringEncoding)
|
|
|
|
|
{
|
2018-02-01 21:31:15 +00:00
|
|
|
|
if (flag == YES)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(chars.c), chars.c);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
|
|
|
|
return nil; // Invalid data
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (i == length)
|
|
|
|
|
{
|
|
|
|
|
/*
|
2006-05-30 11:19:44 +00:00
|
|
|
|
* This is actually ASCII data ... so we can just store it as if
|
2006-05-14 18:01:13 +00:00
|
|
|
|
* in the internal 8bit encoding scheme.
|
|
|
|
|
*/
|
|
|
|
|
encoding = internalEncoding;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (encoding == internalEncoding)
|
|
|
|
|
{
|
2015-05-25 11:47:13 +00:00
|
|
|
|
me = (GSStr)NSAllocateObject(GSCBufferStringClass, 0, myZone);
|
2006-05-30 11:19:44 +00:00
|
|
|
|
me->_contents.c = chars.c;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
me->_count = length;
|
|
|
|
|
me->_flags.wide = 0;
|
2009-04-10 08:25:03 +00:00
|
|
|
|
me->_flags.owned = flag;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return (id)me;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Any remaining encoding needs to be converted to UTF-16.
|
|
|
|
|
*/
|
|
|
|
|
if (encoding != NSUnicodeStringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unichar *u = 0;
|
|
|
|
|
unsigned l = 0;
|
|
|
|
|
|
2015-05-22 14:28:08 +00:00
|
|
|
|
if (GSPrivateIsEncodingSupported(encoding) == NO)
|
|
|
|
|
{
|
|
|
|
|
if (flag == YES && bytes != 0)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSZoneFromPointer(bytes), bytes);
|
|
|
|
|
}
|
|
|
|
|
return nil; // Invalid encoding
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-25 11:47:13 +00:00
|
|
|
|
if (GSToUnicode(&u, &l, chars.c, length, encoding, myZone, 0) == NO)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
if (flag == YES && chars.c != 0)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(chars.c), chars.c);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
|
|
|
|
return nil; // Invalid data
|
|
|
|
|
}
|
2006-05-30 11:19:44 +00:00
|
|
|
|
if (flag == YES && chars.c != 0)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(chars.c), chars.c);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
2006-05-30 11:19:44 +00:00
|
|
|
|
chars.u = u;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
length = l * sizeof(unichar);
|
|
|
|
|
flag = YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length /= sizeof(unichar);
|
2006-05-30 11:19:44 +00:00
|
|
|
|
if (GSUnicode(chars.u, length, &isASCII, &isLatin1) != length)
|
2006-03-26 10:59:57 +00:00
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
if (flag == YES && chars.u != 0)
|
2006-03-28 06:05:04 +00:00
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(chars.u), chars.u);
|
2006-03-28 06:05:04 +00:00
|
|
|
|
}
|
2006-03-26 10:59:57 +00:00
|
|
|
|
return nil; // Invalid data
|
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
|
2006-03-26 10:59:57 +00:00
|
|
|
|
if (isASCII == YES
|
2006-05-14 18:01:13 +00:00
|
|
|
|
|| (internalEncoding == NSISOLatin1StringEncoding && isLatin1 == YES))
|
2002-04-07 16:54:35 +00:00
|
|
|
|
{
|
2015-05-25 11:47:13 +00:00
|
|
|
|
me = (GSStr)newCInline(length, myZone);
|
2006-03-26 10:59:57 +00:00
|
|
|
|
while (length-- > 0)
|
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
me->_contents.c[length] = chars.u[length];
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
2006-05-30 11:19:44 +00:00
|
|
|
|
if (flag == YES && chars.u != 0)
|
2006-03-28 06:05:04 +00:00
|
|
|
|
{
|
2006-05-30 11:19:44 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(chars.u), chars.u);
|
2006-03-28 06:05:04 +00:00
|
|
|
|
}
|
2006-03-26 10:59:57 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-05-25 11:47:13 +00:00
|
|
|
|
me = (GSStr)NSAllocateObject(GSUnicodeBufferStringClass, 0, myZone);
|
2006-05-30 11:19:44 +00:00
|
|
|
|
me->_contents.u = chars.u;
|
2006-03-26 10:59:57 +00:00
|
|
|
|
me->_count = length;
|
|
|
|
|
me->_flags.wide = 1;
|
2009-04-10 08:25:03 +00:00
|
|
|
|
me->_flags.owned = flag;
|
2002-04-07 16:54:35 +00:00
|
|
|
|
}
|
2013-03-05 16:20:10 +00:00
|
|
|
|
return (id)me;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-05 10:06:56 +00:00
|
|
|
|
- (id) initWithFormat: (NSString*)format
|
|
|
|
|
locale: (NSDictionary*)locale
|
|
|
|
|
arguments: (va_list)argList
|
|
|
|
|
{
|
2010-02-14 10:48:10 +00:00
|
|
|
|
GSStr f;
|
2004-06-05 10:06:56 +00:00
|
|
|
|
unsigned char buf[2048];
|
|
|
|
|
unichar fbuf[1024];
|
|
|
|
|
unichar *fmt = fbuf;
|
|
|
|
|
size_t len;
|
|
|
|
|
GSStr me;
|
|
|
|
|
|
2018-07-06 21:53:32 +00:00
|
|
|
|
if (NULL == format)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[GSPlaceholderString-initWithFormat:locale:arguments:]: NULL format"];
|
2004-06-05 10:06:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* First we provide an array of unichar characters containing the
|
|
|
|
|
* format string. For performance reasons we try to use an on-stack
|
|
|
|
|
* buffer if the format string is small enough ... it almost always
|
|
|
|
|
* will be.
|
|
|
|
|
*/
|
|
|
|
|
len = [format length];
|
|
|
|
|
if (len >= 1024)
|
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
fmt = NSZoneMalloc(NSDefaultMallocZone(), (len+1)*sizeof(unichar));
|
2004-06-05 10:06:56 +00:00
|
|
|
|
}
|
|
|
|
|
[format getCharacters: fmt];
|
|
|
|
|
fmt[len] = '\0';
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now set up 'f' as a GSMutableString object whose initial buffer is
|
2006-10-20 10:56:27 +00:00
|
|
|
|
* allocated on the stack. The GSPrivateFormat function can write into it.
|
2004-06-05 10:06:56 +00:00
|
|
|
|
*/
|
2010-02-14 10:48:10 +00:00
|
|
|
|
f = (GSStr)alloca(class_getInstanceSize(GSMutableStringClass));
|
|
|
|
|
object_setClass(f, GSMutableStringClass);
|
|
|
|
|
f->_zone = NSDefaultMallocZone();
|
|
|
|
|
f->_contents.c = buf;
|
|
|
|
|
f->_capacity = sizeof(buf);
|
|
|
|
|
f->_count = 0;
|
|
|
|
|
f->_flags.wide = 0;
|
|
|
|
|
f->_flags.owned = 0;
|
|
|
|
|
GSPrivateFormat(f, fmt, argList, locale);
|
2004-06-05 10:06:56 +00:00
|
|
|
|
if (fmt != fbuf)
|
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), fmt);
|
2004-06-05 10:06:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2010-02-14 10:48:10 +00:00
|
|
|
|
* Don't use noCopy because f->_contents.u may be memory on the stack,
|
|
|
|
|
* and even if it wasn't f->_capacity may be greater than f->_count so
|
2004-06-05 10:06:56 +00:00
|
|
|
|
* we could be wasting quite a bit of space. Better to accept a
|
|
|
|
|
* performance hit due to copying data (and allocating/deallocating
|
|
|
|
|
* the temporary buffer) for large strings. For most strings, the
|
|
|
|
|
* on-stack memory will have been used, so we will get better performance.
|
|
|
|
|
*/
|
2010-02-14 10:48:10 +00:00
|
|
|
|
if (f->_flags.wide == 1)
|
2004-06-05 10:06:56 +00:00
|
|
|
|
{
|
2015-05-25 11:47:13 +00:00
|
|
|
|
me = (GSStr)newUInline(f->_count, myZone);
|
2010-02-14 10:48:10 +00:00
|
|
|
|
memcpy(me->_contents.u, f->_contents.u, f->_count*sizeof(unichar));
|
2004-06-05 10:06:56 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-05-25 11:47:13 +00:00
|
|
|
|
me = (GSStr)newCInline(f->_count, myZone);
|
2010-02-14 10:48:10 +00:00
|
|
|
|
memcpy(me->_contents.c, f->_contents.c, f->_count);
|
2004-06-05 10:06:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the string had to grow beyond the initial buffer size, we must
|
|
|
|
|
* release any allocated memory.
|
|
|
|
|
*/
|
2012-08-08 09:46:08 +00:00
|
|
|
|
if (1 == f->_flags.owned)
|
2004-06-05 10:06:56 +00:00
|
|
|
|
{
|
2010-02-14 10:48:10 +00:00
|
|
|
|
NSZoneFree(f->_zone, f->_contents.c);
|
2004-06-05 10:06:56 +00:00
|
|
|
|
}
|
|
|
|
|
return (id)me;
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* Replace self with an inline string matching the sort of information
|
|
|
|
|
* given.
|
|
|
|
|
*/
|
|
|
|
|
- (id) initWithString: (NSString*)string
|
|
|
|
|
{
|
|
|
|
|
unsigned length;
|
|
|
|
|
Class c;
|
2004-05-14 10:52:30 +00:00
|
|
|
|
GSStr me;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
|
|
|
|
|
if (string == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2018-07-06 21:53:32 +00:00
|
|
|
|
format: @"GSPlaceholderString-initWithString: given nil string"];
|
2010-02-08 17:52:36 +00:00
|
|
|
|
if (NO == [string isKindOfClass: NSStringClass]) // may be proxy
|
2000-11-03 10:11:56 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-initWithString: given non-string object"];
|
|
|
|
|
|
2010-02-22 10:13:20 +00:00
|
|
|
|
c = object_getClass(string);
|
2000-11-03 10:11:56 +00:00
|
|
|
|
length = [string length];
|
2011-10-12 14:28:44 +00:00
|
|
|
|
if (GSObjCIsKindOf(c, GSCStringClass) == YES
|
2000-11-03 10:11:56 +00:00
|
|
|
|
|| (GSObjCIsKindOf(c, GSMutableStringClass) == YES
|
2004-05-14 10:52:30 +00:00
|
|
|
|
&& ((GSStr)string)->_flags.wide == 0))
|
2000-11-03 10:11:56 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
2011-10-28 14:31:46 +00:00
|
|
|
|
* For a GSCString subclass, or an 8-bit GSMutableString,
|
2012-08-08 09:46:08 +00:00
|
|
|
|
* we can copy the bytes directly into an inline string.
|
2000-11-03 10:11:56 +00:00
|
|
|
|
*/
|
2015-05-25 11:47:13 +00:00
|
|
|
|
me = (GSStr)newCInline(length, myZone);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
memcpy(me->_contents.c, ((GSStr)string)->_contents.c, length);
|
2000-11-03 10:11:56 +00:00
|
|
|
|
}
|
|
|
|
|
else if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|
|
|
|
|
|| GSObjCIsKindOf(c, GSMutableStringClass) == YES)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* For a GSUnicodeString subclass, or a 16-bit GSMutableString,
|
2012-08-08 09:46:08 +00:00
|
|
|
|
* we can copy the bytes directly into an inline string.
|
2000-11-03 10:11:56 +00:00
|
|
|
|
*/
|
2015-05-25 11:47:13 +00:00
|
|
|
|
me = (GSStr)newUInline(length, myZone);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
memcpy(me->_contents.u, ((GSStr)string)->_contents.u,
|
2000-11-03 10:11:56 +00:00
|
|
|
|
length*sizeof(unichar));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* For a string with an unknown class, we can initialise by
|
|
|
|
|
* having the string copy its content directly into our buffer.
|
|
|
|
|
*/
|
2015-05-25 11:47:13 +00:00
|
|
|
|
me = (GSStr)newUInline(length, myZone);
|
2000-11-03 10:11:56 +00:00
|
|
|
|
[string getCharacters: me->_contents.u];
|
|
|
|
|
}
|
|
|
|
|
return (id)me;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-25 11:11:24 +00:00
|
|
|
|
- (id) initWithUTF8String: (const char*)bytes
|
|
|
|
|
{
|
2015-05-26 09:56:55 +00:00
|
|
|
|
const uint8_t *b = (const uint8_t*)bytes;
|
2015-05-25 11:11:24 +00:00
|
|
|
|
BOOL ascii = YES;
|
|
|
|
|
NSUInteger length;
|
|
|
|
|
GSStr me;
|
2015-05-26 09:56:55 +00:00
|
|
|
|
uint8_t c;
|
2015-05-25 11:11:24 +00:00
|
|
|
|
|
2018-07-06 21:53:32 +00:00
|
|
|
|
if (NULL == bytes)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[GSPlaceholderString-initWithUTF8String:]: NULL cString"];
|
2015-05-25 11:11:24 +00:00
|
|
|
|
/* Skip leading BOM
|
|
|
|
|
*/
|
2015-05-25 18:13:10 +00:00
|
|
|
|
if (b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF)
|
2015-05-25 11:11:24 +00:00
|
|
|
|
{
|
2015-05-25 18:13:10 +00:00
|
|
|
|
b = &b[3];
|
2015-05-25 11:11:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-25 11:47:13 +00:00
|
|
|
|
length = 0;
|
2015-05-25 18:13:10 +00:00
|
|
|
|
while ((c = b[length]))
|
2015-05-25 11:11:24 +00:00
|
|
|
|
{
|
2015-05-25 11:47:13 +00:00
|
|
|
|
length++;
|
|
|
|
|
if (c > 127)
|
2015-05-25 11:11:24 +00:00
|
|
|
|
{
|
|
|
|
|
ascii = NO;
|
2015-05-25 18:13:10 +00:00
|
|
|
|
while (b[length])
|
2015-05-25 11:47:13 +00:00
|
|
|
|
{
|
|
|
|
|
length++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-05-25 11:11:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (YES == ascii)
|
|
|
|
|
{
|
2015-05-25 18:13:10 +00:00
|
|
|
|
id o = createTinyString((const char*)b, length);
|
2015-05-25 17:55:51 +00:00
|
|
|
|
|
|
|
|
|
if (nil == o)
|
|
|
|
|
{
|
|
|
|
|
me = (GSStr)newCInline(length, myZone);
|
2015-05-25 18:13:10 +00:00
|
|
|
|
memcpy(me->_contents.c, b, length);
|
2015-05-25 17:55:51 +00:00
|
|
|
|
o = (id)me;
|
|
|
|
|
}
|
|
|
|
|
return o;
|
2015-05-25 11:11:24 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unichar *u = 0;
|
|
|
|
|
unsigned l = 0;
|
|
|
|
|
|
2015-05-25 11:47:13 +00:00
|
|
|
|
if (GSToUnicode(&u, &l, b, length, NSUTF8StringEncoding, myZone, 0) == NO)
|
2015-05-25 11:11:24 +00:00
|
|
|
|
{
|
|
|
|
|
return nil; // Invalid data
|
|
|
|
|
}
|
2015-05-25 11:47:13 +00:00
|
|
|
|
me = (GSStr)NSAllocateObject(GSUnicodeBufferStringClass, 0, myZone);
|
2015-05-25 11:11:24 +00:00
|
|
|
|
me->_contents.u = u;
|
|
|
|
|
me->_count = l;
|
|
|
|
|
me->_flags.wide = 1;
|
|
|
|
|
me->_flags.owned = YES;
|
|
|
|
|
}
|
|
|
|
|
return (id)me;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) length
|
2000-11-03 10:11:56 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"attempt to use uninitialised string"];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-31 15:31:39 +00:00
|
|
|
|
- (oneway void) release
|
2000-11-03 10:11:56 +00:00
|
|
|
|
{
|
|
|
|
|
return; // placeholders never get released.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
|
|
|
|
return self; // placeholders never get retained.
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* The following inline functions are used by the concrete string classes
|
|
|
|
|
* to implement their core functionality.
|
|
|
|
|
* GSCString uses the functions with the _c suffix.
|
2011-10-28 14:31:46 +00:00
|
|
|
|
* GSCSubString, GSCInlineString, GSCBufferString
|
2003-11-05 02:11:49 +00:00
|
|
|
|
* inherit methods from GSCString.
|
2000-11-03 10:11:56 +00:00
|
|
|
|
* GSUnicodeString uses the functions with the _u suffix.
|
2012-08-08 09:46:08 +00:00
|
|
|
|
* GSUnicodeSubString, GSUInlineString, and GSUnicodeBufferString
|
2003-11-05 02:11:49 +00:00
|
|
|
|
* inherit methods from GSUnicodeString.
|
2000-11-03 10:11:56 +00:00
|
|
|
|
* GSMutableString uses all the functions, selecting the _c or _u versions
|
2000-10-20 10:30:51 +00:00
|
|
|
|
* depending on whether its storage is 8-bit or 16-bit.
|
2000-11-03 10:11:56 +00:00
|
|
|
|
* In addition, GSMutableString uses a few functions without a suffix that are
|
2000-10-20 10:30:51 +00:00
|
|
|
|
* peculiar to its memory management (shrinking, growing, and converting).
|
|
|
|
|
*/
|
|
|
|
|
|
2008-11-17 13:45:32 +00:00
|
|
|
|
static inline const char*
|
2004-05-14 10:52:30 +00:00
|
|
|
|
UTF8String_c(GSStr self)
|
2002-10-05 17:47:54 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned char *r;
|
|
|
|
|
|
|
|
|
|
if (self->_count == 0)
|
|
|
|
|
{
|
|
|
|
|
return "";
|
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (internalEncoding == NSASCIIStringEncoding)
|
2002-10-05 17:47:54 +00:00
|
|
|
|
{
|
2003-01-31 17:23:15 +00:00
|
|
|
|
unsigned i = self->_count;
|
2002-10-05 17:47:54 +00:00
|
|
|
|
|
2003-03-02 07:47:18 +00:00
|
|
|
|
r = (unsigned char*)GSAutoreleasedBuffer(self->_count+1);
|
2003-01-31 17:23:15 +00:00
|
|
|
|
while (i-- > 0)
|
2002-10-05 17:47:54 +00:00
|
|
|
|
{
|
2003-01-31 17:23:15 +00:00
|
|
|
|
r[i] = self->_contents.c[i] & 0x7f;
|
2002-10-05 17:47:54 +00:00
|
|
|
|
}
|
|
|
|
|
r[self->_count] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unichar *u = 0;
|
|
|
|
|
unsigned l = 0;
|
|
|
|
|
unsigned s = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We must convert from internal format to unicode and then to
|
|
|
|
|
* UTF8 string encoding.
|
|
|
|
|
*/
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (GSToUnicode(&u, &l, self->_contents.c, self->_count, internalEncoding,
|
2002-10-05 17:47:54 +00:00
|
|
|
|
NSDefaultMallocZone(), 0) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't convert to Unicode string."];
|
|
|
|
|
}
|
2018-01-30 15:01:01 +00:00
|
|
|
|
r = 0;
|
2002-10-05 17:47:54 +00:00
|
|
|
|
if (GSFromUnicode((unsigned char**)&r, &s, u, l, NSUTF8StringEncoding,
|
|
|
|
|
NSDefaultMallocZone(), GSUniTerminate|GSUniTemporary|GSUniStrict) == NO)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't convert from Unicode to UTF8."];
|
|
|
|
|
}
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2008-11-17 13:45:32 +00:00
|
|
|
|
return (const char*)r;
|
2002-10-05 17:47:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-17 13:45:32 +00:00
|
|
|
|
static inline const char*
|
2004-05-14 10:52:30 +00:00
|
|
|
|
UTF8String_u(GSStr self)
|
2002-10-05 17:47:54 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned c = self->_count;
|
|
|
|
|
|
|
|
|
|
if (c == 0)
|
|
|
|
|
{
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned int l = 0;
|
|
|
|
|
unsigned char *r = 0;
|
|
|
|
|
|
|
|
|
|
if (GSFromUnicode(&r, &l, self->_contents.u, c, NSUTF8StringEncoding,
|
|
|
|
|
NSDefaultMallocZone(), GSUniTerminate|GSUniTemporary|GSUniStrict) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't get UTF8 from Unicode string."];
|
|
|
|
|
}
|
2008-11-17 13:45:32 +00:00
|
|
|
|
return (const char*)r;
|
2002-10-05 17:47:54 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
static inline BOOL
|
2004-05-14 10:52:30 +00:00
|
|
|
|
boolValue_c(GSStr self)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2015-05-05 11:54:14 +00:00
|
|
|
|
unsigned count = self->_count;
|
2008-02-20 09:56:25 +00:00
|
|
|
|
unsigned i;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
for (i = 0; i < count; i++)
|
2008-02-20 09:56:25 +00:00
|
|
|
|
{
|
2009-08-24 07:07:36 +00:00
|
|
|
|
char c = self->_contents.c[i];
|
|
|
|
|
|
|
|
|
|
if (strchr("123456789yYtT", c) != 0)
|
2008-02-20 09:56:25 +00:00
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2009-08-24 07:07:36 +00:00
|
|
|
|
if (!isspace(c) && c != '0' && c != '-' && c != '+')
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2008-02-20 09:56:25 +00:00
|
|
|
|
return NO;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline BOOL
|
2004-05-14 10:52:30 +00:00
|
|
|
|
boolValue_u(GSStr self)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2015-05-05 11:54:14 +00:00
|
|
|
|
unsigned count = self->_count;
|
2008-02-20 09:56:25 +00:00
|
|
|
|
unsigned i;
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
for (i = 0; i < count; i++)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2009-08-24 07:07:36 +00:00
|
|
|
|
unichar c = self->_contents.u[i];
|
|
|
|
|
|
|
|
|
|
if (c > 'y')
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (strchr("123456789yYtT", c) != 0)
|
2008-02-20 09:56:25 +00:00
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2009-08-24 07:07:36 +00:00
|
|
|
|
if (!isspace(c) && c != '0' && c != '-' && c != '+')
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2008-02-20 09:56:25 +00:00
|
|
|
|
return NO;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
static inline void
|
|
|
|
|
intBuf_c(GSStr self, char *buf)
|
|
|
|
|
{
|
|
|
|
|
unsigned c = self->_count;
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
unsigned j = 0;
|
|
|
|
|
|
|
|
|
|
while (i < c && isspace(self->_contents.c[i]))
|
|
|
|
|
{
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
if (i < c)
|
|
|
|
|
{
|
|
|
|
|
char sign = self->_contents.c[i];
|
|
|
|
|
|
|
|
|
|
if ('+' == sign || '-' == sign)
|
|
|
|
|
{
|
|
|
|
|
buf[j++] = sign;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (i < c && j < 20 && isdigit(self->_contents.c[i]))
|
|
|
|
|
{
|
|
|
|
|
buf[j++] = self->_contents.c[i++];
|
|
|
|
|
}
|
|
|
|
|
buf[j] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
intBuf_u(GSStr self, char *buf)
|
|
|
|
|
{
|
|
|
|
|
unsigned c = self->_count;
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
unsigned j = 0;
|
|
|
|
|
|
|
|
|
|
while (i < c && isspace(self->_contents.u[i]))
|
|
|
|
|
{
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
if (i < c)
|
|
|
|
|
{
|
|
|
|
|
unichar sign = self->_contents.u[i];
|
|
|
|
|
|
|
|
|
|
if ('+' == sign || '-' == sign)
|
|
|
|
|
{
|
|
|
|
|
buf[j++] = (char)sign;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (i < c && j < 20 && isdigit(self->_contents.u[i]))
|
|
|
|
|
{
|
|
|
|
|
buf[j++] = (char)self->_contents.u[i++];
|
|
|
|
|
}
|
|
|
|
|
buf[j] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
static inline BOOL
|
2004-05-14 10:52:30 +00:00
|
|
|
|
canBeConvertedToEncoding_c(GSStr self, NSStringEncoding enc)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-01-19 13:28:02 +00:00
|
|
|
|
unsigned c = self->_count;
|
|
|
|
|
BOOL result = YES;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the length is zero, or we are already using the required encoding,
|
|
|
|
|
* or the required encoding is unicode (can hold any character) then we
|
|
|
|
|
* can assume that a conversion would succeed.
|
|
|
|
|
* We also know a conversion must succeed if the internal encoding is
|
|
|
|
|
* ascii and the required encoding has ascii as a subset.
|
|
|
|
|
*/
|
|
|
|
|
if (c > 0
|
2006-05-14 18:01:13 +00:00
|
|
|
|
&& enc != internalEncoding
|
2006-01-19 13:28:02 +00:00
|
|
|
|
&& enc != NSUTF8StringEncoding
|
|
|
|
|
&& enc != NSUnicodeStringEncoding
|
2006-10-09 14:00:01 +00:00
|
|
|
|
&& ((internalEncoding != NSASCIIStringEncoding) || !isByteEncoding(enc)))
|
2000-10-20 10:30:51 +00:00
|
|
|
|
{
|
2006-01-19 13:28:02 +00:00
|
|
|
|
unsigned l = 0;
|
|
|
|
|
unichar *r = 0;
|
2000-10-20 10:30:51 +00:00
|
|
|
|
|
2006-01-19 13:28:02 +00:00
|
|
|
|
/*
|
|
|
|
|
* To check whether conversion is possible, we first convert to
|
|
|
|
|
* unicode and then check to see whether it is possible to convert
|
|
|
|
|
* to the desired encoding.
|
|
|
|
|
*/
|
2006-05-14 18:01:13 +00:00
|
|
|
|
result = GSToUnicode(&r, &l, self->_contents.c, self->_count,
|
|
|
|
|
internalEncoding, NSDefaultMallocZone(), GSUniStrict);
|
2006-01-19 13:28:02 +00:00
|
|
|
|
if (result == YES)
|
|
|
|
|
{
|
|
|
|
|
if (enc == NSISOLatin1StringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If all the unicode characters are in the 0 to 255 range
|
|
|
|
|
* they are all latin1.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < l; i++)
|
|
|
|
|
{
|
|
|
|
|
if (r[i] > 255)
|
|
|
|
|
{
|
|
|
|
|
result = NO;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (enc == NSASCIIStringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If all the unicode characters are in the 0 to 127 range
|
|
|
|
|
* they are all ascii.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < l; i++)
|
|
|
|
|
{
|
|
|
|
|
if (r[i] > 127)
|
|
|
|
|
{
|
|
|
|
|
result = NO;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned dummy = 0; // Hold returned length.
|
|
|
|
|
|
|
|
|
|
result = GSFromUnicode(0, &dummy, r, l, enc, 0, GSUniStrict);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Temporary unicode string no longer needed.
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), r);
|
|
|
|
|
}
|
2000-10-20 10:30:51 +00:00
|
|
|
|
}
|
2006-01-19 13:28:02 +00:00
|
|
|
|
return result;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline BOOL
|
2004-05-14 10:52:30 +00:00
|
|
|
|
canBeConvertedToEncoding_u(GSStr self, NSStringEncoding enc)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-01-19 13:28:02 +00:00
|
|
|
|
unsigned c = self->_count;
|
|
|
|
|
BOOL result = YES;
|
2004-05-14 10:52:30 +00:00
|
|
|
|
|
2006-05-12 10:05:52 +00:00
|
|
|
|
if (c > 0)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
2006-05-12 10:05:52 +00:00
|
|
|
|
if (enc == NSUTF8StringEncoding || enc == NSUnicodeStringEncoding)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
2006-05-12 10:05:52 +00:00
|
|
|
|
if (GSUnicode(self->_contents.u, c, 0, 0) != c)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
2006-05-12 10:05:52 +00:00
|
|
|
|
return NO;
|
2004-05-14 10:52:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-05-12 10:05:52 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
2006-05-12 10:05:52 +00:00
|
|
|
|
if (enc == NSISOLatin1StringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
2006-01-19 13:28:02 +00:00
|
|
|
|
|
2006-05-12 10:05:52 +00:00
|
|
|
|
/*
|
|
|
|
|
* If all the unicode characters are in the 0 to 255 range
|
|
|
|
|
* they are all latin1.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < self->_count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (self->_contents.u[i] > 255)
|
|
|
|
|
{
|
|
|
|
|
result = NO;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (enc == NSASCIIStringEncoding)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
2006-05-12 10:05:52 +00:00
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If all the unicode characters are in the 0 to 127 range
|
|
|
|
|
* they are all ascii.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < self->_count; i++)
|
2006-01-19 13:28:02 +00:00
|
|
|
|
{
|
2006-05-12 10:05:52 +00:00
|
|
|
|
if (self->_contents.u[i] > 127)
|
|
|
|
|
{
|
|
|
|
|
result = NO;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2006-01-19 13:28:02 +00:00
|
|
|
|
}
|
2004-05-14 10:52:30 +00:00
|
|
|
|
}
|
2006-05-12 10:05:52 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned dummy = 0; // Hold returned length.
|
2006-01-19 13:28:02 +00:00
|
|
|
|
|
2006-05-12 10:05:52 +00:00
|
|
|
|
result = GSFromUnicode(0, &dummy, self->_contents.u, c, enc,
|
|
|
|
|
0, GSUniStrict);
|
|
|
|
|
}
|
2006-01-19 13:28:02 +00:00
|
|
|
|
}
|
2004-05-14 10:52:30 +00:00
|
|
|
|
}
|
2000-10-23 06:18:03 +00:00
|
|
|
|
return result;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unichar
|
2004-05-14 10:52:30 +00:00
|
|
|
|
characterAtIndex_c(GSStr self, unsigned index)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-08-12 15:09:23 +00:00
|
|
|
|
unichar u;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
if (index >= self->_count)
|
|
|
|
|
[NSException raise: NSRangeException format: @"Invalid index."];
|
2006-08-12 15:09:23 +00:00
|
|
|
|
u = self->_contents.c[index];
|
|
|
|
|
if (u > 127)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-08-12 15:09:23 +00:00
|
|
|
|
unsigned char c = (unsigned char)u;
|
|
|
|
|
unsigned int s = 1;
|
|
|
|
|
unichar *d = &u;
|
|
|
|
|
|
2018-02-07 10:38:57 +00:00
|
|
|
|
if (GSToUnicode(&d, &s, &c, 1, internalEncoding, 0, 0) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"unable to convert character to unicode"];
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2006-08-12 15:09:23 +00:00
|
|
|
|
return u;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unichar
|
2004-05-14 10:52:30 +00:00
|
|
|
|
characterAtIndex_u(GSStr self,unsigned index)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (index >= self->_count)
|
|
|
|
|
[NSException raise: NSRangeException format: @"Invalid index."];
|
|
|
|
|
return self->_contents.u[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline NSComparisonResult
|
2004-05-14 10:52:30 +00:00
|
|
|
|
compare_c(GSStr self, NSString *aString, unsigned mask, NSRange aRange)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
Class c;
|
|
|
|
|
|
2010-02-22 10:13:20 +00:00
|
|
|
|
c = object_getClass(aString);
|
2000-11-03 10:11:56 +00:00
|
|
|
|
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|
2004-05-14 10:52:30 +00:00
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1))
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return strCompCsUs((id)self, aString, mask, aRange);
|
2000-10-31 16:17:33 +00:00
|
|
|
|
else if (GSObjCIsKindOf(c, GSCStringClass) == YES
|
2004-05-14 10:52:30 +00:00
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 0))
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return strCompCsCs((id)self, aString, mask, aRange);
|
|
|
|
|
else
|
|
|
|
|
return strCompCsNs((id)self, aString, mask, aRange);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline NSComparisonResult
|
2004-05-14 10:52:30 +00:00
|
|
|
|
compare_u(GSStr self, NSString *aString, unsigned mask, NSRange aRange)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
Class c;
|
|
|
|
|
|
2010-02-22 10:13:20 +00:00
|
|
|
|
c = object_getClass(aString);
|
2000-11-03 10:11:56 +00:00
|
|
|
|
if (GSObjCIsKindOf(c, GSUnicodeStringClass)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1))
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return strCompUsUs((id)self, aString, mask, aRange);
|
2000-10-31 16:17:33 +00:00
|
|
|
|
else if (GSObjCIsKindOf(c, GSCStringClass)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 0))
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return strCompUsCs((id)self, aString, mask, aRange);
|
|
|
|
|
else
|
|
|
|
|
return strCompUsNs((id)self, aString, mask, aRange);
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-17 13:45:32 +00:00
|
|
|
|
static inline const char*
|
2005-05-08 07:08:28 +00:00
|
|
|
|
cString_c(GSStr self, NSStringEncoding enc)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2014-06-01 18:08:44 +00:00
|
|
|
|
unsigned char *r = 0;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2002-03-16 09:54:50 +00:00
|
|
|
|
if (self->_count == 0)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2005-05-08 15:07:59 +00:00
|
|
|
|
return "\0";
|
2002-03-16 09:54:50 +00:00
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
else if (enc == internalEncoding)
|
2002-03-16 09:54:50 +00:00
|
|
|
|
{
|
2003-03-02 07:47:18 +00:00
|
|
|
|
r = (unsigned char*)GSAutoreleasedBuffer(self->_count+1);
|
2002-03-16 09:54:50 +00:00
|
|
|
|
|
|
|
|
|
if (self->_count > 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy(r, self->_contents.c, self->_count);
|
|
|
|
|
}
|
|
|
|
|
r[self->_count] = '\0';
|
|
|
|
|
}
|
2005-06-04 05:48:40 +00:00
|
|
|
|
else if (enc == NSUnicodeStringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unsigned l = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
2006-02-27 09:35:19 +00:00
|
|
|
|
* The external C string encoding is unicode ... convert to it.
|
2005-06-04 05:48:40 +00:00
|
|
|
|
*/
|
2005-06-04 07:54:04 +00:00
|
|
|
|
if (GSToUnicode((unichar**)&r, &l, self->_contents.c, self->_count,
|
2006-05-14 18:01:13 +00:00
|
|
|
|
internalEncoding, NSDefaultMallocZone(),
|
2005-06-04 07:54:04 +00:00
|
|
|
|
GSUniTerminate|GSUniTemporary|GSUniStrict) == NO)
|
2005-06-04 05:48:40 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't convert to Unicode string."];
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-03-16 09:54:50 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unichar *u = 0;
|
|
|
|
|
unsigned l = 0;
|
|
|
|
|
unsigned s = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The external C string encoding is not compatible with the internal
|
2002-03-18 09:10:05 +00:00
|
|
|
|
* 8-bit character strings ... we must convert from internal format to
|
|
|
|
|
* unicode and then to the external C string encoding.
|
2002-03-16 09:54:50 +00:00
|
|
|
|
*/
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (GSToUnicode(&u, &l, self->_contents.c, self->_count, internalEncoding,
|
2002-03-16 09:54:50 +00:00
|
|
|
|
NSDefaultMallocZone(), 0) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
2005-06-04 05:48:40 +00:00
|
|
|
|
format: @"Can't convert to Unicode string."];
|
2002-03-16 09:54:50 +00:00
|
|
|
|
}
|
2005-05-08 07:08:28 +00:00
|
|
|
|
if (GSFromUnicode((unsigned char**)&r, &s, u, l, enc,
|
2002-03-16 09:54:50 +00:00
|
|
|
|
NSDefaultMallocZone(), GSUniTerminate|GSUniTemporary|GSUniStrict) == NO)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
2005-06-04 05:48:40 +00:00
|
|
|
|
format: @"Can't convert from Unicode string."];
|
2002-03-16 09:54:50 +00:00
|
|
|
|
}
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2003-08-20 12:13:34 +00:00
|
|
|
|
|
2008-11-17 13:45:32 +00:00
|
|
|
|
return (const char*)r;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-17 13:45:32 +00:00
|
|
|
|
static inline const char*
|
2005-05-08 07:08:28 +00:00
|
|
|
|
cString_u(GSStr self, NSStringEncoding enc)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2002-03-16 09:54:50 +00:00
|
|
|
|
unsigned c = self->_count;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2002-03-16 09:54:50 +00:00
|
|
|
|
if (c == 0)
|
|
|
|
|
{
|
2005-05-08 15:07:59 +00:00
|
|
|
|
return "\0";
|
|
|
|
|
}
|
|
|
|
|
else if (enc == NSUnicodeStringEncoding)
|
|
|
|
|
{
|
2006-05-12 10:05:52 +00:00
|
|
|
|
unichar *tmp;
|
|
|
|
|
unsigned l;
|
2005-05-08 15:07:59 +00:00
|
|
|
|
|
2006-05-12 10:05:52 +00:00
|
|
|
|
if ((l = GSUnicode(self->_contents.u, c, 0, 0)) != c)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"NSString is not legal UTF-16 at %u", l];
|
|
|
|
|
}
|
|
|
|
|
tmp = (unichar*)NSZoneMalloc(NSDefaultMallocZone(), (c + 1)*2);
|
2005-05-08 15:07:59 +00:00
|
|
|
|
memcpy(tmp, self->_contents.u, c*2);
|
|
|
|
|
tmp[c] = 0;
|
2006-08-15 04:51:18 +00:00
|
|
|
|
[NSDataClass dataWithBytesNoCopy: tmp
|
|
|
|
|
length: (c + 1)*2
|
|
|
|
|
freeWhenDone: YES];
|
2008-11-17 13:45:32 +00:00
|
|
|
|
return (const char*)tmp;
|
2002-03-16 09:54:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2002-03-16 09:54:50 +00:00
|
|
|
|
unsigned int l = 0;
|
|
|
|
|
unsigned char *r = 0;
|
|
|
|
|
|
2005-05-08 07:08:28 +00:00
|
|
|
|
if (GSFromUnicode(&r, &l, self->_contents.u, c, enc,
|
2002-03-16 09:54:50 +00:00
|
|
|
|
NSDefaultMallocZone(), GSUniTerminate|GSUniTemporary|GSUniStrict) == NO)
|
2000-10-23 11:44:34 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't get cString from Unicode string."];
|
|
|
|
|
}
|
2008-11-17 13:45:32 +00:00
|
|
|
|
return (const char*)r;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int
|
2005-05-08 07:08:28 +00:00
|
|
|
|
cStringLength_c(GSStr self, NSStringEncoding enc)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (enc == internalEncoding)
|
2002-03-16 09:54:50 +00:00
|
|
|
|
{
|
|
|
|
|
return self->_count;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The external C string encoding is not compatible with the internal
|
2002-03-18 09:10:05 +00:00
|
|
|
|
* 8-bit character strings ... we must convert from internal format to
|
|
|
|
|
* unicode and then to the external C string encoding.
|
2002-03-16 09:54:50 +00:00
|
|
|
|
*/
|
|
|
|
|
if (self->_count == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unichar *u = 0;
|
|
|
|
|
unsigned l = 0;
|
|
|
|
|
unsigned s = 0;
|
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (GSToUnicode(&u, &l, self->_contents.c, self->_count,
|
|
|
|
|
internalEncoding, NSDefaultMallocZone(), 0) == NO)
|
2002-03-16 09:54:50 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't convert to/from Unicode string."];
|
|
|
|
|
}
|
2005-05-08 07:08:28 +00:00
|
|
|
|
if (GSFromUnicode(0, &s, u, l, enc, 0, GSUniStrict) == NO)
|
2002-03-16 09:54:50 +00:00
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't get cStringLength from string."];
|
|
|
|
|
}
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int
|
2005-05-08 07:08:28 +00:00
|
|
|
|
cStringLength_u(GSStr self, NSStringEncoding enc)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2002-03-16 09:54:50 +00:00
|
|
|
|
unsigned c = self->_count;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2002-03-16 09:54:50 +00:00
|
|
|
|
if (c == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2002-03-16 09:54:50 +00:00
|
|
|
|
unsigned l = 0;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2006-05-12 10:05:52 +00:00
|
|
|
|
if (GSFromUnicode(0, &l, self->_contents.u, c, enc, 0, GSUniStrict) == NO)
|
2000-10-23 11:44:34 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't get cStringLength from Unicode string."];
|
|
|
|
|
}
|
2002-03-16 09:54:50 +00:00
|
|
|
|
return l;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
2004-05-14 10:52:30 +00:00
|
|
|
|
fillHole(GSStr self, unsigned index, unsigned size)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
NSCAssert(size > 0, @"size <= zero");
|
|
|
|
|
NSCAssert(index + size <= self->_count, @"index + size > length");
|
|
|
|
|
|
2000-10-10 20:54:08 +00:00
|
|
|
|
self->_count -= size;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
if (self->_flags.wide == 1)
|
|
|
|
|
{
|
2003-05-05 13:36:25 +00:00
|
|
|
|
memmove(self->_contents.u + index,
|
2003-03-23 07:06:27 +00:00
|
|
|
|
self->_contents.u + index + size,
|
2000-10-09 05:32:50 +00:00
|
|
|
|
sizeof(unichar)*(self->_count - index));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-05-05 13:36:25 +00:00
|
|
|
|
memmove(self->_contents.c + index,
|
2003-03-23 07:06:27 +00:00
|
|
|
|
self->_contents.c + index + size, (self->_count - index));
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
self->_flags.hash = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_c(GSStr self, unichar *buffer, NSRange aRange)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2015-05-24 14:12:42 +00:00
|
|
|
|
if (aRange.length)
|
|
|
|
|
{
|
|
|
|
|
if (NSISOLatin1StringEncoding == internalEncoding)
|
|
|
|
|
{
|
|
|
|
|
register NSUInteger count = aRange.length;
|
|
|
|
|
register NSUInteger base = aRange.location;
|
2002-03-16 09:54:50 +00:00
|
|
|
|
|
2015-05-24 14:12:42 +00:00
|
|
|
|
while (count-- > 0)
|
|
|
|
|
{
|
|
|
|
|
buffer[count] = self->_contents.c[base + count];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned len = aRange.length;
|
2003-05-05 13:36:25 +00:00
|
|
|
|
|
2015-05-24 14:12:42 +00:00
|
|
|
|
if (!GSToUnicode(&buffer, &len, self->_contents.c + aRange.location,
|
|
|
|
|
aRange.length, internalEncoding, 0, 0))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Can't convert to Unicode."];
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-05-05 13:36:25 +00:00
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_u(GSStr self, unichar *buffer, NSRange aRange)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
memcpy(buffer, self->_contents.u + aRange.location,
|
|
|
|
|
aRange.length*sizeof(unichar));
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-12 04:55:36 +00:00
|
|
|
|
static void
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_c(GSStr self, char *buffer, unsigned int maxLength,
|
2000-10-09 05:32:50 +00:00
|
|
|
|
NSRange aRange, NSRange *leftoverRange)
|
|
|
|
|
{
|
2010-02-21 11:12:17 +00:00
|
|
|
|
GSMutableString *o;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
int len;
|
|
|
|
|
|
2000-10-09 06:34:05 +00:00
|
|
|
|
if (maxLength > self->_count)
|
|
|
|
|
{
|
|
|
|
|
maxLength = self->_count;
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
if (maxLength < aRange.length)
|
|
|
|
|
{
|
|
|
|
|
len = maxLength;
|
|
|
|
|
if (leftoverRange != 0)
|
|
|
|
|
{
|
2001-06-20 19:12:31 +00:00
|
|
|
|
leftoverRange->location = aRange.location + maxLength;
|
|
|
|
|
leftoverRange->length = aRange.length - maxLength;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
len = aRange.length;
|
|
|
|
|
if (leftoverRange != 0)
|
|
|
|
|
{
|
2001-06-20 19:12:31 +00:00
|
|
|
|
leftoverRange->location = 0;
|
|
|
|
|
leftoverRange->length = 0;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-21 11:12:17 +00:00
|
|
|
|
if (externalEncoding == internalEncoding)
|
|
|
|
|
{
|
|
|
|
|
memcpy(buffer, &self->_contents.c[aRange.location], len);
|
|
|
|
|
buffer[len] = '\0';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isByteEncoding(internalEncoding))
|
|
|
|
|
{
|
|
|
|
|
if (externalEncoding == NSUTF8StringEncoding
|
|
|
|
|
|| isByteEncoding(externalEncoding))
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *ptr = self->_contents.c + aRange.location;
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Maybe we actually contain ascii data, which can be
|
|
|
|
|
* copied out directly.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
unsigned char c = ptr[i];
|
|
|
|
|
|
|
|
|
|
if (c > 127)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
buffer[i] = c;
|
|
|
|
|
}
|
|
|
|
|
if (i == len)
|
|
|
|
|
{
|
|
|
|
|
buffer[i] = '\0';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* As the internal and external encodings don't match, the simplest
|
|
|
|
|
* thing to do is widen the internal data to unicode and use the
|
|
|
|
|
* unicode function to get the cString.
|
|
|
|
|
*/
|
|
|
|
|
o = (GSMutableString*)alloca(class_getInstanceSize(GSMutableStringClass));
|
|
|
|
|
object_setClass(o, GSMutableStringClass);
|
|
|
|
|
o->_count = self->_count;
|
|
|
|
|
o->_flags.wide = 0;
|
|
|
|
|
o->_flags.owned = 0;
|
|
|
|
|
o->_flags.unused = 0;
|
|
|
|
|
o->_flags.hash = 0;
|
|
|
|
|
o->_capacity = self->_count;
|
|
|
|
|
o->_contents.c = self->_contents.c;
|
|
|
|
|
o->_zone = NSDefaultMallocZone();
|
|
|
|
|
GSStrWiden(o);
|
|
|
|
|
getCString_u(o, buffer, maxLength, aRange, leftoverRange);
|
|
|
|
|
if (o->_flags.owned == 1)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(o->_zone, o->_contents.u);
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-08-12 04:55:36 +00:00
|
|
|
|
static void
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_u(GSStr self, char *buffer, unsigned int maxLength,
|
2000-10-09 05:32:50 +00:00
|
|
|
|
NSRange aRange, NSRange *leftoverRange)
|
|
|
|
|
{
|
2003-07-09 02:13:58 +00:00
|
|
|
|
/* The primitive we have for converting from unicode, GSFromUnicode,
|
|
|
|
|
can't deal with our leftoverRange case, so we need to use a bit of
|
|
|
|
|
complexity instead. */
|
|
|
|
|
unsigned int len;
|
2004-05-03 20:16:37 +00:00
|
|
|
|
|
2003-07-09 02:13:58 +00:00
|
|
|
|
/* TODO: this is an extremely ugly hack to work around buggy iconvs
|
|
|
|
|
that return -1/E2BIG for buffers larger than 0x40000acf */
|
|
|
|
|
if (maxLength > 0x40000000)
|
|
|
|
|
maxLength = 0x40000000;
|
|
|
|
|
|
|
|
|
|
/* First, try converting the whole thing. */
|
|
|
|
|
len = maxLength;
|
|
|
|
|
if (GSFromUnicode((unsigned char **)&buffer, &len,
|
2006-05-14 18:01:13 +00:00
|
|
|
|
self->_contents.u + aRange.location, aRange.length,
|
|
|
|
|
externalEncoding, 0, GSUniTerminate | GSUniStrict) == YES)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2003-07-09 02:13:58 +00:00
|
|
|
|
if (leftoverRange)
|
|
|
|
|
leftoverRange->location = leftoverRange->length = 0;
|
|
|
|
|
return;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-09 02:13:58 +00:00
|
|
|
|
/* The conversion failed. Either the buffer is too small for the whole
|
|
|
|
|
range, or there are characters in it we can't convert. Check for
|
|
|
|
|
unconvertable characters first. */
|
|
|
|
|
len = 0;
|
|
|
|
|
if (GSFromUnicode(NULL, &len,
|
2006-05-14 18:01:13 +00:00
|
|
|
|
self->_contents.u + aRange.location, aRange.length,
|
|
|
|
|
externalEncoding, 0, GSUniTerminate | GSUniStrict) == NO)
|
2000-12-14 09:47:02 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't get cString from Unicode string."];
|
2003-07-09 02:13:58 +00:00
|
|
|
|
return;
|
2000-12-14 09:47:02 +00:00
|
|
|
|
}
|
2003-07-09 02:13:58 +00:00
|
|
|
|
|
|
|
|
|
/* The string can be converted, but not all of it. Do a binary search
|
|
|
|
|
to find the longest subrange that fits in the buffer. */
|
|
|
|
|
{
|
|
|
|
|
unsigned int lo, hi, mid;
|
|
|
|
|
|
|
|
|
|
lo = 0;
|
|
|
|
|
hi = aRange.length;
|
|
|
|
|
while (lo < hi)
|
|
|
|
|
{
|
|
|
|
|
mid = (lo + hi + 1) / 2; /* round up to get edge case right */
|
|
|
|
|
len = maxLength;
|
|
|
|
|
if (GSFromUnicode((unsigned char **)&buffer, &len,
|
2006-05-14 18:01:13 +00:00
|
|
|
|
self->_contents.u + aRange.location, mid,
|
|
|
|
|
externalEncoding, 0, GSUniTerminate | GSUniStrict) == YES)
|
2003-07-09 02:13:58 +00:00
|
|
|
|
{
|
|
|
|
|
lo = mid;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
hi = mid - 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* lo==hi characters fit. Do the real conversion. */
|
|
|
|
|
len = maxLength;
|
|
|
|
|
if (lo == 0)
|
|
|
|
|
{
|
|
|
|
|
buffer[0] = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (GSFromUnicode((unsigned char **)&buffer, &len,
|
2006-05-14 18:01:13 +00:00
|
|
|
|
self->_contents.u + aRange.location, lo,
|
|
|
|
|
externalEncoding, 0, GSUniTerminate | GSUniStrict) == NO)
|
2003-07-09 02:13:58 +00:00
|
|
|
|
{
|
|
|
|
|
NSCAssert(NO, @"binary search gave inconsistent results");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (leftoverRange)
|
|
|
|
|
{
|
|
|
|
|
leftoverRange->location = aRange.location + lo;
|
|
|
|
|
leftoverRange->length = NSMaxRange(aRange) - leftoverRange->location;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
static inline BOOL
|
|
|
|
|
getCStringE_c(GSStr self, char *buffer, unsigned int maxLength,
|
|
|
|
|
NSStringEncoding enc)
|
|
|
|
|
{
|
2006-06-29 13:32:56 +00:00
|
|
|
|
if (buffer == 0)
|
|
|
|
|
{
|
|
|
|
|
return NO; // Can't fit in here
|
|
|
|
|
}
|
2006-02-27 09:35:19 +00:00
|
|
|
|
if (enc == NSUnicodeStringEncoding)
|
|
|
|
|
{
|
|
|
|
|
if (maxLength >= sizeof(unichar))
|
|
|
|
|
{
|
|
|
|
|
unsigned bytes = maxLength - sizeof(unichar);
|
2011-02-19 15:34:21 +00:00
|
|
|
|
unichar *u = (unichar*)(void*)buffer;
|
2006-02-27 09:35:19 +00:00
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (GSToUnicode(&u, &bytes, self->_contents.c, self->_count,
|
|
|
|
|
internalEncoding, NSDefaultMallocZone(), GSUniTerminate) == NO)
|
2006-02-27 09:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't convert to Unicode string."];
|
|
|
|
|
}
|
2011-02-19 15:34:21 +00:00
|
|
|
|
if (u == (unichar*)(void*)buffer)
|
2006-02-27 09:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (maxLength > sizeof(char))
|
|
|
|
|
{
|
|
|
|
|
unsigned bytes = maxLength - sizeof(char);
|
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (enc == internalEncoding)
|
2006-02-27 09:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
if (bytes > self->_count)
|
|
|
|
|
{
|
|
|
|
|
bytes = self->_count;
|
|
|
|
|
}
|
|
|
|
|
memcpy(buffer, self->_contents.c, bytes);
|
|
|
|
|
buffer[bytes] = '\0';
|
|
|
|
|
if (bytes < self->_count)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2006-06-29 13:32:56 +00:00
|
|
|
|
|
|
|
|
|
if (enc == NSUTF8StringEncoding
|
2006-10-09 14:00:01 +00:00
|
|
|
|
&& isByteEncoding(internalEncoding))
|
2006-06-29 13:32:56 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Maybe we actually contain ascii data, which can be
|
|
|
|
|
* copied out directly as a utf-8 string.
|
|
|
|
|
*/
|
|
|
|
|
if (bytes > self->_count)
|
|
|
|
|
{
|
|
|
|
|
bytes = self->_count;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < bytes; i++)
|
|
|
|
|
{
|
|
|
|
|
unsigned char c = self->_contents.c[i];
|
|
|
|
|
|
|
|
|
|
if (c > 127)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
buffer[i] = c;
|
|
|
|
|
}
|
|
|
|
|
if (i == bytes)
|
|
|
|
|
{
|
|
|
|
|
buffer[bytes] = '\0';
|
|
|
|
|
if (bytes < self->_count)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (enc == NSASCIIStringEncoding
|
2006-10-09 14:00:01 +00:00
|
|
|
|
&& isByteEncoding(internalEncoding))
|
2006-02-27 09:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
if (bytes > self->_count)
|
|
|
|
|
{
|
|
|
|
|
bytes = self->_count;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < bytes; i++)
|
|
|
|
|
{
|
|
|
|
|
unsigned char c = self->_contents.c[i];
|
|
|
|
|
|
|
|
|
|
if (c > 127)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"unable to convert to encoding"];
|
|
|
|
|
}
|
|
|
|
|
buffer[i] = c;
|
|
|
|
|
}
|
|
|
|
|
buffer[bytes] = '\0';
|
|
|
|
|
if (bytes < self->_count)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unichar *u = 0;
|
|
|
|
|
unsigned char *c = (unsigned char*)buffer;
|
|
|
|
|
unsigned l = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The specified C string encoding is not compatible with
|
|
|
|
|
* the internal 8-bit character strings ... we must convert
|
|
|
|
|
* from internal format to unicode and then to the specified
|
|
|
|
|
* C string encoding.
|
|
|
|
|
*/
|
2007-06-08 06:00:11 +00:00
|
|
|
|
bytes = maxLength - sizeof(char);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (GSToUnicode(&u, &l, self->_contents.c, self->_count,
|
|
|
|
|
internalEncoding, NSDefaultMallocZone(), 0) == NO)
|
2006-02-27 09:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't convert to Unicode string."];
|
|
|
|
|
}
|
|
|
|
|
if (GSFromUnicode((unsigned char**)&c, &bytes, u, l, enc,
|
2006-06-29 13:32:56 +00:00
|
|
|
|
0, GSUniTerminate|GSUniStrict) == NO)
|
2006-02-27 09:35:19 +00:00
|
|
|
|
{
|
2006-06-29 13:32:56 +00:00
|
|
|
|
c = 0; // Unable to convert
|
2006-02-27 09:35:19 +00:00
|
|
|
|
}
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
if (c == (unsigned char*)buffer)
|
|
|
|
|
{
|
|
|
|
|
return YES; // Fitted in original buffer
|
|
|
|
|
}
|
2006-06-29 13:32:56 +00:00
|
|
|
|
else if (c != 0)
|
2006-02-27 09:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline BOOL
|
|
|
|
|
getCStringE_u(GSStr self, char *buffer, unsigned int maxLength,
|
|
|
|
|
NSStringEncoding enc)
|
|
|
|
|
{
|
|
|
|
|
if (enc == NSUnicodeStringEncoding)
|
|
|
|
|
{
|
|
|
|
|
if (maxLength >= sizeof(unichar))
|
|
|
|
|
{
|
|
|
|
|
unsigned bytes = maxLength - sizeof(unichar);
|
|
|
|
|
|
|
|
|
|
if (bytes/sizeof(unichar) > self->_count)
|
|
|
|
|
{
|
|
|
|
|
bytes = self->_count * sizeof(unichar);
|
|
|
|
|
}
|
|
|
|
|
memcpy(buffer, self->_contents.u, bytes);
|
|
|
|
|
buffer[bytes] = '\0';
|
|
|
|
|
buffer[bytes + 1] = '\0';
|
|
|
|
|
if (bytes/sizeof(unichar) == self->_count)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (maxLength >= 1)
|
|
|
|
|
{
|
|
|
|
|
if (enc == NSISOLatin1StringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unsigned bytes = maxLength - sizeof(char);
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
if (bytes > self->_count)
|
|
|
|
|
{
|
|
|
|
|
bytes = self->_count;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < bytes; i++)
|
|
|
|
|
{
|
|
|
|
|
unichar u = self->_contents.u[i];
|
|
|
|
|
|
|
|
|
|
if (u & 0xff00)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"unable to convert to encoding"];
|
|
|
|
|
}
|
|
|
|
|
buffer[i] = (char)u;
|
|
|
|
|
}
|
2011-03-09 10:24:18 +00:00
|
|
|
|
buffer[i] = '\0';
|
2006-02-27 09:35:19 +00:00
|
|
|
|
if (bytes == self->_count)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (enc == NSASCIIStringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unsigned bytes = maxLength - sizeof(char);
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
if (bytes > self->_count)
|
|
|
|
|
{
|
|
|
|
|
bytes = self->_count;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < bytes; i++)
|
|
|
|
|
{
|
|
|
|
|
unichar u = self->_contents.u[i];
|
|
|
|
|
|
|
|
|
|
if (u & 0xff80)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"unable to convert to encoding"];
|
|
|
|
|
}
|
|
|
|
|
buffer[i] = (char)u;
|
|
|
|
|
}
|
2011-03-09 10:24:18 +00:00
|
|
|
|
buffer[i] = '\0';
|
2006-02-27 09:35:19 +00:00
|
|
|
|
if (bytes == self->_count)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned char *c = (unsigned char*)buffer;
|
|
|
|
|
|
|
|
|
|
if (GSFromUnicode((unsigned char**)&c, &maxLength,
|
|
|
|
|
self->_contents.u, self->_count, enc,
|
2006-06-29 13:32:56 +00:00
|
|
|
|
0, GSUniTerminate|GSUniStrict) == NO)
|
2006-02-27 09:35:19 +00:00
|
|
|
|
{
|
2006-06-29 13:32:56 +00:00
|
|
|
|
return NO;
|
2006-02-27 09:35:19 +00:00
|
|
|
|
}
|
2006-06-29 13:32:56 +00:00
|
|
|
|
return YES;
|
2006-02-27 09:35:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
static inline BOOL
|
2004-05-14 10:52:30 +00:00
|
|
|
|
isEqual_c(GSStr self, id anObject)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
Class c;
|
|
|
|
|
|
|
|
|
|
if (anObject == (id)self)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
if (anObject == nil)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2015-05-25 14:51:02 +00:00
|
|
|
|
c = object_getClass(anObject);
|
|
|
|
|
if (class_isMetaClass(c) == YES)
|
2000-10-20 10:30:51 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2011-10-31 08:12:26 +00:00
|
|
|
|
if (c == NSConstantStringClass)
|
|
|
|
|
{
|
2011-11-01 09:43:25 +00:00
|
|
|
|
return literalIsEqualInternal((NXConstantString*)anObject, (GSStr)self);
|
2011-10-31 08:12:26 +00:00
|
|
|
|
}
|
2011-10-12 14:28:44 +00:00
|
|
|
|
if (c == GSMutableStringClass || GSObjCIsKindOf(c, GSStringClass) == YES)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
GSStr other = (GSStr)anObject;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
NSRange r = {0, self->_count};
|
|
|
|
|
|
2015-05-25 14:51:02 +00:00
|
|
|
|
/* First see if the hash is the same - if not, we can't be equal.
|
|
|
|
|
* However, it's not worth calculating hashes unless the strings
|
|
|
|
|
* are fairly long.
|
2000-10-09 05:32:50 +00:00
|
|
|
|
*/
|
2015-05-25 14:51:02 +00:00
|
|
|
|
if (self->_count > 15)
|
|
|
|
|
{
|
|
|
|
|
if (self->_flags.hash == 0)
|
|
|
|
|
self->_flags.hash = (*hashImp)((id)self, hashSel);
|
|
|
|
|
if (other->_flags.hash == 0)
|
|
|
|
|
other->_flags.hash = (*hashImp)((id)other, hashSel);
|
|
|
|
|
if (self->_flags.hash != other->_flags.hash)
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else if (self->_flags.hash && other->_flags.hash)
|
|
|
|
|
{
|
|
|
|
|
if (self->_flags.hash != other->_flags.hash)
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Do a compare depending on the type of the other string.
|
|
|
|
|
*/
|
|
|
|
|
if (other->_flags.wide == 1)
|
|
|
|
|
{
|
2000-10-20 10:30:51 +00:00
|
|
|
|
if (strCompCsUs((id)self, (id)other, 0, r) == NSOrderedSame)
|
|
|
|
|
return YES;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-06-08 16:03:54 +00:00
|
|
|
|
if (other->_count == self->_count
|
|
|
|
|
&& memcmp(other->_contents.c, self->_contents.c, self->_count) == 0)
|
2000-10-20 10:30:51 +00:00
|
|
|
|
return YES;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2010-02-08 17:52:36 +00:00
|
|
|
|
else if (YES == [anObject isKindOfClass: NSStringClass]) // may be proxy
|
2000-10-20 10:30:51 +00:00
|
|
|
|
{
|
|
|
|
|
return (*equalImp)((id)self, equalSel, anObject);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline BOOL
|
2004-05-14 10:52:30 +00:00
|
|
|
|
isEqual_u(GSStr self, id anObject)
|
2000-10-20 10:30:51 +00:00
|
|
|
|
{
|
|
|
|
|
Class c;
|
|
|
|
|
|
|
|
|
|
if (anObject == (id)self)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
if (anObject == nil)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2015-05-25 14:51:02 +00:00
|
|
|
|
c = object_getClass(anObject);
|
|
|
|
|
if (class_isMetaClass(c) == YES)
|
2000-10-20 10:30:51 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2011-10-31 08:12:26 +00:00
|
|
|
|
if (c == NSConstantStringClass)
|
|
|
|
|
{
|
2011-11-01 09:43:25 +00:00
|
|
|
|
return literalIsEqualInternal((NXConstantString*)anObject, (GSStr)self);
|
2011-10-31 08:12:26 +00:00
|
|
|
|
}
|
2011-10-12 14:28:44 +00:00
|
|
|
|
if (c == GSMutableStringClass || GSObjCIsKindOf(c, GSStringClass) == YES)
|
2000-10-20 10:30:51 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
GSStr other = (GSStr)anObject;
|
2000-10-20 10:30:51 +00:00
|
|
|
|
NSRange r = {0, self->_count};
|
|
|
|
|
|
2015-05-25 14:51:02 +00:00
|
|
|
|
/* First see if the hash is the same - if not, we can't be equal.
|
|
|
|
|
* However, it's not worth calculating hashes unless the strings
|
|
|
|
|
* are fairly long.
|
2000-10-20 10:30:51 +00:00
|
|
|
|
*/
|
2015-05-25 14:51:02 +00:00
|
|
|
|
if (self->_count > 15)
|
|
|
|
|
{
|
|
|
|
|
if (self->_flags.hash == 0)
|
|
|
|
|
self->_flags.hash = (*hashImp)((id)self, hashSel);
|
|
|
|
|
if (other->_flags.hash == 0)
|
|
|
|
|
other->_flags.hash = (*hashImp)((id)other, hashSel);
|
|
|
|
|
if (self->_flags.hash != other->_flags.hash)
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else if (self->_flags.hash && other->_flags.hash)
|
|
|
|
|
{
|
|
|
|
|
if (self->_flags.hash != other->_flags.hash)
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2000-10-20 10:30:51 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Do a compare depending on the type of the other string.
|
|
|
|
|
*/
|
|
|
|
|
if (other->_flags.wide == 1)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2000-10-20 10:30:51 +00:00
|
|
|
|
if (strCompUsUs((id)self, (id)other, 0, r) == NSOrderedSame)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2000-10-20 10:30:51 +00:00
|
|
|
|
if (strCompUsCs((id)self, (id)other, 0, r) == NSOrderedSame)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2010-02-08 17:52:36 +00:00
|
|
|
|
else if (YES == [anObject isKindOfClass: NSStringClass]) // may be proxy
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
return (*equalImp)((id)self, equalSel, anObject);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline const char*
|
2004-05-14 10:52:30 +00:00
|
|
|
|
lossyCString_c(GSStr self)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2002-03-19 07:39:05 +00:00
|
|
|
|
char *r;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2002-03-19 07:39:05 +00:00
|
|
|
|
if (self->_count == 0)
|
|
|
|
|
{
|
|
|
|
|
return "";
|
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (externalEncoding == internalEncoding)
|
2002-03-19 07:39:05 +00:00
|
|
|
|
{
|
2003-03-02 07:47:18 +00:00
|
|
|
|
r = (char*)GSAutoreleasedBuffer(self->_count+1);
|
2002-03-19 07:39:05 +00:00
|
|
|
|
|
|
|
|
|
if (self->_count > 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy(r, self->_contents.c, self->_count);
|
|
|
|
|
}
|
|
|
|
|
r[self->_count] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unichar *u = 0;
|
|
|
|
|
unsigned l = 0;
|
|
|
|
|
unsigned s = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The external C string encoding is not compatible with the internal
|
|
|
|
|
* 8-bit character strings ... we must convert from internal format to
|
|
|
|
|
* unicode and then to the external C string encoding.
|
|
|
|
|
*/
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (GSToUnicode(&u, &l, self->_contents.c, self->_count,
|
|
|
|
|
internalEncoding, NSDefaultMallocZone(), 0) == NO)
|
2002-03-19 07:39:05 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't convert to/from Unicode string."];
|
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (GSFromUnicode((unsigned char**)&r, &s, u, l, externalEncoding,
|
2002-03-19 07:39:05 +00:00
|
|
|
|
NSDefaultMallocZone(), GSUniTerminate|GSUniTemporary) == NO)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't convert to/from Unicode string."];
|
|
|
|
|
}
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-03-19 07:39:05 +00:00
|
|
|
|
return r;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline const char*
|
2004-05-14 10:52:30 +00:00
|
|
|
|
lossyCString_u(GSStr self)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2002-03-20 06:46:26 +00:00
|
|
|
|
unsigned l = 0;
|
|
|
|
|
unsigned char *r = 0;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2021-01-25 12:25:49 +00:00
|
|
|
|
(void)GSFromUnicode(&r, &l, self->_contents.u, self->_count,
|
|
|
|
|
externalEncoding, NSDefaultMallocZone(), GSUniTemporary|GSUniTerminate);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return (const char*)r;
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
static void GSStrMakeSpace(GSStr s, unsigned size)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned want;
|
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
want = size + s->_count + 1;
|
|
|
|
|
s->_capacity += s->_capacity/2;
|
|
|
|
|
if (want > s->_capacity)
|
|
|
|
|
{
|
|
|
|
|
s->_capacity = want;
|
|
|
|
|
}
|
2009-04-10 08:25:03 +00:00
|
|
|
|
if (s->_flags.owned == 1)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we own the character buffer, we can simply realloc.
|
|
|
|
|
*/
|
|
|
|
|
if (s->_flags.wide == 1)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
s->_contents.u = NSZoneRealloc(s->_zone,
|
|
|
|
|
s->_contents.u, s->_capacity*sizeof(unichar));
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2004-05-14 10:52:30 +00:00
|
|
|
|
else
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
s->_contents.c = NSZoneRealloc(s->_zone,
|
|
|
|
|
s->_contents.c, s->_capacity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If the initial data was not to be freed, we must allocate new
|
|
|
|
|
* buffer, copy the data, and set up the zone we are using.
|
|
|
|
|
*/
|
|
|
|
|
if (s->_zone == 0)
|
|
|
|
|
{
|
2010-03-05 09:30:18 +00:00
|
|
|
|
s->_zone = [(NSString*)s zone];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2004-05-14 10:52:30 +00:00
|
|
|
|
if (s->_flags.wide == 1)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
unichar *tmp = s->_contents.u;
|
|
|
|
|
|
|
|
|
|
s->_contents.u = NSZoneMalloc(s->_zone,
|
|
|
|
|
s->_capacity*sizeof(unichar));
|
|
|
|
|
if (s->_count > 0)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
memcpy(s->_contents.u, tmp, s->_count*sizeof(unichar));
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2004-05-14 10:52:30 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned char *tmp = s->_contents.c;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
s->_contents.c = NSZoneMalloc(s->_zone, s->_capacity);
|
|
|
|
|
if (s->_count > 0)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
memcpy(s->_contents.c, tmp, s->_count);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-04-10 08:25:03 +00:00
|
|
|
|
s->_flags.owned = 1;
|
2004-05-14 10:52:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
static void GSStrWiden(GSStr s)
|
|
|
|
|
{
|
|
|
|
|
unichar *tmp = 0;
|
2005-07-08 11:48:37 +00:00
|
|
|
|
unsigned len = 0;
|
2004-05-14 10:52:30 +00:00
|
|
|
|
|
|
|
|
|
NSCAssert(s->_flags.wide == 0, @"string is not wide");
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* As a special case, where we are ascii or latin1 and the buffer size
|
|
|
|
|
* is big enough, we can widen to unicode without having to allocate
|
|
|
|
|
* more memory or call a character conversion function.
|
|
|
|
|
*/
|
|
|
|
|
if (s->_count <= s->_capacity / 2)
|
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (internalEncoding == NSISOLatin1StringEncoding
|
|
|
|
|
|| internalEncoding == NSASCIIStringEncoding)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
|
|
|
|
len = s->_count;
|
|
|
|
|
while (len-- > 0)
|
|
|
|
|
{
|
|
|
|
|
s->_contents.u[len] = s->_contents.c[len];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2004-05-14 10:52:30 +00:00
|
|
|
|
s->_capacity /= 2;
|
|
|
|
|
s->_flags.wide = 1;
|
|
|
|
|
return;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
if (!s->_zone)
|
|
|
|
|
{
|
2010-03-05 09:30:18 +00:00
|
|
|
|
s->_zone = [(NSString*)s zone];
|
2004-05-14 10:52:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (!GSToUnicode(&tmp, &len, s->_contents.c, s->_count,
|
|
|
|
|
internalEncoding, s->_zone, 0))
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"widen of string failed"];
|
|
|
|
|
}
|
2009-04-10 08:25:03 +00:00
|
|
|
|
if (s->_flags.owned == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
|
|
|
|
NSZoneFree(s->_zone, s->_contents.c);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
s->_flags.owned = 1;
|
2004-05-14 10:52:30 +00:00
|
|
|
|
}
|
|
|
|
|
s->_contents.u = tmp;
|
|
|
|
|
s->_flags.wide = 1;
|
|
|
|
|
s->_count = len;
|
|
|
|
|
s->_capacity = len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
makeHole(GSStr self, unsigned int index, unsigned int size)
|
|
|
|
|
{
|
|
|
|
|
NSCAssert(size > 0, @"size < zero");
|
|
|
|
|
NSCAssert(index <= self->_count, @"index > length");
|
|
|
|
|
|
|
|
|
|
if (self->_count + size + 1 >= self->_capacity)
|
|
|
|
|
{
|
|
|
|
|
GSStrMakeSpace((GSStr)self, size);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
if (index < self->_count)
|
|
|
|
|
{
|
|
|
|
|
if (self->_flags.wide == 1)
|
|
|
|
|
{
|
2003-05-05 13:36:25 +00:00
|
|
|
|
memmove(self->_contents.u + index + size,
|
|
|
|
|
self->_contents.u + index,
|
2000-10-09 05:32:50 +00:00
|
|
|
|
sizeof(unichar)*(self->_count - index));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-05-05 13:36:25 +00:00
|
|
|
|
memmove(self->_contents.c + index + size,
|
|
|
|
|
self->_contents.c + index,
|
2000-10-09 05:32:50 +00:00
|
|
|
|
(self->_count - index));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self->_count += size;
|
|
|
|
|
self->_flags.hash = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline NSRange
|
2004-05-14 10:52:30 +00:00
|
|
|
|
rangeOfSequence_c(GSStr self, unsigned anIndex)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (anIndex >= self->_count)
|
|
|
|
|
[NSException raise: NSRangeException format:@"Invalid location."];
|
|
|
|
|
|
|
|
|
|
return (NSRange){anIndex, 1};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline NSRange
|
2004-05-14 10:52:30 +00:00
|
|
|
|
rangeOfSequence_u(GSStr self, unsigned anIndex)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned start;
|
|
|
|
|
unsigned end;
|
|
|
|
|
|
|
|
|
|
if (anIndex >= self->_count)
|
|
|
|
|
[NSException raise: NSRangeException format:@"Invalid location."];
|
|
|
|
|
|
|
|
|
|
start = anIndex;
|
|
|
|
|
while (uni_isnonsp(self->_contents.u[start]) && start > 0)
|
|
|
|
|
start--;
|
|
|
|
|
end = start + 1;
|
|
|
|
|
if (end < self->_count)
|
2005-02-22 11:22:44 +00:00
|
|
|
|
while ((end < self->_count) && (uni_isnonsp(self->_contents.u[end])))
|
2000-10-09 05:32:50 +00:00
|
|
|
|
end++;
|
|
|
|
|
return (NSRange){start, end-start};
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-06 13:44:03 +00:00
|
|
|
|
static inline NSRange
|
2004-05-14 10:52:30 +00:00
|
|
|
|
rangeOfCharacter_c(GSStr self, NSCharacterSet *aSet, unsigned mask,
|
2002-02-06 13:44:03 +00:00
|
|
|
|
NSRange aRange)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int start;
|
|
|
|
|
int stop;
|
|
|
|
|
int step;
|
|
|
|
|
NSRange range;
|
|
|
|
|
BOOL (*mImp)(id, SEL, unichar);
|
|
|
|
|
|
|
|
|
|
if (aSet == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException format: @"range of nil"];
|
|
|
|
|
|
|
|
|
|
if ((mask & NSBackwardsSearch) == NSBackwardsSearch)
|
|
|
|
|
{
|
2011-03-09 10:24:18 +00:00
|
|
|
|
start = NSMaxRange(aRange) - 1;
|
|
|
|
|
stop = aRange.location - 1;
|
|
|
|
|
step = -1;
|
2002-02-06 13:44:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-03-09 10:24:18 +00:00
|
|
|
|
start = aRange.location;
|
|
|
|
|
stop = NSMaxRange(aRange);
|
|
|
|
|
step = 1;
|
2002-02-06 13:44:03 +00:00
|
|
|
|
}
|
|
|
|
|
range.location = NSNotFound;
|
|
|
|
|
range.length = 0;
|
|
|
|
|
|
|
|
|
|
mImp = (BOOL(*)(id,SEL,unichar))
|
|
|
|
|
[aSet methodForSelector: cMemberSel];
|
|
|
|
|
|
|
|
|
|
for (i = start; i != stop; i += step)
|
|
|
|
|
{
|
2006-08-12 15:09:23 +00:00
|
|
|
|
unichar u = self->_contents.c[i];
|
2002-02-06 13:44:03 +00:00
|
|
|
|
|
2008-07-15 07:31:55 +00:00
|
|
|
|
if (u > 127 && internalEncoding != NSISOLatin1StringEncoding)
|
2002-02-06 13:44:03 +00:00
|
|
|
|
{
|
2006-08-12 15:09:23 +00:00
|
|
|
|
unsigned char c = (unsigned char)u;
|
|
|
|
|
unsigned int s = 1;
|
|
|
|
|
unichar *d = &u;
|
|
|
|
|
|
2018-02-07 10:49:02 +00:00
|
|
|
|
if (GSToUnicode(&d, &s, &c, 1, internalEncoding, 0, 0) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"unable to convert character to unicode"];
|
|
|
|
|
}
|
2002-02-06 13:44:03 +00:00
|
|
|
|
}
|
2008-07-15 07:31:55 +00:00
|
|
|
|
/* FIXME ... what about UTF-16 sequences of more than one 16bit value
|
|
|
|
|
* corresponding to a single UCS-32 codepoint?
|
|
|
|
|
*/
|
2006-08-12 15:09:23 +00:00
|
|
|
|
if ((*mImp)(aSet, cMemberSel, u))
|
2002-02-06 13:44:03 +00:00
|
|
|
|
{
|
|
|
|
|
range = NSMakeRange(i, 1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return range;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline NSRange
|
2004-05-14 10:52:30 +00:00
|
|
|
|
rangeOfCharacter_u(GSStr self, NSCharacterSet *aSet, unsigned mask,
|
2002-02-06 13:44:03 +00:00
|
|
|
|
NSRange aRange)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int start;
|
|
|
|
|
int stop;
|
|
|
|
|
int step;
|
|
|
|
|
NSRange range;
|
|
|
|
|
BOOL (*mImp)(id, SEL, unichar);
|
|
|
|
|
|
|
|
|
|
if (aSet == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException format: @"range of nil"];
|
|
|
|
|
|
|
|
|
|
if ((mask & NSBackwardsSearch) == NSBackwardsSearch)
|
|
|
|
|
{
|
2011-03-09 10:24:18 +00:00
|
|
|
|
start = NSMaxRange(aRange) - 1;
|
|
|
|
|
stop = aRange.location - 1;
|
|
|
|
|
step = -1;
|
2002-02-06 13:44:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-03-09 10:24:18 +00:00
|
|
|
|
start = aRange.location;
|
|
|
|
|
stop = NSMaxRange(aRange);
|
|
|
|
|
step = 1;
|
2002-02-06 13:44:03 +00:00
|
|
|
|
}
|
|
|
|
|
range.location = NSNotFound;
|
|
|
|
|
range.length = 0;
|
|
|
|
|
|
|
|
|
|
mImp = (BOOL(*)(id,SEL,unichar))
|
|
|
|
|
[aSet methodForSelector: cMemberSel];
|
|
|
|
|
|
2008-07-15 07:31:55 +00:00
|
|
|
|
/* FIXME ... what about UTF-16 sequences of more than one 16bit value
|
|
|
|
|
* corresponding to a single UCS-32 codepoint?
|
|
|
|
|
*/
|
2002-02-06 13:44:03 +00:00
|
|
|
|
for (i = start; i != stop; i += step)
|
|
|
|
|
{
|
|
|
|
|
unichar letter = self->_contents.u[i];
|
|
|
|
|
|
|
|
|
|
if ((*mImp)(aSet, cMemberSel, letter))
|
|
|
|
|
{
|
|
|
|
|
range = NSMakeRange(i, 1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return range;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-15 06:57:01 +00:00
|
|
|
|
GSRSFunc
|
|
|
|
|
GSPrivateRangeOfString(NSString *receiver, NSString *target)
|
|
|
|
|
{
|
|
|
|
|
Class c;
|
|
|
|
|
|
2010-02-22 10:13:20 +00:00
|
|
|
|
c = object_getClass(receiver);
|
2008-07-15 06:57:01 +00:00
|
|
|
|
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)receiver)->_flags.wide == 1))
|
|
|
|
|
{
|
2010-02-22 10:13:20 +00:00
|
|
|
|
c = object_getClass(target);
|
2008-07-15 06:57:01 +00:00
|
|
|
|
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)target)->_flags.wide == 1))
|
|
|
|
|
return (GSRSFunc)strRangeUsUs;
|
|
|
|
|
else if (GSObjCIsKindOf(c, GSCStringClass) == YES
|
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)target)->_flags.wide == 0))
|
|
|
|
|
return (GSRSFunc)strRangeUsCs;
|
|
|
|
|
else
|
|
|
|
|
return (GSRSFunc)strRangeUsNs;
|
|
|
|
|
}
|
|
|
|
|
else if (GSObjCIsKindOf(c, GSCStringClass) == YES
|
2018-04-06 09:40:08 +00:00
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)receiver)->_flags.wide == 0))
|
2008-07-15 06:57:01 +00:00
|
|
|
|
{
|
2010-02-22 10:13:20 +00:00
|
|
|
|
c = object_getClass(target);
|
2008-07-15 06:57:01 +00:00
|
|
|
|
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)target)->_flags.wide == 1))
|
|
|
|
|
return (GSRSFunc)strRangeCsUs;
|
|
|
|
|
else if (GSObjCIsKindOf(c, GSCStringClass) == YES
|
|
|
|
|
|| (c == GSMutableStringClass && ((GSStr)target)->_flags.wide == 0))
|
|
|
|
|
return (GSRSFunc)strRangeCsCs;
|
|
|
|
|
else
|
|
|
|
|
return (GSRSFunc)strRangeCsNs;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return (GSRSFunc)strRangeNsNs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-24 11:58:25 +00:00
|
|
|
|
static inline NSString*
|
2004-05-14 10:52:30 +00:00
|
|
|
|
substring_c(GSStr self, NSRange aRange)
|
2000-10-24 11:58:25 +00:00
|
|
|
|
{
|
2010-02-14 10:48:10 +00:00
|
|
|
|
GSCSubString *o;
|
2000-10-24 11:58:25 +00:00
|
|
|
|
|
2006-05-23 19:29:52 +00:00
|
|
|
|
if (aRange.length == 0)
|
|
|
|
|
{
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
2020-12-15 13:01:00 +00:00
|
|
|
|
o = (__typeof__(o))NSAllocateObject(GSCSubStringClass,
|
2006-05-20 14:52:38 +00:00
|
|
|
|
0, NSDefaultMallocZone());
|
|
|
|
|
o->_contents.c = self->_contents.c + aRange.location;
|
|
|
|
|
o->_count = aRange.length;
|
|
|
|
|
o->_flags.wide = 0;
|
2009-04-10 08:25:03 +00:00
|
|
|
|
o->_flags.owned = 0;
|
2009-01-12 12:48:46 +00:00
|
|
|
|
ASSIGN(o->_parent, (id)self);
|
|
|
|
|
return AUTORELEASE((id)o);
|
2000-10-24 11:58:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline NSString*
|
2004-05-14 10:52:30 +00:00
|
|
|
|
substring_u(GSStr self, NSRange aRange)
|
2000-10-24 11:58:25 +00:00
|
|
|
|
{
|
2010-02-14 10:48:10 +00:00
|
|
|
|
GSCSubString *o;
|
2000-10-24 11:58:25 +00:00
|
|
|
|
|
2006-05-23 19:29:52 +00:00
|
|
|
|
if (aRange.length == 0)
|
|
|
|
|
{
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
2020-12-15 13:01:00 +00:00
|
|
|
|
o = (__typeof__(o))NSAllocateObject(GSUnicodeSubStringClass,
|
2006-05-20 14:52:38 +00:00
|
|
|
|
0, NSDefaultMallocZone());
|
|
|
|
|
o->_contents.u = self->_contents.u + aRange.location;
|
|
|
|
|
o->_count = aRange.length;
|
|
|
|
|
o->_flags.wide = 1;
|
2009-04-10 08:25:03 +00:00
|
|
|
|
o->_flags.owned = 0;
|
2009-01-12 12:48:46 +00:00
|
|
|
|
ASSIGN(o->_parent, (id)self);
|
|
|
|
|
return AUTORELEASE((id)o);
|
2000-10-24 11:58:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* Function to examine the given string and see if it is one of our concrete
|
2000-10-09 05:32:50 +00:00
|
|
|
|
* string classes. Converts the mutable string (self) from 8-bit to 16-bit
|
|
|
|
|
* representation if necessary in order to contain the data in aString.
|
2004-05-14 10:52:30 +00:00
|
|
|
|
* Returns a pointer to aStrings GSStr if aString is a concrete class
|
2000-10-09 05:32:50 +00:00
|
|
|
|
* from which contents may be copied directly without conversion.
|
|
|
|
|
*/
|
2004-05-14 10:52:30 +00:00
|
|
|
|
static inline GSStr
|
|
|
|
|
transmute(GSStr self, NSString *aString)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
GSStr other = (GSStr)aString;
|
|
|
|
|
BOOL transmute = YES;
|
2010-02-22 10:13:20 +00:00
|
|
|
|
Class c = object_getClass(aString); // NB aString must not be nil
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2020-11-22 14:55:39 +00:00
|
|
|
|
/* If the string is an immutable proxy to a mutable string, we want to
|
|
|
|
|
* access the original (which we won't modify) for better performance.
|
|
|
|
|
*/
|
|
|
|
|
if (c == GSImmutableStringClass)
|
|
|
|
|
{
|
|
|
|
|
aString = object_getIvar(aString, immutableIvar);
|
|
|
|
|
other = (GSStr)aString;
|
|
|
|
|
c = object_getClass(aString);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
if (self->_flags.wide == 1)
|
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* This is already a unicode string, so we don't need to transmute,
|
2000-10-20 10:30:51 +00:00
|
|
|
|
* but we still need to know if the other string is a unicode
|
2004-05-14 10:52:30 +00:00
|
|
|
|
* string whose GSStr we can access directly.
|
2000-10-20 10:30:51 +00:00
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
transmute = NO;
|
2000-11-08 16:02:49 +00:00
|
|
|
|
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == NO
|
|
|
|
|
&& (c != GSMutableStringClass || other->_flags.wide != 1))
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
other = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* This is a string held in the internal 8-bit encoding.
|
2002-04-16 11:18:14 +00:00
|
|
|
|
*/
|
2011-10-12 14:28:44 +00:00
|
|
|
|
if (GSObjCIsKindOf(c, GSCStringClass)
|
2000-11-03 10:11:56 +00:00
|
|
|
|
|| (c == GSMutableStringClass && other->_flags.wide == 0))
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* The other string is also held in the internal 8-bit encoding,
|
2004-05-14 10:52:30 +00:00
|
|
|
|
* so we don't need to transmute, and we can use its GSStr.
|
2000-10-20 10:30:51 +00:00
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
transmute = NO;
|
|
|
|
|
}
|
2011-10-28 15:02:46 +00:00
|
|
|
|
else if ([aString canBeConvertedToEncoding: internalEncoding] == YES)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* The other string can be converted to the internal 8-bit encoding,
|
2011-10-28 15:02:46 +00:00
|
|
|
|
* so we don't need to transmute, but we can *not* use its GSStr.
|
2000-10-20 10:30:51 +00:00
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
transmute = NO;
|
|
|
|
|
other = 0;
|
|
|
|
|
}
|
2000-11-03 10:11:56 +00:00
|
|
|
|
else if ((c == GSMutableStringClass && other->_flags.wide == 1)
|
2000-11-08 16:02:49 +00:00
|
|
|
|
|| GSObjCIsKindOf(c, GSUnicodeStringClass) == YES)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* The other string can not be converted to the internal 8-bit
|
2002-04-16 11:18:14 +00:00
|
|
|
|
* encoding, so we need to transmute, and will then be able to
|
2004-05-14 10:52:30 +00:00
|
|
|
|
* use its GSStr.
|
2000-10-20 10:30:51 +00:00
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
transmute = YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* The other string can not be converted to the internal 8-bit
|
2002-04-16 11:18:14 +00:00
|
|
|
|
* character string, so we need to transmute, but even then we
|
2004-05-14 10:52:30 +00:00
|
|
|
|
* will not be able to use the other strings GSStr because that
|
2002-04-16 11:18:14 +00:00
|
|
|
|
* string is not a known GSString subclass.
|
2000-10-20 10:30:51 +00:00
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
other = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (transmute == YES)
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
GSStrWiden((GSStr)self);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return other;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* The GSString class is actually only provided to provide a common ivar
|
|
|
|
|
* layout for all subclasses, so that they can all share the same code.
|
2003-11-05 02:11:49 +00:00
|
|
|
|
* This class should never be instantiated, and with the exception of
|
|
|
|
|
* -copyWithZone:, none of its memory management related methods
|
|
|
|
|
* (initializers and -dealloc) should ever be called. We guard against
|
|
|
|
|
* this happening.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
2003-11-05 02:11:49 +00:00
|
|
|
|
@implementation GSString
|
2000-11-06 19:55:23 +00:00
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
2010-07-19 17:10:46 +00:00
|
|
|
|
setup(NO);
|
|
|
|
|
}
|
2011-02-23 07:25:12 +00:00
|
|
|
|
|
2010-07-19 17:10:46 +00:00
|
|
|
|
+ (void) reinitialize
|
|
|
|
|
{
|
|
|
|
|
setup(YES);
|
2000-11-06 19:55:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-12-07 05:02:55 +00:00
|
|
|
|
/*
|
|
|
|
|
* Return a 28-bit hash value for the string contents - this
|
|
|
|
|
* MUST match the algorithm used by the NSString base class.
|
|
|
|
|
*/
|
2009-12-04 09:52:14 +00:00
|
|
|
|
- (NSUInteger) hash
|
|
|
|
|
{
|
|
|
|
|
if (self->_flags.hash == 0)
|
|
|
|
|
{
|
2013-03-12 16:11:10 +00:00
|
|
|
|
uint32_t ret = 0;
|
|
|
|
|
int len = (int)self->_count;
|
2009-12-07 05:02:55 +00:00
|
|
|
|
|
|
|
|
|
if (len > 0)
|
|
|
|
|
{
|
|
|
|
|
if (self->_flags.wide)
|
|
|
|
|
{
|
2013-03-12 16:11:10 +00:00
|
|
|
|
const unichar *p = self->_contents.u;
|
2009-12-07 05:02:55 +00:00
|
|
|
|
|
2013-03-12 16:11:10 +00:00
|
|
|
|
ret = GSPrivateHash(0, p, len * sizeof(unichar));
|
2009-12-07 05:02:55 +00:00
|
|
|
|
}
|
2013-03-12 16:11:10 +00:00
|
|
|
|
else if (len > 64)
|
|
|
|
|
{
|
|
|
|
|
return (self->_flags.hash = [super hash]);
|
|
|
|
|
}
|
|
|
|
|
else
|
2009-12-07 05:02:55 +00:00
|
|
|
|
{
|
2013-03-12 16:11:10 +00:00
|
|
|
|
unichar buf[64];
|
|
|
|
|
unsigned index;
|
|
|
|
|
const unsigned char *p = self->_contents.c;
|
2009-12-07 05:02:55 +00:00
|
|
|
|
|
|
|
|
|
if (internalEncoding == NSISOLatin1StringEncoding)
|
|
|
|
|
{
|
2013-03-12 16:11:10 +00:00
|
|
|
|
for (index = 0; index < len; index++)
|
|
|
|
|
{
|
|
|
|
|
buf[index] = p[index];
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-07 05:02:55 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2013-03-12 16:11:10 +00:00
|
|
|
|
for (index = 0; index < len; index++)
|
|
|
|
|
{
|
|
|
|
|
unichar u = p[index];
|
2009-12-07 05:02:55 +00:00
|
|
|
|
|
2013-03-12 16:11:10 +00:00
|
|
|
|
if (u > 127)
|
|
|
|
|
{
|
|
|
|
|
return (self->_flags.hash = [super hash]);
|
|
|
|
|
}
|
|
|
|
|
buf[index] = u;
|
|
|
|
|
}
|
2009-12-07 05:02:55 +00:00
|
|
|
|
}
|
2013-03-12 16:11:10 +00:00
|
|
|
|
ret = GSPrivateHash(0, buf, len * sizeof(unichar));
|
2009-12-07 05:02:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The hash caching in our concrete string classes uses zero to denote
|
|
|
|
|
* an empty cache value, so we MUST NOT return a hash of zero.
|
|
|
|
|
*/
|
|
|
|
|
ret &= 0x0fffffff;
|
|
|
|
|
if (ret == 0)
|
|
|
|
|
{
|
|
|
|
|
ret = 0x0fffffff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = 0x0ffffffe; /* Hash for an empty string. */
|
|
|
|
|
}
|
|
|
|
|
self->_flags.hash = ret;
|
2009-12-04 09:52:14 +00:00
|
|
|
|
}
|
2009-12-07 05:02:55 +00:00
|
|
|
|
|
2009-12-04 09:52:14 +00:00
|
|
|
|
return self->_flags.hash;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-20 14:52:38 +00:00
|
|
|
|
- (id) initWithBytesNoCopy: (void*)chars
|
2009-02-23 20:42:32 +00:00
|
|
|
|
length: (NSUInteger)length
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
freeWhenDone: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
NSString *c = NSStringFromClass([self class]);
|
|
|
|
|
NSString *s = NSStringFromSelector(_cmd);
|
|
|
|
|
|
2010-02-25 18:49:31 +00:00
|
|
|
|
DESTROY(self);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"[%@-%@] called on string already initialised", c, s];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-10 16:50:41 +00:00
|
|
|
|
- (BOOL) makeImmutable
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-16 08:44:15 +00:00
|
|
|
|
- (NSUInteger) sizeInBytesExcluding: (NSHashTable*)exclude
|
2015-07-15 14:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
NSUInteger size = GSPrivateMemorySize(self, exclude);
|
|
|
|
|
|
|
|
|
|
if (size > 0 && _flags.owned)
|
|
|
|
|
{
|
|
|
|
|
size += _count;
|
|
|
|
|
if (_flags.wide)
|
|
|
|
|
{
|
|
|
|
|
size += _count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
@implementation GSCString
|
2002-10-05 17:47:54 +00:00
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (BOOL) boolValue
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return boolValue_c((GSStr)self);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) canBeConvertedToEncoding: (NSStringEncoding)enc
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return canBeConvertedToEncoding_c((GSStr)self, enc);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (unichar) characterAtIndex: (NSUInteger)index
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return characterAtIndex_c((GSStr)self, index);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSComparisonResult) compare: (NSString*)aString
|
2009-02-23 20:42:32 +00:00
|
|
|
|
options: (NSUInteger)mask
|
2000-10-09 05:32:50 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
{
|
2016-04-13 12:45:03 +00:00
|
|
|
|
if (mask & NSNumericSearch)
|
|
|
|
|
{
|
|
|
|
|
return [super compare: aString options: mask range: aRange];
|
|
|
|
|
}
|
2008-07-15 08:05:33 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
if (aString == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ -%@] nil string argument",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
|
|
|
if (GSObjCIsInstance(aString) == NO)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ -%@] not a string argument",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return compare_c((GSStr)self, aString, mask, aRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-23 07:25:12 +00:00
|
|
|
|
/*
|
|
|
|
|
Default copy implementation. Retain if we own the buffer and the zones
|
|
|
|
|
agree, create a new GSCInlineString otherwise.
|
|
|
|
|
*/
|
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (!_flags.owned || NSShouldRetainWithZone(self, z) == NO)
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSCInlineString *me = newCInline(_count, z);
|
2011-02-23 07:25:12 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
memcpy(me->_contents.c, _contents.c, _count);
|
|
|
|
|
return me;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return RETAIN(self);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (const char *) cString
|
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return cString_c((GSStr)self, externalEncoding);
|
2005-05-08 07:08:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (const char *) cStringUsingEncoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
return cString_c((GSStr)self, encoding);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) cStringLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return cStringLength_c((GSStr)self, externalEncoding);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
|
|
|
{
|
2006-12-27 15:30:27 +00:00
|
|
|
|
if ([aCoder allowsKeyedCoding])
|
|
|
|
|
{
|
|
|
|
|
[(NSKeyedArchiver*)aCoder _encodePropertyList: self forKey: @"NS.string"];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(unsigned) at: &_count];
|
|
|
|
|
if (_count > 0)
|
|
|
|
|
{
|
2010-12-27 11:28:01 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(int)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
at: &internalEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
[aCoder encodeArrayOfObjCType: @encode(unsigned char)
|
|
|
|
|
count: _count
|
|
|
|
|
at: _contents.c];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSStringEncoding) fastestEncoding
|
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return internalEncoding;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCharacters: (unichar*)buffer
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_c((GSStr)self, buffer, (NSRange){0, _count});
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCharacters: (unichar*)buffer range: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_c((GSStr)self, buffer, aRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCString: (char*)buffer
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_c((GSStr)self, buffer, NSMaximumStringLength,
|
2000-10-09 05:32:50 +00:00
|
|
|
|
(NSRange){0, _count}, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCString: (char*)buffer
|
2009-02-23 20:42:32 +00:00
|
|
|
|
maxLength: (NSUInteger)maxLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_c((GSStr)self, buffer, maxLength, (NSRange){0, _count}, 0);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
- (BOOL) getCString: (char*)buffer
|
2009-02-23 20:42:32 +00:00
|
|
|
|
maxLength: (NSUInteger)maxLength
|
2006-02-27 09:35:19 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
return getCStringE_c((GSStr)self, buffer, maxLength, encoding);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (void) getCString: (char*)buffer
|
2009-02-23 20:42:32 +00:00
|
|
|
|
maxLength: (NSUInteger)maxLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
remainingRange: (NSRange*)leftoverRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_c((GSStr)self, buffer, maxLength, aRange, leftoverRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-09-12 17:05:30 +00:00
|
|
|
|
- (int) intValue
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2015-05-05 11:54:14 +00:00
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
|
|
intBuf_c((GSStr)self, buf);
|
|
|
|
|
return strtol(buf, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSInteger) integerValue
|
|
|
|
|
{
|
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
|
|
intBuf_c((GSStr)self, buf);
|
|
|
|
|
#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG
|
|
|
|
|
return strtol(buf, 0, 10);
|
|
|
|
|
#else
|
|
|
|
|
return strtoll(buf, 0, 10);
|
|
|
|
|
#endif
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return isEqual_c((GSStr)self, anObject);
|
2000-10-20 10:30:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isEqualToString: (NSString*)anObject
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return isEqual_c((GSStr)self, anObject);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) length
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
return _count;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding
|
2005-05-08 07:08:28 +00:00
|
|
|
|
{
|
|
|
|
|
return cStringLength_c((GSStr)self, encoding);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
- (long long) longLongValue
|
|
|
|
|
{
|
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
|
|
intBuf_c((GSStr)self, buf);
|
|
|
|
|
return strtoll(buf, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (const char*) lossyCString
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return lossyCString_c((GSStr)self);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) mutableCopy
|
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSMutableString *obj;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
obj = (GSMutableString*)NSAllocateObject(GSMutableStringClass, 0,
|
|
|
|
|
NSDefaultMallocZone());
|
2006-05-12 17:46:32 +00:00
|
|
|
|
obj = [obj initWithBytes: (char*)_contents.c
|
|
|
|
|
length: _count
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: internalEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) mutableCopyWithZone: (NSZone*)z
|
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSMutableString *obj;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
obj = (GSMutableString*)NSAllocateObject(GSMutableStringClass, 0, z);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
obj = [obj initWithBytes: (char*)_contents.c
|
|
|
|
|
length: _count
|
|
|
|
|
encoding: internalEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSRange) rangeOfComposedCharacterSequenceAtIndex: (NSUInteger)anIndex
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return rangeOfSequence_c((GSStr)self, anIndex);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-02-06 13:44:03 +00:00
|
|
|
|
- (NSRange) rangeOfCharacterFromSet: (NSCharacterSet*)aSet
|
2009-02-23 20:42:32 +00:00
|
|
|
|
options: (NSUInteger)mask
|
2002-02-06 13:44:03 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return rangeOfCharacter_c((GSStr)self, aSet, mask, aRange);
|
2002-02-06 13:44:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (NSStringEncoding) smallestEncoding
|
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return internalEncoding;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-24 11:58:25 +00:00
|
|
|
|
- (NSString*) substringFromRange: (NSRange)aRange
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2012-08-25 12:31:41 +00:00
|
|
|
|
if (!_flags.wide)
|
2012-08-25 12:15:11 +00:00
|
|
|
|
{
|
2013-01-07 21:39:35 +00:00
|
|
|
|
id tinyString;
|
2012-08-25 12:15:11 +00:00
|
|
|
|
|
2013-01-07 21:39:35 +00:00
|
|
|
|
tinyString = createTinyString((char*)_contents.c + aRange.location,
|
|
|
|
|
aRange.length);
|
2012-08-25 12:15:11 +00:00
|
|
|
|
if (tinyString)
|
2013-01-07 21:39:35 +00:00
|
|
|
|
{
|
|
|
|
|
return tinyString;
|
|
|
|
|
}
|
2012-08-25 12:15:11 +00:00
|
|
|
|
}
|
2012-03-02 19:01:30 +00:00
|
|
|
|
if (_flags.owned)
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
return substring_c((GSStr)self, aRange);
|
|
|
|
|
}
|
|
|
|
|
return [super substringWithRange: aRange];
|
2000-10-24 11:58:25 +00:00
|
|
|
|
}
|
2000-10-20 10:30:51 +00:00
|
|
|
|
|
2000-10-24 11:58:25 +00:00
|
|
|
|
- (NSString*) substringWithRange: (NSRange)aRange
|
|
|
|
|
{
|
2012-03-02 19:01:30 +00:00
|
|
|
|
if (_flags.owned)
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
return substring_c((GSStr)self, aRange);
|
|
|
|
|
}
|
2012-08-25 12:31:41 +00:00
|
|
|
|
if (!_flags.wide)
|
2012-08-25 12:15:11 +00:00
|
|
|
|
{
|
2013-01-07 21:39:35 +00:00
|
|
|
|
id tinyString;
|
2012-08-25 12:15:11 +00:00
|
|
|
|
|
2013-01-07 21:39:35 +00:00
|
|
|
|
tinyString = createTinyString((char*)_contents.c + aRange.location,
|
|
|
|
|
aRange.length);
|
2012-08-25 12:15:11 +00:00
|
|
|
|
if (tinyString)
|
2013-01-07 21:39:35 +00:00
|
|
|
|
{
|
|
|
|
|
return tinyString;
|
|
|
|
|
}
|
2012-08-25 12:15:11 +00:00
|
|
|
|
}
|
2012-03-02 19:01:30 +00:00
|
|
|
|
return [super substringWithRange: aRange];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-23 07:25:12 +00:00
|
|
|
|
- (const char *) UTF8String
|
2003-11-05 02:11:49 +00:00
|
|
|
|
{
|
2011-02-23 07:25:12 +00:00
|
|
|
|
return UTF8String_c((GSStr)self);
|
|
|
|
|
}
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2011-02-23 07:25:12 +00:00
|
|
|
|
// private method for Unicode level 3 implementation
|
|
|
|
|
- (int) _baseLength
|
|
|
|
|
{
|
|
|
|
|
return _count;
|
2003-11-05 02:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-05 02:11:49 +00:00
|
|
|
|
@implementation GSCBufferString
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2009-10-10 08:16:17 +00:00
|
|
|
|
if (_contents.c != 0)
|
2003-11-05 02:11:49 +00:00
|
|
|
|
{
|
2009-10-10 08:16:17 +00:00
|
|
|
|
if (_flags.owned)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSZoneFromPointer(_contents.c), _contents.c);
|
|
|
|
|
}
|
2003-11-05 02:11:49 +00:00
|
|
|
|
_contents.c = 0;
|
|
|
|
|
}
|
2009-10-10 08:16:17 +00:00
|
|
|
|
[super dealloc];
|
2003-11-05 02:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation GSCInlineString
|
2019-08-08 16:20:25 +00:00
|
|
|
|
- (NSUInteger) sizeOfContentExcluding: (NSHashTable*)exclude
|
|
|
|
|
{
|
|
|
|
|
return 0; // Inline string content uses no heap
|
|
|
|
|
}
|
|
|
|
|
- (NSUInteger) sizeOfInstance
|
|
|
|
|
{
|
|
|
|
|
NSUInteger size;
|
|
|
|
|
|
|
|
|
|
#if HAVE_MALLOC_USABLE_SIZE
|
|
|
|
|
size = malloc_usable_size((void*)self - sizeof(intptr_t));
|
|
|
|
|
#else
|
|
|
|
|
size = class_getInstanceSize(GSCInlineStringClass);
|
|
|
|
|
size += _count;
|
|
|
|
|
#endif
|
|
|
|
|
return size;
|
|
|
|
|
}
|
2000-10-29 14:52:33 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
|
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
@implementation GSCSubString
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2000-12-21 11:55:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* Assume that a copy should be a new string, never just a retained substring.
|
|
|
|
|
*/
|
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
|
|
|
|
{
|
2010-02-14 10:48:10 +00:00
|
|
|
|
GSCInlineString *o;
|
2000-12-21 11:55:30 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = newCInline(_count, z);
|
2006-05-20 14:52:38 +00:00
|
|
|
|
memcpy(o->_contents.c, _contents.c, _count);
|
|
|
|
|
return (id)o;
|
2000-12-21 11:55:30 +00:00
|
|
|
|
}
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2003-11-05 02:11:49 +00:00
|
|
|
|
DESTROY(_parent);
|
2009-10-10 08:16:17 +00:00
|
|
|
|
[super dealloc];
|
2000-10-20 10:30:51 +00:00
|
|
|
|
}
|
2013-01-08 08:25:18 +00:00
|
|
|
|
|
|
|
|
|
- (NSString*) substringFromRange: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
id s;
|
|
|
|
|
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
s = createTinyString((char*)_contents.c + aRange.location, aRange.length);
|
|
|
|
|
if (nil == s)
|
|
|
|
|
{
|
2013-01-08 21:59:38 +00:00
|
|
|
|
aRange.location += (_contents.c - _parent->_contents.c);
|
2013-01-08 08:25:18 +00:00
|
|
|
|
s = substring_c((GSStr)_parent, aRange);
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) substringWithRange: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
id s;
|
|
|
|
|
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
s = createTinyString((char*)_contents.c + aRange.location, aRange.length);
|
|
|
|
|
if (nil == s)
|
|
|
|
|
{
|
2013-01-08 21:59:38 +00:00
|
|
|
|
aRange.location += (_contents.c - _parent->_contents.c);
|
2013-01-08 08:25:18 +00:00
|
|
|
|
s = substring_c((GSStr)_parent, aRange);
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
@implementation GSUnicodeString
|
2002-10-05 17:47:54 +00:00
|
|
|
|
- (const char *) UTF8String
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return UTF8String_u((GSStr)self);
|
2002-10-05 17:47:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (BOOL) boolValue
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return boolValue_u((GSStr)self);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) canBeConvertedToEncoding: (NSStringEncoding)enc
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return canBeConvertedToEncoding_u((GSStr)self, enc);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (unichar) characterAtIndex: (NSUInteger)index
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return characterAtIndex_u((GSStr)self, index);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSComparisonResult) compare: (NSString*)aString
|
2009-02-23 20:42:32 +00:00
|
|
|
|
options: (NSUInteger)mask
|
2000-10-09 05:32:50 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
{
|
2016-04-13 12:45:03 +00:00
|
|
|
|
if (mask & NSNumericSearch)
|
|
|
|
|
{
|
|
|
|
|
return [super compare: aString options: mask range: aRange];
|
|
|
|
|
}
|
2008-07-15 08:05:33 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
if (aString == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ -%@] nil string argument",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
|
|
|
if (GSObjCIsInstance(aString) == NO)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ -%@] not a string argument",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return compare_u((GSStr)self, aString, mask, aRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (const char *) cString
|
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return cString_u((GSStr)self, externalEncoding);
|
2005-05-08 07:08:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (const char *) cStringUsingEncoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
return cString_u((GSStr)self, encoding);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) cStringLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return cStringLength_u((GSStr)self, externalEncoding);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
|
|
|
{
|
2006-12-27 15:30:27 +00:00
|
|
|
|
if ([aCoder allowsKeyedCoding])
|
|
|
|
|
{
|
|
|
|
|
[(NSKeyedArchiver*)aCoder _encodePropertyList: self forKey: @"NS.string"];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(unsigned) at: &_count];
|
|
|
|
|
if (_count > 0)
|
|
|
|
|
{
|
|
|
|
|
NSStringEncoding enc = NSUnicodeStringEncoding;
|
|
|
|
|
|
2010-12-27 11:28:01 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(int) at: &enc];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
[aCoder encodeArrayOfObjCType: @encode(unichar)
|
|
|
|
|
count: _count
|
|
|
|
|
at: _contents.u];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSStringEncoding) fastestEncoding
|
|
|
|
|
{
|
|
|
|
|
return NSUnicodeStringEncoding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCharacters: (unichar*)buffer
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_u((GSStr)self, buffer, (NSRange){0, _count});
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCharacters: (unichar*)buffer range: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_u((GSStr)self, buffer, aRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCString: (char*)buffer
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_u((GSStr)self, buffer, NSMaximumStringLength,
|
2000-10-09 05:32:50 +00:00
|
|
|
|
(NSRange){0, _count}, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCString: (char*)buffer
|
2009-02-23 20:42:32 +00:00
|
|
|
|
maxLength: (NSUInteger)maxLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_u((GSStr)self, buffer, maxLength, (NSRange){0, _count}, 0);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
- (BOOL) getCString: (char*)buffer
|
2009-02-23 20:42:32 +00:00
|
|
|
|
maxLength: (NSUInteger)maxLength
|
2006-02-27 09:35:19 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
return getCStringE_u((GSStr)self, buffer, maxLength, encoding);
|
|
|
|
|
}
|
2018-07-01 21:27:09 +00:00
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (void) getCString: (char*)buffer
|
2009-02-23 20:42:32 +00:00
|
|
|
|
maxLength: (NSUInteger)maxLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
remainingRange: (NSRange*)leftoverRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_u((GSStr)self, buffer, maxLength, aRange, leftoverRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-09-12 17:05:30 +00:00
|
|
|
|
- (int) intValue
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2015-05-05 11:54:14 +00:00
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
|
|
intBuf_u((GSStr)self, buf);
|
|
|
|
|
return strtol(buf, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSInteger) integerValue
|
|
|
|
|
{
|
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
|
|
intBuf_u((GSStr)self, buf);
|
|
|
|
|
#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG
|
|
|
|
|
return strtol(buf, 0, 10);
|
|
|
|
|
#else
|
|
|
|
|
return strtoll(buf, 0, 10);
|
|
|
|
|
#endif
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return isEqual_u((GSStr)self, anObject);
|
2000-10-20 10:30:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isEqualToString: (NSString*)anObject
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return isEqual_u((GSStr)self, anObject);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) length
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
return _count;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding
|
2005-05-08 07:08:28 +00:00
|
|
|
|
{
|
|
|
|
|
return cStringLength_u((GSStr)self, encoding);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
- (long long) longLongValue
|
|
|
|
|
{
|
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
|
|
intBuf_u((GSStr)self, buf);
|
|
|
|
|
return strtoll(buf, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (const char*) lossyCString
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return lossyCString_u((GSStr)self);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-23 07:25:12 +00:00
|
|
|
|
- (id) lowercaseString
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineString *o;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
unsigned i;
|
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = [newUInline(_count, [self zone]) autorelease];
|
|
|
|
|
i = _count;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
while (i-- > 0)
|
|
|
|
|
{
|
|
|
|
|
o->_contents.u[i] = uni_tolower(_contents.u[i]);
|
|
|
|
|
}
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return o;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (id) mutableCopy
|
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSMutableString *obj;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
obj = (GSMutableString*)NSAllocateObject(GSMutableStringClass, 0,
|
|
|
|
|
NSDefaultMallocZone());
|
2006-05-20 14:52:38 +00:00
|
|
|
|
obj = [obj initWithBytes: (const void*)_contents.u
|
|
|
|
|
length: _count * sizeof(unichar)
|
|
|
|
|
encoding: NSUnicodeStringEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) mutableCopyWithZone: (NSZone*)z
|
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSMutableString *obj;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
obj = (GSMutableString*)NSAllocateObject(GSMutableStringClass, 0, z);
|
2006-05-20 14:52:38 +00:00
|
|
|
|
obj = [obj initWithBytes: (const void*)_contents.u
|
|
|
|
|
length: _count * sizeof(unichar)
|
|
|
|
|
encoding: NSUnicodeStringEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSRange) rangeOfComposedCharacterSequenceAtIndex: (NSUInteger)anIndex
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return rangeOfSequence_u((GSStr)self, anIndex);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-02-06 13:44:03 +00:00
|
|
|
|
- (NSRange) rangeOfCharacterFromSet: (NSCharacterSet*)aSet
|
2009-02-23 20:42:32 +00:00
|
|
|
|
options: (NSUInteger)mask
|
2002-02-06 13:44:03 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return rangeOfCharacter_u((GSStr)self, aSet, mask, aRange);
|
2002-02-06 13:44:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (NSStringEncoding) smallestEncoding
|
|
|
|
|
{
|
|
|
|
|
return NSUnicodeStringEncoding;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-24 11:58:25 +00:00
|
|
|
|
- (NSString*) substringFromRange: (NSRange)aRange
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2012-08-25 12:31:41 +00:00
|
|
|
|
if (!_flags.wide)
|
2012-08-25 12:15:11 +00:00
|
|
|
|
{
|
2013-01-07 21:39:35 +00:00
|
|
|
|
id tinyString;
|
2012-08-25 12:15:11 +00:00
|
|
|
|
|
2013-01-07 21:39:35 +00:00
|
|
|
|
tinyString = createTinyString((char*)_contents.c + aRange.location,
|
|
|
|
|
aRange.length);
|
2012-08-25 12:15:11 +00:00
|
|
|
|
if (tinyString)
|
2013-01-07 21:39:35 +00:00
|
|
|
|
{
|
|
|
|
|
return tinyString;
|
|
|
|
|
}
|
2012-08-25 12:15:11 +00:00
|
|
|
|
}
|
2012-03-02 19:01:30 +00:00
|
|
|
|
if (_flags.owned)
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
return substring_u((GSStr)self, aRange);
|
|
|
|
|
}
|
|
|
|
|
return [super substringWithRange: aRange];
|
2000-10-24 11:58:25 +00:00
|
|
|
|
}
|
2000-10-20 10:30:51 +00:00
|
|
|
|
|
2000-10-24 11:58:25 +00:00
|
|
|
|
- (NSString*) substringWithRange: (NSRange)aRange
|
|
|
|
|
{
|
2012-08-25 12:31:41 +00:00
|
|
|
|
if (!_flags.wide)
|
2012-08-25 12:15:11 +00:00
|
|
|
|
{
|
2013-01-07 21:39:35 +00:00
|
|
|
|
id tinyString;
|
2012-08-25 12:15:11 +00:00
|
|
|
|
|
2013-01-07 21:39:35 +00:00
|
|
|
|
tinyString = createTinyString((char*)_contents.c + aRange.location,
|
|
|
|
|
aRange.length);
|
2012-08-25 12:15:11 +00:00
|
|
|
|
if (tinyString)
|
2013-01-07 21:39:35 +00:00
|
|
|
|
{
|
|
|
|
|
return tinyString;
|
|
|
|
|
}
|
2012-08-25 12:15:11 +00:00
|
|
|
|
}
|
2012-03-02 19:01:30 +00:00
|
|
|
|
if (_flags.owned)
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
return substring_u((GSStr)self, aRange);
|
|
|
|
|
}
|
|
|
|
|
return [super substringWithRange: aRange];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-23 07:25:12 +00:00
|
|
|
|
- (id) uppercaseString
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineString *o;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
unsigned i;
|
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = [newUInline(_count, [self zone]) autorelease];
|
|
|
|
|
i = _count;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
while (i-- > 0)
|
|
|
|
|
{
|
|
|
|
|
o->_contents.u[i] = uni_toupper(_contents.u[i]);
|
|
|
|
|
}
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return o;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
// private method for Unicode level 3 implementation
|
2010-09-12 17:05:30 +00:00
|
|
|
|
- (int) _baseLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int count = 0;
|
|
|
|
|
unsigned int blen = 0;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
while (count < _count)
|
|
|
|
|
if (!uni_isnonsp(_contents.u[count++]))
|
|
|
|
|
blen++;
|
|
|
|
|
return blen;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2003-11-05 02:11:49 +00:00
|
|
|
|
/*
|
|
|
|
|
Default -copy implementation. Retain if we own the buffer and the zones
|
2012-08-08 09:46:08 +00:00
|
|
|
|
agree, create a new GSUInlineString otherwise.
|
2003-11-05 02:11:49 +00:00
|
|
|
|
*/
|
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
if (!_flags.owned || NSShouldRetainWithZone(self, z) == NO)
|
2003-11-05 02:11:49 +00:00
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineString *o;
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = newUInline(_count, z);
|
2006-05-20 14:52:38 +00:00
|
|
|
|
memcpy(o->_contents.u, _contents.u, _count * sizeof(unichar));
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return o;
|
2003-11-05 02:11:49 +00:00
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
else
|
2003-11-05 02:11:49 +00:00
|
|
|
|
{
|
|
|
|
|
return RETAIN(self);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-05 02:11:49 +00:00
|
|
|
|
@implementation GSUnicodeBufferString
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2009-10-10 08:16:17 +00:00
|
|
|
|
if (_contents.u != 0)
|
2003-11-05 02:11:49 +00:00
|
|
|
|
{
|
2009-10-10 08:16:17 +00:00
|
|
|
|
if (_flags.owned)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSZoneFromPointer(_contents.u), _contents.u);
|
|
|
|
|
}
|
2003-11-05 02:11:49 +00:00
|
|
|
|
_contents.u = 0;
|
|
|
|
|
}
|
2009-10-10 08:16:17 +00:00
|
|
|
|
[super dealloc];
|
2003-11-05 02:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
@implementation GSUInlineString
|
2019-08-08 16:20:25 +00:00
|
|
|
|
- (NSUInteger) sizeOfContentExcluding: (NSHashTable*)exclude
|
|
|
|
|
{
|
|
|
|
|
return 0; // Inline string content uses no heap
|
|
|
|
|
}
|
|
|
|
|
- (NSUInteger) sizeOfInstance
|
|
|
|
|
{
|
|
|
|
|
NSUInteger size;
|
|
|
|
|
|
|
|
|
|
#if HAVE_MALLOC_USABLE_SIZE
|
|
|
|
|
size = malloc_usable_size((void*)self - sizeof(intptr_t));
|
|
|
|
|
#else
|
|
|
|
|
size = class_getInstanceSize(GSUInlineStringClass);
|
|
|
|
|
size += _count * sizeof(unichar);
|
|
|
|
|
#endif
|
|
|
|
|
return size;
|
|
|
|
|
}
|
2000-10-29 14:52:33 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation GSUnicodeSubString
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2000-12-21 11:55:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* Assume that a copy should be a new string, never just a retained substring.
|
|
|
|
|
*/
|
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineString *o;
|
2000-12-21 11:55:30 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = newUInline(_count, z);
|
2006-05-20 14:52:38 +00:00
|
|
|
|
memcpy(o->_contents.u, _contents.u, _count * sizeof(unichar));
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return o;
|
2000-12-21 11:55:30 +00:00
|
|
|
|
}
|
2003-11-05 02:11:49 +00:00
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2003-11-05 02:11:49 +00:00
|
|
|
|
DESTROY(_parent);
|
2009-10-10 08:16:17 +00:00
|
|
|
|
[super dealloc];
|
2000-10-20 10:30:51 +00:00
|
|
|
|
}
|
2013-01-08 08:25:18 +00:00
|
|
|
|
|
|
|
|
|
- (NSString*) substringFromRange: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
aRange.location += (_contents.u - _parent->_contents.u);
|
|
|
|
|
return substring_u((GSStr)_parent, aRange);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) substringWithRange: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
aRange.location += (_contents.u - _parent->_contents.u);
|
|
|
|
|
return substring_u((GSStr)_parent, aRange);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-20 10:30:51 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
2003-05-06 06:54:22 +00:00
|
|
|
|
* The GSMutableString class shares a common initial ivar layout with
|
2000-11-03 10:11:56 +00:00
|
|
|
|
* the GSString class, but adds a few of its own. It uses _flags.wide
|
|
|
|
|
* to determine whether it should use 8-bit or 16-bit characters and
|
2002-02-06 13:44:03 +00:00
|
|
|
|
* is capable of changing that flag (and its underlying storage) to
|
2000-11-03 10:11:56 +00:00
|
|
|
|
* move from an 8-bit to a 16-bit representation is that should be
|
|
|
|
|
* necessary because wide characters have been placed in the string.
|
|
|
|
|
*/
|
|
|
|
|
@implementation GSMutableString
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
2010-07-19 17:10:46 +00:00
|
|
|
|
setup(NO);
|
2009-12-07 05:10:50 +00:00
|
|
|
|
GSObjCAddClassBehavior(self, [GSString class]);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-02-02 06:14:42 +00:00
|
|
|
|
- (void) appendFormat: (NSString*)format, ...
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
2004-05-14 10:52:30 +00:00
|
|
|
|
unichar buf[1024];
|
|
|
|
|
unichar *fmt = buf;
|
|
|
|
|
size_t len;
|
2001-02-02 06:14:42 +00:00
|
|
|
|
|
|
|
|
|
va_start(ap, format);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
|
2001-02-02 06:14:42 +00:00
|
|
|
|
/*
|
2004-05-14 10:52:30 +00:00
|
|
|
|
* Make sure we have the format string in a nul terminated array of
|
2006-10-20 10:56:27 +00:00
|
|
|
|
* unichars for passing to GSPrivateFormat. Use on-stack memory for
|
|
|
|
|
* performance unless the size of the format string is really big
|
|
|
|
|
* (a rare occurrence).
|
2001-02-02 06:14:42 +00:00
|
|
|
|
*/
|
2004-05-14 10:52:30 +00:00
|
|
|
|
len = [format length];
|
|
|
|
|
if (len >= 1024)
|
2001-02-02 06:14:42 +00:00
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
fmt = NSZoneMalloc(NSDefaultMallocZone(), (len+1)*sizeof(unichar));
|
2004-05-14 10:52:30 +00:00
|
|
|
|
}
|
|
|
|
|
[format getCharacters: fmt];
|
|
|
|
|
fmt[len] = '\0';
|
2003-05-06 06:54:22 +00:00
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* If no zone is set, make sure we have one so any memory mangement
|
|
|
|
|
* (buffer growth) is done with the correct zone.
|
|
|
|
|
*/
|
|
|
|
|
if (_zone == 0)
|
|
|
|
|
{
|
2010-03-05 09:30:18 +00:00
|
|
|
|
_zone = [self zone];
|
2001-02-02 06:14:42 +00:00
|
|
|
|
}
|
2006-10-20 10:56:27 +00:00
|
|
|
|
GSPrivateFormat((GSStr)self, fmt, ap, nil);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
_flags.hash = 0; // Invalidate the hash for this string.
|
|
|
|
|
if (fmt != buf)
|
2001-02-02 06:14:42 +00:00
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), fmt);
|
2001-02-02 06:14:42 +00:00
|
|
|
|
}
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (BOOL) boolValue
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return boolValue_u((GSStr)self);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return boolValue_c((GSStr)self);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) canBeConvertedToEncoding: (NSStringEncoding)enc
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return canBeConvertedToEncoding_u((GSStr)self, enc);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return canBeConvertedToEncoding_c((GSStr)self, enc);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (unichar) characterAtIndex: (NSUInteger)index
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return characterAtIndex_u((GSStr)self, index);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return characterAtIndex_c((GSStr)self, index);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSComparisonResult) compare: (NSString*)aString
|
2009-02-23 20:42:32 +00:00
|
|
|
|
options: (NSUInteger)mask
|
2000-10-09 05:32:50 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
{
|
2016-04-13 12:45:03 +00:00
|
|
|
|
if (mask & NSNumericSearch)
|
|
|
|
|
{
|
|
|
|
|
return [super compare: aString options: mask range: aRange];
|
|
|
|
|
}
|
2008-07-15 08:05:33 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
if (aString == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ -%@] nil string argument",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
|
|
|
if (GSObjCIsInstance(aString) == NO)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ -%@] not a string argument",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return compare_u((GSStr)self, aString, mask, aRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return compare_c((GSStr)self, aString, mask, aRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineString *o;
|
2006-05-20 14:52:38 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = newUInline(_count, z);
|
2006-05-20 14:52:38 +00:00
|
|
|
|
memcpy(o->_contents.u, _contents.u, _count * sizeof(unichar));
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return o;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-02-14 10:48:10 +00:00
|
|
|
|
GSCInlineString *o;
|
2006-05-20 14:52:38 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = newCInline(_count, z);
|
2006-05-20 14:52:38 +00:00
|
|
|
|
memcpy(o->_contents.c, _contents.c, _count);
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return o;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (const char *) cString
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return cString_u((GSStr)self, externalEncoding);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return cString_c((GSStr)self, externalEncoding);
|
2005-05-08 07:08:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (const char *) cStringUsingEncoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
return cString_u((GSStr)self, encoding);
|
|
|
|
|
else
|
|
|
|
|
return cString_c((GSStr)self, encoding);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) cStringLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return cStringLength_u((GSStr)self, externalEncoding);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return cStringLength_c((GSStr)self, externalEncoding);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2006-06-17 06:51:53 +00:00
|
|
|
|
if (_contents.c != 0)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2010-03-08 12:11:03 +00:00
|
|
|
|
NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
NSZoneFree(self->_zone, self->_contents.c);
|
|
|
|
|
self->_contents.c = 0;
|
|
|
|
|
self->_zone = 0;
|
|
|
|
|
}
|
2009-10-10 08:16:17 +00:00
|
|
|
|
[super dealloc];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) deleteCharactersInRange: (NSRange)range
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(range, _count);
|
2000-10-30 19:51:32 +00:00
|
|
|
|
if (range.length > 0)
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
fillHole((GSStr)self, range.location, range.length);
|
2000-10-30 19:51:32 +00:00
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
|
|
|
{
|
2006-12-27 15:30:27 +00:00
|
|
|
|
if ([aCoder allowsKeyedCoding])
|
|
|
|
|
{
|
|
|
|
|
[(NSKeyedArchiver*)aCoder _encodePropertyList: self forKey: @"NS.string"];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(unsigned) at: &_count];
|
|
|
|
|
if (_count > 0)
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
|
|
|
|
NSStringEncoding enc = NSUnicodeStringEncoding;
|
|
|
|
|
|
2010-12-27 11:28:01 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(int) at: &enc];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
[aCoder encodeArrayOfObjCType: @encode(unichar)
|
|
|
|
|
count: _count
|
|
|
|
|
at: _contents.u];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-12-27 11:28:01 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(int)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
at: &internalEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
[aCoder encodeArrayOfObjCType: @encode(unsigned char)
|
|
|
|
|
count: _count
|
|
|
|
|
at: _contents.c];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSStringEncoding) fastestEncoding
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
return NSUnicodeStringEncoding;
|
|
|
|
|
else
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return internalEncoding;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCharacters: (unichar*)buffer
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_u((GSStr)self, buffer, (NSRange){0, _count});
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_c((GSStr)self, buffer, (NSRange){0, _count});
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCharacters: (unichar*)buffer range: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_u((GSStr)self, buffer, aRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCharacters_c((GSStr)self, buffer, aRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCString: (char*)buffer
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_u((GSStr)self, buffer, NSMaximumStringLength,
|
2000-10-09 05:32:50 +00:00
|
|
|
|
(NSRange){0, _count}, 0);
|
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_c((GSStr)self, buffer, NSMaximumStringLength,
|
2000-10-09 05:32:50 +00:00
|
|
|
|
(NSRange){0, _count}, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCString: (char*)buffer
|
2009-02-23 20:42:32 +00:00
|
|
|
|
maxLength: (NSUInteger)maxLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_u((GSStr)self, buffer, maxLength, (NSRange){0, _count}, 0);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_c((GSStr)self, buffer, maxLength, (NSRange){0, _count}, 0);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
- (BOOL) getCString: (char*)buffer
|
2009-02-23 20:42:32 +00:00
|
|
|
|
maxLength: (NSUInteger)maxLength
|
2006-02-27 09:35:19 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
return getCStringE_u((GSStr)self, buffer, maxLength, encoding);
|
|
|
|
|
else
|
|
|
|
|
return getCStringE_c((GSStr)self, buffer, maxLength, encoding);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (void) getCString: (char*)buffer
|
2009-02-23 20:42:32 +00:00
|
|
|
|
maxLength: (NSUInteger)maxLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
remainingRange: (NSRange*)leftoverRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_u((GSStr)self, buffer, maxLength, aRange, leftoverRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2004-05-14 10:52:30 +00:00
|
|
|
|
getCString_c((GSStr)self, buffer, maxLength, aRange, leftoverRange);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
return [self initWithCapacity: 0];
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-12 17:46:32 +00:00
|
|
|
|
- (id) initWithBytes: (const void*)bytes
|
2009-02-23 20:42:32 +00:00
|
|
|
|
length: (NSUInteger)length
|
2006-05-12 17:46:32 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
unsigned char *chars = 0;
|
|
|
|
|
BOOL isASCII = NO;
|
|
|
|
|
BOOL isLatin1 = NO;
|
|
|
|
|
BOOL shouldFree = NO;
|
2006-05-12 17:46:32 +00:00
|
|
|
|
|
2009-04-10 08:25:03 +00:00
|
|
|
|
_flags.owned = YES;
|
2010-03-05 09:30:18 +00:00
|
|
|
|
_zone = [self zone];
|
2006-06-17 06:51:53 +00:00
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (length > 0)
|
|
|
|
|
{
|
|
|
|
|
fixBOM((unsigned char**)&bytes, &length, &shouldFree, encoding);
|
|
|
|
|
chars = (unsigned char*)bytes;
|
|
|
|
|
}
|
2013-04-14 16:25:27 +00:00
|
|
|
|
if (0 == length)
|
|
|
|
|
{
|
|
|
|
|
return [self initWithCapacity: 0];
|
|
|
|
|
}
|
|
|
|
|
if (0 == chars)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-initWithBytes:lenth:encoding given nul bytes"];
|
|
|
|
|
}
|
2006-05-12 17:46:32 +00:00
|
|
|
|
|
2006-06-22 22:36:46 +00:00
|
|
|
|
if (encoding == NSUTF8StringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (chars[i] > 127)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (i == length)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* This is actually ASCII data ... so we can just store it as if
|
|
|
|
|
* in the internal 8bit encoding scheme.
|
|
|
|
|
*/
|
|
|
|
|
encoding = internalEncoding;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-10-09 14:00:01 +00:00
|
|
|
|
else if (encoding != internalEncoding && isByteEncoding(encoding) == YES)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-05-12 17:46:32 +00:00
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (((unsigned char*)chars)[i] > 127)
|
2006-05-12 17:46:32 +00:00
|
|
|
|
{
|
|
|
|
|
if (encoding == NSASCIIStringEncoding)
|
|
|
|
|
{
|
2010-02-25 18:49:31 +00:00
|
|
|
|
DESTROY(self);
|
2006-06-17 06:51:53 +00:00
|
|
|
|
if (shouldFree == YES)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSZoneFromPointer(chars), chars);
|
|
|
|
|
}
|
2006-05-12 17:46:32 +00:00
|
|
|
|
return nil; // Invalid data
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (i == length)
|
|
|
|
|
{
|
|
|
|
|
/*
|
2006-05-14 18:01:13 +00:00
|
|
|
|
* This is actually ASCII data ... so we can just store it as if
|
2006-05-12 17:46:32 +00:00
|
|
|
|
* in the internal 8bit encoding scheme.
|
|
|
|
|
*/
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding = internalEncoding;
|
2006-05-12 17:46:32 +00:00
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2006-05-12 17:46:32 +00:00
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (encoding == internalEncoding)
|
2006-05-12 17:46:32 +00:00
|
|
|
|
{
|
2012-01-30 11:31:40 +00:00
|
|
|
|
if (0 != chars)
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
2012-01-30 11:31:40 +00:00
|
|
|
|
if (shouldFree == YES)
|
|
|
|
|
{
|
|
|
|
|
_zone = NSZoneFromPointer(chars);
|
|
|
|
|
_contents.c = chars;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_contents.c = NSZoneMalloc(_zone, length);
|
|
|
|
|
memcpy(_contents.c, chars, length);
|
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
2006-05-12 17:46:32 +00:00
|
|
|
|
_count = length;
|
|
|
|
|
_flags.wide = 0;
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2006-05-12 17:46:32 +00:00
|
|
|
|
/*
|
|
|
|
|
* Any remaining encoding needs to be converted to UTF-16.
|
|
|
|
|
*/
|
|
|
|
|
if (encoding != NSUnicodeStringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unichar *u = 0;
|
|
|
|
|
unsigned l = 0;
|
2006-03-26 10:59:57 +00:00
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (GSToUnicode(&u, &l, (unsigned char*)chars, length, encoding,
|
2006-06-17 06:51:53 +00:00
|
|
|
|
_zone, 0) == NO)
|
2006-05-12 17:46:32 +00:00
|
|
|
|
{
|
2010-02-25 18:49:31 +00:00
|
|
|
|
DESTROY(self);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (shouldFree == YES)
|
2006-05-12 17:46:32 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(chars), chars);
|
2006-05-12 17:46:32 +00:00
|
|
|
|
}
|
|
|
|
|
return nil; // Invalid data
|
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
chars = (unsigned char*)u;
|
2006-05-12 17:46:32 +00:00
|
|
|
|
length = l * sizeof(unichar);
|
2006-05-14 18:01:13 +00:00
|
|
|
|
shouldFree = YES;
|
2006-05-12 17:46:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length /= sizeof(unichar);
|
2011-02-19 15:34:21 +00:00
|
|
|
|
if (GSUnicode((unichar*)(void*)chars, length, &isASCII, &isLatin1) != length)
|
2006-03-26 10:59:57 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (shouldFree == YES && chars != 0)
|
2006-03-28 06:05:04 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(chars), chars);
|
2006-03-28 06:05:04 +00:00
|
|
|
|
}
|
2006-03-26 10:59:57 +00:00
|
|
|
|
return nil; // Invalid data
|
|
|
|
|
}
|
2006-05-12 17:46:32 +00:00
|
|
|
|
|
2006-03-26 10:59:57 +00:00
|
|
|
|
if (isASCII == YES
|
2006-05-14 18:01:13 +00:00
|
|
|
|
|| (internalEncoding == NSISOLatin1StringEncoding && isLatin1 == YES))
|
2006-03-26 10:59:57 +00:00
|
|
|
|
{
|
2006-06-17 06:51:53 +00:00
|
|
|
|
_contents.c = NSZoneMalloc(_zone, length);
|
2006-03-28 06:05:04 +00:00
|
|
|
|
_count = length;
|
|
|
|
|
_flags.wide = 0;
|
|
|
|
|
while (length-- > 0)
|
|
|
|
|
{
|
2011-02-19 15:34:21 +00:00
|
|
|
|
_contents.c[length] = ((unichar*)(void*)chars)[length];
|
2006-03-28 06:05:04 +00:00
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (shouldFree == YES && chars != 0)
|
2006-03-28 06:05:04 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(chars), chars);
|
2006-03-28 06:05:04 +00:00
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
return self;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (shouldFree == YES)
|
|
|
|
|
{
|
2006-06-17 06:51:53 +00:00
|
|
|
|
_zone = NSZoneFromPointer(chars);
|
2011-02-19 15:34:21 +00:00
|
|
|
|
_contents.u = (unichar*)(void*)chars;
|
2006-05-14 18:01:13 +00:00
|
|
|
|
}
|
2006-03-28 06:05:04 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2006-06-17 06:51:53 +00:00
|
|
|
|
_contents.u = NSZoneMalloc(_zone, length * sizeof(unichar));
|
2006-05-14 18:01:13 +00:00
|
|
|
|
memcpy(_contents.u, chars, length * sizeof(unichar));
|
2006-03-28 06:05:04 +00:00
|
|
|
|
}
|
2006-05-14 18:01:13 +00:00
|
|
|
|
_count = length;
|
|
|
|
|
_flags.wide = 1;
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-20 14:52:38 +00:00
|
|
|
|
- (id) initWithBytesNoCopy: (void*)bytes
|
2009-02-23 20:42:32 +00:00
|
|
|
|
length: (NSUInteger)length
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
freeWhenDone: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
self = [self initWithBytes: bytes
|
|
|
|
|
length: length
|
|
|
|
|
encoding: encoding];
|
|
|
|
|
if (flag == YES && bytes != 0)
|
|
|
|
|
{
|
2006-05-20 14:52:38 +00:00
|
|
|
|
NSZoneFree(NSZoneFromPointer(bytes), bytes);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (id) initWithCapacity: (NSUInteger)capacity
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2006-05-12 17:46:32 +00:00
|
|
|
|
if (capacity < 2)
|
2003-05-07 13:15:15 +00:00
|
|
|
|
{
|
2006-05-12 17:46:32 +00:00
|
|
|
|
capacity = 2;
|
2003-05-07 13:15:15 +00:00
|
|
|
|
}
|
2006-05-12 17:46:32 +00:00
|
|
|
|
_count = 0;
|
|
|
|
|
_capacity = capacity;
|
2010-03-05 09:30:18 +00:00
|
|
|
|
_zone = [self zone];
|
2006-05-12 17:46:32 +00:00
|
|
|
|
_contents.c = NSZoneMalloc(_zone, capacity + 1);
|
2003-05-07 13:15:15 +00:00
|
|
|
|
_flags.wide = 0;
|
2009-04-10 08:25:03 +00:00
|
|
|
|
_flags.owned = 1;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-12 17:46:32 +00:00
|
|
|
|
- (id) initWithCharactersNoCopy: (unichar*)chars
|
2009-02-23 20:42:32 +00:00
|
|
|
|
length: (NSUInteger)length
|
2006-05-12 17:46:32 +00:00
|
|
|
|
freeWhenDone: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
return [self initWithBytesNoCopy: (void*)chars
|
|
|
|
|
length: length*sizeof(unichar)
|
|
|
|
|
encoding: NSUnicodeStringEncoding
|
|
|
|
|
freeWhenDone: flag];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithCStringNoCopy: (char*)chars
|
2009-02-23 20:42:32 +00:00
|
|
|
|
length: (NSUInteger)length
|
2006-05-12 17:46:32 +00:00
|
|
|
|
freeWhenDone: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
return [self initWithBytesNoCopy: (void*)chars
|
|
|
|
|
length: length
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: externalEncoding
|
2006-05-12 17:46:32 +00:00
|
|
|
|
freeWhenDone: flag];
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-05 10:06:56 +00:00
|
|
|
|
- (id) initWithFormat: (NSString*)format
|
|
|
|
|
locale: (NSDictionary*)locale
|
|
|
|
|
arguments: (va_list)argList
|
|
|
|
|
{
|
|
|
|
|
unichar fbuf[1024];
|
|
|
|
|
unichar *fmt = fbuf;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
2018-07-06 21:53:32 +00:00
|
|
|
|
if (NULL == format)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[GSMutableString-initWithFormat:locale:arguments:]: NULL format"];
|
2004-06-05 10:06:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* First we provide an array of unichar characters containing the
|
|
|
|
|
* format string. For performance reasons we try to use an on-stack
|
|
|
|
|
* buffer if the format string is small enough ... it almost always
|
|
|
|
|
* will be.
|
|
|
|
|
*/
|
|
|
|
|
len = [format length];
|
|
|
|
|
if (len >= 1024)
|
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
fmt = NSZoneMalloc(NSDefaultMallocZone(), (len+1)*sizeof(unichar));
|
2004-06-05 10:06:56 +00:00
|
|
|
|
}
|
|
|
|
|
[format getCharacters: fmt];
|
|
|
|
|
fmt[len] = '\0';
|
|
|
|
|
|
2006-10-20 10:56:27 +00:00
|
|
|
|
GSPrivateFormat((GSStr)self, fmt, argList, locale);
|
2004-08-19 14:50:44 +00:00
|
|
|
|
if (fmt != fbuf)
|
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), fmt);
|
2004-08-19 14:50:44 +00:00
|
|
|
|
}
|
2004-06-05 10:06:56 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-12 17:05:30 +00:00
|
|
|
|
- (int) intValue
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2015-05-05 11:54:14 +00:00
|
|
|
|
char buf[24];
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
if (_flags.wide == 1)
|
2015-05-05 11:54:14 +00:00
|
|
|
|
intBuf_u((GSStr)self, buf);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2015-05-05 11:54:14 +00:00
|
|
|
|
intBuf_c((GSStr)self, buf);
|
|
|
|
|
return strtol(buf, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSInteger) integerValue
|
|
|
|
|
{
|
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
intBuf_u((GSStr)self, buf);
|
|
|
|
|
else
|
|
|
|
|
intBuf_c((GSStr)self, buf);
|
|
|
|
|
#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG
|
|
|
|
|
return strtol(buf, 0, 10);
|
|
|
|
|
#else
|
|
|
|
|
return strtoll(buf, 0, 10);
|
|
|
|
|
#endif
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
|
{
|
2000-10-20 10:30:51 +00:00
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return isEqual_u((GSStr)self, anObject);
|
2000-10-20 10:30:51 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return isEqual_c((GSStr)self, anObject);
|
2000-10-20 10:30:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isEqualToString: (NSString*)anObject
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return isEqual_u((GSStr)self, anObject);
|
2000-10-20 10:30:51 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return isEqual_c((GSStr)self, anObject);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) length
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
return _count;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding
|
2005-05-08 07:08:28 +00:00
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
return cStringLength_u((GSStr)self, encoding);
|
|
|
|
|
else
|
|
|
|
|
return cStringLength_c((GSStr)self, encoding);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
- (long long) longLongValue
|
|
|
|
|
{
|
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
intBuf_u((GSStr)self, buf);
|
|
|
|
|
else
|
|
|
|
|
intBuf_c((GSStr)self, buf);
|
|
|
|
|
return strtoll(buf, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (const char*) lossyCString
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return lossyCString_u((GSStr)self);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return lossyCString_c((GSStr)self);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-23 07:25:12 +00:00
|
|
|
|
- (id) lowercaseString
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineString *o;
|
|
|
|
|
unsigned i;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = newUInline(_count, [self zone]);
|
|
|
|
|
i = _count;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
while (i-- > 0)
|
|
|
|
|
{
|
|
|
|
|
o->_contents.u[i] = uni_tolower(_contents.u[i]);
|
|
|
|
|
}
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return [o autorelease];
|
2011-02-23 07:25:12 +00:00
|
|
|
|
}
|
2012-08-08 16:54:08 +00:00
|
|
|
|
return [super lowercaseString];
|
2011-02-23 07:25:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-10 16:50:41 +00:00
|
|
|
|
- (BOOL) makeImmutable
|
|
|
|
|
{
|
|
|
|
|
NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException);
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
|
|
|
|
GSClassSwizzle(self, [GSUnicodeBufferString class]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GSClassSwizzle(self, [GSCBufferString class]);
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-14 08:52:39 +00:00
|
|
|
|
- (id) makeImmutableCopyOnFail: (BOOL)force
|
|
|
|
|
{
|
2009-04-10 08:25:03 +00:00
|
|
|
|
NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException);
|
2002-11-07 21:07:19 +00:00
|
|
|
|
if (_flags.wide == 1)
|
2002-11-10 13:56:34 +00:00
|
|
|
|
{
|
2011-02-20 16:21:43 +00:00
|
|
|
|
GSClassSwizzle(self, [GSUnicodeBufferString class]);
|
2002-11-10 13:56:34 +00:00
|
|
|
|
}
|
2002-11-07 21:07:19 +00:00
|
|
|
|
else
|
2002-11-10 13:56:34 +00:00
|
|
|
|
{
|
2011-02-20 16:21:43 +00:00
|
|
|
|
GSClassSwizzle(self, [GSCBufferString class]);
|
2002-11-10 13:56:34 +00:00
|
|
|
|
}
|
2002-10-14 08:52:39 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (id) mutableCopy
|
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSMutableString *obj;
|
|
|
|
|
|
|
|
|
|
obj = (GSMutableString*)NSAllocateObject(GSMutableStringClass, 0,
|
|
|
|
|
NSDefaultMallocZone());
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
if (_flags.wide == 1)
|
2006-05-20 14:52:38 +00:00
|
|
|
|
obj = [obj initWithBytes: (void*)_contents.u
|
|
|
|
|
length: _count * sizeof(unichar)
|
|
|
|
|
encoding: NSUnicodeStringEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2006-05-20 14:52:38 +00:00
|
|
|
|
obj = [obj initWithBytes: (void*)_contents.c
|
2006-05-12 17:46:32 +00:00
|
|
|
|
length: _count
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: internalEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) mutableCopyWithZone: (NSZone*)z
|
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSMutableString *obj;
|
|
|
|
|
|
|
|
|
|
obj = (GSMutableString*)NSAllocateObject(GSMutableStringClass, 0, z);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
if (_flags.wide == 1)
|
2006-05-20 14:52:38 +00:00
|
|
|
|
obj = [obj initWithBytes: (void*)_contents.u
|
|
|
|
|
length: _count * sizeof(unichar)
|
|
|
|
|
encoding: NSUnicodeStringEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2006-05-12 17:46:32 +00:00
|
|
|
|
obj = [obj initWithBytes: (char*)_contents.c
|
|
|
|
|
length: _count
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: internalEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSRange) rangeOfComposedCharacterSequenceAtIndex: (NSUInteger)anIndex
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return rangeOfSequence_u((GSStr)self, anIndex);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return rangeOfSequence_c((GSStr)self, anIndex);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-02-06 13:44:03 +00:00
|
|
|
|
- (NSRange) rangeOfCharacterFromSet: (NSCharacterSet*)aSet
|
2009-02-23 20:42:32 +00:00
|
|
|
|
options: (NSUInteger)mask
|
2002-02-06 13:44:03 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
|
|
|
|
if (_flags.wide == 1)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return rangeOfCharacter_u((GSStr)self, aSet, mask, aRange);
|
2002-02-06 13:44:03 +00:00
|
|
|
|
else
|
2004-05-14 10:52:30 +00:00
|
|
|
|
return rangeOfCharacter_c((GSStr)self, aSet, mask, aRange);
|
2002-02-06 13:44:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (void) replaceCharactersInRange: (NSRange)aRange
|
|
|
|
|
withString: (NSString*)aString
|
|
|
|
|
{
|
2001-03-03 14:49:11 +00:00
|
|
|
|
unsigned length = 0;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
2001-03-03 14:49:11 +00:00
|
|
|
|
if (aString != nil)
|
2001-02-08 17:12:40 +00:00
|
|
|
|
{
|
2001-03-03 14:49:11 +00:00
|
|
|
|
if (GSObjCIsInstance(aString) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"replace characters with non-string"];
|
|
|
|
|
}
|
2020-11-22 13:08:34 +00:00
|
|
|
|
length = [aString length];
|
2001-02-08 17:12:40 +00:00
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* Either we have data to copy into the string (possibly requiring
|
|
|
|
|
* length adjustment first), or we have no data but possibly a gap
|
|
|
|
|
* (the range specified) needing to be closed.
|
2001-06-05 08:21:09 +00:00
|
|
|
|
*/
|
|
|
|
|
if (length > 0)
|
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
int offset = length - aRange.length;
|
|
|
|
|
GSStr other = 0;
|
2001-06-05 08:21:09 +00:00
|
|
|
|
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* We must change into a unicode string (if necessary) *before*
|
|
|
|
|
* adjusting length and capacity, so that the transmute doesn't
|
|
|
|
|
* mess up due to any hole in the string etc.
|
|
|
|
|
*/
|
|
|
|
|
other = transmute((GSStr)self, aString);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2020-11-22 14:55:39 +00:00
|
|
|
|
if (other == self)
|
|
|
|
|
{
|
|
|
|
|
if (aRange.length == _count)
|
|
|
|
|
{
|
|
|
|
|
// NSLog(@"replace all characters with self ... nothing to do");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (aRange.length == 0
|
|
|
|
|
&& (aRange.location == _count || aRange.location == 0))
|
|
|
|
|
{
|
|
|
|
|
/* We are appending self at the end of self, or we are
|
|
|
|
|
* prepending self at the start of the self.
|
|
|
|
|
* Either way in effect we double the string, so we can
|
|
|
|
|
* do an efficient size extension and copy.
|
|
|
|
|
*/
|
|
|
|
|
makeHole((GSStr)self, length, length);
|
|
|
|
|
if (_flags.wide)
|
|
|
|
|
{
|
|
|
|
|
memcpy(&_contents.u[length], _contents.u,
|
|
|
|
|
length * sizeof(unichar));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memcpy(&_contents.c[length], _contents.c,
|
|
|
|
|
length * sizeof(char));
|
|
|
|
|
}
|
|
|
|
|
_flags.hash = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// NSLog(@"replace characters in range with self");
|
|
|
|
|
}
|
2020-11-22 13:08:34 +00:00
|
|
|
|
if (0 == other || other == self)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
/* Either we couldn't get access to the internal of the string
|
|
|
|
|
* to be copied, or we are copying from ourself and need to
|
|
|
|
|
* use an intermediate buffer to prevent overwriting.
|
|
|
|
|
*/
|
|
|
|
|
if (_flags.wide)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
GS_BEGINITEMBUF(buf, (length * sizeof(unichar)), unichar);
|
|
|
|
|
|
|
|
|
|
[aString getCharacters: buf];
|
|
|
|
|
if (offset < 0)
|
|
|
|
|
{
|
|
|
|
|
fillHole((GSStr)self, NSMaxRange(aRange) + offset, -offset);
|
|
|
|
|
}
|
|
|
|
|
else if (offset > 0)
|
|
|
|
|
{
|
|
|
|
|
makeHole((GSStr)self, NSMaxRange(aRange), (NSUInteger)offset);
|
|
|
|
|
}
|
|
|
|
|
memcpy(&_contents.u[aRange.location], buf,
|
|
|
|
|
length * sizeof(unichar));
|
|
|
|
|
GS_ENDITEMBUF()
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
GS_BEGINITEMBUF(buf, ((length+1) * sizeof(char)), char);
|
|
|
|
|
|
|
|
|
|
[aString getCString: buf
|
|
|
|
|
maxLength: length+1
|
|
|
|
|
encoding: internalEncoding];
|
|
|
|
|
if (offset < 0)
|
|
|
|
|
{
|
|
|
|
|
fillHole((GSStr)self, NSMaxRange(aRange) + offset, -offset);
|
|
|
|
|
}
|
|
|
|
|
else if (offset > 0)
|
|
|
|
|
{
|
|
|
|
|
makeHole((GSStr)self, NSMaxRange(aRange), (NSUInteger)offset);
|
|
|
|
|
}
|
|
|
|
|
memcpy(&_contents.c[aRange.location], buf,
|
|
|
|
|
length * sizeof(char));
|
|
|
|
|
GS_ENDITEMBUF()
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
if (offset < 0)
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
fillHole((GSStr)self, NSMaxRange(aRange) + offset, -offset);
|
|
|
|
|
}
|
|
|
|
|
else if (offset > 0)
|
|
|
|
|
{
|
|
|
|
|
makeHole((GSStr)self, NSMaxRange(aRange), (NSUInteger)offset);
|
|
|
|
|
}
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
|
|
|
|
memcpy(&_contents.u[aRange.location], other->_contents.u,
|
|
|
|
|
length * sizeof(unichar));
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-11-22 13:08:34 +00:00
|
|
|
|
memcpy(&_contents.c[aRange.location], other->_contents.c,
|
|
|
|
|
length * sizeof(char));
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_flags.hash = 0;
|
|
|
|
|
}
|
2020-11-22 13:08:34 +00:00
|
|
|
|
else if (aRange.length > 0)
|
|
|
|
|
{
|
|
|
|
|
fillHole((GSStr)self, aRange.location, aRange.length);
|
|
|
|
|
_flags.hash = 0;
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setString: (NSString*)aString
|
|
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int len = (aString == nil) ? 0 : [aString length];
|
2004-05-14 10:52:30 +00:00
|
|
|
|
GSStr other;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
_count = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2004-05-14 10:52:30 +00:00
|
|
|
|
other = transmute((GSStr)self, aString);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
if (_count < len)
|
|
|
|
|
{
|
2009-02-23 20:42:32 +00:00
|
|
|
|
makeHole((GSStr)self, _count, (NSUInteger)(len - _count));
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_count = len;
|
|
|
|
|
_flags.hash = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
|
|
|
|
if (other == 0)
|
|
|
|
|
{
|
|
|
|
|
[aString getCharacters: _contents.u];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memcpy(_contents.u, other->_contents.u, len * sizeof(unichar));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (other == 0)
|
|
|
|
|
{
|
|
|
|
|
unsigned l;
|
2006-08-12 15:09:23 +00:00
|
|
|
|
unsigned s = 1;
|
|
|
|
|
unichar u;
|
|
|
|
|
unsigned char *d;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Since getCString appends a '\0' terminator, we must ask for
|
|
|
|
|
* one character less than we actually want, then get the last
|
|
|
|
|
* character separately.
|
|
|
|
|
*/
|
|
|
|
|
l = len - 1;
|
|
|
|
|
if (l > 0)
|
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
[aString getCString: (char*)_contents.c
|
2006-06-02 05:25:21 +00:00
|
|
|
|
maxLength: l+1
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: internalEncoding];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
2006-08-12 15:09:23 +00:00
|
|
|
|
u = [aString characterAtIndex: l];
|
|
|
|
|
d = _contents.c + l;
|
2006-08-12 16:33:39 +00:00
|
|
|
|
GSFromUnicode(&d, &s, &u, 1, internalEncoding, 0, GSUniStrict);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memcpy(_contents.c, other->_contents.c, len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSStringEncoding) smallestEncoding
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
2000-10-23 06:18:03 +00:00
|
|
|
|
return NSUnicodeStringEncoding;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2006-05-14 18:01:13 +00:00
|
|
|
|
{
|
|
|
|
|
return internalEncoding;
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-24 11:58:25 +00:00
|
|
|
|
- (NSString*) substringFromRange: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
2000-11-06 14:15:27 +00:00
|
|
|
|
|
2006-05-23 19:29:52 +00:00
|
|
|
|
if (aRange.length == 0)
|
|
|
|
|
{
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
2000-10-24 11:58:25 +00:00
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineString *o;
|
2006-05-20 14:52:38 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = [newUInline(aRange.length, [self zone]) autorelease];
|
2006-05-20 14:52:38 +00:00
|
|
|
|
memcpy(o->_contents.u, _contents.u + aRange.location,
|
|
|
|
|
aRange.length * sizeof(unichar));
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return o;
|
2000-10-24 11:58:25 +00:00
|
|
|
|
}
|
2012-08-25 12:31:41 +00:00
|
|
|
|
else
|
2012-08-25 12:15:11 +00:00
|
|
|
|
{
|
2013-01-07 21:39:35 +00:00
|
|
|
|
id tinyString;
|
2012-08-25 12:15:11 +00:00
|
|
|
|
|
2013-01-07 21:39:35 +00:00
|
|
|
|
tinyString = createTinyString((char*)_contents.c + aRange.location,
|
|
|
|
|
aRange.length);
|
2012-08-25 12:15:11 +00:00
|
|
|
|
if (tinyString)
|
2013-01-07 21:39:35 +00:00
|
|
|
|
{
|
|
|
|
|
return tinyString;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GSCInlineString *o;
|
2006-05-20 14:52:38 +00:00
|
|
|
|
|
2013-01-07 21:39:35 +00:00
|
|
|
|
o = [newCInline(aRange.length, [self zone]) autorelease];
|
|
|
|
|
memcpy(o->_contents.c, _contents.c + aRange.location, aRange.length);
|
|
|
|
|
return o;
|
|
|
|
|
}
|
2000-10-24 11:58:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-23 23:18:44 +00:00
|
|
|
|
- (NSString*) substringWithRange: (NSRange)aRange
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
GS_RANGE_CHECK(aRange, _count);
|
2000-11-06 14:15:27 +00:00
|
|
|
|
|
2006-05-23 19:29:52 +00:00
|
|
|
|
if (aRange.length == 0)
|
|
|
|
|
{
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
if (_flags.wide == 1)
|
2000-10-20 10:30:51 +00:00
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineString *o;
|
2006-05-20 14:52:38 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = [newUInline(aRange.length, [self zone]) autorelease];
|
2006-05-20 14:52:38 +00:00
|
|
|
|
memcpy(o->_contents.u, _contents.u + aRange.location,
|
|
|
|
|
aRange.length * sizeof(unichar));
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return o;
|
2000-10-20 10:30:51 +00:00
|
|
|
|
}
|
2012-08-25 12:31:41 +00:00
|
|
|
|
else
|
2012-08-25 12:15:11 +00:00
|
|
|
|
{
|
2013-01-07 21:39:35 +00:00
|
|
|
|
id tinyString;
|
2012-08-25 12:15:11 +00:00
|
|
|
|
|
2013-01-07 21:39:35 +00:00
|
|
|
|
tinyString = createTinyString((char*)_contents.c + aRange.location,
|
|
|
|
|
aRange.length);
|
2012-08-25 12:15:11 +00:00
|
|
|
|
if (tinyString)
|
2013-01-07 21:39:35 +00:00
|
|
|
|
{
|
|
|
|
|
return tinyString;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GSCInlineString *o;
|
2006-05-20 14:52:38 +00:00
|
|
|
|
|
2013-01-07 21:39:35 +00:00
|
|
|
|
o = [newCInline(aRange.length, [self zone]) autorelease];
|
|
|
|
|
memcpy(o->_contents.c, _contents.c + aRange.location, aRange.length);
|
|
|
|
|
return o;
|
|
|
|
|
}
|
2000-10-20 10:30:51 +00:00
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-23 07:25:12 +00:00
|
|
|
|
- (id) uppercaseString
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
GSUInlineString *o;
|
|
|
|
|
unsigned i;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
o = [newUInline(_count, [self zone]) autorelease];
|
|
|
|
|
i = _count;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
while (i-- > 0)
|
|
|
|
|
{
|
|
|
|
|
o->_contents.u[i] = uni_toupper(_contents.u[i]);
|
|
|
|
|
}
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return o;
|
2011-02-23 07:25:12 +00:00
|
|
|
|
}
|
2012-08-08 16:54:08 +00:00
|
|
|
|
return [super uppercaseString];
|
2011-02-23 07:25:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-26 09:56:55 +00:00
|
|
|
|
- (const char *) UTF8String
|
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
return UTF8String_u((GSStr)self);
|
|
|
|
|
return UTF8String_c((GSStr)self);
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
// private method for Unicode level 3 implementation
|
2010-09-12 17:05:30 +00:00
|
|
|
|
- (int) _baseLength
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (_flags.wide == 1)
|
|
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int count = 0;
|
|
|
|
|
unsigned int blen = 0;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
|
|
|
|
while (count < _count)
|
|
|
|
|
if (!uni_isnonsp(_contents.u[count++]))
|
|
|
|
|
blen++;
|
|
|
|
|
return blen;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return _count;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
}
|
2000-10-09 05:32:50 +00:00
|
|
|
|
|
2015-07-16 08:44:15 +00:00
|
|
|
|
- (NSUInteger) sizeInBytesExcluding: (NSHashTable*)exclude
|
2015-07-15 14:14:21 +00:00
|
|
|
|
{
|
|
|
|
|
NSUInteger size = GSPrivateMemorySize(self, exclude);
|
|
|
|
|
|
|
|
|
|
if (size > 0 && _flags.owned)
|
|
|
|
|
{
|
|
|
|
|
size += _capacity;
|
|
|
|
|
if (_flags.wide)
|
|
|
|
|
{
|
|
|
|
|
size += _capacity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-11-11 22:23:13 +00:00
|
|
|
|
#ifndef GNUSTEP_NEW_STRING_ABI
|
2011-10-31 08:12:26 +00:00
|
|
|
|
static BOOL
|
|
|
|
|
literalIsEqual(NXConstantString *self, id anObject)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2011-10-31 08:12:26 +00:00
|
|
|
|
Class c;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
|
2011-10-31 08:12:26 +00:00
|
|
|
|
if (anObject == (id)self)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2011-10-31 08:12:26 +00:00
|
|
|
|
return YES;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2011-10-31 08:12:26 +00:00
|
|
|
|
if (anObject == nil)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2011-10-31 08:12:26 +00:00
|
|
|
|
return NO;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2015-05-22 16:24:27 +00:00
|
|
|
|
#if defined(OBJC_SMALL_OBJECT_SHIFT) && (OBJC_SMALL_OBJECT_SHIFT == 3)
|
|
|
|
|
if (useTinyStrings)
|
|
|
|
|
{
|
|
|
|
|
uintptr_t s = (uintptr_t)anObject;
|
|
|
|
|
|
|
|
|
|
if (s & TINY_STRING_MASK)
|
|
|
|
|
{
|
|
|
|
|
return tinyEqualToString((uintptr_t)anObject, self);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2011-10-31 08:12:26 +00:00
|
|
|
|
if (GSObjCIsInstance(anObject) == NO)
|
2011-10-14 13:45:52 +00:00
|
|
|
|
{
|
2011-10-31 08:12:26 +00:00
|
|
|
|
return NO;
|
2011-10-14 13:45:52 +00:00
|
|
|
|
}
|
2011-10-31 08:12:26 +00:00
|
|
|
|
c = object_getClass(anObject);
|
|
|
|
|
if (c == NSConstantStringClass)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2011-10-31 08:12:26 +00:00
|
|
|
|
NXConstantString *other = (NXConstantString*)anObject;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
|
2011-10-31 08:12:26 +00:00
|
|
|
|
if (other->nxcslen != self->nxcslen
|
|
|
|
|
|| strcmp(other->nxcsptr, self->nxcsptr) != 0)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2011-11-01 09:43:25 +00:00
|
|
|
|
else if (c == GSMutableStringClass || GSObjCIsKindOf(c, GSStringClass) == YES)
|
|
|
|
|
{
|
|
|
|
|
return literalIsEqualInternal(self, (GSStr)anObject);
|
|
|
|
|
}
|
2011-10-31 08:12:26 +00:00
|
|
|
|
else if (YES == [anObject isKindOfClass: NSStringClass]) // may be proxy
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2011-10-31 08:12:26 +00:00
|
|
|
|
unichar (*imp)(id, SEL, NSUInteger);
|
|
|
|
|
NSUInteger len = [anObject length];
|
|
|
|
|
NSUInteger pos = 0;
|
|
|
|
|
unichar n = 0;
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
unichar u;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
|
2011-10-31 10:00:29 +00:00
|
|
|
|
if (len > self->nxcslen)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2011-10-31 08:12:26 +00:00
|
|
|
|
/* Since UTF-8 is a multibyte character set, it must have at least
|
|
|
|
|
* as many bytes as another string of the same length. So if the
|
2011-10-31 10:00:29 +00:00
|
|
|
|
* UTF-8 string is shorter, the two cannot be equal.
|
2011-10-31 08:12:26 +00:00
|
|
|
|
*/
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2011-10-12 14:28:44 +00:00
|
|
|
|
|
2011-11-01 09:43:25 +00:00
|
|
|
|
/* Do a character by character comparison using characterAtIndex:
|
2011-10-31 08:12:26 +00:00
|
|
|
|
*/
|
|
|
|
|
imp = (unichar(*)(id,SEL,NSUInteger))[anObject methodForSelector:
|
|
|
|
|
@selector(characterAtIndex:)];
|
|
|
|
|
while (i < self->nxcslen || n > 0)
|
|
|
|
|
{
|
|
|
|
|
u = nextUTF8((const uint8_t *)self->nxcsptr,
|
|
|
|
|
self->nxcslen, &i, &n);
|
|
|
|
|
if (pos >= len
|
|
|
|
|
|| (*imp)(anObject, @selector(characterAtIndex:), pos) != u)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2011-10-31 08:12:26 +00:00
|
|
|
|
return NO;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2011-10-31 08:12:26 +00:00
|
|
|
|
pos++;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2011-10-31 08:12:26 +00:00
|
|
|
|
if (pos != len)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2011-10-31 08:12:26 +00:00
|
|
|
|
return NO;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2011-10-31 08:12:26 +00:00
|
|
|
|
return YES;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2011-10-31 08:12:26 +00:00
|
|
|
|
return NO;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2020-11-11 22:23:13 +00:00
|
|
|
|
#endif
|
2011-10-12 14:28:44 +00:00
|
|
|
|
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifdef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
# define CONSTANT_STRING_ENCODING() (flags & 3)
|
|
|
|
|
# define CONSTANT_STRING_HAS_HASH() ((flags & (1<<16)) == (1<<16))
|
|
|
|
|
# define CONSTANT_STRING_SET_HAS_HASH() do { flags |= (1<<16); } while(0)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
2002-03-13 09:58:43 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>The NXConstantString class is used by the compiler for constant
|
2000-11-03 10:11:56 +00:00
|
|
|
|
* strings, as such its ivar layout is determined by the compiler
|
|
|
|
|
* and consists of a pointer (_contents.c) and a character count
|
2011-10-28 14:31:46 +00:00
|
|
|
|
* (_count).
|
2000-11-03 10:11:56 +00:00
|
|
|
|
*/
|
2000-10-09 05:32:50 +00:00
|
|
|
|
@implementation NXConstantString
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NXConstantString class])
|
|
|
|
|
{
|
2018-04-07 19:03:33 +00:00
|
|
|
|
NSConstantStringClass = self;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 14:28:44 +00:00
|
|
|
|
- (const char*) UTF8String
|
|
|
|
|
{
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifdef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
switch (CONSTANT_STRING_ENCODING())
|
|
|
|
|
{
|
|
|
|
|
case 0: // ASCII
|
|
|
|
|
case 1: // UTF-8
|
|
|
|
|
return nxcsptr;
|
|
|
|
|
case 2: // UTF-16
|
|
|
|
|
{
|
|
|
|
|
unsigned int l = 0;
|
|
|
|
|
unsigned char *r = 0;
|
|
|
|
|
|
|
|
|
|
if (GSFromUnicode(&r, &l, (const unichar*)(void*)nxcsptr, nxcslen, NSUTF8StringEncoding,
|
|
|
|
|
NSDefaultMallocZone(), GSUniTerminate|GSUniTemporary|GSUniStrict) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"Can't get UTF8 from Unicode string."];
|
|
|
|
|
}
|
|
|
|
|
return (const char*)r;
|
|
|
|
|
}
|
|
|
|
|
case 4: // UTF-32
|
|
|
|
|
return [super UTF8String];
|
|
|
|
|
}
|
|
|
|
|
GS_UNREACHABLE();
|
|
|
|
|
#else
|
2011-10-12 14:28:44 +00:00
|
|
|
|
return nxcsptr;
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unichar) characterAtIndex: (NSUInteger)index
|
|
|
|
|
{
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifdef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
if (index >= nxcslen)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-characterAtIndex: index out of range"];
|
|
|
|
|
}
|
|
|
|
|
switch (CONSTANT_STRING_ENCODING())
|
|
|
|
|
{
|
|
|
|
|
case 0: // ASCII
|
|
|
|
|
case 1: // UTF-8
|
|
|
|
|
return nxcsptr[index];
|
|
|
|
|
case 2: // UTF-16
|
|
|
|
|
return ((unichar*)(void*)nxcsptr)[index];
|
|
|
|
|
}
|
|
|
|
|
GS_UNREACHABLE();
|
|
|
|
|
#else
|
2011-10-12 14:28:44 +00:00
|
|
|
|
NSUInteger l = 0;
|
|
|
|
|
unichar u;
|
|
|
|
|
unichar n = 0;
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
|
2011-10-14 07:07:39 +00:00
|
|
|
|
while (i < nxcslen || n > 0)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
|
|
|
|
u = nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
|
|
|
|
if (l++ == index)
|
|
|
|
|
{
|
|
|
|
|
return u;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-characterAtIndex: index out of range"];
|
|
|
|
|
return 0;
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifndef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
|
2011-10-28 14:25:17 +00:00
|
|
|
|
- (BOOL) canBeConvertedToEncoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
/* If the string contains bad (non-utf8) data, the lengthUTF8() function
|
|
|
|
|
* will raise an exception ... we catch it and return NO in that case
|
|
|
|
|
* since this method is not expected to raise exceptions.
|
|
|
|
|
*/
|
|
|
|
|
NS_DURING
|
2011-10-28 14:25:17 +00:00
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
if (NSASCIIStringEncoding == encoding)
|
|
|
|
|
{
|
|
|
|
|
BOOL ascii;
|
2011-10-28 14:25:17 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
lengthUTF8((const uint8_t*)nxcsptr, nxcslen, &ascii, 0);
|
2012-08-08 15:10:13 +00:00
|
|
|
|
NS_VALRETURN(ascii);
|
2012-08-08 09:46:08 +00:00
|
|
|
|
}
|
|
|
|
|
else if (NSISOLatin1StringEncoding == encoding)
|
|
|
|
|
{
|
|
|
|
|
BOOL latin1;
|
2011-10-28 14:25:17 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
lengthUTF8((const uint8_t*)nxcsptr, nxcslen, 0, &latin1);
|
2012-08-08 15:10:13 +00:00
|
|
|
|
NS_VALRETURN(latin1);
|
2012-08-08 09:46:08 +00:00
|
|
|
|
}
|
|
|
|
|
else if (NSUTF8StringEncoding == encoding
|
|
|
|
|
|| NSUnicodeStringEncoding == encoding)
|
|
|
|
|
{
|
|
|
|
|
lengthUTF8((const uint8_t*)nxcsptr, nxcslen, 0, 0);
|
2012-08-08 15:10:13 +00:00
|
|
|
|
NS_VALRETURN(YES);
|
2012-08-08 09:46:08 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
id d = [self dataUsingEncoding: encoding allowLossyConversion: NO];
|
|
|
|
|
|
2012-08-08 15:10:13 +00:00
|
|
|
|
NS_VALRETURN(d != nil ? YES : NO);
|
2012-08-08 09:46:08 +00:00
|
|
|
|
}
|
2011-10-28 14:30:47 +00:00
|
|
|
|
}
|
2012-08-08 09:46:08 +00:00
|
|
|
|
NS_HANDLER
|
2011-10-28 14:25:17 +00:00
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
return NO;
|
2011-10-28 14:25:17 +00:00
|
|
|
|
}
|
2012-08-08 09:46:08 +00:00
|
|
|
|
NS_ENDHANDLER
|
2011-10-28 14:25:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 14:28:44 +00:00
|
|
|
|
- (NSData*) dataUsingEncoding: (NSStringEncoding)encoding
|
|
|
|
|
allowLossyConversion: (BOOL)flag
|
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
BOOL ascii;
|
|
|
|
|
BOOL latin1;
|
|
|
|
|
unsigned length;
|
|
|
|
|
|
|
|
|
|
/* Check what is actually in this string ... if it's corrupt an exception
|
|
|
|
|
* is raised.
|
|
|
|
|
*/
|
|
|
|
|
length = lengthUTF8((const uint8_t*)nxcsptr, nxcslen, &ascii, &latin1);
|
|
|
|
|
|
2011-10-12 14:28:44 +00:00
|
|
|
|
if (NSUTF8StringEncoding == encoding)
|
|
|
|
|
{
|
2011-10-14 13:45:52 +00:00
|
|
|
|
/* We want utf-8, so we can just return an object pointing to the
|
2012-08-08 09:46:08 +00:00
|
|
|
|
* constant string data since e just checked that it's UTF8 in
|
|
|
|
|
* lengthUTF8().
|
2011-10-14 13:45:52 +00:00
|
|
|
|
*/
|
2011-10-12 14:28:44 +00:00
|
|
|
|
return [NSDataClass dataWithBytesNoCopy: (void*)nxcsptr
|
|
|
|
|
length: nxcslen
|
|
|
|
|
freeWhenDone: NO];
|
|
|
|
|
}
|
2012-08-08 09:46:08 +00:00
|
|
|
|
|
|
|
|
|
if (YES == ascii && GSPrivateIsByteEncoding(encoding))
|
2011-10-14 13:45:52 +00:00
|
|
|
|
{
|
2012-08-08 09:46:08 +00:00
|
|
|
|
/* The constant string data is just ascii, so we can return a
|
|
|
|
|
* pointer to it directly for any encoding which has ascii as
|
|
|
|
|
* a subset.
|
|
|
|
|
*/
|
|
|
|
|
return [NSDataClass dataWithBytesNoCopy: (void*)nxcsptr
|
|
|
|
|
length: nxcslen
|
|
|
|
|
freeWhenDone: NO];
|
|
|
|
|
}
|
2011-10-14 13:45:52 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
if (YES == latin1 && NSISOLatin1StringEncoding == encoding)
|
|
|
|
|
{
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
unichar n = 0;
|
|
|
|
|
uint8_t *b;
|
2016-01-21 12:27:25 +00:00
|
|
|
|
uint8_t *p;
|
2011-10-14 13:45:52 +00:00
|
|
|
|
|
2012-08-08 09:46:08 +00:00
|
|
|
|
/* If all the characters are latin1 we can copy them efficiently.
|
|
|
|
|
*/
|
2016-01-21 12:27:25 +00:00
|
|
|
|
p = b = NSAllocateCollectable(length, 0);
|
2016-01-21 12:42:43 +00:00
|
|
|
|
while (i < nxcslen)
|
2012-08-08 09:46:08 +00:00
|
|
|
|
{
|
2016-01-21 12:27:25 +00:00
|
|
|
|
*p++ = (uint8_t)nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
2012-08-08 09:46:08 +00:00
|
|
|
|
}
|
|
|
|
|
return [NSDataClass dataWithBytesNoCopy: (void*)b
|
|
|
|
|
length: length
|
|
|
|
|
freeWhenDone: YES];
|
2011-10-14 13:45:52 +00:00
|
|
|
|
}
|
2012-08-08 09:46:08 +00:00
|
|
|
|
|
2011-10-12 14:28:44 +00:00
|
|
|
|
return [super dataUsingEncoding: encoding allowLossyConversion: flag];
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2011-10-12 14:28:44 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
GSNOSUPERDEALLOC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) getCharacters: (unichar*)buffer
|
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
{
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifdef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
GS_RANGE_CHECK(aRange, nxcslen);
|
|
|
|
|
switch (CONSTANT_STRING_ENCODING())
|
|
|
|
|
{
|
|
|
|
|
case 0: // ASCII
|
|
|
|
|
for (int i=0 ; i<aRange.length ; i++)
|
|
|
|
|
{
|
|
|
|
|
buffer[i] = (unichar)nxcsptr[aRange.location + i];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
case 1: // UTF-8
|
|
|
|
|
NSAssert(0, @"UTF-8 constant strings not yet supported");
|
|
|
|
|
case 2: // UTF-16
|
|
|
|
|
memcpy(buffer, nxcsptr + (aRange.location * sizeof(unichar)), aRange.length * sizeof(unichar));
|
|
|
|
|
return;
|
|
|
|
|
case 3:
|
|
|
|
|
NSAssert(0, @"UTF-32 constant strings not yet supported");
|
|
|
|
|
}
|
|
|
|
|
GS_UNREACHABLE();
|
|
|
|
|
#else
|
2011-10-12 14:28:44 +00:00
|
|
|
|
unichar n = 0;
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
NSUInteger max = NSMaxRange(aRange);
|
|
|
|
|
NSUInteger index = 0;
|
|
|
|
|
|
|
|
|
|
if (NSNotFound == aRange.location)
|
2013-07-02 15:46:26 +00:00
|
|
|
|
[NSException raise: NSRangeException format:
|
|
|
|
|
@"in %s, range { %"PRIuPTR", %"PRIuPTR" } extends beyond string",
|
|
|
|
|
GSNameFromSelector(_cmd), aRange.location, aRange.length];
|
2011-10-12 14:28:44 +00:00
|
|
|
|
|
2011-10-14 07:07:39 +00:00
|
|
|
|
while (index < aRange.location && (i < nxcslen || n > 0))
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
|
|
|
|
nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
if (index == aRange.location)
|
|
|
|
|
{
|
2011-10-14 07:07:39 +00:00
|
|
|
|
while (index < max && (i < nxcslen || n > 0))
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
|
|
|
|
*buffer++ = nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (index != max)
|
|
|
|
|
{
|
2013-07-02 15:46:26 +00:00
|
|
|
|
[NSException raise: NSRangeException format:
|
|
|
|
|
@"in %s, range { %"PRIuPTR", %"PRIuPTR" } extends beyond string",
|
|
|
|
|
GSNameFromSelector(_cmd), aRange.location, aRange.length];
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2002-03-13 13:46:12 +00:00
|
|
|
|
|
2018-12-27 13:42:12 +00:00
|
|
|
|
// This method was deprecated on Mac OS X 10.5, so if we provide an improved
|
|
|
|
|
// version here then we should do it using the newer version.
|
|
|
|
|
#ifndef GNUSTEP_NEW_STRING_ABI
|
2016-06-23 18:27:22 +00:00
|
|
|
|
- (BOOL) getCString: (char*)buffer
|
|
|
|
|
maxLength: (NSUInteger)maxLength
|
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
const uint8_t *ptr = (const uint8_t*)nxcsptr;
|
|
|
|
|
int length = nxcslen;
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
|
|
if (0 == maxLength || 0 == buffer)
|
|
|
|
|
{
|
|
|
|
|
return NO; // Can't fit in here
|
|
|
|
|
}
|
|
|
|
|
if (NSUTF8StringEncoding == encoding)
|
|
|
|
|
{
|
2016-06-25 18:27:33 +00:00
|
|
|
|
BOOL result = (length < maxLength) ? YES : NO;
|
|
|
|
|
|
2016-06-23 18:27:22 +00:00
|
|
|
|
/* We are already using UTF-8 so we can just copy directly.
|
|
|
|
|
*/
|
|
|
|
|
if (maxLength <= length)
|
|
|
|
|
{
|
|
|
|
|
length = maxLength - 1;
|
|
|
|
|
}
|
|
|
|
|
for (index = 0; index < length; index++)
|
|
|
|
|
{
|
|
|
|
|
buffer[index] = (char)ptr[index];
|
|
|
|
|
}
|
|
|
|
|
/* Step back before any multibyte sequence
|
|
|
|
|
*/
|
|
|
|
|
while (index > 0 && (ptr[index - 1] & 0x80))
|
|
|
|
|
{
|
|
|
|
|
index--;
|
|
|
|
|
}
|
|
|
|
|
buffer[index] = '\0';
|
2016-06-25 18:27:33 +00:00
|
|
|
|
return result;
|
2016-06-23 18:27:22 +00:00
|
|
|
|
}
|
|
|
|
|
else if (isByteEncoding(encoding))
|
|
|
|
|
{
|
2016-06-25 18:27:33 +00:00
|
|
|
|
BOOL result = (length < maxLength) ? YES : NO;
|
|
|
|
|
|
2016-06-23 18:27:22 +00:00
|
|
|
|
/* We want a single-byte encoding (ie ascii is a subset),
|
|
|
|
|
* so as long as this constant string is ascii, we can just
|
|
|
|
|
* copy directly.
|
|
|
|
|
*/
|
|
|
|
|
if (maxLength <= length)
|
|
|
|
|
{
|
|
|
|
|
length = maxLength - 1;
|
|
|
|
|
}
|
|
|
|
|
for (index = 0; index < length; index++)
|
|
|
|
|
{
|
|
|
|
|
buffer[index] = (char)ptr[index];
|
|
|
|
|
if (ptr[index] & 0x80)
|
|
|
|
|
{
|
|
|
|
|
break; // Not ascii
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (index == length)
|
2016-06-25 18:27:33 +00:00
|
|
|
|
{
|
2016-06-23 18:27:22 +00:00
|
|
|
|
buffer[index] = '\0';
|
2016-06-25 18:27:33 +00:00
|
|
|
|
return result;
|
2016-06-23 18:27:22 +00:00
|
|
|
|
}
|
|
|
|
|
// Fall through to use superclass method.
|
|
|
|
|
}
|
|
|
|
|
return [super getCString: buffer maxLength: maxLength encoding: encoding];
|
|
|
|
|
}
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif
|
2016-06-23 18:27:22 +00:00
|
|
|
|
|
2011-10-14 07:07:39 +00:00
|
|
|
|
/* Must match the implementation in NSString
|
2013-03-12 16:11:10 +00:00
|
|
|
|
* To avoid allocating memory, we build the hash incrementally.
|
2011-10-14 07:07:39 +00:00
|
|
|
|
*/
|
|
|
|
|
- (NSUInteger) hash
|
|
|
|
|
{
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifdef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
if (CONSTANT_STRING_HAS_HASH())
|
|
|
|
|
return hash;
|
|
|
|
|
hash = [super hash];
|
|
|
|
|
CONSTANT_STRING_SET_HAS_HASH();
|
|
|
|
|
return hash;
|
|
|
|
|
#else
|
2011-10-14 07:07:39 +00:00
|
|
|
|
if (nxcslen > 0)
|
|
|
|
|
{
|
2013-03-12 16:11:10 +00:00
|
|
|
|
uint32_t s0 = 0;
|
|
|
|
|
uint32_t s1 = 0;
|
|
|
|
|
unichar chunk[64];
|
|
|
|
|
uint32_t ret;
|
2011-10-14 07:07:39 +00:00
|
|
|
|
unichar n = 0;
|
|
|
|
|
unsigned i = 0;
|
2013-03-12 16:11:10 +00:00
|
|
|
|
int l = 0;
|
|
|
|
|
uint32_t t = 0;
|
2011-10-14 07:07:39 +00:00
|
|
|
|
|
|
|
|
|
while (i < nxcslen)
|
|
|
|
|
{
|
2013-03-12 16:11:10 +00:00
|
|
|
|
chunk[l++] = nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
|
|
|
|
if (64 == l)
|
|
|
|
|
{
|
|
|
|
|
GSPrivateIncrementalHash(&s0, &s1, chunk, l * sizeof(unichar));
|
|
|
|
|
t += l;
|
|
|
|
|
l = 0;
|
|
|
|
|
}
|
2011-10-14 07:07:39 +00:00
|
|
|
|
}
|
|
|
|
|
if (0 != n)
|
|
|
|
|
{
|
2013-03-12 16:11:10 +00:00
|
|
|
|
chunk[l++] = n; // Add final character
|
2011-10-14 07:07:39 +00:00
|
|
|
|
}
|
2013-03-12 16:11:10 +00:00
|
|
|
|
if (l > 0)
|
|
|
|
|
{
|
|
|
|
|
GSPrivateIncrementalHash(&s0, &s1, chunk, l * sizeof(unichar));
|
|
|
|
|
t += l;
|
|
|
|
|
}
|
|
|
|
|
ret = GSPrivateFinishHash(s0, s1, t * sizeof(unichar));
|
2011-10-14 07:07:39 +00:00
|
|
|
|
ret &= 0x0fffffff;
|
|
|
|
|
if (ret == 0)
|
|
|
|
|
{
|
|
|
|
|
ret = 0x0fffffff;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0x0ffffffe; /* Hash for an empty string. */
|
|
|
|
|
}
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif
|
2011-10-14 07:07:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-05-20 14:52:38 +00:00
|
|
|
|
- (id) initWithBytes: (const void*)bytes
|
2009-02-23 20:42:32 +00:00
|
|
|
|
length: (NSUInteger)length
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSGenericException
|
2002-05-29 16:32:27 +00:00
|
|
|
|
format: @"Attempt to init a constant string"];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
- (id) initWithBytesNoCopy: (void*)bytes
|
2009-02-23 20:42:32 +00:00
|
|
|
|
length: (NSUInteger)length
|
2006-05-14 18:01:13 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
freeWhenDone: (BOOL)flag
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSGenericException
|
2002-05-29 16:32:27 +00:00
|
|
|
|
format: @"Attempt to init a constant string"];
|
2000-10-09 05:32:50 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifdef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
- (NSUInteger) length
|
|
|
|
|
{
|
|
|
|
|
// In the new encoding, nxcslen is always the length of the string in UTF-16
|
|
|
|
|
// codepoints
|
|
|
|
|
return nxcslen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
2011-10-31 08:12:26 +00:00
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
return literalIsEqual(self, anObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isEqualToString: (NSString*)other
|
|
|
|
|
{
|
|
|
|
|
return literalIsEqual(self, other);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
- (int) intValue
|
|
|
|
|
{
|
|
|
|
|
return strtol((const char*)nxcsptr, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSInteger) integerValue
|
|
|
|
|
{
|
|
|
|
|
#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG
|
|
|
|
|
return strtol((const char*)nxcsptr, 0, 10);
|
|
|
|
|
#else
|
|
|
|
|
return strtoll((const char*)nxcsptr, 0, 10);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 14:28:44 +00:00
|
|
|
|
- (NSUInteger) length
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2011-10-14 13:45:52 +00:00
|
|
|
|
return lengthUTF8((const uint8_t*)nxcsptr, nxcslen, 0, 0);
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-05 11:54:14 +00:00
|
|
|
|
- (long long) longLongValue
|
|
|
|
|
{
|
|
|
|
|
return strtoll((const char*)nxcsptr, 0, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-12 14:28:44 +00:00
|
|
|
|
- (NSRange) rangeOfCharacterFromSet: (NSCharacterSet*)aSet
|
|
|
|
|
options: (NSUInteger)mask
|
|
|
|
|
range: (NSRange)aRange
|
2000-10-09 05:32:50 +00:00
|
|
|
|
{
|
2011-10-12 14:28:44 +00:00
|
|
|
|
NSUInteger index;
|
|
|
|
|
NSUInteger start;
|
|
|
|
|
NSUInteger stop;
|
|
|
|
|
NSRange range;
|
|
|
|
|
BOOL ascii;
|
|
|
|
|
|
2011-10-14 13:45:52 +00:00
|
|
|
|
index = lengthUTF8((const uint8_t*)nxcsptr, nxcslen, &ascii, 0);
|
2011-10-12 14:28:44 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, index);
|
|
|
|
|
|
|
|
|
|
start = aRange.location;
|
|
|
|
|
stop = NSMaxRange(aRange);
|
|
|
|
|
|
|
|
|
|
range.location = NSNotFound;
|
|
|
|
|
range.length = 0;
|
|
|
|
|
|
2012-01-30 11:31:40 +00:00
|
|
|
|
if (stop > start)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2012-01-30 11:31:40 +00:00
|
|
|
|
BOOL (*mImp)(id, SEL, unichar);
|
|
|
|
|
unichar n = 0;
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
|
|
|
|
|
mImp = (BOOL(*)(id,SEL,unichar))
|
|
|
|
|
[aSet methodForSelector: @selector(characterIsMember:)];
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < start; index++)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2012-01-30 11:31:40 +00:00
|
|
|
|
nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
2012-01-30 11:31:40 +00:00
|
|
|
|
if ((mask & NSBackwardsSearch) == NSBackwardsSearch)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2012-01-30 11:31:40 +00:00
|
|
|
|
unichar buf[stop - start];
|
|
|
|
|
NSUInteger pos = 0;
|
|
|
|
|
|
|
|
|
|
for (pos = 0; pos + start < stop; pos++)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2012-01-30 11:31:40 +00:00
|
|
|
|
buf[pos] = nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
|
|
|
|
}
|
|
|
|
|
index = stop;
|
2013-02-28 12:51:27 +00:00
|
|
|
|
while (index-- > start)
|
2012-01-30 11:31:40 +00:00
|
|
|
|
{
|
|
|
|
|
if ((*mImp)(aSet, @selector(characterIsMember:), buf[--pos]))
|
|
|
|
|
{
|
|
|
|
|
range = NSMakeRange(index, 1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-01-30 11:31:40 +00:00
|
|
|
|
else
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2012-01-30 11:31:40 +00:00
|
|
|
|
while (index < stop)
|
2011-10-12 14:28:44 +00:00
|
|
|
|
{
|
2012-01-30 11:31:40 +00:00
|
|
|
|
unichar letter;
|
|
|
|
|
|
|
|
|
|
letter = nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
|
|
|
|
if ((*mImp)(aSet, @selector(characterIsMember:), letter))
|
|
|
|
|
{
|
|
|
|
|
range = NSMakeRange(index, 1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
index++;
|
2011-10-12 14:28:44 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return range;
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-31 08:12:26 +00:00
|
|
|
|
- (NSRange) rangeOfComposedCharacterSequenceAtIndex: (NSUInteger)anIndex
|
|
|
|
|
{
|
|
|
|
|
NSUInteger start = 0;
|
|
|
|
|
NSUInteger pos = 0;
|
|
|
|
|
unichar n = 0;
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
unichar u;
|
|
|
|
|
|
|
|
|
|
/* A composed character sequence consists of a single base character
|
|
|
|
|
* followed by zero or more non-base characters.
|
|
|
|
|
*/
|
|
|
|
|
while (i < nxcslen || n > 0)
|
|
|
|
|
{
|
|
|
|
|
u = nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
|
|
|
|
if (!uni_isnonsp(u))
|
|
|
|
|
{
|
|
|
|
|
/* This may be the base character at the start of the sequence.
|
|
|
|
|
*/
|
|
|
|
|
start = pos;
|
|
|
|
|
}
|
|
|
|
|
if (pos++ == anIndex)
|
|
|
|
|
{
|
|
|
|
|
/* Look ahead to see if the character at the specified index is
|
|
|
|
|
* followed by one or more non-base characters. If it is, we
|
|
|
|
|
* make the range longer before returning it.
|
|
|
|
|
*/
|
|
|
|
|
while (i < nxcslen || n > 0)
|
|
|
|
|
{
|
|
|
|
|
u = nextUTF8((const uint8_t *)nxcsptr, nxcslen, &i, &n);
|
|
|
|
|
if (!uni_isnonsp(u))
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
pos++;
|
|
|
|
|
}
|
|
|
|
|
return NSMakeRange(start, pos - start);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-rangeOfComposedCharacterSequenceAtIndex: index out of range"];
|
|
|
|
|
return NSMakeRange(NSNotFound, 0);
|
|
|
|
|
}
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif // GNUSTEP_NEW_STRING_ABI
|
2011-10-31 08:12:26 +00:00
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (oneway void) release
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) autorelease
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSZone*) zone
|
|
|
|
|
{
|
|
|
|
|
return NSDefaultMallocZone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSStringEncoding) fastestEncoding
|
|
|
|
|
{
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifdef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
switch (CONSTANT_STRING_ENCODING())
|
|
|
|
|
{
|
|
|
|
|
case 0: // ASCII
|
|
|
|
|
return NSASCIIStringEncoding;
|
|
|
|
|
case 1: // UTF-8
|
|
|
|
|
return NSUTF8StringEncoding;
|
|
|
|
|
case 2: // UTF-16
|
|
|
|
|
return NSUTF16StringEncoding;
|
|
|
|
|
case 3: // UTF-32
|
|
|
|
|
return NSUTF32StringEncoding;
|
|
|
|
|
}
|
|
|
|
|
GS_UNREACHABLE();
|
|
|
|
|
#else
|
2011-10-12 14:28:44 +00:00
|
|
|
|
return NSUTF8StringEncoding;
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSStringEncoding) smallestEncoding
|
|
|
|
|
{
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#ifdef GNUSTEP_NEW_STRING_ABI
|
|
|
|
|
// UTF-16 might not be the smallest encoding for UTF-16 strings, but for now
|
|
|
|
|
// we'll pretend that it is.
|
|
|
|
|
switch (CONSTANT_STRING_ENCODING())
|
|
|
|
|
{
|
|
|
|
|
case 0: // ASCII
|
|
|
|
|
return NSASCIIStringEncoding;
|
|
|
|
|
case 1: // UTF-8
|
|
|
|
|
return NSUTF8StringEncoding;
|
|
|
|
|
case 2: // UTF-16
|
|
|
|
|
case 3: // UTF-32
|
|
|
|
|
return NSUTF16StringEncoding;
|
|
|
|
|
}
|
|
|
|
|
GS_UNREACHABLE();
|
|
|
|
|
#else
|
2011-10-12 14:28:44 +00:00
|
|
|
|
return NSUTF8StringEncoding;
|
2018-12-27 13:42:12 +00:00
|
|
|
|
#endif
|
2000-10-09 05:32:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-08 16:20:25 +00:00
|
|
|
|
- (NSUInteger) sizeOfContentExcluding: (NSHashTable*)exclude
|
|
|
|
|
{
|
|
|
|
|
return 0; // Constant string uses no heap
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSUInteger) sizeOfInstance
|
|
|
|
|
{
|
|
|
|
|
return 0; // Constant string uses no heap
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 05:32:50 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
/**
|
|
|
|
|
* Append characters to a string.
|
|
|
|
|
*/
|
2006-10-20 12:57:59 +00:00
|
|
|
|
void
|
|
|
|
|
GSPrivateStrAppendUnichars(GSStr s, const unichar *u, unsigned l)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Make the string wide if necessary.
|
|
|
|
|
*/
|
|
|
|
|
if (s->_flags.wide == 0)
|
|
|
|
|
{
|
|
|
|
|
BOOL widen = NO;
|
|
|
|
|
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (internalEncoding == NSISOLatin1StringEncoding)
|
2004-05-14 10:52:30 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < l; i++)
|
|
|
|
|
{
|
|
|
|
|
if (u[i] > 255)
|
|
|
|
|
{
|
|
|
|
|
widen = YES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < l; i++)
|
|
|
|
|
{
|
|
|
|
|
if (u[i] > 127)
|
|
|
|
|
{
|
|
|
|
|
widen = YES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (widen == YES)
|
|
|
|
|
{
|
|
|
|
|
GSStrWiden(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make room for the characters we are appending.
|
|
|
|
|
*/
|
|
|
|
|
if (s->_count + l + 1 >= s->_capacity)
|
|
|
|
|
{
|
|
|
|
|
GSStrMakeSpace(s, l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copy the characters into place.
|
|
|
|
|
*/
|
|
|
|
|
if (s->_flags.wide == 1)
|
|
|
|
|
{
|
2015-09-04 09:48:07 +00:00
|
|
|
|
memcpy(s->_contents.u + s->_count, u, l * sizeof(unichar));
|
|
|
|
|
s->_count += l;
|
2004-05-14 10:52:30 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < l; i++)
|
|
|
|
|
{
|
|
|
|
|
s->_contents.c[s->_count++] = u[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-10-20 12:57:59 +00:00
|
|
|
|
void
|
|
|
|
|
GSPrivateStrExternalize(GSStr s)
|
2004-06-05 09:34:41 +00:00
|
|
|
|
{
|
2006-05-14 18:01:13 +00:00
|
|
|
|
if (s->_flags.wide == 0 && internalEncoding != externalEncoding)
|
2004-06-05 09:34:41 +00:00
|
|
|
|
{
|
|
|
|
|
GSStrWiden(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|