| /* |
| * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| // |
| // Most of this is adapted from Ken Ferry's KFAppleScript Additions, contributed with permission |
| // http://homepage.mac.com/kenferry/software.html |
| // |
| |
| #import "AS_NS_ConversionUtils.h" |
| |
| #import <Cocoa/Cocoa.h> |
| #import <Carbon/Carbon.h> |
| |
| |
| @interface NSAppleEventDescriptor (JavaAppleScriptEngineAdditionsPrivate) |
| |
| // just returns self. This means that you can pass custom descriptors |
| // to -[NSAppleScript executeHandler:error:withParameters:]. |
| - (NSAppleEventDescriptor *)aeDescriptorValue; |
| |
| // working with primitive descriptor types |
| + (id)descriptorWithInt16:(SInt16)val; |
| - (SInt16)int16Value; |
| + (id)descriptorWithUnsignedInt32:(UInt32)val; |
| - (UInt32)unsignedInt32Value; |
| + (id)descriptorWithFloat32:(Float32)val; |
| - (Float32)float32Value; |
| + (id)descriptorWithFloat64:(Float64)val; |
| - (Float64)float64Value; |
| + (id)descriptorWithLongDateTime:(LongDateTime)val; |
| - (LongDateTime)longDateTimeValue; |
| |
| |
| // These are the methods for converting AS objects to objective-C objects. |
| // -[NSAppleEventDescriptor objCObjectValue] is the general method for converting |
| // AS objects to ObjC objects, and is called by -[NSAppleScript executeHandler:error:withParameters:]. |
| // It does no work itself. It finds a handler based on the type of the descriptor and lets that |
| // handler object do the work. If there is no handler type registered for a the type of a descriptor, |
| // the raw descriptor is returned. |
| // |
| // You can designate a handlers for descriptor types with |
| // +[NSAppleEventDescriptor registerConversionHandler:selector:forDescriptorTypes:]. Please note |
| // that this method does _not_ retain the handler object (for now anyway). The selector should |
| // take a single argument, a descriptor to translate, and should return an object. An example such |
| // selector is @selector(dictionaryWithAEDesc:), for which the handler object would be [NSDictionary class]. |
| // |
| // A number of handlers are designated by default. The methods and objects can be easily inferred (or check |
| // the implementation), but the automatically handled types are |
| // typeUnicodeText, |
| // typeText, |
| // typeUTF8Text, |
| // typeCString, |
| // typeChar, |
| // typeBoolean, |
| // typeTrue, |
| // typeFalse, |
| // typeSInt16, |
| // typeSInt32, |
| // typeUInt32, |
| // typeSInt64, |
| // typeIEEE32BitFloatingPoint, |
| // typeIEEE64BitFloatingPoint, |
| // type128BitFloatingPoint, |
| // typeAEList, |
| // typeAERecord, |
| // typeLongDateTime, |
| // typeNull. |
| + (void)registerConversionHandler:(id)anObject selector:(SEL)aSelector forDescriptorTypes:(DescType)firstType, ...; |
| + (void) jaseSetUpHandlerDict; |
| @end |
| |
| // wrap the NSAppleEventDescriptor string methods |
| @interface NSString (JavaAppleScriptEngineAdditions) |
| - (NSAppleEventDescriptor *)aeDescriptorValue; |
| + (NSString *)stringWithAEDesc:(NSAppleEventDescriptor *)desc; |
| @end |
| |
| // wrap the NSAppleEventDescriptor longDateTime methods |
| @interface NSDate (JavaAppleScriptEngineAdditions) |
| - (NSAppleEventDescriptor *)aeDescriptorValue; |
| + (NSDate *)dateWithAEDesc:(NSAppleEventDescriptor *)desc; |
| @end |
| |
| // these are fairly complicated methods, due to having to try to match up the various |
| // AS number types (see NSAppleEventDescriptor for the primitive number methods) |
| // with NSNumber variants. For complete behavior it's best to look at the implementation. |
| // Some notes: |
| // NSNumbers created with numberWithBool should be correctly translated to AS booleans and vice versa. |
| // NSNumbers created with large integer types may have to be translated to AS doubles, |
| // so be careful if checking equality (you may have to check equality within epsilon). |
| // Since NSNumbers can't remember if they were created with an unsigned value, |
| // [[NSNumber numberWithUnsignedChar:255] aeDescriptorValue] is going to get you an AS integer |
| // with value -1. If you really need a descriptor with an unsigned value, you'll need to do it |
| // manually using the primitive methods on NSAppleEventDescriptor. The resulting descriptor |
| // can still be passed to AS with -[NSAppleScript executeHandler:error:withParameters:]. |
| @interface NSNumber (JavaAppleScriptEngineAdditions) |
| - (NSAppleEventDescriptor *)aeDescriptorValue; |
| + (id)numberWithAEDesc:(NSAppleEventDescriptor *)desc; |
| @end |
| |
| // Here we're following the behavior described in the CocoaScripting release note. |
| // |
| // NSPoint -> list of two numbers: {x, y} |
| // NSRange -> list of two numbers: {begin offset, end offset} |
| // NSRect -> list of four numbers: {left, bottom, right, top} |
| // NSSize -> list of two numbers: {width, height} |
| @interface NSValue (JavaAppleScriptEngineAdditions) |
| - (NSAppleEventDescriptor *)aeDescriptorValue; |
| @end |
| |
| // No need for ObjC -> AS conversion here, we fall through to NSObject as a collection. |
| // For AS -> ObjC conversion, we build an array using the primitive list methods on |
| // NSAppleEventDescriptor. |
| @interface NSArray (JavaAppleScriptEngineAdditions) |
| + (NSArray *)arrayWithAEDesc:(NSAppleEventDescriptor *)desc; |
| @end |
| |
| |
| // Please see the CocoaScripting release note for behavior. It's kind of complicated. |
| // |
| // methods wrap the primitive record methods on NSAppleEventDescriptor. |
| @interface NSDictionary (JavaAppleScriptEngineAdditions) |
| - (NSAppleEventDescriptor *)aeDescriptorValue; |
| + (NSDictionary *)dictionaryWithAEDesc:(NSAppleEventDescriptor *)desc; |
| @end |
| |
| // be aware that a null descriptor does not correspond to the 'null' keyword in |
| // AppleScript - it's more like nothing at all. For example, the return |
| // from an empty handler. |
| @interface NSNull (JavaAppleScriptEngineAdditions) |
| - (NSAppleEventDescriptor *)aeDescriptorValue; |
| + (NSNull *)nullWithAEDesc:(NSAppleEventDescriptor *)desc; |
| @end |
| |
| |
| @interface NSNumber (JavaAppleScriptEngineAdditionsPrivate) |
| + (id) jaseNumberWithSignedIntP:(void *)int_p byteCount:(int)bytes; |
| + (id) jaseNumberWithUnsignedIntP:(void *)int_p byteCount:(int)bytes; |
| + (id) jaseNumberWithFloatP:(void *)float_p byteCount:(int)bytes; |
| @end |
| |
| |
| @implementation NSObject (JavaAppleScriptEngineAdditions) |
| |
| - (NSAppleEventDescriptor *)aeDescriptorValue { |
| // collections go to lists |
| if (![self respondsToSelector:@selector(objectEnumerator)]) { |
| // encode the description as a fallback - this is pretty useless, only helpful for debugging |
| return [[self description] aeDescriptorValue]; |
| } |
| |
| NSAppleEventDescriptor *resultDesc = [NSAppleEventDescriptor listDescriptor]; |
| NSEnumerator *objectEnumerator = [(id)self objectEnumerator]; |
| |
| unsigned int i = 1; // apple event descriptors are 1-indexed |
| id currentObject; |
| while((currentObject = [objectEnumerator nextObject]) != nil) { |
| [resultDesc insertDescriptor:[currentObject aeDescriptorValue] atIndex:i++]; |
| } |
| |
| return resultDesc; |
| } |
| |
| @end |
| |
| |
| @implementation NSArray (JavaAppleScriptEngineAdditions) |
| |
| // don't need to override aeDescriptorValue, the NSObject will treat the array as a collection |
| + (NSArray *)arrayWithAEDesc:(NSAppleEventDescriptor *)desc { |
| NSAppleEventDescriptor *listDesc = [desc coerceToDescriptorType:typeAEList]; |
| NSMutableArray *resultArray = [NSMutableArray array]; |
| |
| // apple event descriptors are 1-indexed |
| unsigned int listCount = [listDesc numberOfItems]; |
| unsigned int i; |
| for (i = 1; i <= listCount; i++) { |
| [resultArray addObject:[[listDesc descriptorAtIndex:i] objCObjectValue]]; |
| } |
| |
| return resultArray; |
| } |
| |
| @end |
| |
| |
| @implementation NSDictionary (JavaAppleScriptEngineAdditions) |
| |
| - (NSAppleEventDescriptor *)aeDescriptorValue { |
| NSAppleEventDescriptor *resultDesc = [NSAppleEventDescriptor recordDescriptor]; |
| NSMutableArray *userFields = [NSMutableArray array]; |
| NSArray *keys = [self allKeys]; |
| |
| unsigned int keyCount = [keys count]; |
| unsigned int i; |
| for (i = 0; i < keyCount; i++) { |
| id key = [keys objectAtIndex:i]; |
| |
| if ([key isKindOfClass:[NSNumber class]]) { |
| [resultDesc setDescriptor:[[self objectForKey:key] aeDescriptorValue] forKeyword:[(NSNumber *)key intValue]]; |
| } else if ([key isKindOfClass:[NSString class]]) { |
| [userFields addObject:key]; |
| [userFields addObject:[self objectForKey:key]]; |
| } |
| } |
| |
| if ([userFields count] > 0) { |
| [resultDesc setDescriptor:[userFields aeDescriptorValue] forKeyword:keyASUserRecordFields]; |
| } |
| |
| return resultDesc; |
| } |
| |
| + (NSDictionary *)dictionaryWithAEDesc:(NSAppleEventDescriptor *)desc { |
| NSAppleEventDescriptor *recDescriptor = [desc coerceToDescriptorType:typeAERecord]; |
| NSMutableDictionary *resultDict = [NSMutableDictionary dictionary]; |
| |
| // NSAppleEventDescriptor uses 1 indexing |
| unsigned int recordCount = [recDescriptor numberOfItems]; |
| unsigned int recordIndex; |
| for (recordIndex = 1; recordIndex <= recordCount; recordIndex++) { |
| AEKeyword keyword = [recDescriptor keywordForDescriptorAtIndex:recordIndex]; |
| |
| if(keyword == keyASUserRecordFields) { |
| NSAppleEventDescriptor *listDescriptor = [recDescriptor descriptorAtIndex:recordIndex]; |
| |
| // NSAppleEventDescriptor uses 1 indexing |
| unsigned int listCount = [listDescriptor numberOfItems]; |
| unsigned int listIndex; |
| for (listIndex = 1; listIndex <= listCount; listIndex += 2) { |
| id keyObj = [[listDescriptor descriptorAtIndex:listIndex] objCObjectValue]; |
| id valObj = [[listDescriptor descriptorAtIndex:listIndex+1] objCObjectValue]; |
| |
| [resultDict setObject:valObj forKey:keyObj]; |
| } |
| } else { |
| id keyObj = [NSNumber numberWithInt:keyword]; |
| id valObj = [[recDescriptor descriptorAtIndex:recordIndex] objCObjectValue]; |
| |
| [resultDict setObject:valObj forKey:keyObj]; |
| } |
| } |
| |
| return resultDict; |
| } |
| |
| @end |
| |
| |
| @implementation NSString (JavaAppleScriptEngineAdditions) |
| |
| - (NSAppleEventDescriptor *)aeDescriptorValue { |
| return [NSAppleEventDescriptor descriptorWithString:self]; |
| } |
| |
| + (NSString *)stringWithAEDesc:(NSAppleEventDescriptor *)desc { |
| return [desc stringValue]; |
| } |
| |
| + (NSString *)versionWithAEDesc:(NSAppleEventDescriptor *)desc { |
| const AEDesc *aeDesc = [desc aeDesc]; |
| VersRec v; |
| AEGetDescData(aeDesc, &v, sizeof(v)); |
| return [[[NSString alloc] initWithBytes:&v.shortVersion[1] length:StrLength(v.shortVersion) encoding:NSUTF8StringEncoding] autorelease]; |
| } |
| |
| @end |
| |
| |
| @implementation NSNull (JavaAppleScriptEngineAdditions) |
| |
| - (NSAppleEventDescriptor *)aeDescriptorValue { |
| return [NSAppleEventDescriptor nullDescriptor]; |
| } |
| |
| + (NSNull *)nullWithAEDesc:(NSAppleEventDescriptor *)desc { |
| return [NSNull null]; |
| } |
| |
| @end |
| |
| |
| @implementation NSDate (JavaAppleScriptEngineAdditions) |
| |
| - (NSAppleEventDescriptor *)aeDescriptorValue { |
| LongDateTime ldt; |
| UCConvertCFAbsoluteTimeToLongDateTime(CFDateGetAbsoluteTime((CFDateRef)self), &ldt); |
| return [NSAppleEventDescriptor descriptorWithLongDateTime:ldt]; |
| } |
| |
| + (NSDate *)dateWithAEDesc:(NSAppleEventDescriptor *)desc { |
| CFAbsoluteTime absTime; |
| UCConvertLongDateTimeToCFAbsoluteTime([desc longDateTimeValue], &absTime); |
| NSDate *resultDate = (NSDate *)CFDateCreate(NULL, absTime); |
| return [resultDate autorelease]; |
| } |
| |
| @end |
| |
| |
| |
| static inline int areEqualEncodings(const char *enc1, const char *enc2) { |
| return (strcmp(enc1, enc2) == 0); |
| } |
| |
| @implementation NSNumber (JavaAppleScriptEngineAdditions) |
| |
| -(id)jaseDescriptorValueWithFloatP:(void *)float_p byteCount:(int)bytes { |
| float floatVal; |
| if (bytes < sizeof(Float32)) { |
| floatVal = [self floatValue]; |
| float_p = &floatVal; |
| bytes = sizeof(floatVal); |
| } |
| |
| double doubleVal; |
| if (bytes > sizeof(Float64)) { |
| doubleVal = [self doubleValue]; |
| float_p = &doubleVal; |
| bytes = sizeof(doubleVal); |
| } |
| |
| if (bytes == sizeof(Float32)) { |
| return [NSAppleEventDescriptor descriptorWithFloat32:*(Float32 *)float_p]; |
| } |
| |
| if (bytes == sizeof(Float64)) { |
| return [NSAppleEventDescriptor descriptorWithFloat64:*(Float64 *)float_p]; |
| } |
| |
| [NSException raise:NSInvalidArgumentException |
| format:@"Cannot create an NSAppleEventDescriptor for float with %d bytes of data.", bytes]; |
| |
| return nil; |
| } |
| |
| -(id)jaseDescriptorValueWithSignedIntP:(void *)int_p byteCount:(int)bytes { |
| int intVal; |
| |
| if (bytes < sizeof(SInt16)) { |
| intVal = [self intValue]; |
| int_p = &intVal; |
| bytes = sizeof(intVal); |
| } |
| |
| if (bytes == sizeof(SInt16)) { |
| return [NSAppleEventDescriptor descriptorWithInt16:*(SInt16 *)int_p]; |
| } |
| |
| if (bytes == sizeof(SInt32)) { |
| return [NSAppleEventDescriptor descriptorWithInt32:*(SInt32 *)int_p]; |
| } |
| |
| double val = [self doubleValue]; |
| return [self jaseDescriptorValueWithFloatP:&val byteCount:sizeof(val)]; |
| } |
| |
| -(id)jaseDescriptorValueWithUnsignedIntP:(void *)int_p byteCount:(int)bytes { |
| unsigned int uIntVal; |
| |
| if (bytes < sizeof(UInt32)) { |
| uIntVal = [self unsignedIntValue]; |
| int_p = &uIntVal; |
| bytes = sizeof(uIntVal); |
| } |
| |
| if (bytes == sizeof(UInt32)) { |
| return [NSAppleEventDescriptor descriptorWithUnsignedInt32:*(UInt32 *)int_p]; |
| } |
| |
| double val = (double)[self unsignedLongLongValue]; |
| return [self jaseDescriptorValueWithFloatP:&val byteCount:sizeof(val)]; |
| } |
| |
| - (NSAppleEventDescriptor *)aeDescriptorValue { |
| // NSNumber is unfortunately complicated, because the applescript |
| // type we should use depends on the c type that our NSNumber corresponds to |
| |
| const char *type = [self objCType]; |
| |
| // convert |
| if (areEqualEncodings(type, @encode(BOOL))) { |
| return [NSAppleEventDescriptor descriptorWithBoolean:[self boolValue]]; |
| } |
| |
| if (areEqualEncodings(type, @encode(char))) { |
| char val = [self charValue]; |
| return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(short))) { |
| short val = [self shortValue]; |
| return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(int))) { |
| int val = [self intValue]; |
| return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(long))) { |
| long val = [self longValue]; |
| return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(long long))) { |
| long long val = [self longLongValue]; |
| return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(unsigned char))) { |
| unsigned char val = [self unsignedCharValue]; |
| return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(unsigned short))) { |
| unsigned short val = [self unsignedShortValue]; |
| return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(unsigned int))) { |
| unsigned int val = [self unsignedIntValue]; |
| return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(unsigned long))) { |
| unsigned long val = [self unsignedLongValue]; |
| return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(unsigned long long))) { |
| unsigned long long val = [self unsignedLongLongValue]; |
| return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(float))) { |
| float val = [self floatValue]; |
| return [self jaseDescriptorValueWithFloatP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (areEqualEncodings(type, @encode(double))) { |
| double val = [self doubleValue]; |
| return [self jaseDescriptorValueWithFloatP:&val byteCount:sizeof(val)]; |
| } |
| |
| [NSException raise:@"jaseUnsupportedAEDescriptorConversion" |
| format:@"JavaAppleScriptEngineAdditions: conversion of an NSNumber with objCType '%s' to an aeDescriptor is not supported.", type]; |
| |
| return nil; |
| } |
| |
| + (id)numberWithAEDesc:(NSAppleEventDescriptor *)desc { |
| DescType type = [desc descriptorType]; |
| |
| if ((type == typeTrue) || (type == typeFalse) || (type == typeBoolean)) { |
| return [NSNumber numberWithBool:[desc booleanValue]]; |
| } |
| |
| if (type == typeSInt16) { |
| SInt16 val = [desc int16Value]; |
| return [NSNumber jaseNumberWithSignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (type == typeSInt32) { |
| SInt32 val = [desc int32Value]; |
| return [NSNumber jaseNumberWithSignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (type == typeUInt32) { |
| UInt32 val = [desc unsignedInt32Value]; |
| return [NSNumber jaseNumberWithUnsignedIntP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (type == typeIEEE32BitFloatingPoint) { |
| Float32 val = [desc float32Value]; |
| return [NSNumber jaseNumberWithFloatP:&val byteCount:sizeof(val)]; |
| } |
| |
| if (type == typeIEEE64BitFloatingPoint) { |
| Float64 val = [desc float64Value]; |
| return [NSNumber jaseNumberWithFloatP:&val byteCount:sizeof(val)]; |
| } |
| |
| // try to coerce to 64bit floating point |
| desc = [desc coerceToDescriptorType:typeIEEE64BitFloatingPoint]; |
| if (desc != nil) { |
| Float64 val = [desc float64Value]; |
| return [NSNumber jaseNumberWithFloatP:&val byteCount:sizeof(val)]; |
| } |
| |
| [NSException raise:@"jaseUnsupportedAEDescriptorConversion" |
| format:@"JavaAppleScriptEngineAdditions: conversion of an NSAppleEventDescriptor with objCType '%s' to an aeDescriptor is not supported.", type]; |
| |
| return nil; |
| } |
| |
| + (id) jaseNumberWithSignedIntP:(void *)int_p byteCount:(int)bytes { |
| if (bytes == sizeof(char)) { |
| return [NSNumber numberWithChar:*(char *)int_p]; |
| } |
| |
| if (bytes == sizeof(short)) { |
| return [NSNumber numberWithShort:*(short *)int_p]; |
| } |
| |
| if (bytes == sizeof(int)) { |
| return [NSNumber numberWithInt:*(int *)int_p]; |
| } |
| |
| if (bytes == sizeof(long)) { |
| return [NSNumber numberWithLong:*(long *)int_p]; |
| } |
| |
| if (bytes == sizeof(long long)) { |
| return [NSNumber numberWithLongLong:*(long long *)int_p]; |
| } |
| |
| [NSException raise:NSInvalidArgumentException |
| format:@"NSNumber jaseNumberWithSignedIntP:byteCount: number with %i bytes not supported.", bytes]; |
| |
| return nil; |
| } |
| |
| + (id) jaseNumberWithUnsignedIntP:(void *)int_p byteCount:(int)bytes { |
| if (bytes == sizeof(unsigned char)) { |
| return [NSNumber numberWithUnsignedChar:*(unsigned char *)int_p]; |
| } |
| |
| if (bytes == sizeof(unsigned short)) { |
| return [NSNumber numberWithUnsignedShort:*(unsigned short *)int_p]; |
| } |
| |
| if (bytes == sizeof(unsigned int)) { |
| return [NSNumber numberWithUnsignedInt:*(unsigned int *)int_p]; |
| } |
| |
| if (bytes == sizeof(unsigned long)) { |
| return [NSNumber numberWithUnsignedLong:*(unsigned long *)int_p]; |
| } |
| |
| if (bytes == sizeof(unsigned long long)) { |
| return [NSNumber numberWithUnsignedLongLong:*(unsigned long long *)int_p]; |
| } |
| |
| [NSException raise:NSInvalidArgumentException |
| format:@"NSNumber numberWithUnsignedInt:byteCount: number with %i bytes not supported.", bytes]; |
| |
| return nil; |
| } |
| |
| + (id) jaseNumberWithFloatP:(void *)float_p byteCount:(int)bytes { |
| if (bytes == sizeof(float)) { |
| return [NSNumber numberWithFloat:*(float *)float_p]; |
| } |
| |
| if (bytes == sizeof(double)) { |
| return [NSNumber numberWithFloat:*(double *)float_p]; |
| } |
| |
| [NSException raise:NSInvalidArgumentException |
| format:@"NSNumber numberWithFloat:byteCount: floating point number with %i bytes not supported.", bytes]; |
| |
| return nil; |
| } |
| |
| @end |
| |
| @implementation NSValue (JavaAppleScriptEngineAdditions) |
| |
| - (NSAppleEventDescriptor *)aeDescriptorValue { |
| const char *type = [self objCType]; |
| |
| if (areEqualEncodings(type, @encode(NSSize))) { |
| NSSize size = [self sizeValue]; |
| return [[NSArray arrayWithObjects: |
| [NSNumber numberWithFloat:size.width], |
| [NSNumber numberWithFloat:size.height], nil] aeDescriptorValue]; |
| } |
| |
| if (areEqualEncodings(type, @encode(NSPoint))) { |
| NSPoint point = [self pointValue]; |
| return [[NSArray arrayWithObjects: |
| [NSNumber numberWithFloat:point.x], |
| [NSNumber numberWithFloat:point.y], nil] aeDescriptorValue]; |
| } |
| |
| if (areEqualEncodings(type, @encode(NSRange))) { |
| NSRange range = [self rangeValue]; |
| return [[NSArray arrayWithObjects: |
| [NSNumber numberWithUnsignedInt:range.location], |
| [NSNumber numberWithUnsignedInt:range.location + range.length], nil] aeDescriptorValue]; |
| } |
| |
| if (areEqualEncodings(type, @encode(NSRect))) { |
| NSRect rect = [self rectValue]; |
| return [[NSArray arrayWithObjects: |
| [NSNumber numberWithFloat:rect.origin.x], |
| [NSNumber numberWithFloat:rect.origin.y], |
| [NSNumber numberWithFloat:rect.origin.x + rect.size.width], |
| [NSNumber numberWithFloat:rect.origin.y + rect.size.height], nil] aeDescriptorValue]; |
| } |
| |
| [NSException raise:@"jaseUnsupportedAEDescriptorConversion" |
| format:@"JavaAppleScriptEngineAdditions: conversion of an NSNumber with objCType '%s' to an aeDescriptor is not supported.", type]; |
| |
| return nil; |
| } |
| |
| @end |
| |
| |
| @implementation NSImage (JavaAppleScriptEngineAdditions) |
| |
| - (NSAppleEventDescriptor *)aeDescriptorValue { |
| NSData *data = [self TIFFRepresentation]; |
| return [NSAppleEventDescriptor descriptorWithDescriptorType:typeTIFF data:data]; |
| } |
| |
| + (NSImage *)imageWithAEDesc:(NSAppleEventDescriptor *)desc { |
| const AEDesc *d = [desc aeDesc]; |
| NSMutableData *data = [NSMutableData dataWithLength:AEGetDescDataSize(d)]; |
| AEGetDescData(d, [data mutableBytes], [data length]); |
| return [[[NSImage alloc] initWithData:data] autorelease]; |
| } |
| |
| @end |
| |
| |
| |
| @implementation NSAppleEventDescriptor (JavaAppleScriptEngineAdditions) |
| |
| // we're going to leak this. It doesn't matter much for running apps, but |
| // for developers it might be nice to try to dispose of it (so it would not clutter the |
| // output when testing for leaks) |
| static NSMutableDictionary *handlerDict = nil; |
| |
| - (id)objCObjectValue { |
| if (handlerDict == nil) [NSAppleEventDescriptor jaseSetUpHandlerDict]; |
| |
| id returnObj; |
| DescType type = [self descriptorType]; |
| NSInvocation *handlerInvocation = [handlerDict objectForKey:[NSValue valueWithBytes:&type objCType:@encode(DescType)]]; |
| if (handlerInvocation == nil) { |
| if (type == typeType) { |
| DescType subType; |
| AEGetDescData([self aeDesc], &subType, sizeof(subType)); |
| if (subType == typeNull) return [NSNull null]; |
| } |
| // return raw apple event descriptor if no handler is registered |
| returnObj = self; |
| } else { |
| [handlerInvocation setArgument:&self atIndex:2]; |
| [handlerInvocation invoke]; |
| [handlerInvocation getReturnValue:&returnObj]; |
| } |
| |
| return returnObj; |
| } |
| |
| // FIXME - error checking, non nil handler |
| + (void)registerConversionHandler:(id)anObject selector:(SEL)aSelector forDescriptorTypes:(DescType)firstType, ... { |
| if (handlerDict == nil) [NSAppleEventDescriptor jaseSetUpHandlerDict]; |
| |
| NSInvocation *handlerInvocation = [NSInvocation invocationWithMethodSignature:[anObject methodSignatureForSelector:aSelector]]; |
| [handlerInvocation setTarget:anObject]; |
| [handlerInvocation setSelector:aSelector]; |
| |
| DescType aType = firstType; |
| va_list typesList; |
| va_start(typesList, firstType); |
| do { |
| NSValue *type = [NSValue valueWithBytes:&aType objCType:@encode(DescType)]; |
| [handlerDict setObject:handlerInvocation forKey:type]; |
| } while((aType = va_arg(typesList, DescType)) != 0); |
| va_end(typesList); |
| } |
| |
| |
| - (NSAppleEventDescriptor *)aeDescriptorValue { |
| return self; |
| } |
| |
| + (id)descriptorWithInt16:(SInt16)val { |
| return [NSAppleEventDescriptor descriptorWithDescriptorType:typeSInt16 bytes:&val length:sizeof(val)]; |
| } |
| |
| - (SInt16)int16Value { |
| SInt16 retValue; |
| [[[self coerceToDescriptorType:typeSInt16] data] getBytes:&retValue]; |
| return retValue; |
| } |
| |
| + (id)descriptorWithUnsignedInt32:(UInt32)val { |
| return [NSAppleEventDescriptor descriptorWithDescriptorType:typeUInt32 bytes:&val length:sizeof(val)]; |
| } |
| |
| - (UInt32)unsignedInt32Value { |
| UInt32 retValue; |
| [[[self coerceToDescriptorType:typeUInt32] data] getBytes:&retValue]; |
| return retValue; |
| } |
| |
| |
| + (id)descriptorWithFloat32:(Float32)val { |
| return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE32BitFloatingPoint bytes:&val length:sizeof(val)]; |
| } |
| |
| - (Float32)float32Value { |
| Float32 retValue; |
| [[[self coerceToDescriptorType:typeIEEE32BitFloatingPoint] data] getBytes:&retValue]; |
| return retValue; |
| } |
| |
| |
| + (id)descriptorWithFloat64:(Float64)val { |
| return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint bytes:&val length:sizeof(val)]; |
| } |
| |
| - (Float64)float64Value { |
| Float64 retValue; |
| [[[self coerceToDescriptorType:typeIEEE64BitFloatingPoint] data] getBytes:&retValue]; |
| return retValue; |
| } |
| |
| + (id)descriptorWithLongDateTime:(LongDateTime)val { |
| return [NSAppleEventDescriptor descriptorWithDescriptorType:typeLongDateTime bytes:&val length:sizeof(val)]; |
| } |
| |
| - (LongDateTime)longDateTimeValue { |
| LongDateTime retValue; |
| [[[self coerceToDescriptorType:typeLongDateTime] data] getBytes:&retValue]; |
| return retValue; |
| } |
| |
| + (void)jaseSetUpHandlerDict { |
| handlerDict = [[NSMutableDictionary alloc] init]; |
| |
| // register default handlers |
| // types are culled from AEDataModel.h and AERegistry.h |
| |
| // string -> NSStrings |
| [NSAppleEventDescriptor registerConversionHandler:[NSString class] selector:@selector(stringWithAEDesc:) forDescriptorTypes: |
| typeUnicodeText, typeText, typeUTF8Text, typeCString, typeChar, nil]; |
| |
| // number/bool -> NSNumber |
| [NSAppleEventDescriptor registerConversionHandler:[NSNumber class] selector:@selector(numberWithAEDesc:) forDescriptorTypes: |
| typeBoolean, typeTrue, typeFalse, |
| typeSInt16, typeSInt32, typeUInt32, typeSInt64, |
| typeIEEE32BitFloatingPoint, typeIEEE64BitFloatingPoint, type128BitFloatingPoint, nil]; |
| |
| // list -> NSArray |
| [NSAppleEventDescriptor registerConversionHandler:[NSArray class] selector:@selector(arrayWithAEDesc:) forDescriptorTypes:typeAEList, nil]; |
| |
| // record -> NSDictionary |
| [NSAppleEventDescriptor registerConversionHandler:[NSDictionary class] selector:@selector(dictionaryWithAEDesc:) forDescriptorTypes:typeAERecord, nil]; |
| |
| // date -> NSDate |
| [NSAppleEventDescriptor registerConversionHandler:[NSDate class] selector:@selector(dateWithAEDesc:) forDescriptorTypes:typeLongDateTime, nil]; |
| |
| // images -> NSImage |
| [NSAppleEventDescriptor registerConversionHandler:[NSImage class] selector:@selector(imageWithAEDesc:) forDescriptorTypes: |
| typeTIFF, typeJPEG, typeGIF, typePict, typeIconFamily, typeIconAndMask, nil]; |
| |
| // vers -> NSString |
| [NSAppleEventDescriptor registerConversionHandler:[NSString class] selector:@selector(versionWithAEDesc:) forDescriptorTypes:typeVersion, nil]; |
| |
| // null -> NSNull |
| [NSAppleEventDescriptor registerConversionHandler:[NSNull class] selector:@selector(nullWithAEDesc:) forDescriptorTypes:typeNull, nil]; |
| } |
| |
| @end |