mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
iProperty list and encoding fixes
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@7888 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
38b8d11f24
commit
9cf69df9a9
6 changed files with 920 additions and 937 deletions
|
@ -4,11 +4,13 @@
|
|||
implemented to return NSUnicodeStringEncoding. Use new string
|
||||
classes more effectively - let GSString turn itsself into either
|
||||
GSCString or GSUstring when initialised.
|
||||
Merged in code from propList.h
|
||||
* Source/GSString.m: ([-dataUsingEncoding:allowLossyConversion:])
|
||||
bugfixes for cString reported by Freed Kiefer
|
||||
Removed 'ascii' flag - more trouble than a minor optimisation is
|
||||
worth.
|
||||
Fixed transmute() to be careful about freeing old string.
|
||||
* Source/Unicode.m: encode_ustrtostr_strict() return 0 on failure.
|
||||
|
||||
2000-10-21 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
|
|
|
@ -389,7 +389,12 @@ cString_u(ivars self)
|
|||
|
||||
if (self->_count > 0)
|
||||
{
|
||||
encode_ustrtostr_strict(r, self->_contents.u, self->_count, defEnc);
|
||||
if (encode_ustrtostr_strict(r, self->_contents.u, self->_count, defEnc)
|
||||
== 0)
|
||||
{
|
||||
[NSException raise: NSCharacterConversionException
|
||||
format: @"Can't get cString from Unicode string."];
|
||||
}
|
||||
}
|
||||
r[self->_count] = '\0';
|
||||
|
||||
|
@ -412,7 +417,12 @@ cStringLength_u(ivars self)
|
|||
char *r;
|
||||
|
||||
r = (char*)NSZoneMalloc(NSDefaultMallocZone(), self->_count+1);
|
||||
encode_ustrtostr(r, self->_contents.u, self->_count, defEnc);
|
||||
if (encode_ustrtostr(r, self->_contents.u, self->_count, defEnc) == 0)
|
||||
{
|
||||
NSZoneFree(NSDefaultMallocZone(), r);
|
||||
[NSException raise: NSCharacterConversionException
|
||||
format: @"Can't get cStringLength from Unicode string."];
|
||||
}
|
||||
r[self->_count] = '\0';
|
||||
c = strlen(r);
|
||||
NSZoneFree(NSDefaultMallocZone(), r);
|
||||
|
@ -452,10 +462,12 @@ dataUsingEncoding_c(ivars self, NSStringEncoding encoding, BOOL flag)
|
|||
int t;
|
||||
unichar *buff;
|
||||
|
||||
buff = (unichar*)NSZoneMalloc(NSDefaultMallocZone(), 2*len+2);
|
||||
buff = (unichar*)NSZoneMalloc(NSDefaultMallocZone(),
|
||||
sizeof(unichar)*(len+1));
|
||||
buff[0] = 0xFEFF;
|
||||
t = encode_strtoustr(buff+1, self->_contents.c, len, defEnc);
|
||||
return [NSDataClass dataWithBytesNoCopy: buff length: t+2];
|
||||
return [NSDataClass dataWithBytesNoCopy: buff
|
||||
length: sizeof(unichar)*(t+1)];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -463,16 +475,16 @@ dataUsingEncoding_c(ivars self, NSStringEncoding encoding, BOOL flag)
|
|||
unichar *ubuff;
|
||||
unsigned char *buff;
|
||||
|
||||
ubuff = (unichar*)NSZoneMalloc(NSDefaultMallocZone(), 2*len);
|
||||
ubuff = (unichar*)NSZoneMalloc(NSDefaultMallocZone(),
|
||||
sizeof(unichar)*len);
|
||||
t = encode_strtoustr(ubuff, self->_contents.c, len, defEnc);
|
||||
buff = (unsigned char*)NSZoneMalloc(NSDefaultMallocZone(), t+1);
|
||||
buff = (unsigned char*)NSZoneMalloc(NSDefaultMallocZone(), t);
|
||||
if (flag)
|
||||
t = encode_ustrtostr(buff, ubuff, t, encoding);
|
||||
else
|
||||
t = encode_ustrtostr_strict(buff, ubuff, t, encoding);
|
||||
buff[t] = '\0';
|
||||
NSZoneFree(NSDefaultMallocZone(), ubuff);
|
||||
if (t != len)
|
||||
if (t == 0)
|
||||
{
|
||||
NSZoneFree(NSDefaultMallocZone(), buff);
|
||||
return nil;
|
||||
|
@ -495,22 +507,23 @@ dataUsingEncoding_u(ivars self, NSStringEncoding encoding, BOOL flag)
|
|||
{
|
||||
unichar *buff;
|
||||
|
||||
buff = (unichar*)NSZoneMalloc(NSDefaultMallocZone(), 2*len+2);
|
||||
buff = (unichar*)NSZoneMalloc(NSDefaultMallocZone(),
|
||||
sizeof(unichar)*(len+1));
|
||||
buff[0] = 0xFEFF;
|
||||
memcpy(buff+1, self->_contents.u, 2*len);
|
||||
return [NSData dataWithBytesNoCopy: buff length: 2*len+2];
|
||||
memcpy(buff+1, self->_contents.u, sizeof(unichar)*len);
|
||||
return [NSData dataWithBytesNoCopy: buff
|
||||
length: sizeof(unichar)*(len+1)];
|
||||
}
|
||||
else
|
||||
{
|
||||
int t;
|
||||
unsigned char *buff;
|
||||
|
||||
buff = (unsigned char*)NSZoneMalloc(NSDefaultMallocZone(), len+1);
|
||||
buff = (unsigned char*)NSZoneMalloc(NSDefaultMallocZone(), len);
|
||||
if (flag == YES)
|
||||
t = encode_ustrtostr(buff, self->_contents.u, len, encoding);
|
||||
else
|
||||
t = encode_ustrtostr_strict(buff, self->_contents.u, len, encoding);
|
||||
buff[t] = '\0';
|
||||
if (!t)
|
||||
{
|
||||
NSZoneFree(NSDefaultMallocZone(), buff);
|
||||
|
|
|
@ -231,12 +231,11 @@ $(GNUSTEP_OBJ_DIR)/NSSerializer.o \
|
|||
#
|
||||
# Files that include fast.x will need a rebuild if it is changed.
|
||||
#
|
||||
$(GNUSTEP_OBJ_DIR)/GSString.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSArchiver.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSArray.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSData.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSGCString.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSGDictionary.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSGString.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSInvocation.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSObjCRuntime.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSObject.o \
|
||||
|
@ -245,20 +244,11 @@ $(GNUSTEP_OBJ_DIR)/NSString.o \
|
|||
$(GNUSTEP_OBJ_DIR)/NSUnarchiver.o \
|
||||
: $(HEADER_DIR)/fast.x
|
||||
|
||||
#
|
||||
# Files that include propList.h will need a rebuild if it is changed.
|
||||
#
|
||||
$(GNUSTEP_OBJ_DIR)/NSString.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSGString.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSGCString.o \
|
||||
: propList.h
|
||||
|
||||
#
|
||||
# Files that include GSeq.h will need a rebuild if it is changed.
|
||||
#
|
||||
$(GNUSTEP_OBJ_DIR)/NSString.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSGString.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSGCString.o \
|
||||
$(GNUSTEP_OBJ_DIR)/GSString.o \
|
||||
: GSeq.h
|
||||
|
||||
#
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -339,13 +339,14 @@ iconv_strtoustr(unichar *u2, int size2, const char *s1, int size1, NSStringEncod
|
|||
}
|
||||
|
||||
int
|
||||
iconv_ustrtostr(char *s2, int size2, unichar *u1, int size1, NSStringEncoding enc)
|
||||
iconv_ustrtostr(char *s2, int size2, unichar *u1, int size1,
|
||||
NSStringEncoding enc)
|
||||
{
|
||||
iconv_t conv;
|
||||
int usize = sizeof(unichar)*size1;
|
||||
char *s1 = s2;
|
||||
const char *u2 = (const char*)u1;
|
||||
int ret_val;
|
||||
iconv_t conv;
|
||||
int usize = sizeof(unichar)*size1;
|
||||
char *s1 = s2;
|
||||
const char *u2 = (const char*)u1;
|
||||
int ret_val;
|
||||
|
||||
conv = iconv_open(iconv_stringforencoding(enc), UNICODE_ENC);
|
||||
if (conv == (iconv_t)-1)
|
||||
|
@ -867,7 +868,7 @@ encode_ustrtostr_strict(char *s2, unichar *u1, int size, NSStringEncoding enc)
|
|||
if (u < 128)
|
||||
s2[count] = (char)u;
|
||||
else
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
|
||||
|
@ -878,7 +879,7 @@ encode_ustrtostr_strict(char *s2, unichar *u1, int size, NSStringEncoding enc)
|
|||
if (u < 128)
|
||||
s2[count] = (char)u;
|
||||
else
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
|
||||
|
@ -890,7 +891,7 @@ encode_ustrtostr_strict(char *s2, unichar *u1, int size, NSStringEncoding enc)
|
|||
if (u < 256)
|
||||
s2[count] = (char)u;
|
||||
else
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
|
||||
|
@ -906,11 +907,11 @@ encode_ustrtostr_strict(char *s2, unichar *u1, int size, NSStringEncoding enc)
|
|||
int i = 0;
|
||||
|
||||
while (((res = u - Next_uni_to_char_table[i++].from) > 0)
|
||||
&& (i < Next_uni_to_char_table_size));
|
||||
&& (i < Next_uni_to_char_table_size));
|
||||
if (!res)
|
||||
s2[count] = Next_uni_to_char_table[--i].to;
|
||||
else
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
@ -927,11 +928,11 @@ encode_ustrtostr_strict(char *s2, unichar *u1, int size, NSStringEncoding enc)
|
|||
int i = 0;
|
||||
|
||||
while (((res = u - Cyrillic_uni_to_char_table[i++].from) > 0)
|
||||
&& (i < Cyrillic_uni_to_char_table_size));
|
||||
&& (i < Cyrillic_uni_to_char_table_size));
|
||||
if (!res)
|
||||
s2[count] = Cyrillic_uni_to_char_table[--i].to;
|
||||
else
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
@ -948,11 +949,11 @@ encode_ustrtostr_strict(char *s2, unichar *u1, int size, NSStringEncoding enc)
|
|||
int i = 0;
|
||||
|
||||
while (((res = u - Latin2_uni_to_char_table[i++].from) > 0)
|
||||
&& (i < Latin2_uni_to_char_table_size));
|
||||
&& (i < Latin2_uni_to_char_table_size));
|
||||
if (!res)
|
||||
s2[count] = Latin2_uni_to_char_table[--i].to;
|
||||
else
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
@ -970,11 +971,11 @@ encode_ustrtostr_strict(char *s2, unichar *u1, int size, NSStringEncoding enc)
|
|||
int i = 0;
|
||||
|
||||
while (((res = u - Symbol_uni_to_char_table[i++].from) > 0)
|
||||
&& (i < Symbol_uni_to_char_table_size));
|
||||
&& (i < Symbol_uni_to_char_table_size));
|
||||
if (!res)
|
||||
s2[count] = Symbol_uni_to_char_table[--i].to;
|
||||
else
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
|
|
@ -1,828 +0,0 @@
|
|||
/* Text Property-List parsing code for NSString.m and NSGCString.m
|
||||
Copyright (C) 1998,2000 Free Software Foundation, Inc.
|
||||
|
||||
Written by Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
Date: October 1998
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#if HAVE_LIBXML
|
||||
#include <Foundation/GSXML.h>
|
||||
|
||||
static void
|
||||
decodeBase64Unit(const char* ptr, unsigned char *out)
|
||||
{
|
||||
out[0] = (ptr[0] << 2) | ((ptr[1] & 0x30) >> 4);
|
||||
out[1] = ((ptr[1] & 0x0F) << 4) | ((ptr[2] & 0x3C) >> 2);
|
||||
out[2] = ((ptr[2] & 0x03) << 6) | (ptr[3] & 0x3F);
|
||||
out[3] = 0;
|
||||
}
|
||||
|
||||
static NSData*
|
||||
decodeBase64(const char *source)
|
||||
{
|
||||
int length = strlen(source);
|
||||
char *sourceBuffer = objc_malloc(length+1);
|
||||
NSMutableData *data = [NSMutableData dataWithCapacity:0];
|
||||
int i, j;
|
||||
unsigned char tmp[4];
|
||||
|
||||
strcpy(sourceBuffer, source);
|
||||
j = 0;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
if (!isspace(source[i]))
|
||||
{
|
||||
sourceBuffer[j++] = source[i];
|
||||
}
|
||||
}
|
||||
|
||||
sourceBuffer[j] = '\0';
|
||||
length = strlen(sourceBuffer);
|
||||
while (length > 0 && sourceBuffer[length-1] == '=')
|
||||
{
|
||||
sourceBuffer[--length] = '\0';
|
||||
}
|
||||
for (i = 0; i < length; i += 4)
|
||||
{
|
||||
decodeBase64Unit(&sourceBuffer[i], tmp);
|
||||
[data appendBytes: tmp length: strlen(tmp)];
|
||||
}
|
||||
|
||||
objc_free(sourceBuffer);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Cache some commonly used character sets along with methods to
|
||||
* check membership.
|
||||
*/
|
||||
|
||||
static SEL cMemberSel = @selector(characterIsMember:);
|
||||
|
||||
static NSCharacterSet *hexdigits = nil;
|
||||
static BOOL (*hexdigitsImp)(id, SEL, unichar) = 0;
|
||||
static void setupHexdigits()
|
||||
{
|
||||
if (hexdigits == nil)
|
||||
{
|
||||
hexdigits = [NSCharacterSet characterSetWithCharactersInString:
|
||||
@"0123456789abcdefABCDEF"];
|
||||
IF_NO_GC(RETAIN(hexdigits));
|
||||
hexdigitsImp =
|
||||
(BOOL(*)(id,SEL,unichar)) [hexdigits methodForSelector: cMemberSel];
|
||||
}
|
||||
}
|
||||
|
||||
static NSCharacterSet *quotables = nil;
|
||||
static BOOL (*quotablesImp)(id, SEL, unichar) = 0;
|
||||
static void setupQuotables()
|
||||
{
|
||||
if (quotables == nil)
|
||||
{
|
||||
NSMutableCharacterSet *s;
|
||||
|
||||
s = [[NSCharacterSet characterSetWithCharactersInString:
|
||||
@"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$./_"]
|
||||
mutableCopy];
|
||||
[s invert];
|
||||
quotables = [s copy];
|
||||
RELEASE(s);
|
||||
quotablesImp =
|
||||
(BOOL(*)(id,SEL,unichar)) [quotables methodForSelector: cMemberSel];
|
||||
}
|
||||
}
|
||||
|
||||
static NSCharacterSet *whitespce = nil;
|
||||
static BOOL (*whitespceImp)(id, SEL, unichar) = 0;
|
||||
static void setupWhitespce()
|
||||
{
|
||||
if (whitespce == nil)
|
||||
{
|
||||
whitespce = [NSCharacterSet characterSetWithCharactersInString:
|
||||
@" \t\r\n\f\b"];
|
||||
IF_NO_GC(RETAIN(whitespce));
|
||||
whitespceImp =
|
||||
(BOOL(*)(id,SEL,unichar)) [whitespce methodForSelector: cMemberSel];
|
||||
}
|
||||
}
|
||||
|
||||
@class NSGMutableArray;
|
||||
@class NSGMutableDictionary;
|
||||
|
||||
static Class plCls;
|
||||
static Class plArray;
|
||||
static id (*plAdd)(id, SEL, id);
|
||||
static Class plDictionary;
|
||||
static id (*plSet)(id, SEL, id, id);
|
||||
static id (*plInit)(id, SEL, void*, unsigned) = 0;
|
||||
static id (*plAlloc)(Class, SEL, NSZone*);
|
||||
#if GSPLUNI
|
||||
static SEL plSel = @selector(initWithCharacters:length:);
|
||||
#else
|
||||
static SEL plSel = @selector(initWithCString:length:);
|
||||
#endif
|
||||
|
||||
static void setupPl(Class c)
|
||||
{
|
||||
if (plInit == 0)
|
||||
{
|
||||
plCls = c;
|
||||
plAlloc = (id (*)(id, SEL, NSZone*))
|
||||
[c methodForSelector: @selector(allocWithZone:)];
|
||||
plInit = (id (*)(id, SEL, void*, unsigned))
|
||||
[c instanceMethodForSelector: plSel];
|
||||
plArray = [NSGMutableArray class];
|
||||
plAdd = (id (*)(id, SEL, id))
|
||||
[plArray instanceMethodForSelector: @selector(addObject:)];
|
||||
plDictionary = [NSGMutableDictionary class];
|
||||
plSet = (id (*)(id, SEL, id, id))
|
||||
[plDictionary instanceMethodForSelector: @selector(setObject:forKey:)];
|
||||
}
|
||||
setupHexdigits();
|
||||
setupQuotables();
|
||||
setupWhitespce();
|
||||
}
|
||||
|
||||
|
||||
#define inrange(ch,min,max) ((ch)>=(min) && (ch)<=(max))
|
||||
#define char2num(ch) \
|
||||
inrange(ch,'0','9') \
|
||||
? ((ch)-0x30) \
|
||||
: (inrange(ch,'a','f') \
|
||||
? ((ch)-0x57) : ((ch)-0x37))
|
||||
|
||||
typedef struct {
|
||||
#if GSPLUNI
|
||||
const unichar *ptr;
|
||||
#else
|
||||
const char *ptr;
|
||||
#endif
|
||||
unsigned end;
|
||||
unsigned pos;
|
||||
unsigned lin;
|
||||
NSString *err;
|
||||
} pldata;
|
||||
|
||||
/*
|
||||
* Property list parsing - skip whitespace keeping count of lines and
|
||||
* regarding objective-c style comments as whitespace.
|
||||
* Returns YES if there is any non-whitespace text remaining.
|
||||
*/
|
||||
static BOOL skipSpace(pldata *pld)
|
||||
{
|
||||
unichar c;
|
||||
|
||||
while (pld->pos < pld->end)
|
||||
{
|
||||
c = (unichar)pld->ptr[pld->pos];
|
||||
|
||||
if ((*whitespceImp)(whitespce, cMemberSel, c) == NO)
|
||||
{
|
||||
if (c == '/' && pld->pos < pld->end - 1)
|
||||
{
|
||||
/*
|
||||
* Check for comments beginning '/' followed by '/' or '*'
|
||||
*/
|
||||
if (pld->ptr[pld->pos + 1] == '/')
|
||||
{
|
||||
pld->pos += 2;
|
||||
while (pld->pos < pld->end)
|
||||
{
|
||||
c = pld->ptr[pld->pos];
|
||||
if (c == '\n')
|
||||
break;
|
||||
pld->pos++;
|
||||
}
|
||||
if (pld->pos >= pld->end)
|
||||
{
|
||||
pld->err = @"reached end of string in comment";
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
else if (pld->ptr[pld->pos + 1] == '*')
|
||||
{
|
||||
pld->pos += 2;
|
||||
while (pld->pos < pld->end)
|
||||
{
|
||||
c = pld->ptr[pld->pos];
|
||||
if (c == '\n')
|
||||
pld->lin++;
|
||||
else if (c == '*' && pld->pos < pld->end - 1
|
||||
&& pld->ptr[pld->pos+1] == '/')
|
||||
{
|
||||
pld->pos++; /* Skip past '*' */
|
||||
break;
|
||||
}
|
||||
pld->pos++;
|
||||
}
|
||||
if (pld->pos >= pld->end)
|
||||
{
|
||||
pld->err = @"reached end of string in comment";
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
else
|
||||
return YES;
|
||||
}
|
||||
else
|
||||
return YES;
|
||||
}
|
||||
if (c == '\n')
|
||||
pld->lin++;
|
||||
pld->pos++;
|
||||
}
|
||||
pld->err = @"reached end of string";
|
||||
return NO;
|
||||
}
|
||||
|
||||
static inline id parseQuotedString(pldata* pld)
|
||||
{
|
||||
unsigned start = ++pld->pos;
|
||||
unsigned escaped = 0;
|
||||
unsigned shrink = 0;
|
||||
BOOL hex = NO;
|
||||
NSString *obj;
|
||||
|
||||
while (pld->pos < pld->end)
|
||||
{
|
||||
unichar c = (unichar)pld->ptr[pld->pos];
|
||||
|
||||
if (escaped)
|
||||
{
|
||||
if (escaped == 1 && c == '0')
|
||||
{
|
||||
escaped = 2;
|
||||
hex = NO;
|
||||
}
|
||||
else if (escaped > 1)
|
||||
{
|
||||
if (escaped == 2 && c == 'x')
|
||||
{
|
||||
hex = YES;
|
||||
shrink++;
|
||||
escaped++;
|
||||
}
|
||||
else if (hex && (*hexdigitsImp)(hexdigits, cMemberSel, c))
|
||||
{
|
||||
shrink++;
|
||||
escaped++;
|
||||
}
|
||||
else if (c >= '0' && c <= '7')
|
||||
{
|
||||
shrink++;
|
||||
escaped++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pld->pos--;
|
||||
escaped = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
escaped = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == '\\')
|
||||
{
|
||||
escaped = 1;
|
||||
shrink++;
|
||||
}
|
||||
else if (c == '"')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == '\n')
|
||||
pld->lin++;
|
||||
pld->pos++;
|
||||
}
|
||||
if (pld->pos >= pld->end)
|
||||
{
|
||||
pld->err = @"reached end of string while parsing quoted string";
|
||||
return nil;
|
||||
}
|
||||
if (pld->pos - start - shrink == 0)
|
||||
{
|
||||
obj = @"";
|
||||
}
|
||||
else
|
||||
{
|
||||
#if GSPLUNI
|
||||
unichar chars[pld->pos - start - shrink];
|
||||
#else
|
||||
char chars[pld->pos - start - shrink];
|
||||
#endif
|
||||
unsigned j;
|
||||
unsigned k;
|
||||
|
||||
escaped = 0;
|
||||
hex = NO;
|
||||
for (j = start, k = 0; j < pld->pos; j++)
|
||||
{
|
||||
unichar c = (unichar)pld->ptr[j];
|
||||
|
||||
if (escaped)
|
||||
{
|
||||
if (escaped == 1 && c == '0')
|
||||
{
|
||||
chars[k] = 0;
|
||||
hex = NO;
|
||||
escaped++;
|
||||
}
|
||||
else if (escaped > 1)
|
||||
{
|
||||
if (escaped == 2 && c == 'x')
|
||||
{
|
||||
hex = YES;
|
||||
escaped++;
|
||||
}
|
||||
else if (hex && (*hexdigitsImp)(hexdigits, cMemberSel, c))
|
||||
{
|
||||
chars[k] <<= 4;
|
||||
chars[k] |= char2num(c);
|
||||
escaped++;
|
||||
}
|
||||
else if (c >= '0' && c <= '7')
|
||||
{
|
||||
chars[k] <<= 3;
|
||||
chars[k] |= (c - '0');
|
||||
escaped++;
|
||||
}
|
||||
else
|
||||
{
|
||||
escaped = 0;
|
||||
j--;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
escaped = 0;
|
||||
switch (c)
|
||||
{
|
||||
case 'a' : chars[k] = '\a'; break;
|
||||
case 'b' : chars[k] = '\b'; break;
|
||||
case 't' : chars[k] = '\t'; break;
|
||||
case 'r' : chars[k] = '\r'; break;
|
||||
case 'n' : chars[k] = '\n'; break;
|
||||
case 'v' : chars[k] = '\v'; break;
|
||||
case 'f' : chars[k] = '\f'; break;
|
||||
default : chars[k] = c; break;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
chars[k] = c;
|
||||
if (c == '\\')
|
||||
{
|
||||
escaped = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
obj = (*plAlloc)(plCls, @selector(allocWithZone:), NSDefaultMallocZone());
|
||||
obj = (*plInit)(obj, plSel, (void*)chars, pld->pos - start - shrink);
|
||||
}
|
||||
pld->pos++;
|
||||
return obj;
|
||||
}
|
||||
|
||||
static inline id parseUnquotedString(pldata *pld)
|
||||
{
|
||||
unsigned start = pld->pos;
|
||||
id obj;
|
||||
|
||||
while (pld->pos < pld->end)
|
||||
{
|
||||
if ((*quotablesImp)(quotables, cMemberSel,
|
||||
(unichar)pld->ptr[pld->pos]) == YES)
|
||||
break;
|
||||
pld->pos++;
|
||||
}
|
||||
obj = (*plAlloc)(plCls, @selector(allocWithZone:), NSDefaultMallocZone());
|
||||
obj = (*plInit)(obj, plSel, (void*)&pld->ptr[start], pld->pos-start);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static id parsePlItem(pldata* pld)
|
||||
{
|
||||
if (skipSpace(pld) == NO)
|
||||
return nil;
|
||||
|
||||
switch (pld->ptr[pld->pos])
|
||||
{
|
||||
case '{':
|
||||
{
|
||||
NSMutableDictionary *dict;
|
||||
|
||||
dict = [[plDictionary allocWithZone: NSDefaultMallocZone()]
|
||||
initWithCapacity: 0];
|
||||
pld->pos++;
|
||||
while (skipSpace(pld) == YES && pld->ptr[pld->pos] != '}')
|
||||
{
|
||||
id key;
|
||||
id val;
|
||||
|
||||
key = parsePlItem(pld);
|
||||
if (key == nil)
|
||||
return nil;
|
||||
if (skipSpace(pld) == NO)
|
||||
{
|
||||
RELEASE(key);
|
||||
return nil;
|
||||
}
|
||||
if (pld->ptr[pld->pos] != '=')
|
||||
{
|
||||
pld->err = @"unexpected character (wanted '=')";
|
||||
RELEASE(key);
|
||||
return nil;
|
||||
}
|
||||
pld->pos++;
|
||||
val = parsePlItem(pld);
|
||||
if (val == nil)
|
||||
{
|
||||
RELEASE(key);
|
||||
return nil;
|
||||
}
|
||||
if (skipSpace(pld) == NO)
|
||||
{
|
||||
RELEASE(key);
|
||||
RELEASE(val);
|
||||
return nil;
|
||||
}
|
||||
if (pld->ptr[pld->pos] == ';')
|
||||
{
|
||||
pld->pos++;
|
||||
}
|
||||
else if (pld->ptr[pld->pos] != '}')
|
||||
{
|
||||
pld->err = @"unexpected character (wanted ';' or '}')";
|
||||
RELEASE(key);
|
||||
RELEASE(val);
|
||||
return nil;
|
||||
}
|
||||
(*plSet)(dict, @selector(setObject:forKey:), val, key);
|
||||
RELEASE(key);
|
||||
RELEASE(val);
|
||||
}
|
||||
if (pld->pos >= pld->end)
|
||||
{
|
||||
pld->err = @"unexpected end of string when parsing dictionary";
|
||||
RELEASE(dict);
|
||||
return nil;
|
||||
}
|
||||
pld->pos++;
|
||||
return dict;
|
||||
}
|
||||
|
||||
case '(':
|
||||
{
|
||||
NSMutableArray *array;
|
||||
|
||||
array = [[plArray allocWithZone: NSDefaultMallocZone()]
|
||||
initWithCapacity: 0];
|
||||
pld->pos++;
|
||||
while (skipSpace(pld) == YES && pld->ptr[pld->pos] != ')')
|
||||
{
|
||||
id val;
|
||||
|
||||
val = parsePlItem(pld);
|
||||
if (val == nil)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
if (skipSpace(pld) == NO)
|
||||
{
|
||||
RELEASE(val);
|
||||
return nil;
|
||||
}
|
||||
if (pld->ptr[pld->pos] == ',')
|
||||
{
|
||||
pld->pos++;
|
||||
}
|
||||
else if (pld->ptr[pld->pos] != ')')
|
||||
{
|
||||
pld->err = @"unexpected character (wanted ',' or ')')";
|
||||
RELEASE(val);
|
||||
return nil;
|
||||
}
|
||||
(*plAdd)(array, @selector(addObject:), val);
|
||||
RELEASE(val);
|
||||
}
|
||||
if (pld->pos >= pld->end)
|
||||
{
|
||||
pld->err = @"unexpected end of string when parsing array";
|
||||
RELEASE(array);
|
||||
return nil;
|
||||
}
|
||||
pld->pos++;
|
||||
return array;
|
||||
}
|
||||
|
||||
case '<':
|
||||
{
|
||||
NSMutableData *data;
|
||||
unsigned max = pld->end - 1;
|
||||
unsigned char buf[BUFSIZ];
|
||||
unsigned len = 0;
|
||||
|
||||
data = [[NSMutableData alloc] initWithCapacity: 0];
|
||||
pld->pos++;
|
||||
while (skipSpace(pld) == YES && pld->ptr[pld->pos] != '>')
|
||||
{
|
||||
while (pld->pos < max
|
||||
&& (*hexdigitsImp)(hexdigits, cMemberSel,
|
||||
(unichar)pld->ptr[pld->pos])
|
||||
&& (*hexdigitsImp)(hexdigits, cMemberSel,
|
||||
(unichar)pld->ptr[pld->pos+1]))
|
||||
{
|
||||
unsigned char byte;
|
||||
|
||||
byte = (char2num(pld->ptr[pld->pos])) << 4;
|
||||
pld->pos++;
|
||||
byte |= char2num(pld->ptr[pld->pos]);
|
||||
pld->pos++;
|
||||
buf[len++] = byte;
|
||||
if (len == sizeof(buf))
|
||||
{
|
||||
[data appendBytes: buf length: len];
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pld->pos >= pld->end)
|
||||
{
|
||||
pld->err = @"unexpected end of string when parsing data";
|
||||
RELEASE(data);
|
||||
return nil;
|
||||
}
|
||||
if (pld->ptr[pld->pos] != '>')
|
||||
{
|
||||
pld->err = @"unexpected character in string";
|
||||
RELEASE(data);
|
||||
return nil;
|
||||
}
|
||||
if (len > 0)
|
||||
{
|
||||
[data appendBytes: buf length: len];
|
||||
}
|
||||
pld->pos++;
|
||||
return data;
|
||||
}
|
||||
|
||||
case '"':
|
||||
return parseQuotedString(pld);
|
||||
|
||||
default:
|
||||
return parseUnquotedString(pld);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_LIBXML
|
||||
static GSXMLNode*
|
||||
elementNode(GSXMLNode* node)
|
||||
{
|
||||
while (node != nil)
|
||||
{
|
||||
if ([node type] == XML_ELEMENT_NODE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
node = [node next];
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static id
|
||||
nodeToObject(GSXMLNode* node)
|
||||
{
|
||||
NSString *name;
|
||||
NSString *content;
|
||||
GSXMLNode *children;
|
||||
|
||||
node = elementNode(node);
|
||||
if (node == nil)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
name = [node name];
|
||||
children = [node children];
|
||||
content = [children content];
|
||||
children = elementNode(children);
|
||||
|
||||
if ([name isEqualToString: @"string"])
|
||||
{
|
||||
return content;
|
||||
}
|
||||
else if ([name isEqualToString: @"key"])
|
||||
{
|
||||
return content;
|
||||
}
|
||||
else if ([name isEqualToString: @"true"])
|
||||
{
|
||||
return [NSNumber numberWithBool: YES];
|
||||
}
|
||||
else if ([name isEqualToString: @"false"])
|
||||
{
|
||||
return [NSNumber numberWithBool: NO];
|
||||
}
|
||||
else if ([name isEqualToString: @"integer"])
|
||||
{
|
||||
return [NSNumber numberWithInt: [content intValue]];
|
||||
}
|
||||
else if ([name isEqualToString: @"real"])
|
||||
{
|
||||
return [NSNumber numberWithDouble: [content doubleValue]];
|
||||
}
|
||||
else if ([name isEqualToString: @"date"])
|
||||
{
|
||||
return [NSCalendarDate dateWithString: content
|
||||
calendarFormat: @"%Y-%m-%d %H:%M:%S %z"];
|
||||
}
|
||||
else if ([name isEqualToString: @"data"])
|
||||
{
|
||||
return decodeBase64([content cString]);
|
||||
}
|
||||
// container class
|
||||
else if ([name isEqualToString: @"array"])
|
||||
{
|
||||
NSMutableArray *container = [NSMutableArray array];
|
||||
|
||||
while (children != nil)
|
||||
{
|
||||
id val;
|
||||
|
||||
val = nodeToObject(children);
|
||||
[container addObject: val];
|
||||
children = elementNode([children next]);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
else if ([name isEqualToString: @"dict"])
|
||||
{
|
||||
NSMutableDictionary *container = [NSMutableDictionary dictionary];
|
||||
|
||||
while (children != nil)
|
||||
{
|
||||
NSString *key;
|
||||
id val;
|
||||
|
||||
key = nodeToObject(children);
|
||||
children = elementNode([children next]);
|
||||
val = nodeToObject(children);
|
||||
children = elementNode([children next]);
|
||||
[container setObject: val forKey: key];
|
||||
}
|
||||
return container;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static id parsePl(pldata* pld)
|
||||
{
|
||||
#if HAVE_LIBXML
|
||||
while (pld->pos < pld->end && isspace(pld->ptr[pld->pos]))
|
||||
{
|
||||
pld->pos++;
|
||||
}
|
||||
/*
|
||||
* A string beginning with a '<?' must be an XML file
|
||||
*/
|
||||
if (pld->pos + 1 < pld->end && pld->ptr[pld->pos] == '<'
|
||||
&& pld->ptr[pld->pos+1] == '?')
|
||||
{
|
||||
NSData *data;
|
||||
GSXMLParser *parser;
|
||||
char *buf = NSZoneMalloc(NSDefaultMallocZone(), pld->end);
|
||||
|
||||
memcpy(buf, pld->ptr, pld->end);
|
||||
data = [NSData dataWithBytesNoCopy: buf length: pld->end];
|
||||
parser = [GSXMLParser parserWithData: data];
|
||||
[parser substituteEntities: NO];
|
||||
if ([parser parse] == YES)
|
||||
{
|
||||
if (![[[[parser doc] root] name] isEqualToString: @"plist"])
|
||||
{
|
||||
NSLog(@"not a property list - because name node is %@",
|
||||
[[[parser doc] root] name]);
|
||||
return nil;
|
||||
}
|
||||
return RETAIN(nodeToObject([[[parser doc] root] children]));
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"not a property list - failed to parse as XML");
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return parsePlItem(pld);
|
||||
}
|
||||
|
||||
static id parseSfItem(pldata* pld)
|
||||
{
|
||||
NSMutableDictionary *dict;
|
||||
|
||||
dict = [[plDictionary allocWithZone: NSDefaultMallocZone()]
|
||||
initWithCapacity: 0];
|
||||
while (skipSpace(pld) == YES)
|
||||
{
|
||||
id key;
|
||||
id val;
|
||||
|
||||
if (pld->ptr[pld->pos] == '"')
|
||||
key = parseQuotedString(pld);
|
||||
else
|
||||
key = parseUnquotedString(pld);
|
||||
if (key == nil)
|
||||
return nil;
|
||||
if (skipSpace(pld) == NO)
|
||||
{
|
||||
pld->err = @"incomplete final entry (no semicolon?)";
|
||||
RELEASE(key);
|
||||
return nil;
|
||||
}
|
||||
if (pld->ptr[pld->pos] == ';')
|
||||
{
|
||||
pld->pos++;
|
||||
(*plSet)(dict, @selector(setObject:forKey:), @"", key);
|
||||
RELEASE(key);
|
||||
}
|
||||
else if (pld->ptr[pld->pos] == '=')
|
||||
{
|
||||
pld->pos++;
|
||||
if (skipSpace(pld) == NO)
|
||||
{
|
||||
RELEASE(key);
|
||||
return nil;
|
||||
}
|
||||
if (pld->ptr[pld->pos] == '"')
|
||||
val = parseQuotedString(pld);
|
||||
else
|
||||
val = parseUnquotedString(pld);
|
||||
if (val == nil)
|
||||
{
|
||||
RELEASE(key);
|
||||
return nil;
|
||||
}
|
||||
if (skipSpace(pld) == NO)
|
||||
{
|
||||
pld->err = @"missing final semicolon";
|
||||
RELEASE(key);
|
||||
RELEASE(val);
|
||||
return nil;
|
||||
}
|
||||
(*plSet)(dict, @selector(setObject:forKey:), val, key);
|
||||
RELEASE(key);
|
||||
RELEASE(val);
|
||||
if (pld->ptr[pld->pos] == ';')
|
||||
pld->pos++;
|
||||
else
|
||||
{
|
||||
pld->err = @"unexpected character (wanted ';')";
|
||||
RELEASE(dict);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RELEASE(key);
|
||||
RELEASE(dict);
|
||||
pld->err = @"unexpected character (wanted '=' or ';')";
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return dict;
|
||||
}
|
Loading…
Reference in a new issue