diff --git a/ChangeLog b/ChangeLog index 99d3eedbdc..541c6ed8b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2024-11-21 Matvii Jarosh + + * NSValue: add valueWithEdgeInsets and edgeInsetsValue. + * typeEncodingHelper.h: add NSINSETS_ENCODING_PREFIX and + IS_NSINSETS_ENCODING and update comment. + * type_encoding.m: add test NSINSETS_ENCODING_PREFIX. + * GSConcreteValueTamplate.m: add GSEdgeInsetsValue. + * GSConcreteValue.m: add TYPE_ORDER 6. + 2024-11-19 Richard Frith-Macdonald * GSMime: fixed buffer overrun in rare circumstances when decoding diff --git a/Headers/Foundation/NSValue.h b/Headers/Foundation/NSValue.h index a68b4dfa74..36ce47a116 100644 --- a/Headers/Foundation/NSValue.h +++ b/Headers/Foundation/NSValue.h @@ -96,6 +96,14 @@ GS_EXPORT_CLASS */ + (NSValue*) valueWithSize: (NSSize)size; +#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) +/** + * Convenience method to create instance holding an NSEdgeInsets + * structure. + */ ++ (NSValue*) valueWithEdgeInsets: (NSEdgeInsets)insets; +#endif + #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST) /** * Synonym for value:withObjCType: . @@ -166,6 +174,14 @@ GS_EXPORT_CLASS */ - (NSPoint) pointValue; +#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) +/** + * If receiver was initialized with an NSEdgeInsets value, return it, + * else raises NSInternalInconsistencyException. + */ +- (NSEdgeInsets) edgeInsetsValue; +#endif + @end /** diff --git a/Source/GSConcreteValue.m b/Source/GSConcreteValue.m index a4296da0ec..a87488b106 100644 --- a/Source/GSConcreteValue.m +++ b/Source/GSConcreteValue.m @@ -50,3 +50,7 @@ #include "GSConcreteValueTemplate.m" #undef TYPE_ORDER +#define TYPE_ORDER 6 +#include "GSConcreteValueTemplate.m" +#undef TYPE_ORDER + diff --git a/Source/GSConcreteValueTemplate.m b/Source/GSConcreteValueTemplate.m index e29c6b6b30..f93c912739 100644 --- a/Source/GSConcreteValueTemplate.m +++ b/Source/GSConcreteValueTemplate.m @@ -79,6 +79,15 @@ @interface GSSizeValue : NSValue # define GSTemplateValue GSSizeValue # define TYPE_METHOD sizeValue # define TYPE_NAME NSSize +#elif TYPE_ORDER == 6 +@interface GSEdgeInsetsValue : NSValue +{ + NSEdgeInsets data; +} +@end +# define GSTemplateValue GSEdgeInsetsValue +# define TYPE_METHOD edgeInsetsValue +# define TYPE_NAME NSEdgeInsets #endif @implementation GSTemplateValue @@ -164,6 +173,11 @@ - (BOOL) isEqualToValue: (NSValue*)aValue return YES; else return NO; +#elif TYPE_ORDER == 6 + if (data.top == val.top && data.left == val.left && data.bottom == val.bottom && data.right == val.right) + return YES; + else + return NO; #endif } return NO; @@ -213,6 +227,18 @@ - (NSUInteger) hash for (i = 0; i < sizeof(double); i++) hash += val.c[i]; return hash; +#elif TYPE_ORDER == 6 + union { + double d; + unsigned char c[sizeof(double)]; + } val; + NSUInteger hash = 0; + unsigned int i; + + val.d = data.top + data.left + data.bottom + data.right; + for (i = 0; i < sizeof(double); i++) + hash += val.c[i]; + return hash; #endif } @@ -241,6 +267,9 @@ - (NSString *) description return NSStringFromRect(data); #elif TYPE_ORDER == 5 return NSStringFromSize(data); +#elif TYPE_ORDER == 6 + return [NSString stringWithFormat:@"{top = %.2f, left = %.2f, bottom = %.2f, right = %.2f}", + data.top, data.left, data.bottom, data.right]; #endif } diff --git a/Source/NSValue.m b/Source/NSValue.m index f55f0fe393..45069a9239 100644 --- a/Source/NSValue.m +++ b/Source/NSValue.m @@ -35,6 +35,7 @@ #import "Foundation/NSMapTable.h" #import "Foundation/NSLock.h" #import "Foundation/NSData.h" +#import "Foundation/NSGeometry.h" #import "GSPThread.h" @interface GSPlaceholderValue : NSValue @@ -64,6 +65,11 @@ @interface GSSizeValue : NSObject // Help the compiler @class NSDataStatic; // Needed for decoding. @interface NSDataStatic : NSData // Help the compiler @end +#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) +@class GSEdgeInsetsValueValue; +@interface GSEdgeInsetsValue : NSObject // Help the compiler +@end +#endif static Class abstractClass; @@ -75,6 +81,9 @@ @interface NSDataStatic : NSData // Help the compiler static Class rectValueClass; static Class sizeValueClass; static Class GSPlaceholderValueClass; +#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) +static Class edgeInsetsValueClass; +#endif static GSPlaceholderValue *defaultPlaceholderValue; @@ -128,6 +137,9 @@ + (void) initialize rectValueClass = [GSRectValue class]; sizeValueClass = [GSSizeValue class]; GSPlaceholderValueClass = [GSPlaceholderValue class]; + #if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) + edgeInsetsValueClass = [GSEdgeInsetsValue class]; + #endif /* * Set up infrastructure for placeholder values. @@ -217,6 +229,10 @@ + (Class) valueClassWithObjCType: (const char *)type theClass = rectValueClass; else if (strcmp(@encode(NSSize), type) == 0) theClass = sizeValueClass; + #if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) + else if (strcmp(@encode(NSEdgeInsets), type) == 0) + theClass = edgeInsetsValueClass; + #endif /* Try for equivalent types match. */ @@ -232,6 +248,10 @@ + (Class) valueClassWithObjCType: (const char *)type theClass = rectValueClass; else if (GSSelectorTypesMatch(@encode(NSSize), type)) theClass = sizeValueClass; + #if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) + else if (GSSelectorTypesMatch(@encode(NSEdgeInsets), type)) + theClass = edgeInsetsValueClass; + #endif return theClass; } @@ -314,6 +334,17 @@ + (NSValue*) valueWithSize: (NSSize)size return AUTORELEASE(theObj); } +#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) ++ (NSValue*) valueWithEdgeInsets: (NSEdgeInsets)insets +{ + NSValue *theObj; + + theObj = [edgeInsetsValueClass allocWithZone: NSDefaultMallocZone()]; + theObj = [theObj initWithBytes: &insets objCType: @encode(NSEdgeInsets)]; + return AUTORELEASE(theObj); +} +#endif + + (NSValue*) valueFromString: (NSString *)string { NSDictionary *dict = [string propertyList]; @@ -424,6 +455,14 @@ - (NSPoint) pointValue return NSMakePoint(0,0); } +#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) +- (NSEdgeInsets) edgeInsetsValue +{ + [self subclassResponsibility: _cmd]; + return NSEdgeInsetsMake(0,0,0,0); +} +#endif + - (Class) classForCoder { return abstractClass; @@ -468,6 +507,15 @@ - (void) encodeWithCoder: (NSCoder *)coder [coder encodeValueOfObjCType: objctype at: &v]; return; } + #if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) + else if (strncmp(NSINSETS_ENCODING_PREFIX, objctype, strlen(NSINSETS_ENCODING_PREFIX)) == 0) + { + NSEdgeInsets v = [self edgeInsetsValue]; + + [coder encodeValueOfObjCType: objctype at: &v]; + return; + } + #endif NSGetSizeAndAlignment(objctype, &tsize, NULL); data = (void *)NSZoneMalloc([self zone], tsize); @@ -517,6 +565,10 @@ - (id) initWithCoder: (NSCoder *)coder c = [abstractClass valueClassWithObjCType: @encode(NSRect)]; else if (strncmp(NSRANGE_ENCODING_PREFIX, objctype, strlen(NSRANGE_ENCODING_PREFIX)) == 0) c = [abstractClass valueClassWithObjCType: @encode(NSRange)]; + #if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) + else if (strncmp(NSINSETS_ENCODING_PREFIX, objctype, strlen(NSINSETS_ENCODING_PREFIX)) == 0) + c = [abstractClass valueClassWithObjCType: @encode(NSEdgeInsets)]; + #endif else c = [abstractClass valueClassWithObjCType: objctype]; o = [c allocWithZone: [coder objectZone]]; @@ -556,6 +608,16 @@ - (id) initWithCoder: (NSCoder *)coder DESTROY(self); return [o initWithBytes: &v objCType: @encode(NSRect)]; } + #if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) + else if (c == edgeInsetsValueClass) + { + NSEdgeInsets v; + + [coder decodeValueOfObjCType: @encode(NSEdgeInsets) at: &v]; + DESTROY(self); + return [o initWithBytes: &v objCType: @encode(NSEdgeInsets)]; + } + #endif } if (ver < 2) @@ -590,6 +652,16 @@ - (id) initWithCoder: (NSCoder *)coder [coder decodeValueOfObjCType: @encode(NSRect) at: &v]; o = [o initWithBytes: &v objCType: @encode(NSRect)]; } + #if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST) + else if (c == edgeInsetsValueClass) + { + NSEdgeInsets v; + + [coder decodeValueOfObjCType: @encode(NSEdgeInsets) at: &v]; + o = [o initWithBytes: &v objCType: @encode(NSEdgeInsets)]; + } + + #endif else { unsigned char *data; diff --git a/Source/typeEncodingHelper.h b/Source/typeEncodingHelper.h index 3a24741efa..1c708649eb 100644 --- a/Source/typeEncodingHelper.h +++ b/Source/typeEncodingHelper.h @@ -36,6 +36,7 @@ * @encoding(CGSize) -> {CGSize=dd} * @encoding(NSRange) -> {_NSRange=QQ} * @encoding(CFRange) -> {?=qq} +* @encoding(NSEdgeInsets) -> {NSEdgeInsets=dddd} * * Note that NSRange and CFRange are not toll-free bridged. * You cannot pass a CFRange to +[NSValue valueWithRange:] @@ -49,11 +50,13 @@ static const char *CGPOINT_ENCODING_PREFIX = "{CGPoint="; static const char *CGSIZE_ENCODING_PREFIX = "{CGSize="; static const char *CGRECT_ENCODING_PREFIX = "{CGRect="; +static const char *NSINSETS_ENCODING_PREFIX __attribute__((used)) = "{NSEdgeInsets="; static const char *NSRANGE_ENCODING_PREFIX = "{_NSRange="; #define IS_CGPOINT_ENCODING(encoding) (strncmp(encoding, CGPOINT_ENCODING_PREFIX, strlen(CGPOINT_ENCODING_PREFIX)) == 0) #define IS_CGSIZE_ENCODING(encoding) (strncmp(encoding, CGSIZE_ENCODING_PREFIX, strlen(CGSIZE_ENCODING_PREFIX)) == 0) #define IS_CGRECT_ENCODING(encoding) (strncmp(encoding, CGRECT_ENCODING_PREFIX, strlen(CGRECT_ENCODING_PREFIX)) == 0) +#define IS_NSINSETS_ENCODING(encoding) (strncmp(encoding, NSINSETS_ENCODING_PREFIX, strlen(NSINSETS_ENCODING_PREFIX)) == 0) #define IS_NSRANGE_ENCODING(encoding) (strncmp(encoding, NSRANGE_ENCODING_PREFIX, strlen(NSRANGE_ENCODING_PREFIX)) == 0) #endif /* __TYPE_ENCODING_HELPER_H */ diff --git a/Tests/base/KVC/type_encoding.m b/Tests/base/KVC/type_encoding.m index 2911705d1e..3a0ff52f6e 100644 --- a/Tests/base/KVC/type_encoding.m +++ b/Tests/base/KVC/type_encoding.m @@ -9,6 +9,7 @@ int main(int argc, char *argv[]) { PASS(strncmp(@encode(NSPoint), CGPOINT_ENCODING_PREFIX, strlen(CGPOINT_ENCODING_PREFIX)) == 0, "CGPoint encoding"); PASS(strncmp(@encode(NSSize), CGSIZE_ENCODING_PREFIX, strlen(CGSIZE_ENCODING_PREFIX)) == 0, "CGSize encoding"); PASS(strncmp(@encode(NSRect), CGRECT_ENCODING_PREFIX, strlen(CGRECT_ENCODING_PREFIX)) == 0, "CGRect encoding"); + PASS(strncmp(@encode(NSEdgeInsets), NSINSETS_ENCODING_PREFIX, strlen(NSINSETS_ENCODING_PREFIX)) == 0, "NSEdgeInsets encoding"); PASS(strncmp(@encode(NSRange), NSRANGE_ENCODING_PREFIX, strlen(NSRANGE_ENCODING_PREFIX)) == 0, "NSRange encoding"); END_SET("Known Struct Type Encodings")