Author: rfm
Date: Mon Jul 14 08:38:16 2014
New Revision: 37994
URL: http://svn.gna.org/viewcvs/gnustep?rev=37994&view=rev
Log:
json fixes by Larry Campbell
Added:
libs/base/trunk/Tests/base/NSJSONSerialization/tests00.m
Modified:
libs/base/trunk/ChangeLog
libs/base/trunk/Source/NSJSONSerialization.m
Modified: libs/base/trunk/ChangeLog
URL:
http://svn.gna.org/viewcvs/gnustep/libs/base/trunk/ChangeLog?rev=37994&r1=37993&r2=37994&view=diff
==============================================================================
--- libs/base/trunk/ChangeLog (original)
+++ libs/base/trunk/ChangeLog Mon Jul 14 08:38:16 2014
@@ -1,3 +1,9 @@
+2014-02-17 Larry Campbell <[email protected]>
+
+ * Source/NSJSONSerialization.m:
+ * Tests/base/NSJSONSerialization/tests00.m:
+ Fixes for bug #41628
+
2014-07-12 Yavor Doganov <[email protected]>
* Tests/GNUmakefile:
Modified: libs/base/trunk/Source/NSJSONSerialization.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/base/trunk/Source/NSJSONSerialization.m?rev=37994&r1=37993&r2=37994&view=diff
==============================================================================
--- libs/base/trunk/Source/NSJSONSerialization.m (original)
+++ libs/base/trunk/Source/NSJSONSerialization.m Mon Jul 14 08:38:16 2014
@@ -154,23 +154,58 @@
{
case NSUTF8StringEncoding:
{
- int i = -1;
-
// Read one UTF8 character from the stream
- do
+ NSUInteger i = 0;
+ NSInteger n;
+
+ n = [stream read: &bytes[0] maxLength: 1];
+ if (n != 1)
{
- [stream read: &bytes[++i] maxLength: 1];
+ state->error = [stream streamError];
+ if (state->error == nil)
+ {
+ state->error
+ = [NSError errorWithDomain: NSCocoaErrorDomain
+ code: 0
+ userInfo: nil];
+ }
+ break;
}
- while (bytes[i] & 0xf);
+ else
+ {
+ if ((bytes[0] & 0xC0) == 0xC0)
+ {
+ for (i = 1; i <= 5; i++)
+ if ((bytes[0] & (0x40 >> i)) == 0)
+ break;
+ }
+ }
if (0 == i)
{
state->buffer[0] = bytes[0];
}
else
{
- str = [[NSString alloc] initWithUTF8String: (char*)bytes];
- [str getCharacters: state->buffer range: NSMakeRange(0,1)];
- [str release];
+ n = [stream read: &bytes[1] maxLength: i];
+ if (n == i)
+ {
+ str = [[NSString alloc] initWithUTF8String:
(char*)bytes];
+ [str getCharacters: state->buffer
+ range: NSMakeRange(0,1)];
+ [str release];
+ }
+ else
+ {
+ state->error = [stream streamError];
+ if (state->error == nil)
+ {
+ state->error
+ = [NSError errorWithDomain: NSCocoaErrorDomain
+ code: 0
+ userInfo: nil];
+ }
+ break;
+ }
}
break;
}
@@ -209,6 +244,7 @@
state->sourceIndex = -1;
state->bufferIndex = 0;
state->bufferLength = 1;
+ return;
}
// Use an NSString to do the character set conversion. We could do this more
// efficiently. We could also reuse the string.
@@ -243,7 +279,7 @@
{
state->sourceIndex++;
state->bufferIndex++;
- if (state->bufferIndex >= BUFFER_SIZE)
+ if (state->bufferIndex >= state->bufferLength)
{
state->updateBuffer(state);
}
Added: libs/base/trunk/Tests/base/NSJSONSerialization/tests00.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/base/trunk/Tests/base/NSJSONSerialization/tests00.m?rev=37994&view=auto
==============================================================================
--- libs/base/trunk/Tests/base/NSJSONSerialization/tests00.m (added)
+++ libs/base/trunk/Tests/base/NSJSONSerialization/tests00.m Mon Jul 14
08:38:16 2014
@@ -0,0 +1,346 @@
+//
+// Created by Larry Campbell on 12/12/08.
+//
+
+#import <Foundation/Foundation.h>
+#import "ObjectTesting.h"
+
+
+@interface GnustepBaseTests : NSObject {
+ unsigned _successes;
+ unsigned _failures;
+}
+@end
+
+@implementation GnustepBaseTests
+
+- (BOOL) performTest: (NSString *)name
+{
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ BOOL result;
+
+ NSLog(@"Performing test %@", name);
+ NS_DURING
+ {
+ [self performSelector: NSSelectorFromString(name)];
+ _successes++;
+ result = YES;
+ }
+ NS_HANDLER
+ {
+ NSLog(@"Test %@ failed: %@", name, [localException reason]);
+ _failures++;
+ result = NO;
+ }
+ NS_ENDHANDLER
+
+ [pool release];
+ return result;
+}
+
+- (unsigned) successes
+{
+ return _successes;
+}
+
+- (unsigned) failures
+{
+ return _failures;
+}
+
+@end
+
+@interface GnustepBaseTests(TheTests)
+@end
+
+@implementation GnustepBaseTests(TheTests)
+
+- (void) cr39118
+{
+ int x = 1999999999;
+ NSString *s = @"1999999999";
+ NSAssert([s intValue] == x, @"intValue botch");
+}
+
+// verify that distinct strings get distinct hashes even if strings are very
long
+- (void) cr48439
+{
+ NSMutableSet *hashes = [NSMutableSet set];
+ NSArray *strings = [NSArray arrayWithObjects:
+ @"",
+ @"a",
+ @"aa",
+ @"123456789012345678901234567890123456789012345678901234567890123",
+ @"123456789012345678901234567890123456789012345678901234567890123a",
+ @"123456789012345678901234567890123456789012345678901234567890123b",
+ @"123456789012345678901234567890123456789012345678901234567890123c",
+ @"123456789012345678901234567890123456789012345678901234567890123d",
+ @"1234567890123456789012345678901234567890123456789012345678901234",
+ @"1234567890123456789012345678901234567890123456789012345678901234a",
+ @"1234567890123456789012345678901234567890123456789012345678901234b",
+ @"1234567890123456789012345678901234567890123456789012345678901234c",
+ @"1234567890123456789012345678901234567890123456789012345678901234d",
+ @"12345678901234567890123456789012345678901234567890123456789012345",
+ @"12345678901234567890123456789012345678901234567890123456789012345a",
+ @"12345678901234567890123456789012345678901234567890123456789012345b",
+ @"12345678901234567890123456789012345678901234567890123456789012345c",
+ @"12345678901234567890123456789012345678901234567890123456789012345d",
+
@"123456789012345678901234567890123456789012345678901234567890123456789012345",
+
@"123456789012345678901234567890123456789012345678901234567890123456789012345a",
+
@"123456789012345678901234567890123456789012345678901234567890123456789012345b",
+
@"123456789012345678901234567890123456789012345678901234567890123456789012345c",
+
@"123456789012345678901234567890123456789012345678901234567890123456789012345d",
+ nil];
+ NSString *s;
+ NSEnumerator *e;
+
+ e = [strings objectEnumerator];
+ while ((s = [e nextObject]) != nil)
+ [hashes addObject:[NSNumber numberWithUnsignedInt:[s hash]]];
+
+ NSAssert([hashes count] == [strings count], @"hash botch");
+}
+
+// this also covers CR 150661
+- (void)cr153594
+{
+ NSDate *t1 = [NSDate date];
+ NSDate *t2;
+ NSData *d;
+
+ d = [NSKeyedArchiver archivedDataWithRootObject: t1];
+ t2 = [NSKeyedUnarchiver unarchiveObjectWithData: d];
+ NSAssert([t1 isEqual:t2], @"equality botch");
+}
+
+- (void)cr1524466
+{
+ NSURL *u = [[[NSURL alloc] initWithScheme: @"http" host: @"1.2.3.4" path:
@"/a?b;foo"] autorelease];
+ NSString *s = [[u absoluteURL] description];
+ NSAssert([s isEqual: @"http://1.2.3.4/a?b;foo"], @"NSURL encoding botch");
+}
+
+- (void)cr2096767
+{
+ static struct {
+ NSString *inputString;
+ NSTimeInterval increment;
+ NSString *expectedOutput;
+ } tests[] = {
+ { @"2006-04-22 22:22:22:901", 0.0, @"2006-04-22 22:22:22:901" },
// gnustep bug https://savannah.gnu.org/bugs/?func=detailitem&item_id=16426
+ { @"2006-04-22 22:22:22:999", 0.0, @"2006-04-22 22:22:22:999" },
+ { @"2006-04-22 22:22:22:999", 0.0005, @"2006-04-22 22:22:22:999" },
+ { @"2006-04-22 22:22:22:999", 0.0006, @"2006-04-22 22:22:22:999" },
+ { @"2006-04-22 22:22:22:999", 0.0007, @"2006-04-22 22:22:22:999" },
+ { @"2006-04-22 22:22:22:999", 0.0008, @"2006-04-22 22:22:22:999" },
+ { @"2006-04-22 22:22:22:999", 0.00089, @"2006-04-22 22:22:22:999" },
+ { @"2006-04-22 22:22:22:999", 0.000899, @"2006-04-22 22:22:22:999" },
+ { @"2006-04-22 22:22:22:999", 0.0008999, @"2006-04-22 22:22:22:999" },
+ { @"2006-04-22 22:22:22:999", 0.00089999, @"2006-04-22 22:22:23:000" },
+ { @"2006-04-22 22:22:22:999", 0.0009, @"2006-04-22 22:22:23:000" },
// CR https://bugzilla.akamai.com/show_bug.cgi?id=2096767
+ };
+ unsigned i;
+ NSString *fmt = [NSString stringWithFormat: @"%%Y-%%m-%%d %%H:%%M:%%S:%%F"];
+
+ for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
+ {
+ NSString *inputString = tests[i].inputString;
+ NSString *expectedOutput = tests[i].expectedOutput;
+ NSCalendarDate *d1 = [NSCalendarDate dateWithString:inputString
calendarFormat:fmt];
+ NSCalendarDate *d2 = [[[NSCalendarDate alloc]
initWithTimeInterval:tests[i].increment sinceDate:d1] autorelease];
+ NSString *result = [d2 descriptionWithCalendarFormat:fmt];
+ NSLog(@"input string: %@, increment: %.4f", inputString,
tests[i].increment);
+ NSLog(@"input date: %@", d1);
+ NSLog(@"output date: %@", result);
+ NSLog(@"expect: %@", expectedOutput);
+ NSAssert([result isEqualToString:expectedOutput], @"mismatch");
+ }
+}
+
+- (void)cr2549370
+{
+ NSString *path = @"/tmp/json.data";
+ NSString *string = @"Hello garçon! ¡Ola! A little more coöperation
please!";
+ NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+ NSMutableArray *array = [NSMutableArray array];
+ NSData *d;
+ NSInputStream *stream;
+
+ [array addObject:[NSDictionary dictionaryWithObjectsAndKeys:string,
@"nickname", nil]];
+ [dict setObject:array forKey: @"datacenters"];
+
+ d = [NSJSONSerialization dataWithJSONObject:dict
options:NSJSONWritingPrettyPrinted error:0];
+ [d writeToFile:path atomically:NO];
+
+ stream = [NSInputStream inputStreamWithFileAtPath:path];
+ [stream open];
+ dict = [NSJSONSerialization JSONObjectWithStream:stream options:0 error:0];
+ dict = [[dict objectForKey: @"datacenters"] objectAtIndex:0];
+ NSAssert(dict != nil, @"JSON returned nil");
+ NSAssert([string isEqualToString:[dict objectForKey: @"nickname"]], @"data
mismatch");
+}
+
+void checkstr(NSString *expected, NSString *got)
+{
+ if ([expected caseInsensitiveCompare:got] != NSOrderedSame) {
+ NSLog(@"expected %@", expected);
+ NSLog(@" got %@", got);
+ [NSException raise: @"error" format: @"test failed"];
+ }
+}
+
+// This is copied from servermonitor. We want to use the same quoting rules it
does.
+// We use this only for the username and password; we assume the
path/query/fragment
+// is already escaped.
+static NSString *percentQuoted(NSString *s)
+{
+ NSMutableString *retval = [NSMutableString stringWithCapacity:[s length]];
+ const unsigned char *p = (const unsigned char *)[s UTF8String];
+ unsigned char c;
+ const char *allowedNonalnumChars = "-_,.'~!$&*();";
+
+ while ((c = *p++) != '\0') {
+ if (isalnum(c) || strchr(allowedNonalnumChars, c) != 0)
+ [retval appendFormat: @"%c", c];
+ else
+ [retval appendFormat: @"%%%02x", c];
+ }
+ return retval;
+}
+
+- (void)urlTest
+{
+ static NSString *schemes[] = { @"ftp", @"http", @"https" };
+ static NSString *hosts[] = { @"www.akamai.com", @"10.0.1.1", @"localhost" };
+ static NSString *usernames[] = { nil, @"username", @"foo", @"a_username" };
+ static NSString *passwords[] = { nil, @"password", @"M@nx2y#" };
+
+ // The path/query/fragment part here must be percent-quoted
+ // as it would have to be if pasted into a curl command.
+ struct {
+ NSString *pqf; // path, query, fragment
+ NSString *path; // expected path returned from NSURL (nil if same as pqf)
+ } pqfs[] = {
+ { @"/", nil },
+ { @"/foo/bar/zot", nil },
+ { @"/a%20dillar%20a%20dollar", nil },
+ { @"/foo:bar:zot", nil },
+ { @"/a?b;foo", @"/a" },
+ { @"/a%25b", nil },
+ {
@"/MHcwdTBOMEwwSjAJBgUrDgMCGgUABBScDhI23ZEqCpe2zGqbkoJVvUaDTgQUf/ZMNigUrs0eN6/eWvJbw6CsK/4CEQCbL3Mm0kXS8q7t0jI7E5gdoiMwITAfBgkrBgEFBQcwAQIEEgQQi7kTQMz7QK60KI2PnRR3mg==",
+ nil },
+ {
@"/interface/6/?mode=rc3&outputType=json&url=http%3A%2F%2Fwww.ehow.com%2Fhow_2324118_take-care-paper-cut.html&category=Health&subCategory=Family%20Health&subSubCategory=General%20Family%20Health&pageLocations=PLATFORM_TL|0&flushPage=1",
+ @"/interface/6" },
+ {
@"/d/search/p/enom/xml/domain/multiset/v4/?url=http%3A%2F%2Fnuseek.com&Partner=enom_internal_d2r_derp&config=1234567890&affilData=ip%3d127.0.0.1%26ua%3dIE|6.0|WinNT%26ur%3d&maxListings=10&maxRT=20&maxRTL=20&maxWeb=4&serveUrl=http://parkingweb30/default.pk",
+ @"/d/search/p/enom/xml/domain/multiset/v4" },
+ };
+ unsigned i, j, k, l, m;
+
+ for (i = 0; i < sizeof(schemes)/sizeof(schemes[0]); i++)
+ {
+ NSString *scheme = schemes[i];
+
+ for (j = 0; j < sizeof(hosts)/sizeof(hosts[0]); j++)
+ {
+ NSString *host = hosts[j];
+
+ for (k = 0; k < sizeof(usernames)/sizeof(usernames[0]); k++)
+ {
+ NSString *username = usernames[k];
+
+ for (l = 0; l < sizeof(passwords)/sizeof(passwords[0]); l++)
+ {
+ NSString *password = passwords[l];
+
+ for (m = 0; m < sizeof(pqfs)/sizeof(pqfs[0]); m++)
+ {
+ NSMutableString *hostpart = [NSMutableString string];
+ NSString *pqf = pqfs[m].pqf;
+ NSString *expectedPath = [(pqfs[m].path == nil ? pqf :
pqfs[m].path)
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ NSString *urlstring;
+ NSURL *url;
+
+ expectedPath = [(pqfs[m].path == nil ? pqf :
pqfs[m].path) stringByReplacingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
+
+ if (username != nil)
+ {
+ if (password != nil)
+ {
+ [hostpart appendFormat: @"%@:%@@",
+ percentQuoted(username),
+ percentQuoted(password)];
+ }
+ else
+ {
+ [hostpart appendFormat: @"%@@",
+ percentQuoted(username)];
+ }
+ }
+ [hostpart appendString:host];
+
+ urlstring = [NSString stringWithFormat: @"%@://%@%@",
+ scheme, hostpart, pqf];
+ url = [[[NSURL alloc] initWithString: urlstring]
+ autorelease];
+
+ // work around Apple bug, which rejects
+ // objects containing vertical bar (turns out
+ // gnustep is bug-for-bug compatible here,
+ // so no need to make this Apple-only)
+ if (url == nil && [pqf rangeOfString: @"|"].length != 0)
+ {
+ NSMutableString *fixedObject = [[pqf mutableCopy]
autorelease];
+ unsigned n;
+ do {
+ n = [fixedObject replaceOccurrencesOfString:
@"|" withString: @"%7C" options:0 range:NSMakeRange(0, [fixedObject length])];
+ } while (n != 0);
+ urlstring = [NSString stringWithFormat:
@"%@://%@%@", scheme, hostpart, fixedObject];
+ url = [[[NSURL alloc] initWithString:urlstring]
autorelease];
+ }
+
+ NSAssert(url != nil, @"URL creation failed");
+
+ NSAssert([[url scheme] isEqual:schemes[i]], @"scheme
botch");
+ NSAssert((username == nil) == ([url user] == nil),
@"username existence botch");
+ if (username != nil) {
+ NSAssert([[url user] isEqual:username], @"username
botch");
+ NSAssert((password == nil) == ([url password] ==
nil), @"password existence botch");
+ if (password != nil) {
+ NSString *urlpassword = [[url password]
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ NSAssert([urlpassword isEqual:password],
@"password botch");
+ }
+ }
+ checkstr(expectedPath, [url path]);
+ checkstr(urlstring, [[url absoluteURL] description]);
+ NSAssert([[url host] isEqual:host], @"host botch");
+ NSAssert([[url path] isEqual:expectedPath],
+ @"path botch");
+ }
+ }
+ }
+ }
+ }
+}
+
+@end
+
+
+int main(int argc, char *argv[])
+{
+ int status = 0;
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ GnustepBaseTests *gtb = [GnustepBaseTests new];
+
+ PASS([gtb performTest: @"cr39118"], "cr39118");
+ PASS([gtb performTest: @"cr48439"], "cr48439");
+ PASS([gtb performTest: @"cr153594"], "cr153594");
+ PASS([gtb performTest: @"urlTest"], "urlTest");
+ PASS([gtb performTest: @"cr1524466"], "cr1524466");
+ PASS([gtb performTest: @"cr2096767"], "cr2096767");
+ PASS([gtb performTest: @"cr2549370"], "cr2549370");
+
+ [gtb release];
+
+ [pool release];
+ return status;
+}
_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs