diff -r 836adbf7a2cd -r 3317bb8137f4 jdk/src/jdk.deploy.osx/macosx/native/libapplescriptengine/AS_NS_ConversionUtils.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.deploy.osx/macosx/native/libapplescriptengine/AS_NS_ConversionUtils.m Sun Aug 17 15:54:13 2014 +0100 @@ -0,0 +1,793 @@ +/* + * 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 +#import + + +@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