Index: third_party/ocmock/OCMock/NSValue+OCMAdditions.m |
diff --git a/third_party/ocmock/OCMock/NSValue+OCMAdditions.m b/third_party/ocmock/OCMock/NSValue+OCMAdditions.m |
new file mode 100644 |
index 0000000000000000000000000000000000000000..076a25c388aa473d551a77a8232e3298a198f603 |
--- /dev/null |
+++ b/third_party/ocmock/OCMock/NSValue+OCMAdditions.m |
@@ -0,0 +1,107 @@ |
+/* |
+ * Copyright (c) 2014-2015 Erik Doernenburg and contributors |
+ * |
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may |
+ * not use these files except in compliance with the License. You may obtain |
+ * a copy of the License at |
+ * |
+ * http://www.apache.org/licenses/LICENSE-2.0 |
+ * |
+ * Unless required by applicable law or agreed to in writing, software |
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
+ * License for the specific language governing permissions and limitations |
+ * under the License. |
+ */ |
+ |
+#import "NSValue+OCMAdditions.h" |
+ |
+ |
+@implementation NSValue(OCMAdditions) |
+ |
+static CFNumberType OCMNumberTypeForObjCType(const char *objcType) |
+{ |
+ switch (objcType[0]) |
+ { |
+ case 'c': return kCFNumberCharType; |
+ case 'C': return kCFNumberCharType; |
+ case 'B': return kCFNumberCharType; |
+ case 's': return kCFNumberShortType; |
+ case 'S': return kCFNumberShortType; |
+ case 'i': return kCFNumberIntType; |
+ case 'I': return kCFNumberIntType; |
+ case 'l': return kCFNumberLongType; |
+ case 'L': return kCFNumberLongType; |
+ case 'q': return kCFNumberLongLongType; |
+ case 'Q': return kCFNumberLongLongType; |
+ case 'f': return kCFNumberFloatType; |
+ case 'd': return kCFNumberDoubleType; |
+ default: return 0; |
+ } |
+} |
+ |
+ |
+static NSNumber *OCMNumberForValue(NSValue *value) |
+{ |
+#define CREATE_NUM(_type) ({ _type _v; [value getValue:&_v]; @(_v); }) |
+ switch([value objCType][0]) |
+ { |
+ case 'c': return CREATE_NUM(char); |
+ case 'C': return CREATE_NUM(unsigned char); |
+ case 'B': return CREATE_NUM(bool); |
+ case 's': return CREATE_NUM(short); |
+ case 'S': return CREATE_NUM(unsigned short); |
+ case 'i': return CREATE_NUM(int); |
+ case 'I': return CREATE_NUM(unsigned int); |
+ case 'l': return CREATE_NUM(long); |
+ case 'L': return CREATE_NUM(unsigned long); |
+ case 'q': return CREATE_NUM(long long); |
+ case 'Q': return CREATE_NUM(unsigned long long); |
+ case 'f': return CREATE_NUM(float); |
+ case 'd': return CREATE_NUM(double); |
+ default: return nil; |
+ } |
+} |
+ |
+ |
+- (BOOL)getBytes:(void *)outputBuf objCType:(const char *)targetType |
+{ |
+ /* |
+ * See if they are similar number types, and if we can convert losslessly between them. |
+ * For the most part, we set things up to use CFNumberGetValue, which returns false if |
+ * conversion will be lossy. |
+ */ |
+ CFNumberType inputType = OCMNumberTypeForObjCType([self objCType]); |
+ CFNumberType outputType = OCMNumberTypeForObjCType(targetType); |
+ |
+ if(inputType == 0 || outputType == 0) // one or both are non-number types |
+ return NO; |
+ |
+ NSNumber *inputNumber = [self isKindOfClass:[NSNumber class]] ? (NSNumber *)self : OCMNumberForValue(self); |
+ |
+ /* |
+ * Due to some legacy, back-compatible requirements in CFNumber.c, CFNumberGetValue can return true for |
+ * some conversions which should not be allowed (by reading source, conversions from integer types to |
+ * 8-bit or 16-bit integer types). So, check ourselves. |
+ */ |
+ long long min; |
+ long long max; |
+ long long val = [inputNumber longLongValue]; |
+ switch(targetType[0]) |
+ { |
+ case 'B': |
+ case 'c': min = CHAR_MIN; max = CHAR_MAX; break; |
+ case 'C': min = 0; max = UCHAR_MAX; break; |
+ case 's': min = SHRT_MIN; max = SHRT_MAX; break; |
+ case 'S': min = 0; max = USHRT_MAX; break; |
+ default: min = LLONG_MIN; max = LLONG_MAX; break; |
+ } |
+ if(val < min || val > max) |
+ return NO; |
+ |
+ /* Get the number, and return NO if the value was out of range or conversion was lossy */ |
+ return CFNumberGetValue((CFNumberRef)inputNumber, outputType, outputBuf); |
+} |
+ |
+ |
+@end |