#include #include #include #include #include #include #include #include #include #include #import #import #include // // FIXME: add support for date type everywhere // FIXME: Separate this from the Cocoa class // using namespace org::xwt; using namespace org::xwt::plat; using namespace org::xwt::js; using namespace java::lang; using gnu::gcj::RawData; // Avoid linking against libstdc++ static void* operator new(size_t size) { return JvMalloc(size); } static void* operator new[](size_t size) { return JvMalloc(size);} static void operator delete(void *p) { JvFree(p); } static void operator delete[](void *p) { JvFree(p); } namespace org { namespace xwt { namespace plat { static Object *jsObjForDesc(AEDesc *desc); static void descForJSObj(Object *o,AEDesc *desc); static void disposeExternalPtrProc(const void *p,Size len,long junk); struct MyASData { MyASData() : component(NULL),scriptID(kOSANullScript) { } ~MyASData() { if(scriptID != kOSANullScript && component) OSADispose(component,scriptID); if(component) CloseComponent(component); } ComponentInstance component; OSAID scriptID; }; class SmartDesc { private: AEDesc mDesc; void free() { AEDisposeDesc(&mDesc); } public: SmartDesc() { AECreateDesc(typeNull,NULL,0,&mDesc); } ~SmartDesc() { free(); } void reset() { free(); AECreateDesc(typeNull,NULL,0,&mDesc); } // The assignment op/copy constructor should never be called, but its here for completeness SmartDesc(const AEDesc& desc) : mDesc(desc) { } SmartDesc& operator=(const AEDesc& desc) { free(); mDesc = desc; return *this; } operator AEDesc*() { return &mDesc; } }; void Cocoa$AppleScript::compile() { JvSynchronize dummy(&Cocoa$AppleScript::class$); SmartDesc desc; MyASData *data; OSStatus r; if(rawMyASData) return; data = new MyASData; try { data->component = OpenDefaultComponent(kOSAComponentType,typeAppleScript); if(!data->component) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("OpenDefaultComponent failed")); descForJSObj(script,desc); r = OSACompile(data->component,desc,kOSAModeCompileIntoContext,&data->scriptID); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("OSACompile failed")); } catch(Cocoa$AppleScript$ASException *e) { delete data; throw e; } script = 0; // allow it to be collected rawMyASData = (RawData*) data; } Object *Cocoa$AppleScript::exec() { JvSynchronize dummy(&Cocoa$AppleScript::class$); MyASData *data; OSAID resultID; OSStatus r; SmartDesc desc; if(!rawMyASData) compile(); data = (MyASData*) rawMyASData; r = OSAExecute(data->component,data->scriptID,kOSANullScript,kOSAModeNull,&resultID); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("OSAExecute failed")); r = OSACoerceToDesc(data->component,resultID,typeWildCard,kOSAModeNull,desc); OSADispose(data->component,resultID); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("OSACoerceToDesc failed")); return jsObjForDesc(desc); } Object *Cocoa$AppleScript::call(JS$Array *jargs) { JvSynchronize dummy(&Cocoa$AppleScript::class$); MyASData *data; ProcessSerialNumber psn = {0, kCurrentProcess}; OSStatus r; OSAID resultID; SmartDesc sub; SmartDesc event; SmartDesc target; SmartDesc args; SmartDesc result; if(!rawMyASData) compile(); data = (MyASData*) rawMyASData; r = AECreateDesc(typeProcessSerialNumber, &psn,sizeof(psn), target); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateDesc failed")); r = AECreateAppleEvent(kASAppleScriptSuite, kASSubroutineEvent,target, kAutoGenerateReturnID,kAnyTransactionID, event); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateAppleEvent failed")); r = AECreateList(NULL, 0, false, args); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateList failed")); for(int i=1;ilength();i++) { SmartDesc item; descForJSObj(jargs->elementAt(i),item); r = AEPutDesc(args,0,item); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEPutDesc failed")); } r = AEPutParamDesc(event, keyDirectObject,args); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEPutParamDesc failed")); descForJSObj(jargs->elementAt(0)->toString(),sub); r = AEPutParamDesc(event,keyASSubroutineName,sub); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEPutParamDesc failed")); r = OSAExecuteEvent(data->component,event,data->scriptID,kOSAModeNull,&resultID); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("OSAExecuteEvent failed")); r = OSACoerceToDesc(data->component,resultID,typeWildCard,kOSAModeNull,result); OSADispose(data->component,resultID); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("OSACoerceToDesc failed")); return jsObjForDesc(result); } void Cocoa$AppleScript::finalize() { JvSynchronize dummy(&Cocoa$AppleScript::class$); MyASData *data = (MyASData*) rawMyASData; if(data) delete data; } static Object *jsObjForDesc(AEDesc *desc) { Size size = AEGetDescDataSize(desc); AEKeyword keyword; // All these are for the various conversions char *buf; SInt32 n; Float64 f; Object *o; OSStatus r; JArray *objs; int i,j; switch(desc->descriptorType) { case typeNull: o = 0; break; case typeChar: buf = new char[size]; r = AEGetDescData(desc,buf,size); if(r != noErr) { delete buf; throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEGetDescData failed")); } o = JvNewStringLatin1(buf,size); delete buf; break; case typeSInt32: r = AEGetDescData(desc,&n,sizeof(n)); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEGetDescData failed")); o = new Integer((jint)n); break; case typeIEEE64BitFloatingPoint: r = AEGetDescData(desc,&f,sizeof(f)); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEGetDescData failed")); o = new Double((jdouble) f); break; case typeTrue: o = java::lang::Boolean::TRUE; break; case typeFalse: o = java::lang::Boolean::FALSE; break; case typeAEList: r = AECountItems(desc,&n); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECountItems failed")); objs = JvNewObjectArray(n,&Object::class$,0); for(i=0;i *newObjs; r = AECountItems(item,&n2); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECountItems failed")); // FIXME: don't bother with the Object[] array once we switch to org.xwt.js newObjs = JvNewObjectArray(((n-1)*2)+(n2&(~1)),&Object::class$,0); memcpy(elements(newObjs),elements(objs),sizeof(Object*)*j); objs = newObjs; for(x=1;x<=n2-1;x+=2) { SmartDesc key,value; r = AEGetNthDesc(item,x,typeWildCard,&keyword,key); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEGetNthDesc failed")); r = AEGetNthDesc(item,x+1,typeWildCard,&keyword,value); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEGetNthDesc failed")); elements(objs)[j++] = jsObjForDesc(key); elements(objs)[j++] = jsObjForDesc(value); } } else { // ugh... we just have the four char code... OSADisplay converts it to the // human readable value, how do we do that? char fourCharCode[sizeof(keyword)+1]; memcpy(fourCharCode,&keyword,sizeof(keyword)); fourCharCode[sizeof(keyword)] = '\0'; elements(objs)[j++] = JvNewStringLatin1(fourCharCode); elements(objs)[j++] = jsObjForDesc(item); } } // FIXME: do JS.Object directly once we switch over to org.xwt.js o = Cocoa$AppleScript::jsHashtableForObjects(objs); break; default: { SmartDesc text; r = AECoerceDesc(desc,typeChar,text); if(r != noErr) { char buf[64]; char *t = (char*)&desc->descriptorType; sprintf(buf,"unknown AE type: %c%c%c%c that can't be coerced to text",t[0],t[1],t[2],t[3]); o = JvNewStringLatin1(buf); } else { o = jsObjForDesc(text); } } break; } return o; } static void descForJSObj(Object *o,AEDesc *desc) { Integer *integer; Number *n; JS$Array *a; JS *h; java::lang::Boolean *b; OSStatus r; int i; if(o == 0l) { AECreateDesc(typeNull,NULL,0,desc); } else if((integer = Cocoa$AppleScript::castToInteger(o))) { SInt32 x = integer->intValue(); r = AECreateDesc(typeSInt32,&x,sizeof(x),desc); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateDesc failed")); } else if((n = Cocoa$AppleScript::castToNumber(o))) { Float64 x = n->doubleValue(); r = AECreateDesc(typeIEEE64BitFloatingPoint,&x,sizeof(x),desc); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateDesc failed")); } else if(( b = Cocoa$AppleScript::castToBoolean(o))) { r = AECreateDesc(b->booleanValue() ? typeTrue : typeFalse,NULL,0,desc); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateDesc failed")); } else if(( a = Cocoa$AppleScript::castToJSArray(o))) { r = AECreateList(NULL,0,false,desc); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateList failed")); for(i=0;ilength();i++) { SmartDesc item; descForJSObj(a->elementAt(0),item); r = AEPutDesc(desc,0,item); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEPutDesc failed")); } } else if(( h = Cocoa$AppleScript::castToJS(o))) { JArray *keys = h->keys(); jsize size = JvGetArrayLength(keys); r = AECreateList(NULL,0,true,desc); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateList failed")); if(size) { SmartDesc list; r = AECreateList(NULL,0,false,list); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateList failed")); for(i=0;iget(elements(keys)[i]->toString()),value); r = AEPutDesc(list,0,key); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEPutDesc failed")); r = AEPutDesc(list,0,value); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEPutDesc failed")); } r = AEPutParamDesc(desc,keyASUserRecordFields,list); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AEPutParamDesc failed")); } } else { jstring js = o->toString(); int utf8len = JvGetStringUTFLength(js); char *buf = new char[utf8len]; JvGetStringUTFRegion(js,0,js->length(),buf); r = AECreateDescFromExternalPtr(typeChar,buf,utf8len,disposeExternalPtrProc,0,desc); if(r != noErr) throw new Cocoa$AppleScript$ASException(JvNewStringLatin1("AECreateDesc failed")); } } static void disposeExternalPtrProc(const void *p,Size len,long junk) { delete[] (char*)p; } } } } /* end namespace */