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

Reply via email to