From a6ae2d4a2d73d550fae6be08ddebd6225b17f139 Mon Sep 17 00:00:00 2001 From: Richard Frith-MacDonald Date: Thu, 18 Jul 2013 15:40:11 +0000 Subject: [PATCH] fix for word size issues with arrays git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@36905 72102866-910b-0410-8b05-ffd578937521 --- Source/NSUnarchiver.m | 214 ++++++++++++++++++++++++++++++--- Tests/base/coding/basictypes.m | 44 +++++-- 2 files changed, 232 insertions(+), 26 deletions(-) diff --git a/Source/NSUnarchiver.m b/Source/NSUnarchiver.m index 516b861f9..e924e9d6b 100644 --- a/Source/NSUnarchiver.m +++ b/Source/NSUnarchiver.m @@ -538,6 +538,8 @@ static unsigned encodingVersion; NSUInteger offset = 0; unsigned int size = (unsigned int)objc_sizeof_type(type); unsigned char info; + unsigned char ainfo; + unsigned char amask; NSUInteger count; (*tagImp)(src, tagSel, &info, 0, &cursor); @@ -616,27 +618,211 @@ static unsigned encodingVersion; (*dValImp)(self, dValSel, type, (char*)buf + offset); offset += size; } + return; } - else + + (*tagImp)(src, tagSel, &ainfo, 0, &cursor); + amask = (ainfo & _GSC_MASK); + + /* If we have a perfect type match or we are coding a class as an ID, + * we can just decode the array simply. + */ + if (info == amask || (info == _GSC_ID && amask == _GSC_CID)) { - unsigned char ainfo; - - (*tagImp)(src, tagSel, &ainfo, 0, &cursor); - if (info != (ainfo & _GSC_MASK)) - { - if (info != _GSC_ID || (ainfo & _GSC_MASK) != _GSC_CID) - { - [NSException raise: NSInternalInconsistencyException - format: @"expected %s and got %s", - typeToName2(info), typeToName2(ainfo)]; - } - } - for (i = 0; i < count; i++) { (*desImp)(src, desSel, (char*)buf + offset, type, &cursor, nil); offset += size; } + return; + } + + /* This will raise an exception if the types don't match at all. + */ + typeCheck(*type, ainfo); + + /* We fall through to here only when we have to decode a value + * whose natural size on this system is not the same as on the + * machine on which the archive was created. + */ + + if (*type == _C_FLT) + { + for (i = 0; i < count; i++) + { + double d; + + (*desImp)(src, desSel, &d, @encode(double), &cursor, nil); + *(float*)(buf + offset) = (float)d; + offset += size; + } + } + else if (*type == _C_DBL) + { + for (i = 0; i < count; i++) + { + float f; + + (*desImp)(src, desSel, &f, @encode(float), &cursor, nil); + *(double*)(buf + offset) = (double)f; + offset += size; + } + } + else if (*type == _C_SHT + || *type == _C_INT + || *type == _C_LNG + || *type == _C_LNG_LNG) + { + int64_t big; + int64_t max; + int64_t min; + + switch (size) + { + case 1: + max = 0x80; + min = 0x7f; + break; + case 2: + max = 0x8000; + min = 0x7fff; + break; + case 4: + max = 0x80000000; + min = 0x7fffffff; + break; + default: + max = 0x8000000000000000; + min = 0x7fffffffffffffff; + } + + for (i = 0; i < count; i++) + { + void *address = (void*)buf + offset; + + switch (ainfo & _GSC_SIZE) + { + case _GSC_I16: /* Encoded as 16-bit */ + { + int16_t val; + + (*desImp)(src, desSel, &val, @encode(int16_t), &cursor, nil); + big = val; + break; + } + + case _GSC_I32: /* Encoded as 32-bit */ + { + int32_t val; + + (*desImp)(src, desSel, &val, @encode(int32_t), &cursor, nil); + big = val; + break; + } + + case _GSC_I64: /* Encoded as 64-bit */ + { + (*desImp)(src, desSel, &big, @encode(int64_t), &cursor, nil); + break; + } + } + /* + * Now we copy from the big value to the destination location. + */ + switch (size) + { + case 1: + *(int8_t*)address = (int8_t)big; + break; + case 2: + *(int16_t*)address = (int16_t)big; + break; + case 4: + *(int32_t*)address = (int32_t)big; + break; + default: + *(int64_t*)address = big; + } + if (big < min || big > max) + { + NSLog(@"Loss of information converting large decoded value"); + } + offset += size; + } + } + else + { + uint64_t big; + uint64_t max; + + switch (size) + { + case 1: + max = 0xff; + break; + case 2: + max = 0xffff; + break; + case 4: + max = 0xffffffff; + break; + default: + max = 0xffffffffffffffff; + } + + for (i = 0; i < count; i++) + { + void *address = (void*)buf + offset; + + switch (info & _GSC_SIZE) + { + case _GSC_I16: /* Encoded as 16-bit */ + { + uint16_t val; + + (*desImp)(src, desSel, &val, @encode(uint16_t), &cursor, nil); + big = val; + break; + } + + case _GSC_I32: /* Encoded as 32-bit */ + { + uint32_t val; + + (*desImp)(src, desSel, &val, @encode(uint32_t), &cursor, nil); + big = val; + break; + } + + case _GSC_I64: /* Encoded as 64-bit */ + { + (*desImp)(src, desSel, &big, @encode(uint64_t), &cursor, nil); + break; + } + } + /* + * Now we copy from the big value to the destination location. + */ + switch (size) + { + case 1: + *(uint8_t*)address = (uint8_t)big; + break; + case 2: + *(uint16_t*)address = (uint16_t)big; + break; + case 4: + *(uint32_t*)address = (uint32_t)big; + break; + case 8: + *(uint64_t*)address = big; + } + if (big > max) + { + NSLog(@"Loss of information converting large decoded value"); + } + offset += size; + } } } diff --git a/Tests/base/coding/basictypes.m b/Tests/base/coding/basictypes.m index 3df826257..ea4548349 100644 --- a/Tests/base/coding/basictypes.m +++ b/Tests/base/coding/basictypes.m @@ -11,10 +11,11 @@ @interface Model : NSObject { - int cint; - unsigned int cuint; - NSInteger nsint; - NSUInteger nsuint; + int cint; + unsigned int cuint; + NSInteger nsint; + NSUInteger nsuint; + NSInteger a[4]; } @end @implementation Model @@ -24,33 +25,51 @@ cuint = 1234567890; nsint = -1234567890; nsuint = 1234567890; + a[0] = 1; + a[1] = 1000; + a[2] = 1000000; + a[3] = 100000000; } - (BOOL)testCInt:(Model *)o { - return (cint == o->cint); + return (cint == o->cint) ? YES : NO; } - (BOOL)testCUInt:(Model *)o { - return (cuint == o->cuint); + return (cuint == o->cuint) ? YES : NO; } - (BOOL)testNSInteger:(Model *)o { - return (nsint == o->nsint); + return (nsint == o->nsint) ? YES : NO; } - (BOOL)testNSUInteger:(Model *)o { - return (nsuint == o->nsuint); + return (nsuint == o->nsuint) ? YES : NO; +} +- (BOOL)testArray:(Model *)o +{ + return (a[0] == o->a[0] + && a[1] == o->a[1] + && a[2] == o->a[2] + && a[3] == o->a[3]) ? YES : NO; } -(void)encodeWithCoder:(NSCoder *)coder { - [coder encodeValueOfObjCType:@encode(int) at:&cint]; - [coder encodeValueOfObjCType:@encode(unsigned int) at:&cuint]; - [coder encodeValueOfObjCType:@encode(NSInteger) at:&nsint]; - [coder encodeValueOfObjCType:@encode(NSUInteger) at:&nsuint]; + [coder encodeArrayOfObjCType: @encode(NSInteger) count: 4 at: a]; + [coder encodeValueOfObjCType: @encode(int) at: &cint]; + [coder encodeValueOfObjCType: @encode(unsigned int) at: &cuint]; + [coder encodeValueOfObjCType: @encode(NSInteger) at: &nsint]; + [coder encodeValueOfObjCType: @encode(NSUInteger) at: &nsuint]; } -(id)initWithCoder:(NSCoder *)coder { + long long ia[4]; + [coder decodeArrayOfObjCType: @encode(long long) count: 4 at: ia]; + a[0] = ia[0]; + a[1] = ia[1]; + a[2] = ia[2]; + a[3] = ia[3]; /* encoded as int - decoded as NSInteger. */ [coder decodeValueOfObjCType: @encode(NSInteger) at: &nsint]; /* encoded as unsinged int - decoded as NSUInteger. */ @@ -212,6 +231,7 @@ int main() PASS([obj1 testCUInt:obj2], "archiving as unsigned int - dearchiving as NSUInteger"); PASS([obj1 testNSInteger:obj2], "archiving as NSInteger - dearchiving as int"); PASS([obj1 testNSUInteger:obj2], "archiving as NSUInteger - dearchiving as unsigned int"); + PASS([obj1 testArray:obj2], "archiving as NSInteger array - dearchiving as long long"); [pool release]; pool = nil; return 0;