Permalink
Browse files

Fix conversion of BIT fields (fixes #2254)

  • Loading branch information...
dmoagx committed Oct 2, 2015
1 parent c5878bd commit 11f5bf55b3d6ecb9afe3a19d60aa9669bd449e42
@@ -0,0 +1,71 @@
//
// DataConversion_Tests.m
// SPMySQLFramework
//
// Created by Max Lohrmann on 01.10.15.
// Copyright (c) 2015 Max Lohrmann. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// More info at <https://github.com/sequelpro/sequelpro>
@interface DataConversion_Tests : XCTestCase
- (void)test_bitStringWithBytes;
@end
@implementation DataConversion_Tests
- (void)test_bitStringWithBytes
{
// BIT(1)
{
unsigned char y = 1;
unsigned char n = 0;
XCTAssertEqualObjects(_bitStringWithBytes(&y,sizeof(y),1), @"1");
XCTAssertEqualObjects(_bitStringWithBytes(&n,sizeof(n),0), @"0");
}
// BIT(3)
{
const char input[] = {5};
NSUInteger bitSize = 3;
NSString *res = _bitStringWithBytes(input,sizeof(input),bitSize);
XCTAssertEqualObjects(res, @"101");
}
// BIT(16)
{
const char input[] = {0xcc,0xf0};
NSUInteger bitSize = 16;
NSString *res = _bitStringWithBytes(input,sizeof(input),bitSize);
XCTAssertEqualObjects(res, @"1100110011110000");
}
// BIT(20)
{
const char input[] = {0x0f,0xcc,0xf0};
NSUInteger bitSize = 20;
NSString *res = _bitStringWithBytes(input,sizeof(input),bitSize);
XCTAssertEqualObjects(res, @"11111100110011110000");
}
}
@end
@@ -209,27 +209,26 @@ static inline SPMySQLResultFieldProcessor _processorForField(MYSQL_FIELD aField)
return nil;
}
// Ensure padLength is never lower than the length
if (padLength < bitLength) {
padLength = bitLength;
}
// use whatever is smaller. padLength comes from BIT(x), bitLength from the actual bytes transmitted.
// if bitLength < padLength it means the value is smaller than what the field can accomodate.
// if bitLength > padLength it means BIT(x) is not a full n bytes long and was extended by mysqls storage.
// In that case the additional bits should still be 0 as mysql does not allow to set bits over the size of x.
bitLength = MIN(bitLength,padLength);
// Generate a nul-terminated C string representation of the binary data
char *cStringBuffer = malloc(padLength + 1);
cStringBuffer[padLength] = '\0';
memset(cStringBuffer, '0', padLength);
while (i < bitLength)
{
// start with the least significant bit (the rightmost bit in the last byte) and move left
unsigned char bitInByteMask = i % 8; // 0-7, the cycle is 0,1,...,7,0,...
unsigned long bytesOffset = (length - 1) - (i >> 3); // i>>3 == floor(i/8)
++i;
cStringBuffer[padLength - i] = ((bytes[length - 1 - (i >> 3)] >> (i & 0x7)) & 1 ) ? '1' : '0';
cStringBuffer[padLength - i] = ((bytes[bytesOffset] & (1 << bitInByteMask)) != 0) ? '1' : '0';
}
while (i++ < padLength)
{
cStringBuffer[padLength - i] = '0';
}
cStringBuffer[padLength] = '\0';
// Convert to a string
NSString *returnString = [NSString stringWithUTF8String:cStringBuffer];

0 comments on commit 11f5bf5

Please sign in to comment.