/* * 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