From 32418a87f97fdbc81fb65af784c2099dcca6d088 Mon Sep 17 00:00:00 2001 From: CaS Date: Fri, 2 Jul 2004 10:37:54 +0000 Subject: [PATCH] A lot of property list tidyups git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@19669 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 11 + Source/GSCompatibility.m | 932 -------------------------------- Source/NSHost.m | 22 +- Source/NSPropertyList.m | 140 +++-- Source/NSString.m | 1090 +------------------------------------- 5 files changed, 165 insertions(+), 2030 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6c7003dd8..3f1919a5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2004-07-02 Richard Frith-Macdonald + + * Source/NSHost.m: Use UTF8String rather than cString throughout + as cString is deprecated. + * Source/NSPropertyList.m: Output property list unicode escapes + as \U rather than \u for MacOS-X compatibility. Fix a few bugs + in old style plists. + * Source/GSCompatibility.m: Remove plist stuff which duplicated code + in NSPropertyList.m, so we only have one version to worry about. + * Source/NSString.m ditto. + 2004-07-01 David Ayers * Headers/Foundation/NSMethodSignature.h diff --git a/Source/GSCompatibility.m b/Source/GSCompatibility.m index c6ff3033e..777475e3d 100644 --- a/Source/GSCompatibility.m +++ b/Source/GSCompatibility.m @@ -55,935 +55,3 @@ BOOL GSMacOSXCompatiblePropertyLists(void) return GSUserDefaultsFlag(GSMacOSXCompatible); } -#include -#include "Foundation/NSValue.h" -#include "Foundation/NSString.h" - -static char base64[] - = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static NSString* -encodeBase64(NSData *source) -{ - int length = [source length]; - int enclen = length / 3; - int remlen = length - 3 * enclen; - int destlen = 4 * ((length - 1) / 3) + 5; - unsigned char *sBuf; - unsigned char *dBuf; - int sIndex = 0; - int dIndex = 0; - - if (length == 0) - { - return @""; - } - sBuf = (unsigned char*)[source bytes]; - dBuf = NSZoneMalloc(NSDefaultMallocZone(), destlen); - dBuf[destlen - 1] = '\0'; - - for (sIndex = 0; sIndex < length - 2; sIndex += 3, dIndex += 4) - { - dBuf[dIndex] = base64[sBuf[sIndex] >> 2]; - dBuf[dIndex + 1] - = base64[((sBuf[sIndex] << 4) | (sBuf[sIndex + 1] >> 4)) & 0x3f]; - dBuf[dIndex + 2] - = base64[((sBuf[sIndex + 1] << 2) | (sBuf[sIndex + 2] >> 6)) & 0x3f]; - dBuf[dIndex + 3] = base64[sBuf[sIndex + 2] & 0x3f]; - } - - if (remlen == 1) - { - dBuf[dIndex] = base64[sBuf[sIndex] >> 2]; - dBuf[dIndex + 1] = (sBuf[sIndex] << 4) & 0x30; - dBuf[dIndex + 1] = base64[dBuf[dIndex + 1]]; - dBuf[dIndex + 2] = '='; - dBuf[dIndex + 3] = '='; - } - else if (remlen == 2) - { - dBuf[dIndex] = base64[sBuf[sIndex] >> 2]; - dBuf[dIndex + 1] = (sBuf[sIndex] << 4) & 0x30; - dBuf[dIndex + 1] |= sBuf[sIndex + 1] >> 4; - dBuf[dIndex + 1] = base64[dBuf[dIndex + 1]]; - dBuf[dIndex + 2] = (sBuf[sIndex + 1] << 2) & 0x3c; - dBuf[dIndex + 2] = base64[dBuf[dIndex + 2]]; - dBuf[dIndex + 3] = '='; - } - - return [[NSString allocWithZone: NSDefaultMallocZone()] - initWithCStringNoCopy: dBuf length: destlen-1 freeWhenDone: YES]; -} - -static NSCharacterSet *xmlQuotables = nil; -static NSCharacterSet *plQuotables = nil; -static NSCharacterSet *oldPlQuotables = nil; -static unsigned const char *plQuotablesBitmapRep = NULL; -#define GS_IS_QUOTABLE(X) IS_BIT_SET(plQuotablesBitmapRep[(X)/8], (X) % 8) - -static inline void Append(NSString *src, GSMutableString *dst) -{ - [(NSMutableString*)dst appendString: src]; -} - -static void -PString(NSString *obj, GSMutableString *output) -{ - unsigned length; - - if ((length = [obj length]) == 0) - { - Append(@"\"\"", output); - return; - } - - if ([obj rangeOfCharacterFromSet: oldPlQuotables].length > 0 - || [obj characterAtIndex: 0] == '/') - { - unichar tmp[length <= 1024 ? length : 0]; - unichar *ustring; - unichar *from; - unichar *end; - int len = 0; - - if (length <= 1024) - { - ustring = tmp; - } - else - { - ustring = NSZoneMalloc(NSDefaultMallocZone(), length*sizeof(unichar)); - } - end = &ustring[length]; - [obj getCharacters: ustring]; - for (from = ustring; from < end; from++) - { - switch (*from) - { - case '\a': - case '\b': - case '\t': - case '\r': - case '\n': - case '\v': - case '\f': - case '\\': - case '\'' : - case '"' : - len += 2; - break; - - default: - if (*from < 128) - { - if (isprint(*from) || *from == ' ') - { - len++; - } - else - { - len += 4; - } - } - else - { - len += 6; - } - break; - } - } - - { - char buf[len+3]; - char *ptr = buf; - - *ptr++ = '"'; - for (from = ustring; from < end; from++) - { - switch (*from) - { - case '\a': *ptr++ = '\\'; *ptr++ = 'a'; break; - case '\b': *ptr++ = '\\'; *ptr++ = 'b'; break; - case '\t': *ptr++ = '\\'; *ptr++ = 't'; break; - case '\r': *ptr++ = '\\'; *ptr++ = 'r'; break; - case '\n': *ptr++ = '\\'; *ptr++ = 'n'; break; - case '\v': *ptr++ = '\\'; *ptr++ = 'v'; break; - case '\f': *ptr++ = '\\'; *ptr++ = 'f'; break; - case '\\': *ptr++ = '\\'; *ptr++ = '\\'; break; - case '\'': *ptr++ = '\\'; *ptr++ = '\''; break; - case '"' : *ptr++ = '\\'; *ptr++ = '"'; break; - - default: - if (*from < 128) - { - if (isprint(*from) || *from == ' ') - { - *ptr++ = *from; - } - else - { - unichar c = *from; - - sprintf(ptr, "\\%03o", c); - ptr = &ptr[4]; - } - } - else - { - sprintf(ptr, "\\u%04x", *from); - ptr = &ptr[6]; - } - break; - } - } - *ptr++ = '"'; - *ptr = '\0'; - obj = [[NSString alloc] initWithCString: buf]; - Append(obj, output); - RELEASE(obj); - } - if (length > 1024) - { - NSZoneFree(NSDefaultMallocZone(), ustring); - } - } - else - { - Append(obj, output); - } -} - -static void -XString(NSString* obj, GSMutableString *output) -{ - static char *hexdigits = "0123456789ABCDEF"; - unsigned end; - - end = [obj length]; - if (end == 0) - { - return; - } - - if ([obj rangeOfCharacterFromSet: xmlQuotables].length > 0) - { - unichar *base; - unichar *map; - unichar c; - unsigned len; - unsigned rpos; - unsigned wpos; - - base = NSZoneMalloc(NSDefaultMallocZone(), end * sizeof(unichar)); - [obj getCharacters: base]; - for (len = rpos = 0; rpos < end; rpos++) - { - c = base[rpos]; - switch (c) - { - case '&': - len += 5; - break; - case '<': - case '>': - len += 4; - break; - case '\'': - case '"': - len += 6; - break; - - default: - if ((c < 0x20 && (c != 0x09 && c != 0x0A && c != 0x0D)) - || (c > 0xD7FF && c < 0xE000) || c > 0xFFFD) - { - len += 6; - } - else - { - len++; - } - break; - } - } - map = NSZoneMalloc(NSDefaultMallocZone(), len * sizeof(unichar)); - for (wpos = rpos = 0; rpos < end; rpos++) - { - c = base[rpos]; - switch (c) - { - case '&': - map[wpos++] = '&'; - map[wpos++] = 'a'; - map[wpos++] = 'm'; - map[wpos++] = 'p'; - map[wpos++] = ';'; - break; - case '<': - map[wpos++] = '&'; - map[wpos++] = 'l'; - map[wpos++] = 't'; - map[wpos++] = ';'; - break; - case '>': - map[wpos++] = '&'; - map[wpos++] = 'g'; - map[wpos++] = 't'; - map[wpos++] = ';'; - break; - case '\'': - map[wpos++] = '&'; - map[wpos++] = 'a'; - map[wpos++] = 'p'; - map[wpos++] = 'o'; - map[wpos++] = 's'; - map[wpos++] = ';'; - break; - case '"': - map[wpos++] = '&'; - map[wpos++] = 'q'; - map[wpos++] = 'u'; - map[wpos++] = 'o'; - map[wpos++] = 't'; - map[wpos++] = ';'; - break; - - default: - if ((c < 0x20 && (c != 0x09 && c != 0x0A && c != 0x0D)) - || (c > 0xD7FF && c < 0xE000) || c > 0xFFFD) - { - map[wpos++] = '\\'; - map[wpos++] = 'U'; - map[wpos++] = hexdigits[(c>>12) & 0xf]; - map[wpos++] = hexdigits[(c>>8) & 0xf]; - map[wpos++] = hexdigits[(c>>4) & 0xf]; - map[wpos++] = hexdigits[c & 0xf]; - } - else - { - map[wpos++] = c; - } - break; - } - } - NSZoneFree(NSDefaultMallocZone(), base); - obj = [[NSString alloc] initWithCharacters: map length: len]; - Append(obj, output); - RELEASE(obj); - } - else - { - Append(obj, output); - } -} - -static NSString *indentStrings[] = { - @"", - @" ", - @" ", - @" ", - @"\t", - @"\t ", - @"\t ", - @"\t ", - @"\t\t", - @"\t\t ", - @"\t\t ", - @"\t\t ", - @"\t\t\t", - @"\t\t\t ", - @"\t\t\t ", - @"\t\t\t ", - @"\t\t\t\t", - @"\t\t\t\t ", - @"\t\t\t\t ", - @"\t\t\t\t ", - @"\t\t\t\t\t", - @"\t\t\t\t\t ", - @"\t\t\t\t\t ", - @"\t\t\t\t\t ", - @"\t\t\t\t\t\t" -}; - -#define PLNEW 0 // New extended OpenStep property list -#define PLXML 1 // New MacOS-X XML property list -#define PLOLD 2 // Old (standard) OpenStep property list -#define PLDSC 3 // Just a description -/** - * obj is the object to be written out
- * loc is the locale for formatting (or nil to indicate no formatting)
- * lev is the level of indentation to use
- * step is the indentation step (0 == 0, 1 = 2, 2 = 4, 3 = 8)
- * x is an indicator for xml or old/new openstep property list format
- * dest is the output buffer. - */ -static void -OAppend(id obj, NSDictionary *loc, unsigned lev, unsigned step, - int x, GSMutableString *dest) -{ - if ([obj isKindOfClass: [NSString class]]) - { - if (x == PLXML) - { - Append(@"", dest); - XString(obj, dest); - Append(@"\n", dest); - } - else - { - PString(obj, dest); - } - } - else if ([obj isKindOfClass: [NSNumber class]]) - { - const char *t = [obj objCType]; - - if (*t == 'c' || *t == 'C') - { - BOOL val = [obj boolValue]; - - if (val == YES) - { - if (x == PLXML) - { - Append(@"\n", dest); - } - else if (x == PLNEW) - { - Append(@"<*BY>", dest); - } - else - { - PString([obj description], dest); - } - } - else - { - if (x == PLXML) - { - Append(@"\n", dest); - } - else if (x == PLNEW) - { - Append(@"<*BN>", dest); - } - else - { - PString([obj description], dest); - } - } - } - else if (strchr("sSiIlLqQ", *t) != 0) - { - if (x == PLXML) - { - Append(@"", dest); - XString([obj stringValue], dest); - Append(@"\n", dest); - } - else if (x == PLNEW) - { - Append(@"<*I", dest); - PString([obj stringValue], dest); - Append(@">", dest); - } - else - { - PString([obj description], dest); - } - } - else - { - if (x == PLXML) - { - Append(@"", dest); - XString([obj stringValue], dest); - Append(@"\n", dest); - } - else if (x == PLNEW) - { - Append(@"<*R", dest); - PString([obj stringValue], dest); - Append(@">", dest); - } - else - { - PString([obj description], dest); - } - } - } - else if ([obj isKindOfClass: [NSData class]]) - { - if (x == PLXML) - { - Append(@"", dest); - Append(encodeBase64(obj), dest); - Append(@"\n", dest); - } - else - { - NSString *str; - const char *src; - char *dst; - int length; - int i; - int j; - NSZone *z = NSDefaultMallocZone(); - - src = [obj bytes]; - length = [obj length]; - #define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57)) - - dst = (char*) NSZoneMalloc(z, 2*length+length/4+3); - dst[0] = '<'; - for (i = 0, j = 1; i < length; i++, j++) - { - dst[j++] = num2char((src[i]>>4) & 0x0f); - dst[j] = num2char(src[i] & 0x0f); - if ((i&0x3) == 3 && i != length-1) - { - /* if we've just finished a 32-bit int, print a space */ - dst[++j] = ' '; - } - } - dst[j++] = '>'; - dst[j] = '\0'; - str = [[NSString allocWithZone: z] initWithCStringNoCopy: dst - length: j - freeWhenDone: YES]; - Append(str, dest); - RELEASE(str); - } - } - else if ([obj isKindOfClass: [NSDate class]]) - { - if (x == PLXML) - { - Append(@"", dest); - Append([obj descriptionWithCalendarFormat: @"%Y-%m-%d %H:%M:%S %z" - timeZone: nil locale: nil], dest); - Append(@"\n", dest); - } - else if (x == PLNEW) - { - Append(@"<*D", dest); - Append([obj descriptionWithCalendarFormat: @"%Y-%m-%d %H:%M:%S %z" - timeZone: nil locale: nil], dest); - Append(@">", dest); - } - else - { - PString([obj description], dest); - } - } - else if ([obj isKindOfClass: [NSArray class]]) - { - NSString *iBaseString; - NSString *iSizeString; - unsigned level = lev; - - if (level*step < sizeof(indentStrings)/sizeof(id)) - { - iBaseString = indentStrings[level*step]; - } - else - { - iBaseString - = indentStrings[sizeof(indentStrings)/sizeof(id)-1]; - } - level++; - if (level*step < sizeof(indentStrings)/sizeof(id)) - { - iSizeString = indentStrings[level*step]; - } - else - { - iSizeString - = indentStrings[sizeof(indentStrings)/sizeof(id)-1]; - } - - if (x == PLXML) - { - NSEnumerator *e; - - Append(@"\n", dest); - e = [obj objectEnumerator]; - while ((obj = [e nextObject])) - { - Append(iSizeString, dest); - OAppend(obj, loc, level, step, x, dest); - } - Append(iBaseString, dest); - Append(@"\n", dest); - } - else - { - unsigned count = [obj count]; - unsigned last = count - 1; - NSString *plists[count]; - unsigned i; - - if ([obj isProxy] == YES) - { - for (i = 0; i < count; i++) - { - plists[i] = [obj objectAtIndex: i]; - } - } - else - { - [obj getObjects: plists]; - } - - if (loc == nil) - { - Append(@"(", dest); - for (i = 0; i < count; i++) - { - id item = plists[i]; - - OAppend(item, nil, 0, step, x, dest); - if (i != last) - { - Append(@", ", dest); - } - } - Append(@")", dest); - } - else - { - Append(@"(\n", dest); - for (i = 0; i < count; i++) - { - id item = plists[i]; - - Append(iSizeString, dest); - OAppend(item, loc, level, step, x, dest); - if (i == last) - { - Append(@"\n", dest); - } - else - { - Append(@",\n", dest); - } - } - Append(iBaseString, dest); - Append(@")", dest); - } - } - } - else if ([obj isKindOfClass: [NSDictionary class]]) - { - NSString *iBaseString; - NSString *iSizeString; - unsigned level = lev; - - if (level*step < sizeof(indentStrings)/sizeof(id)) - { - iBaseString = indentStrings[level*step]; - } - else - { - iBaseString - = indentStrings[sizeof(indentStrings)/sizeof(id)-1]; - } - level++; - if (level*step < sizeof(indentStrings)/sizeof(id)) - { - iSizeString = indentStrings[level*step]; - } - else - { - iSizeString - = indentStrings[sizeof(indentStrings)/sizeof(id)-1]; - } - - if (x == PLXML) - { - NSEnumerator *e; - id key; - - Append(@"\n", dest); - e = [obj keyEnumerator]; - while ((key = [e nextObject])) - { - id val; - - val = [obj objectForKey: key]; - Append(iSizeString, dest); - Append(@"", dest); - XString(key, dest); - Append(@"\n", dest); - Append(iSizeString, dest); - OAppend(val, loc, level, step, x, dest); - } - Append(iBaseString, dest); - Append(@"\n", dest); - } - else - { - unsigned i; - NSArray *keyArray = [obj allKeys]; - unsigned numKeys = [keyArray count]; - NSString *plists[numKeys]; - NSString *keys[numKeys]; - BOOL canCompare = YES; - Class lastClass = 0; - BOOL isProxy = [obj isProxy]; - - if (isProxy == YES) - { - for (i = 0; i < numKeys; i++) - { - keys[i] = [keyArray objectAtIndex: i]; - } - } - else - { - [keyArray getObjects: keys]; - } - - for (i = 0; i < numKeys; i++) - { - if (GSObjCClass(keys[i]) == lastClass) - continue; - if ([keys[i] respondsToSelector: @selector(compare:)] == NO) - { - canCompare = NO; - break; - } - lastClass = GSObjCClass(keys[i]); - } - - if (canCompare == YES) - { - #define STRIDE_FACTOR 3 - unsigned c,d, stride; - BOOL found; - NSComparisonResult (*comp)(id, SEL, id) = 0; - unsigned int count = numKeys; - #ifdef GSWARN - BOOL badComparison = NO; - #endif - - stride = 1; - while (stride <= count) - { - stride = stride * STRIDE_FACTOR + 1; - } - lastClass = 0; - while (stride > (STRIDE_FACTOR - 1)) - { - // loop to sort for each value of stride - stride = stride / STRIDE_FACTOR; - for (c = stride; c < count; c++) - { - found = NO; - if (stride > c) - { - break; - } - d = c - stride; - while (!found) - { - id a = keys[d + stride]; - id b = keys[d]; - Class x; - NSComparisonResult r; - - x = GSObjCClass(a); - if (x != lastClass) - { - lastClass = x; - comp = (NSComparisonResult (*)(id, SEL, id)) - [a methodForSelector: @selector(compare:)]; - } - r = (*comp)(a, @selector(compare:), b); - if (r < 0) - { - #ifdef GSWARN - if (r != NSOrderedAscending) - { - badComparison = YES; - } - #endif - keys[d + stride] = b; - keys[d] = a; - if (stride > d) - { - break; - } - d -= stride; - } - else - { - #ifdef GSWARN - if (r != NSOrderedDescending - && r != NSOrderedSame) - { - badComparison = YES; - } - #endif - found = YES; - } - } - } - } - #ifdef GSWARN - if (badComparison == YES) - { - NSWarnFLog(@"Detected bad return value from comparison"); - } - #endif - } - - if (isProxy == YES) - { - for (i = 0; i < numKeys; i++) - { - plists[i] = [obj objectForKey: keys[i]]; - } - } - else - { - SEL objSel = @selector(objectForKey:); - IMP myObj = [obj methodForSelector: objSel]; - - for (i = 0; i < numKeys; i++) - { - plists[i] = (*myObj)(obj, objSel, keys[i]); - } - } - - if (loc == nil) - { - Append(@"{", dest); - for (i = 0; i < numKeys; i++) - { - OAppend(keys[i], nil, 0, step, x, dest); - Append(@" = ", dest); - OAppend(plists[i], nil, 0, step, x, dest); - Append(@"; ", dest); - } - Append(@"}", dest); - } - else - { - Append(@"{\n", dest); - for (i = 0; i < numKeys; i++) - { - Append(iSizeString, dest); - OAppend(keys[i], loc, level, step, x, dest); - Append(@" = ", dest); - OAppend(plists[i], loc, level, step, x, dest); - Append(@";\n", dest); - } - Append(iBaseString, dest); - Append(@"}", dest); - } - } - } - else - { - if (x == PLDSC) - { - Append([obj description], dest); - } - else if (x == PLXML) - { - NSDebugLog(@"Non-property-list class (%@) encoded as string", - NSStringFromClass([obj class])); - Append(@"", dest); - XString([obj description], dest); - Append(@"\n", dest); - } - else - { - NSDebugLog(@"Non-property-list class (%@) encoded as string", - NSStringFromClass([obj class])); - Append([obj description], dest); - } - } -} - -void -GSPropertyListMake(id obj, NSDictionary *loc, BOOL xml, - BOOL forDescription, unsigned step, id *str) -{ - GSMutableString *dest; - int style = PLNEW; - - if (plQuotablesBitmapRep == NULL) - { - NSMutableCharacterSet *s; - NSData *bitmap; - - s = [[NSCharacterSet characterSetWithCharactersInString: - @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - @"abcdefghijklmnopqrstuvwxyz!#$%&*+-./:?@|~_^"] - mutableCopy]; - [s invert]; - plQuotables = [s copy]; - RELEASE(s); - bitmap = RETAIN([plQuotables bitmapRepresentation]); - plQuotablesBitmapRep = [bitmap bytes]; - s = [[NSCharacterSet characterSetWithCharactersInString: - @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - @"abcdefghijklmnopqrstuvwxyz$./_"] - mutableCopy]; - [s invert]; - oldPlQuotables = [s copy]; - RELEASE(s); - - s = [[NSCharacterSet characterSetWithCharactersInString: - @"&<>'\\\""] mutableCopy]; - [s addCharactersInRange: NSMakeRange(0x0001, 0x001f)]; - [s removeCharactersInRange: NSMakeRange(0x0009, 0x0002)]; - [s removeCharactersInRange: NSMakeRange(0x000D, 0x0001)]; - [s addCharactersInRange: NSMakeRange(0xD800, 0x07FF)]; - [s addCharactersInRange: NSMakeRange(0xFFFE, 0x0002)]; - xmlQuotables = [s copy]; - RELEASE(s); - } - - if (*str == nil) - { - *str = AUTORELEASE([GSMutableString new]); - } - else if (GSObjCClass(*str) != [GSMutableString class]) - { - [NSException raise: NSInvalidArgumentException - format: @"Illegal object (%@) at argument 0", *str]; - } - dest = *str; - - if (forDescription) - { - style = PLDSC; - } - else if (xml == YES) - { - Append([NSMutableString stringWithCString: - "\n\n" - "\n"], dest); - style = PLXML; - } - else if (GSUserDefaultsFlag(NSWriteOldStylePropertyLists)) - { - style = PLOLD; - } - else - { - style = PLNEW; - } - - OAppend(obj, loc, 0, step > 3 ? 3 : step, style, dest); - if (style == PLXML) - { - Append(@"", dest); - } -} - diff --git a/Source/NSHost.m b/Source/NSHost.m index 10c66bf41..b8ba98a71 100644 --- a/Source/NSHost.m +++ b/Source/NSHost.m @@ -91,13 +91,13 @@ static NSMutableDictionary *_hostCache = nil; struct in_addr hostaddr; #ifndef HAVE_INET_ATON - hostaddr.s_addr = inet_addr([address cString]); + hostaddr.s_addr = inet_addr([address UTF8String]); if (hostaddr.s_addr == INADDR_NONE) { NSLog(@"Attempt to lookup host entry for bad IP address (%@)", address); } #else - if (inet_aton([address cString], (struct in_addr*)&hostaddr.s_addr) == 0) + if (inet_aton([address UTF8String], (struct in_addr*)&hostaddr.s_addr) == 0) { NSLog(@"Attempt to lookup host entry for bad IP address (%@)", address); } @@ -304,6 +304,7 @@ myHostName() + (NSHost*) hostWithName: (NSString*)name { + BOOL tryByAddress = NO; NSHost *host = nil; if (name == nil) @@ -336,9 +337,14 @@ myHostName() else { struct hostent *h = 0; + const char *n = [name UTF8String]; - h = gethostbyname((char*)[name cString]); - if (h == 0) + h = gethostbyname((char*)n); + if (h == 0 && sscanf(n, "%*d.%*d.%*d.%*d") == 4) + { + tryByAddress = YES; + } + else if (h == 0) { if ([name isEqualToString: myHostName()] == YES) { @@ -365,6 +371,10 @@ myHostName() } } [_hostCacheLock unlock]; + if (tryByAddress == YES) + { + return [self hostWithAddress: name]; + } return host; } @@ -400,13 +410,13 @@ myHostName() BOOL badAddr = NO; #ifndef HAVE_INET_ATON - hostaddr.s_addr = inet_addr([address cString]); + hostaddr.s_addr = inet_addr([address UTF8String]); if (hostaddr.s_addr == INADDR_NONE) { badAddr = YES; } #else - if (inet_aton([address cString], + if (inet_aton([address UTF8String], (struct in_addr*)&hostaddr.s_addr) == 0) { badAddr = YES; diff --git a/Source/NSPropertyList.m b/Source/NSPropertyList.m index 90bd651d4..db0330116 100644 --- a/Source/NSPropertyList.m +++ b/Source/NSPropertyList.m @@ -42,6 +42,7 @@ #include "Foundation/NSValue.h" #include "Foundation/NSDebug.h" +#include "GSPrivate.h" extern BOOL GSScanDouble(unichar*, unsigned, double*); @class GSString; @@ -168,9 +169,6 @@ static void setupWhitespace(void) } } -static id GSPropertyListFromStringsFormat(NSString *string); - - #ifdef HAVE_LIBXML #include "GNUstepBase/GSXML.h" static int XML_ELEMENT_NODE; @@ -733,7 +731,7 @@ static id parsePlItem(pldata* pld) } if (pld->ptr[pld->pos] != '>') { - pld->err = @"unexpected character in string"; + pld->err = @"unexpected character (wanted '>')"; return nil; } pld->pos++; @@ -773,7 +771,7 @@ static id parsePlItem(pldata* pld) } if (pld->ptr[pld->pos] != '>') { - pld->err = @"unexpected character in string"; + pld->err = @"unexpected character (wanted '>')"; RELEASE(data); return nil; } @@ -1009,7 +1007,7 @@ nodeToObject(GSXMLNode* node, NSPropertyListMutabilityOptions o, NSString **e) } #endif -static id +id GSPropertyListFromStringsFormat(NSString *string) { NSMutableDictionary *dict; @@ -1026,12 +1024,17 @@ GSPropertyListFromStringsFormat(NSString *string) return nil; } - d = [string dataUsingEncoding: NSUnicodeStringEncoding]; + d = [string dataUsingEncoding: NSASCIIStringEncoding]; + if (d == nil) + { + [NSException raise: NSGenericException + format: @"Non-ascii data in string supposed to be property list"]; + } _pld.ptr = (unsigned char*)[d bytes]; - _pld.pos = 1; - _pld.end = length + 1; + _pld.pos = 0; + _pld.end = length; _pld.err = nil; - _pld.lin = 1; + _pld.lin = 0; _pld.opt = NSPropertyListImmutable; _pld.key = NO; _pld.old = YES; // OpenStep style @@ -1128,7 +1131,7 @@ GSPropertyListFromStringsFormat(NSString *string) RELEASE(dict); [NSException raise: NSGenericException format: @"Parse failed at line %d (char %d) - %@", - _pld.lin, _pld.pos, _pld.err]; + _pld.lin + 1, _pld.pos + 1, _pld.err]; } return AUTORELEASE(dict); } @@ -1217,6 +1220,7 @@ PString(NSString *obj, NSMutableData *output) unichar *from; unichar *end; unsigned char *ptr; + int base = [output length]; int len = 0; if (length <= 1024) @@ -1266,8 +1270,8 @@ PString(NSString *obj, NSMutableData *output) } } - [output setLength: [output length] + len + 2]; - ptr = [output mutableBytes] + [output length]; + [output setLength: base + len + 2]; + ptr = [output mutableBytes] + base; *ptr++ = '"'; for (from = ustring; from < end; from++) { @@ -1295,14 +1299,29 @@ PString(NSString *obj, NSMutableData *output) { unichar c = *from; - sprintf(ptr, "\\%03o", c); - ptr = &ptr[4]; + *ptr++ = '\\'; + ptr[2] = (c & 7) + '0'; + c >>= 3; + ptr[1] = (c & 7) + '0'; + c >>= 3; + ptr[0] = (c & 7) + '0'; + ptr += 3; } } else { - sprintf(ptr, "\\u%04x", *from); - ptr = &ptr[6]; + unichar c = *from; + + *ptr++ = '\\'; + *ptr++ = 'U'; + ptr[3] = (c & 0xf) > 9 ? (c & 0xf) + 'A' : (c & 0xf) + '0'; + c >>= 4; + ptr[2] = (c & 0xf) > 9 ? (c & 0xf) + 'A' : (c & 0xf) + '0'; + c >>= 4; + ptr[1] = (c & 0xf) > 9 ? (c & 0xf) + 'A' : (c & 0xf) + '0'; + c >>= 4; + ptr[0] = (c & 0xf) > 9 ? (c & 0xf) + 'A' : (c & 0xf) + '0'; + ptr += 4; } break; } @@ -1479,10 +1498,6 @@ static const char *indentStrings[] = { "\t\t\t\t\t\t" }; -#define PLNEW 0 // New extended OpenStep property list -#define PLXML 1 // New MacOS-X XML property list -#define PLOLD 2 // Old (standard) OpenStep property list -#define PLDSC 3 // Just a description /** * obj is the object to be written out
* loc is the locale for formatting (or nil to indicate no formatting)
@@ -1607,14 +1622,14 @@ OAppend(id obj, NSDictionary *loc, unsigned lev, unsigned step, #define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57)) j = [dest length]; - [dest setLength: j + 2*length+length/4+3]; + [dest setLength: j + 2*length+(length > 4 ? (length-1)/4+2 : 2)]; dst = [dest mutableBytes]; dst[j++] = '<'; for (i = 0; i < length; i++, j++) { dst[j++] = num2char((src[i]>>4) & 0x0f); dst[j] = num2char(src[i] & 0x0f); - if ((i&0x3) == 3 && i != length-1) + if ((i & 3) == 3 && i < length-1) { /* if we've just finished a 32-bit int, print a space */ dst[++j] = ' '; @@ -1970,13 +1985,13 @@ OAppend(id obj, NSDictionary *loc, unsigned lev, unsigned step, @implementation NSPropertyListSerialization +static BOOL classInitialized = NO; + + (void) initialize { - static BOOL beenHere = NO; - - if (beenHere == NO) + if (classInitialized == NO) { - beenHere = YES; + classInitialized = YES; #ifdef HAVE_LIBXML /* @@ -2040,6 +2055,69 @@ OAppend(id obj, NSDictionary *loc, unsigned lev, unsigned step, return dest; } +void +GSPropertyListMake(id obj, NSDictionary *loc, BOOL xml, + BOOL forDescription, unsigned step, id *str) +{ + NSString *tmp; + NSPropertyListFormat style; + NSMutableData *dest; + + if (classInitialized == NO) + { + [NSPropertyListSerialization class]; + } + + if (*str == nil) + { + *str = AUTORELEASE([GSMutableString new]); + } + else if (GSObjCClass(*str) != [GSMutableString class]) + { + [NSException raise: NSInvalidArgumentException + format: @"Illegal object (%@) at argument 0", *str]; + } + + if (forDescription) + { + style = NSPropertyListOpenStepFormat; + } + else if (xml == YES) + { + style = NSPropertyListXMLFormat_v1_0; + } + else if (GSUserDefaultsFlag(NSWriteOldStylePropertyLists)) + { + style = NSPropertyListOpenStepFormat; + } + else + { + style = NSPropertyListGNUstepFormat; + } + + dest = [NSMutableData dataWithCapacity: 1024]; + + if (style == NSPropertyListXMLFormat_v1_0) + { + const char *prefix = + "\n\n" + "\n"; + + [dest appendBytes: prefix length: strlen(prefix)]; + OAppend(obj, loc, 0, step > 3 ? 3 : step, style, dest); + [dest appendBytes: "" length: 8]; + } + else + { + OAppend(obj, loc, 0, step > 3 ? 3 : step, style, dest); + } + tmp = [[NSString alloc] initWithData: dest encoding: NSASCIIStringEncoding]; + [*str appendString: tmp]; + RELEASE(tmp); +} + + (BOOL) propertyList: (id)aPropertyList isValidForFormat: (NSPropertyListFormat)aFormat { @@ -2165,10 +2243,10 @@ OAppend(id obj, NSDictionary *loc, unsigned lev, unsigned step, pldata _pld; _pld.ptr = bytes; - _pld.pos = 1; - _pld.end = length + 1; + _pld.pos = 0; + _pld.end = length; _pld.err = nil; - _pld.lin = 1; + _pld.lin = 0; _pld.opt = anOption; _pld.key = NO; _pld.old = YES; // OpenStep style @@ -2183,7 +2261,7 @@ OAppend(id obj, NSDictionary *loc, unsigned lev, unsigned step, { error = [NSString stringWithFormat: @"Parse failed at line %d (char %d) - %@", - _pld.lin, _pld.pos, _pld.err]; + _pld.lin + 1, _pld.pos + 1, _pld.err]; } } break; diff --git a/Source/NSString.m b/Source/NSString.m index 55f1f0a06..b7e545002 100644 --- a/Source/NSString.m +++ b/Source/NSString.m @@ -108,69 +108,11 @@ static GSPlaceholderString *defaultPlaceholderString; static NSMapTable *placeholderMap; static NSLock *placeholderLock; -static Class plArray; -static id (*plAdd)(id, SEL, id) = 0; - -static Class plDictionary; -static id (*plSet)(id, SEL, id, id) = 0; - -static id (*plAlloc)(Class, SEL, NSZone*) = 0; -static id (*plInit)(id, SEL, unichar*, unsigned int) = 0; - -static SEL plSel; static SEL cMemberSel = 0; #define IS_BIT_SET(a,i) ((((a) & (1<<(i)))) > 0) -static unsigned const char *hexdigitsBitmapRep = NULL; -#define GS_IS_HEXDIGIT(X) IS_BIT_SET(hexdigitsBitmapRep[(X)/8], (X) % 8) - -static void setupHexdigits(void) -{ - if (hexdigitsBitmapRep == NULL) - { - NSCharacterSet *hexdigits; - NSData *bitmap; - - hexdigits = [NSCharacterSet characterSetWithCharactersInString: - @"0123456789abcdefABCDEF"]; - bitmap = RETAIN([hexdigits bitmapRepresentation]); - hexdigitsBitmapRep = [bitmap bytes]; - } -} - -static NSCharacterSet *quotables = nil; -static NSCharacterSet *oldQuotables = nil; -static unsigned const char *quotablesBitmapRep = NULL; -#define GS_IS_QUOTABLE(X) IS_BIT_SET(quotablesBitmapRep[(X)/8], (X) % 8) - -static void setupQuotables(void) -{ - if (quotablesBitmapRep == NULL) - { - NSMutableCharacterSet *s; - NSData *bitmap; - - s = [[NSCharacterSet characterSetWithCharactersInString: - @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - @"abcdefghijklmnopqrstuvwxyz!#$%&*+-./:?@|~_^"] - mutableCopy]; - [s invert]; - quotables = [s copy]; - RELEASE(s); - bitmap = RETAIN([quotables bitmapRepresentation]); - quotablesBitmapRep = [bitmap bytes]; - s = [[NSCharacterSet characterSetWithCharactersInString: - @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - @"abcdefghijklmnopqrstuvwxyz$./_"] - mutableCopy]; - [s invert]; - oldQuotables = [s copy]; - RELEASE(s); - } -} - static unsigned const char *whitespaceBitmapRep = NULL; #define GS_IS_WHITESPACE(X) IS_BIT_SET(whitespaceBitmapRep[(X)/8], (X) % 8) @@ -205,9 +147,6 @@ static void setupWhitespace(void) #include "GSeq.h" -static id GSPropertyList(NSString *string); -static id GSPropertyListFromStringsFormat(NSString *string); - static NSCharacterSet *myPathSeps = nil; /* * The pathSeps character set is used for parsing paths ... it *must* @@ -376,7 +315,6 @@ handle_printf_atsign (FILE *stream, if (self == [NSString class] && beenHere == NO) { beenHere = YES; - plSel = @selector(initWithCharacters:length:); cMemberSel = @selector(characterIsMember:); caiSel = @selector(characterAtIndex:); gcrSel = @selector(getCharacters:range:); @@ -4463,7 +4401,33 @@ handle_printf_atsign (FILE *stream, */ - (id) propertyList { - return GSPropertyList(self); + NSData *data; + id result = nil; + NSPropertyListFormat format; + NSString *error = nil; + + if ([self length] == 0) + { + return nil; + } + if ((data = [self dataUsingEncoding: NSASCIIStringEncoding]) == nil) + { + [NSException raise: NSGenericException + format: @"Non-ascii data in string supposed to be property list"]; + } + + result = [NSPropertyListSerialization + propertyListFromData: data + mutabilityOption: NSPropertyListImmutable + format: &format + errorDescription: &error]; + + if (result == nil) + { + [NSException raise: NSGenericException + format: @"Parse failed - %@", error]; + } + return result; } /** @@ -4487,6 +4451,8 @@ handle_printf_atsign (FILE *stream, */ - (NSDictionary*) propertyListFromStringsFileFormat { + extern id GSPropertyListFromStringsFormat(NSString *string); + return GSPropertyListFromStringsFormat(self); } @@ -4800,1001 +4766,3 @@ handle_printf_atsign (FILE *stream, @end - - -#ifdef HAVE_LIBXML -#include "GNUstepBase/GSXML.h" -static int XML_ELEMENT_NODE; -#endif - -#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 { - const unichar *ptr; - 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 = pld->ptr[pld->pos]; - - if (GS_IS_WHITESPACE(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 = pld->ptr[pld->pos]; - - if (escaped) - { - if (escaped == 1 && c >= '0' && c <= '7') - { - escaped = 2; - hex = NO; - } - else if (escaped == 1 && (c == 'u' || c == 'U')) - { - escaped = 2; - hex = YES; - } - else if (escaped > 1) - { - if (hex && GS_IS_HEXDIGIT(c)) - { - shrink++; - escaped++; - if (escaped == 6) - { - escaped = 0; - } - } - else if (c >= '0' && c <= '7') - { - shrink++; - escaped++; - if (escaped == 4) - { - escaped = 0; - } - } - 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 - { - unichar chars[pld->pos - start - shrink]; - unsigned j; - unsigned k; - - escaped = 0; - hex = NO; - for (j = start, k = 0; j < pld->pos; j++) - { - unichar c = pld->ptr[j]; - - if (escaped) - { - if (escaped == 1 && c >= '0' && c <= '7') - { - chars[k] = c - '0'; - hex = NO; - escaped++; - } - else if (escaped == 1 && (c == 'u' || c == 'U')) - { - chars[k] = 0; - hex = YES; - escaped++; - } - else if (escaped > 1) - { - if (hex && GS_IS_HEXDIGIT(c)) - { - chars[k] <<= 4; - chars[k] |= char2num(c); - escaped++; - if (escaped == 6) - { - escaped = 0; - k++; - } - } - else if (c >= '0' && c <= '7') - { - chars[k] <<= 3; - chars[k] |= (c - '0'); - escaped++; - if (escaped == 4) - { - escaped = 0; - k++; - } - } - 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)(NSStringClass, @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 (GS_IS_QUOTABLE(pld->ptr[pld->pos]) == YES) - break; - pld->pos++; - } - obj = (*plAlloc)(NSStringClass, @selector(allocWithZone:), - NSDefaultMallocZone()); - obj = (*plInit)(obj, plSel, (void*)&pld->ptr[start], pld->pos-start); - return obj; -} - -static id parsePlItem(pldata* pld) -{ - id result = nil; - BOOL start = (pld->pos == 1 ? YES : NO); - - 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); - RELEASE(dict); - return nil; - } - if (pld->ptr[pld->pos] != '=') - { - pld->err = @"unexpected character (wanted '=')"; - RELEASE(key); - RELEASE(dict); - return nil; - } - pld->pos++; - val = parsePlItem(pld); - if (val == nil) - { - RELEASE(key); - RELEASE(dict); - return nil; - } - if (skipSpace(pld) == NO) - { - RELEASE(key); - RELEASE(val); - RELEASE(dict); - 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); - RELEASE(dict); - 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++; - result = dict; - } - break; - - 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) - { - RELEASE(array); - return nil; - } - if (skipSpace(pld) == NO) - { - RELEASE(val); - RELEASE(array); - return nil; - } - if (pld->ptr[pld->pos] == ',') - { - pld->pos++; - } - else if (pld->ptr[pld->pos] != ')') - { - pld->err = @"unexpected character (wanted ',' or ')')"; - RELEASE(val); - RELEASE(array); - 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++; - result = array; - } - break; - - case '<': - pld->pos++; - if (pld->pos < pld->end && pld->ptr[pld->pos] == '*') - { - const unichar *ptr; - unsigned min; - unsigned len = 0; - unsigned i; - - pld->pos++; - min = pld->pos; - ptr = &(pld->ptr[min]); - while (pld->pos < pld->end && pld->ptr[pld->pos] != '>') - { - pld->pos++; - } - len = pld->pos - min; - if (len > 1) - { - unichar type = *ptr++; - - len--; - if (type == 'I') - { - char buf[len+1]; - - for (i = 0; i < len; i++) buf[i] = (char)ptr[i]; - buf[len] = '\0'; - result = [[NSNumber alloc] initWithLong: atol(buf)]; - } - else if (type == 'B') - { - if (ptr[0] == 'Y') - { - result = [[NSNumber alloc] initWithBool: YES]; - } - else if (ptr[0] == 'N') - { - result = [[NSNumber alloc] initWithBool: NO]; - } - else - { - pld->err = @"bad value for bool"; - return nil; - } - } - else if (type == 'D') - { - NSString *str; - - str = [[NSString alloc] initWithCharacters: ptr - length: len]; - result = [[NSCalendarDate alloc] initWithString: str - calendarFormat: @"%Y-%m-%d %H:%M:%S %z"]; - RELEASE(str); - } - else if (type == 'R') - { - unichar buf[len]; - double d = 0.0; - - for (i = 0; i < len; i++) buf[i] = (char)ptr[i]; - GSScanDouble(buf, len, &d); - result = [[NSNumber alloc] initWithDouble: d]; - } - else - { - pld->err = @"unrecognized type code after '<*'"; - return nil; - } - } - else - { - pld->err = @"missing type code after '<*'"; - return nil; - } - if (pld->pos >= pld->end) - { - pld->err = @"unexpected end of string when parsing data"; - return nil; - } - if (pld->ptr[pld->pos] != '>') - { - pld->err = @"unexpected character in string"; - return nil; - } - pld->pos++; - } - else - { - NSMutableData *data; - unsigned max = pld->end - 1; - unsigned char buf[BUFSIZ]; - unsigned len = 0; - - data = [[NSMutableData alloc] initWithCapacity: 0]; - skipSpace(pld); - while (pld->pos < max - && GS_IS_HEXDIGIT(pld->ptr[pld->pos]) - && GS_IS_HEXDIGIT(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; - } - skipSpace(pld); - } - 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++; - result = data; - } - break; - - case '"': - result = parseQuotedString(pld); - break; - - default: - result = parseUnquotedString(pld); - break; - } - if (start == YES && result != nil) - { - if (skipSpace(pld) == YES) - { - pld->err = @"extra data after parsed string"; - result = nil; // Not at end of string. - } - } - return result; -} - -#ifdef 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) -{ - CREATE_AUTORELEASE_POOL(arp); - id result = nil; - - node = elementNode(node); - if (node != nil) - { - NSString *name; - NSString *content; - GSXMLNode *children; - - name = [node name]; - children = [node firstChild]; - content = [children content]; - children = elementNode(children); - - if ([name isEqualToString: @"string"] - || [name isEqualToString: @"key"]) - { - if (content == nil) - { - content = @""; - } - else - { - NSRange r; - - r = [content rangeOfString: @"\\"]; - if (r.length == 1) - { - unsigned len = [content length]; - unichar buf[len]; - unsigned pos = r.location; - - [content getCharacters: buf]; - while (pos < len) - { - if (++pos < len) - { - if ((buf[pos] == 'u' || buf[pos] == 'U') - && (len >= pos + 4)) - { - unichar val = 0; - unsigned i; - BOOL ok = YES; - - for (i = 1; i < 5; i++) - { - unichar c = buf[pos + i]; - - if (c >= '0' && c <= '9') - { - val = (val << 4) + c - '0'; - } - else if (c >= 'A' && c <= 'F') - { - val = (val << 4) + c - 'A' + 10; - } - else if (c >= 'a' && c <= 'f') - { - val = (val << 4) + c - 'a' + 10; - } - else - { - ok = NO; - } - } - if (ok == YES) - { - len -= 5; - memcpy(&buf[pos], &buf[pos+5], - (len - pos) * sizeof(unichar)); - buf[pos - 1] = val; - } - } - while (pos < len && buf[pos] != '\\') - { - pos++; - } - } - } - content = [NSString stringWithCharacters: buf length: len]; - } - } - result = content; - } - else if ([name isEqualToString: @"true"]) - { - result = [NSNumber numberWithBool: YES]; - } - else if ([name isEqualToString: @"false"]) - { - result = [NSNumber numberWithBool: NO]; - } - else if ([name isEqualToString: @"integer"]) - { - if (content == nil) - { - content = @"0"; - } - result = [NSNumber numberWithInt: [content intValue]]; - } - else if ([name isEqualToString: @"real"]) - { - if (content == nil) - { - content = @"0.0"; - } - result = [NSNumber numberWithDouble: [content doubleValue]]; - } - else if ([name isEqualToString: @"date"]) - { - if (content == nil) - { - content = @""; - } - result = [NSCalendarDate dateWithString: content - calendarFormat: @"%Y-%m-%d %H:%M:%S %z"]; - } - else if ([name isEqualToString: @"data"]) - { - result = [GSMimeDocument decodeBase64String: content]; - } - // container class - else if ([name isEqualToString: @"array"]) - { - NSMutableArray *container = [NSMutableArray array]; - - while (children != nil) - { - id val; - - val = nodeToObject(children); - [container addObject: val]; - children = [children nextElement]; - } - result = container; - } - else if ([name isEqualToString: @"dict"]) - { - NSMutableDictionary *container = [NSMutableDictionary dictionary]; - - while (children != nil) - { - NSString *key; - id val; - - key = nodeToObject(children); - children = [children nextElement]; - val = nodeToObject(children); - children = [children nextElement]; - [container setObject: val forKey: key]; - } - result = container; - } - } - RETAIN(result); - RELEASE(arp); - return AUTORELEASE(result); -} -#endif - -static void -setupPl() -{ -#ifdef HAVE_LIBXML - /* - * Cache XML node information. - */ - XML_ELEMENT_NODE = [GSXMLNode typeFromDescription: @"XML_ELEMENT_NODE"]; -#endif - plAlloc = (id (*)(id, SEL, NSZone*)) - [NSStringClass methodForSelector: @selector(allocWithZone:)]; - plInit = (id (*)(id, SEL, unichar*, unsigned int)) - [NSStringClass instanceMethodForSelector: plSel]; - - plArray = [GSMutableArray class]; - plAdd = (id (*)(id, SEL, id)) - [plArray instanceMethodForSelector: @selector(addObject:)]; - - plDictionary = [GSMutableDictionary class]; - plSet = (id (*)(id, SEL, id, id)) - [plDictionary instanceMethodForSelector: @selector(setObject:forKey:)]; - - setupHexdigits(); - setupQuotables(); - setupWhitespace(); -} - -static id -GSPropertyList(NSString *string) -{ - pldata _pld; - pldata *pld = &_pld; - unsigned length = [string length]; - NSData *d; - id pl; -#ifdef HAVE_LIBXML - unsigned index = 0; -#endif - - /* - * An empty string is a nil property list. - */ - if (length == 0) - { - return nil; - } - - if (plAlloc == 0) - { - setupPl(); - } - -#ifdef HAVE_LIBXML - if (whitespaceBitmapRep == NULL) - { - setupWhitespace(); - } - while (index < length) - { - unsigned c = [string characterAtIndex: index]; - - if (GS_IS_WHITESPACE(c) == NO) - { - break; - } - index++; - } - /* - * A string beginning with a 'ptr[pld->pos] == '"') - { - key = parseQuotedString(pld); - } - else - { - key = parseUnquotedString(pld); - } - if (key == nil) - { - DESTROY(dict); - break; - } - if (skipSpace(pld) == NO) - { - pld->err = @"incomplete final entry (no semicolon?)"; - RELEASE(key); - DESTROY(dict); - break; - } - 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); - DESTROY(dict); - break; - } - if (pld->ptr[pld->pos] == '"') - { - val = parseQuotedString(pld); - } - else - { - val = parseUnquotedString(pld); - } - if (val == nil) - { - RELEASE(key); - DESTROY(dict); - break; - } - if (skipSpace(pld) == NO) - { - pld->err = @"missing final semicolon"; - RELEASE(key); - RELEASE(val); - DESTROY(dict); - break; - } - (*plSet)(dict, @selector(setObject:forKey:), val, key); - RELEASE(key); - RELEASE(val); - if (pld->ptr[pld->pos] == ';') - { - pld->pos++; - } - else - { - pld->err = @"unexpected character (wanted ';')"; - DESTROY(dict); - break; - } - } - else - { - pld->err = @"unexpected character (wanted '=' or ';')"; - RELEASE(key); - DESTROY(dict); - break; - } - } - if (dict == nil && _pld.err != nil) - { - RELEASE(dict); - [NSException raise: NSGenericException - format: @"Parse failed at line %d (char %d) - %@", - _pld.lin, _pld.pos, _pld.err]; - } - return AUTORELEASE(dict); -} -