/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ // // Java-related editor code. // #ifdef EDITOR #include "editor.h" // Local header #ifdef EDITOR_JAVA #include "java.h" #include "libi18n.h" #include "xp_file.h" #define JRI_NO_CPLUSPLUS #ifdef XP_MAC #include "n_p_composer_PluginManager.h" #include "n_plugin_composer_Composer.h" #include "n_p_composer_MozillaCallback.h" #else #include "netscape_plugin_composer_PluginManager.h" #include "netscape_plugin_composer_Composer.h" #include "netscape_plugin_composer_MozillaCallback.h" #endif // This C header file doesn't have C++ linkage #ifdefs. extern "C" { #include "zip.h" }; struct netscape_plugin_composer_PluginManager; #include "jri.h" // Interface for calling editor plugins #define PLUGIN_FAIL 0 #define PLUGIN_CANCEL 1 #define PLUGIN_OK 2 #define PLUGIN_NEWTEXT 3 typedef void (*ComposerPluginCallbackFn)(jint, jint, struct java_lang_Object*); void EDT_ComposerPluginCallback(jint, jint, struct java_lang_Object*); #ifdef XP_WIN16 const int32 MAX_STRING=65530L; #else // const int32 MAX_STRING=500; // For testing const int32 MAX_STRING=1L<<30; #endif class CEditorPluginInterface { public: static XP_Bool IsValidInterface(CEditorPluginInterface* pInterface); CEditorPluginInterface(MWContext* pContext, ComposerPluginCallbackFn callback); ~CEditorPluginInterface(); static void Register(char* plugin); static int32 GetNumberOfCategories(); static int32 GetNumberOfPlugins(int32 type); static char* GetCategoryName(int32 type); static char* GetPluginName(int32 type, int32 index); static char* GetPluginHint(int32 type, int32 index); static int32 GetNumberOfEncoders(); static char* GetEncoderName(int32 index); static XP_Bool GetEncoderNeedsQuantizedSource(int32 index); static char* GetEncoderHint(int32 index); static char* GetEncoderFileExtension(int32 index); static char* GetEncoderFileType(int32 index); XP_Bool StartEncoder(int32 index, int32 width, int32 height, char** pixels, char* fileName, EDT_ImageEncoderCallbackFn doneFunction, void* doneFunctionArgument); XP_Bool Perform(int32 type, int32 index, EDT_ImageEncoderCallbackFn doneFunction, void* hook,netscape_javascript_JSObject *jsobject); XP_Bool Perform(char* pClassName, EDT_ImageEncoderCallbackFn doneFunction, void* hook,netscape_javascript_JSObject *jsobject); void Perform(char* pEvent, char* pDocURL, XP_Bool bCanChangeDocument, XP_Bool bCanCancel, EDT_ImageEncoderCallbackFn doneFunction, void* hook,netscape_javascript_JSObject *jsobject); XP_Bool IsPluginActive(); void StopPlugin(); void PluginCallback(int32 action, struct java_lang_Object* pArgument); static XP_Bool PluginsExist(); protected: struct java_lang_String* GetBaseURL(); struct java_lang_String* GetDocument(); void GetWorkDirectoryAndURL(struct java_lang_String*& workDirectory, struct java_lang_String*& workDirectoryURL); XP_Bool Perform2(char* pClassName, int32 type, int32 index, XP_Bool bCanChangeDocument, XP_Bool bCanCancel, EDT_ImageEncoderCallbackFn doneFunction, void* hook, netscape_javascript_JSObject *jsobject); void PluginFailed(struct java_lang_String* pWhy); void PluginSucceeded(); void NewText(struct java_lang_String* pText); CEditBuffer* GetBuffer(); private: void ImageEncoderFinished(EDT_ImageEncoderStatus status); void DocumentIsTooLarge(int32 docLengthInBytes, int msgid); static netscape_plugin_composer_PluginManager* Manager(); struct netscape_plugin_composer_Composer* Composer(); static JRIEnv* Env(); static XP_Bool g_bJavaInitialized; static JRIEnv* g_pEnv; static JRIGlobalRef g_pManager; static TXP_GrowableArray_pChar g_Plugin; static TXP_GrowableArray_CEditorPluginInterface g_Interface; XP_Bool m_bPluginActive; // True if an image encoder or a plugin is active. XP_Bool m_bImageEncoder; // True if we're exectuing an image encoder. XP_Bool m_bCanChangeDocument; XP_Bool m_bCanCancel; XP_Bool m_bChangedDocument; // True if the current plug-in has changed the document. JRIGlobalRef m_pComposer; EDT_ImageEncoderCallbackFn m_doneFunction; void* m_doneFunctionArgument; MWContext* m_pContext; ComposerPluginCallbackFn m_callback; }; #endif // EDITOR_JAVA // End of local header // Editor Plugin edt.h API functions. void EDT_RegisterPlugin(char* csFileSpec){ #ifdef EDITOR_JAVA CEditorPluginInterface::Register(csFileSpec); #else #ifdef XP_MAC #pragma unused(csFileSpec) #endif XP_TRACE(("EDT_RegisterPlugin(\"%s\")")); #endif } int32 EDT_NumberOfPluginCategories(){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetNumberOfCategories(); } #endif return 0; } int32 EDT_NumberOfPlugins(int32 category){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetNumberOfPlugins(category); } #else #ifdef XP_MAC #pragma unused(category) #endif #endif return 0; } char* EDT_GetPluginCategoryName(int32 pluginIndex){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetCategoryName(pluginIndex); } #else #ifdef XP_MAC #pragma unused(pluginIndex) #endif #endif return 0; } char* EDT_GetPluginName(int32 category, int32 index){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetPluginName(category, index); } #else #ifdef XP_MAC #pragma unused(category, index) #endif #endif return 0; } char* EDT_GetPluginMenuHelp(int32 category, int32 index){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetPluginHint(category, index); } #else #ifdef XP_MAC #pragma unused(category, index) #endif #endif return 0; } XP_Bool EDT_PerformPlugin(MWContext *pContext, int32 category, int32 index, EDT_ImageEncoderCallbackFn doneFunction, void* hook){ #ifndef EDITOR_JAVA #ifdef XP_MAC #pragma unused(category, index, doneFunction, hook) #endif #endif GET_WRITABLE_EDIT_BUF_OR_RETURN(pContext, pEditBuffer) FALSE; #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { XP_Bool saveJS = pContext->forceJSEnabled; pContext->forceJSEnabled = TRUE; netscape_javascript_JSObject *t_object=LJ_GetMochaWindow(pContext); XP_Bool bReturn = ((CEditorPluginInterface*) pEditBuffer->GetPlugins())->Perform(category, index, doneFunction, hook, t_object); pContext->forceJSEnabled = saveJS; return bReturn; } #endif return FALSE; } XP_Bool EDT_PerformPluginByClassName(MWContext *pContext, char* pClassName, EDT_ImageEncoderCallbackFn doneFunction, void* hook){ #ifndef EDITOR_JAVA #ifdef XP_MAC #pragma unused(pClassName, doneFunction, hook) #endif #endif GET_WRITABLE_EDIT_BUF_OR_RETURN(pContext, pEditBuffer) FALSE; #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { XP_Bool saveJS = pContext->forceJSEnabled; pContext->forceJSEnabled = TRUE; netscape_javascript_JSObject *t_object=LJ_GetMochaWindow(pContext); XP_Bool bReturn = ((CEditorPluginInterface*) pEditBuffer->GetPlugins())->Perform(pClassName, doneFunction, hook, t_object); pContext->forceJSEnabled = saveJS; return bReturn; } #endif return FALSE; } void EDT_PerformEvent(MWContext *pContext, char* pEvent, char* pDocURL, XP_Bool bCanChangeDocument, XP_Bool bCanCancel, EDT_ImageEncoderCallbackFn doneFunction, void* hook){ #ifndef EDITOR_JAVA #ifdef XP_MAC #pragma unused(pEvent, pDocURL, bCanChangeDocument, bCanCancel) #endif #endif GET_WRITABLE_EDIT_BUF_OR_RETURN(pContext, pEditBuffer); #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { // We must force JavaScript on with this, else we fail to // get t_object because JS is normally OFF for editor XP_Bool saveJS = pContext->forceJSEnabled; pContext->forceJSEnabled = TRUE; netscape_javascript_JSObject *t_object=LJ_GetMochaWindow(pContext); ((CEditorPluginInterface*) pEditBuffer->GetPlugins())->Perform(pEvent, pDocURL, bCanChangeDocument, bCanCancel, doneFunction, hook, t_object); pContext->forceJSEnabled = saveJS; return; } #endif if ( doneFunction){ (*doneFunction)(ED_IMAGE_ENCODER_OK, hook); } } XP_Bool EDT_IsPluginActive(MWContext* pContext){ GET_EDIT_BUF_OR_RETURN_READY_OR_NOT(pContext, pEditBuffer) FALSE; #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return ((CEditorPluginInterface*) pEditBuffer->GetPlugins())->IsPluginActive(); } #endif return FALSE; } void EDT_StopPlugin(MWContext* pContext){ GET_EDIT_BUF_OR_RETURN_READY_OR_NOT(pContext, pEditBuffer); #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { ((CEditorPluginInterface*) pEditBuffer->GetPlugins())->StopPlugin(); } #endif } #ifdef EDITOR_JAVA void EDT_ComposerPluginCallback(jint hook1, jint action1, struct java_lang_Object* pArg){ CEditorPluginInterface* pInterface = (CEditorPluginInterface*) hook1; if ( ! CEditorPluginInterface::IsValidInterface(pInterface )) { XP_ASSERT(FALSE); // A spurrious callback. return; } int32 action = (int32) action1; if ( pInterface ) { pInterface->PluginCallback(action, pArg); } } #endif int32 EDT_NumberOfEncoders(){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetNumberOfEncoders(); } #endif return 0; } char* EDT_GetEncoderName(int32 index){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetEncoderName(index); } #else #ifdef XP_MAC #pragma unused(index) #endif #endif return 0; } char* EDT_GetEncoderFileExtension(int32 index){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetEncoderFileExtension(index); } #else #ifdef XP_MAC #pragma unused(index) #endif #endif return 0; } char* EDT_GetEncoderFileType(int32 index){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetEncoderFileType(index); } #else #ifdef XP_MAC #pragma unused(index) #endif #endif return 0; } char* EDT_GetEncoderMenuHelp(int32 index){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetEncoderHint(index); } #else #ifdef XP_MAC #pragma unused(index) #endif #endif return 0; } XP_Bool EDT_GetEncoderNeedsQuantizedSource(int32 index){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { return CEditorPluginInterface::GetEncoderNeedsQuantizedSource(index); } #else #ifdef XP_MAC #pragma unused(index) #endif #endif return FALSE; } XP_Bool EDT_StartEncoder(MWContext* pContext, int32 index, int32 width, int32 height, char** pixels, char* csFileName, EDT_ImageEncoderCallbackFn doneFunction, void* doneArgument){ #ifdef EDITOR_JAVA GET_EDIT_BUF_OR_RETURN_READY_OR_NOT(pContext, pEditBuffer) FALSE; if ( EditorPluginManager_PluginsExist() ) { return ((CEditorPluginInterface*) pEditBuffer->GetPlugins())->StartEncoder(index, width, height, pixels, csFileName, doneFunction, doneArgument); } #else #ifdef XP_MAC #pragma unused(pContext, index, width, height, pixels, csFileName, doneFunction, doneArgument) #endif #endif return FALSE; } void EDT_StopEncoder(MWContext* pContext){ #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { EDT_StopPlugin(pContext); } #else #ifdef XP_MAC #pragma unused(pContext) #endif #endif } #ifdef EDITOR_JAVA struct PreOpenCallbackHook { CEditorPluginInterface* pInterface; EDT_PreOpenCallbackFn doneFunction; void* hook; char* pURL; }; static void edt_SetURL(void* hook3, char* pURL){ PreOpenCallbackHook* hook2 = (PreOpenCallbackHook*) hook3; char* pOldURL = hook2->pURL; hook2->pURL = pURL ? XP_STRDUP(pURL) : 0; XP_FREE(pOldURL); } #ifndef XP_OS2 static #else extern "OPTLINK" #endif void edt_PreOpenDoneFunction(EDT_ImageEncoderStatus status, void* hook3){ PreOpenCallbackHook* hook2 = (PreOpenCallbackHook*) hook3; EDT_PreOpenCallbackFn doneFunction = hook2->doneFunction; void* hook = hook2->hook; char* pURL = hook2->pURL; if ( doneFunction ) { (*doneFunction)(status == ED_IMAGE_ENCODER_USER_CANCELED, pURL, hook); } CEditorPluginInterface* epi = hook2->pInterface; if (pURL){ XP_FREE(pURL); } delete epi; delete hook2; } #endif void EDT_PreOpen(MWContext *pErrorContext,char* _pURL, EDT_PreOpenCallbackFn doneFunction, void* hook){ // Make local copy, so we can change it if we want. char *pURL = _pURL ? XP_STRDUP(_pURL) : 0; int urlType = NET_URL_Type(pURL); // Always ignore target or query appendages edt_StripAtHashOrQuestionMark(pURL); XP_Bool bDeleteContext = FALSE; XP_Bool bValid = FALSE; //if( !pErrorContext ) { //Primarily for the Mac, which doesn't create // a context before calling EDT_PreOpen // (Windows and UNIX create a new Composer window + MWContext // first or pass in parent MWContext here ) pErrorContext = XP_NewContext(); if( !pErrorContext ) goto ERROR_EXIT; pErrorContext->type = MWContextBrowser; pErrorContext->is_editor = TRUE; bDeleteContext = TRUE; } XP_ASSERT(pErrorContext); if ( !pURL || !*pURL ) { ERROR_EXIT: // Error or user Canceled. if (doneFunction) { (*doneFunction)(TRUE, _pURL, hook); } goto PRE_OPEN_EXIT; } // Only allow editing of appropriate types of URLs. if (urlType == FILE_TYPE_URL || urlType == FTP_TYPE_URL || urlType == HTTP_TYPE_URL || urlType == SECURE_HTTP_TYPE_URL) { bValid = TRUE; } // Test for platform-specific filename if URL type is unknown. if (urlType == 0) { // don't make assumption that the user wants a local file // If it's not a valid URL, then the user probably wants a remote file // the following behavior is consistent with the browser location field bValid = TRUE; } if (!bValid) { // Tell user that we are rejecting their URL. char *tmplate = XP_GetString(XP_EDT_CANT_EDIT_URL); char *msg = NULL; if (tmplate) { msg = PR_smprintf(tmplate,pURL); } if (msg) { FE_Alert(pErrorContext,msg); XP_FREE(msg); } else { XP_ASSERT(0); } goto ERROR_EXIT; } #ifdef EDITOR_JAVA if ( EditorPluginManager_PluginsExist() ) { CEditorPluginInterface* epi = new CEditorPluginInterface(0, &EDT_ComposerPluginCallback); char temp[500]; XP_SPRINTF(temp, "edit:%s", pURL); PreOpenCallbackHook* hook2 = new PreOpenCallbackHook; hook2->pInterface = epi; hook2->doneFunction = doneFunction; hook2->pURL = pURL ? XP_STRDUP(pURL) : 0; hook2->hook = hook; XP_Bool saveJS = pErrorContext->forceJSEnabled; pErrorContext->forceJSEnabled = TRUE; netscape_javascript_JSObject *t_object=LJ_GetMochaWindow(pErrorContext); // Note: doneFunction will be called via hook2->doneFunction if following is successful XP_Bool bResult = epi->Perform(temp, &edt_PreOpenDoneFunction, hook2, t_object); pErrorContext->forceJSEnabled = saveJS; if ( bResult ) goto PRE_OPEN_EXIT; // Failed, so clean up delete epi; delete hook2; } #endif if ( doneFunction ){ // FALSE means don't cancel. (*doneFunction)(FALSE, pURL, hook); } PRE_OPEN_EXIT: XP_FREEIF(pURL); if( bDeleteContext ) XP_DeleteContext(pErrorContext); } struct PreCloseCallbackHook { EDT_PreCloseCallbackFn doneFunction; void* hook; }; #ifndef XP_OS2 static #else extern "OPTLINK" #endif void edt_PreCloseDoneFunction(EDT_ImageEncoderStatus, void* hook2){ // Ignore status. if (!hook2) { XP_ASSERT(0); return; } PreCloseCallbackHook *preClose = (PreCloseCallbackHook *)hook2; if ( preClose->doneFunction ) (*preClose->doneFunction)(preClose->hook); delete preClose; } void EDT_PreClose(MWContext *pMWContext,char* pURL, EDT_PreCloseCallbackFn doneFunction, void* hook) { PreCloseCallbackHook *hook2 = new PreCloseCallbackHook; if (!hook2) { XP_ASSERT(0); return; } hook2->doneFunction = doneFunction; hook2->hook = hook; // EDT_PerformEvent takes care of #ifdef EDITOR_JAVA. EDT_PerformEvent(pMWContext,"close",pURL,FALSE,FALSE,edt_PreCloseDoneFunction,(void *)hook2); } // End of edt.h API functions #ifdef EDITOR_JAVA #define JAVA_EE_OR_RETURN JRIEnv* ee = Env(); if ( ! ee ) return // Helper class for calling editor plugins extern "C" { JRIEnv* npn_getJavaEnv(); } EditorPluginManager EditorPluginManager_new(MWContext* pContext) { return new CEditorPluginInterface(pContext, &EDT_ComposerPluginCallback); } void EditorPluginManager_delete(EditorPluginManager a){ CEditorPluginInterface* b = (CEditorPluginInterface*) a; delete b; } XP_Bool EditorPluginManager_IsPluginActive(EditorPluginManager a) { CEditorPluginInterface* b = (CEditorPluginInterface*) a; if ( CEditorPluginInterface::PluginsExist() && b ) { return b->IsPluginActive(); } return FALSE; } XP_Bool EditorPluginManager_PluginsExist() { return CEditorPluginInterface::PluginsExist(); } // This method is a modified version of intl_makeJavaString in modules/edtplug/lj_init.c // Really would like this to be standardized. PRIVATE PRBool onlyascii2(char* str, int len) { int i; for(i = 0 ; i < len ; i++, str++) { if((*str & 0x80) != 0x00) return PR_FALSE; } return PR_TRUE; } PRIVATE struct java_lang_String* intl_makeJavaString2(JRIEnv* env, int16 encoding, char* str, int len) { // First, convert from encoding to win_csid encoding &= ~CS_AUTO; if ((encoding == 0) || ((STATEFUL != (encoding & STATEFUL) ) && onlyascii2(str,len) ) ) { return JRI_NewStringUTF(env, str, len); } int16 win_csid = INTL_DocToWinCharSetID(encoding) & ~CS_AUTO; char *str_in_win_csid = NULL; int len_in_win_csid = 0; XP_Bool needConvertToWincsid = (encoding != win_csid); XP_Bool needToFreeMem = needConvertToWincsid; if(needConvertToWincsid) { str_in_win_csid = (char*)INTL_ConvertLineWithoutAutoDetect( (int16)encoding, win_csid, (unsigned char*) str, (uint32) len); if(NULL == str_in_win_csid ) { str_in_win_csid = str; len_in_win_csid = len; needToFreeMem = FALSE; } else { len_in_win_csid = (int)XP_STRLEN( str_in_win_csid ); } } else { str_in_win_csid = str; len_in_win_csid = len; } // Second, convert from win_csid to Unicode INTL_Unicode* q; int unicodelen, realunicodelen; unicodelen = INTL_TextToUnicodeLen(win_csid, (unsigned char*)str_in_win_csid, (int32)len_in_win_csid); struct java_lang_String* result; if ((q = (INTL_Unicode*) XP_ALLOC(sizeof(INTL_Unicode) * unicodelen)) != NULL) { realunicodelen = INTL_TextToUnicode(win_csid, (unsigned char*)str_in_win_csid, len_in_win_csid, q, unicodelen ); result = JRI_NewString(env, (const jchar*)q, realunicodelen); XP_FREE(q); } else { XP_ASSERT(q); result = JRI_NewStringUTF(env, str, len); } // Finally, let's free some memory if(needToFreeMem && str_in_win_csid) { XP_FREE(str_in_win_csid); } return result; } // Returns length accurately. // returns NULL if the string is too large for the platform. PRIVATE char* intl_makeStringFromJava(JRIEnv* env, int16 encoding, struct java_lang_String* jstr, int32& length) { const jchar * juc = JRI_GetStringChars(env, jstr); uint32 jucLen = JRI_GetStringLength(env, jstr); if ( jucLen > (uint32) MAX_STRING ) { length = jucLen; return 0; } encoding &= ~CS_AUTO; int16 win_csid = INTL_DocToWinCharSetID(encoding) & ~CS_AUTO; length = INTL_UnicodeToStrLen(win_csid, (INTL_Unicode*) juc, jucLen); if ( length > MAX_STRING ) { return 0; } char* text_in_win_csid = (char*) XP_ALLOC(length + 1); if ( ! text_in_win_csid ) { return 0; } INTL_UnicodeToStr(win_csid, (INTL_Unicode*) juc, jucLen, (unsigned char*) text_in_win_csid, length + 1); char* text_in_encoding = NULL; if(encoding == win_csid) { text_in_encoding = text_in_win_csid; } else { text_in_encoding = (char*)INTL_ConvertLineWithoutAutoDetect( win_csid, (int16)encoding, (unsigned char*) text_in_win_csid, (uint32) XP_STRLEN(text_in_win_csid)); if ( ! text_in_encoding ){ text_in_encoding = text_in_win_csid; } else { XP_FREE(text_in_win_csid); } } return text_in_encoding; } XP_Bool CEditorPluginInterface::PluginsExist(){ return g_Plugin.Size() > 0; } JRIGlobalRef CEditorPluginInterface::g_pManager; JRIEnv* CEditorPluginInterface::g_pEnv; XP_Bool CEditorPluginInterface::g_bJavaInitialized; JRIEnv* CEditorPluginInterface::Env(){ if ( ! g_bJavaInitialized ) { g_bJavaInitialized = TRUE; g_pEnv = npn_getJavaEnv(); if ( g_pEnv == NULL ) { XP_TRACE(("CEditorPluginInterface::Env() - Could not start Java.")); return NULL; } JRIEnv* ee = g_pEnv; JRI_ExceptionClear(ee); use_netscape_plugin_composer_PluginManager(ee); use_netscape_plugin_composer_Composer(ee); use_netscape_plugin_composer_MozillaCallback(ee); if ( JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); XP_TRACE(("Couldn't find PluginManager class.")); return g_pEnv; } g_pManager = JRI_NewGlobalRef(ee, netscape_plugin_composer_PluginManager_new(ee, class_netscape_plugin_composer_PluginManager(ee))); if ( ! Manager() || JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); XP_TRACE(("Couldn't create PluginManager instance.")); } // Tell the plugin manager about the plugins int size = g_Plugin.Size(); for(int i = 0; i < size; i++ ){ char* pPlugin = g_Plugin[i]; // Until we get java based local file i/o working, help out the plugin by // reading the ini text here. static const char* kComposerIni = "netscape_plugin_composer.ini"; zip_t* pZip = zip_open(pPlugin); if ( pZip ) { struct stat status; if ( zip_stat(pZip, kComposerIni, &status)){ int32_t len = status.st_size; if ( len > 0 ) { char* pBuffer = new char[len]; if ( zip_get(pZip, kComposerIni, pBuffer, len) ){ struct java_lang_String* pluginINI = (struct java_lang_String*) JRI_NewStringUTF(ee, pBuffer, len); struct java_lang_String* pluginFileName = (struct java_lang_String*) JRI_NewStringUTF(ee, pPlugin, XP_STRLEN(pPlugin)); JRI_ExceptionClear(ee); netscape_plugin_composer_PluginManager_registerPlugin(ee, Manager(), pluginFileName, pluginINI); if ( JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); XP_TRACE(("Couldn't registerPlugin %s", pPlugin)); } } } } zip_close(pZip); } } } return g_pEnv; } netscape_plugin_composer_PluginManager* CEditorPluginInterface::Manager(){ JAVA_EE_OR_RETURN 0; return (netscape_plugin_composer_PluginManager*) JRI_GetGlobalRef(ee, g_pManager); } netscape_plugin_composer_Composer* CEditorPluginInterface::Composer(){ JAVA_EE_OR_RETURN 0; return (netscape_plugin_composer_Composer*) JRI_GetGlobalRef(ee, m_pComposer); } TXP_GrowableArray_pChar CEditorPluginInterface::g_Plugin; TXP_GrowableArray_CEditorPluginInterface CEditorPluginInterface::g_Interface; CEditorPluginInterface::CEditorPluginInterface(MWContext* pContext, ComposerPluginCallbackFn callback){ m_pContext = pContext; m_callback = callback; m_bPluginActive = FALSE; m_doneFunction = 0; m_pComposer = 0; m_bImageEncoder = FALSE; JAVA_EE_OR_RETURN; m_pComposer = JRI_NewGlobalRef(ee, netscape_plugin_composer_Composer_new(ee, class_netscape_plugin_composer_Composer(ee), (jint) this, (jint) m_callback, (jint) ee)); g_Interface.Add(this); } CEditorPluginInterface::~CEditorPluginInterface(){ int size = g_Interface.Size(); int i = 0; for(i = 0; i < size; i++ ){ if ( g_Interface[i] == this ) { break; } } if ( i < size ) { for(i++; i < size; i++){ g_Interface[i-1] = g_Interface[i]; } g_Interface.SetSize(size-1); } else { XP_ASSERT(FALSE); // We didn't find ourselves in the interface registry. } JAVA_EE_OR_RETURN; JRI_DisposeGlobalRef(ee, m_pComposer); #if 0 netscape_plugin_composer_PluginManager::_unuse(ee); #endif } XP_Bool CEditorPluginInterface::IsValidInterface(CEditorPluginInterface* pInterface){ int i = 0; int size = g_Interface.Size(); for(i = 0; i < size; i++ ){ if ( g_Interface[i] == pInterface ) { return TRUE; } } return FALSE; } void CEditorPluginInterface::Register(char* plugin){ // This method is called before Java is initialized. // It is designed so that it doesn't need Java to run. // The names of the plugin files are saved until later. // // This way, we don't start Java until the Composer is started. int size = g_Plugin.Size(); for(int i = 0; i < size; i++ ){ if ( XP_STRCMP(g_Plugin[i], plugin) == 0 ) { return; } } // If We've started Java, it's too late to add the plug-in. if ( g_bJavaInitialized ) { // to do: Allow Composer plug-ins to be added after starting. return; } // We don't have to add this plugin to the class path because // LJ_AddToClassPath puts every .zip or .jar file in // the plug-ins directory into the class path. // Save the plugin name. int len = XP_STRLEN(plugin); char* pCopy = (char*) XP_ALLOC(len+1); if ( pCopy ) { XP_STRCPY(pCopy, plugin); g_Plugin.Add(pCopy); } } int32 CEditorPluginInterface::GetNumberOfCategories(){ if ( ! PluginsExist() ) return 0; JAVA_EE_OR_RETURN 0; if ( ! Manager() ) { return 0; } JRI_ExceptionClear(ee); int numPlugins = netscape_plugin_composer_PluginManager_getNumberOfCategories(ee, Manager()); if ( JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); XP_TRACE(("Couldn't getNumberOfCategories.")); return 0; } return numPlugins; } int32 CEditorPluginInterface::GetNumberOfPlugins(int32 type){ if ( ! PluginsExist() ) return 0; JAVA_EE_OR_RETURN 0; if ( ! Manager() ) { return 0; } JRI_ExceptionClear(ee); int numPlugins = netscape_plugin_composer_PluginManager_getNumberOfPlugins(ee, Manager(), type); if ( JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); XP_TRACE(("Couldn't getNumberOfPlugins.")); return 0; } return numPlugins; } static char* getPlatformString(JRIEnv* ee, java_lang_String* name) { if (name == NULL || JRI_ExceptionOccurred(ee)){ #ifdef DEBUG JRI_ExceptionDescribe(ee); #endif XP_TRACE(("Couldn't get composer plugin field.")); return NULL; } /* Get the platform encoding of the string based on the browser's default csid */ char* result = (char*) JRI_GetStringPlatformChars(ee, name, NULL, 0); if (result == NULL) { XP_TRACE(("Couldn't convert unicode string to platform string.")); return NULL; } else if (JRI_ExceptionOccurred(ee)) { #ifdef DEBUG JRI_ExceptionDescribe(ee); #endif XP_TRACE(("Couldn't convert unicode string to platform string.")); return NULL; } return result; } char* CEditorPluginInterface::GetCategoryName(int32 type){ char* result = 0; if ( ! PluginsExist() ) return result; JAVA_EE_OR_RETURN result; if ( ! Manager() ) { return result; } JRI_ExceptionClear(ee); java_lang_String* name = netscape_plugin_composer_PluginManager_getCategoryName(ee, Manager(), type); return getPlatformString(ee, name); } char* CEditorPluginInterface::GetPluginName(int32 type, int32 index){ char* result = 0; if ( ! PluginsExist() ) return result; JAVA_EE_OR_RETURN result; if ( ! Manager() ) { return result; } JRI_ExceptionClear(ee); java_lang_String* name = netscape_plugin_composer_PluginManager_getPluginName(ee, Manager(), type, index); return getPlatformString(ee, name); } char* CEditorPluginInterface::GetPluginHint(int32 type, int32 index){ char* result = 0; if ( ! PluginsExist() ) return result; JAVA_EE_OR_RETURN result; if ( ! Manager() ) { return result; } JRI_ExceptionClear(ee); java_lang_String* hint = netscape_plugin_composer_PluginManager_getPluginHint(ee, Manager(), type, index); return getPlatformString(ee, hint); } int32 CEditorPluginInterface::GetNumberOfEncoders(){ if ( ! PluginsExist() ) return 0; JAVA_EE_OR_RETURN 0; if ( ! Manager() ) { return 0; } JRI_ExceptionClear(ee); int32 result = netscape_plugin_composer_PluginManager_getNumberOfEncoders(ee, Manager()); if ( JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); XP_TRACE(("Couldn't getNumberOfEncoders.")); return 0; } return result; } char* CEditorPluginInterface::GetEncoderName(int32 index){ char* result = 0; if ( ! PluginsExist() ) return result; JAVA_EE_OR_RETURN result; if ( ! Manager() ) { return result; } JRI_ExceptionClear(ee); java_lang_String* hint = netscape_plugin_composer_PluginManager_getEncoderName(ee, Manager(), index); return getPlatformString(ee, hint); } char* CEditorPluginInterface::GetEncoderHint(int32 index){ char* result = 0; if ( ! PluginsExist() ) return result; JAVA_EE_OR_RETURN result; if ( ! Manager() ) { return result; } JRI_ExceptionClear(ee); java_lang_String* hint = netscape_plugin_composer_PluginManager_getEncoderHint(ee, Manager(), index); return getPlatformString(ee, hint); } char* CEditorPluginInterface::GetEncoderFileExtension(int32 index){ char* result = 0; if ( ! PluginsExist() ) return result; JAVA_EE_OR_RETURN result; if ( ! Manager() ) { return result; } JRI_ExceptionClear(ee); java_lang_String* hint = netscape_plugin_composer_PluginManager_getEncoderFileExtension(ee, Manager(), index); return getPlatformString(ee, hint); } char* CEditorPluginInterface::GetEncoderFileType(int32 index){ char* result = 0; if ( ! PluginsExist() ) return result; JAVA_EE_OR_RETURN result; if ( ! Manager() ) { return result; } JRI_ExceptionClear(ee); java_lang_String* hint = netscape_plugin_composer_PluginManager_getEncoderFileType(ee, Manager(), index); return getPlatformString(ee, hint); } XP_Bool CEditorPluginInterface::GetEncoderNeedsQuantizedSource(int32 index){ XP_Bool result = FALSE; if ( ! PluginsExist() ) return result; JAVA_EE_OR_RETURN result; if ( ! Manager() ) { return result; } JRI_ExceptionClear(ee); result = netscape_plugin_composer_PluginManager_getEncoderNeedsQuantizedSource(ee, Manager(), index); if ( JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); XP_TRACE(("Couldn't getEncoderNeedsQuantizedSource.")); return result; } return result; } XP_Bool CEditorPluginInterface::StartEncoder(int32 index, int32 width, int32 height, char** pixels, char* csFileName, EDT_ImageEncoderCallbackFn doneFunction, void* doneArgument){ if ( ! PluginsExist() ) return FALSE; JAVA_EE_OR_RETURN FALSE; if ( ! Manager() ) { return FALSE; } m_bCanChangeDocument = FALSE; m_bCanCancel = TRUE; m_bImageEncoder = TRUE; // Convert the file name struct java_lang_String* javaFileName = (struct java_lang_String*) JRI_NewStringUTF(ee, csFileName, XP_STRLEN(csFileName)); jarrayArray javaPixels = (jarrayArray) JRI_NewObjectArray(ee, height, JRI_FindClass(ee, JRISigArray(JRISigByte)) , NULL); { // Convert the pixels to Java data struct int32 byteLength = width * 3; // Fill it up with the lines for(int hh = 0; hh < height; hh++){ jbyteArray a = (jbyteArray) JRI_NewByteArray(ee, byteLength, pixels[hh]); JRI_SetObjectArrayElement(ee, javaPixels, hh, a); } } // Save the callback info. m_doneFunction = doneFunction; m_doneFunctionArgument = doneArgument; m_bPluginActive = TRUE; // call the encoder JRI_ExceptionClear(ee); XP_Bool result = (XP_Bool) netscape_plugin_composer_PluginManager_startEncoder(ee, Manager(), Composer(), index, width, height, javaPixels, javaFileName); if ( JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); XP_TRACE(("Couldn't start encoder.")); m_bPluginActive = FALSE; result = FALSE; } return result; } XP_Bool CEditorPluginInterface::Perform(int32 type, int32 index, EDT_ImageEncoderCallbackFn doneFunction, void* hook, netscape_javascript_JSObject *jsobject){ return Perform2(NULL, type, index, TRUE, TRUE, doneFunction, hook, jsobject); } XP_Bool CEditorPluginInterface::Perform(char* pPluginName, EDT_ImageEncoderCallbackFn doneFunction, void* hook, netscape_javascript_JSObject *jsobject){ return Perform2(pPluginName, 0, 0, TRUE, TRUE, doneFunction, hook, jsobject); } void CEditorPluginInterface::Perform(char* pEvent, char* pDocURL, XP_Bool bCanChangeDocument, XP_Bool bCanCancel, EDT_ImageEncoderCallbackFn doneFunction, void* hook, netscape_javascript_JSObject *jsobject){ char *pEventName = NULL; StrAllocCat(pEventName,pEvent); StrAllocCat(pEventName,":"); if ( pDocURL ) { StrAllocCat(pEventName,pDocURL); } XP_Bool result = Perform2(pEventName, 0, 0, bCanChangeDocument, bCanCancel, doneFunction, hook, jsobject); XP_FREE(pEventName); if ( !result && doneFunction ) { (*doneFunction)(ED_IMAGE_ENCODER_EXCEPTION, hook); } } XP_Bool CEditorPluginInterface::Perform2(char* pPluginName, int32 type, int32 index, XP_Bool bCanChangeDocument, XP_Bool bCanCancel, EDT_ImageEncoderCallbackFn doneFunction, void* hook, netscape_javascript_JSObject *jsobject){ m_bCanChangeDocument = bCanChangeDocument; m_bCanCancel = bCanCancel; m_bImageEncoder = FALSE; if ( ! pPluginName && ! PluginsExist() ) { return FALSE; } if ( m_bPluginActive ) { return FALSE; } JAVA_EE_OR_RETURN FALSE; if ( ! Manager() ) { return FALSE; } struct java_lang_String* document = GetDocument(); // It is OK for the document to be NULL if we have // no buffer. (This can happen during an edit event.) // Otherwise, it is an error condition. NULL is returned // when the document is too large for Win16. if ( document==NULL && GetBuffer() != NULL){ return FALSE; } struct java_lang_String* base = GetBaseURL(); struct java_lang_String* workDirectoryURL = 0; struct java_lang_String* workDirectory = 0; GetWorkDirectoryAndURL(workDirectory, workDirectoryURL); m_bChangedDocument = FALSE; // call the plugin JRI_ExceptionClear(ee); XP_Bool bResult = FALSE; m_doneFunction = doneFunction; m_doneFunctionArgument = hook; if ( pPluginName ) { // Call plugin by class name. struct java_lang_String* pluginName = (struct java_lang_String*) JRI_NewStringUTF(ee, pPluginName, XP_STRLEN(pPluginName)); JRI_ExceptionClear(ee); bResult = netscape_plugin_composer_PluginManager_performPluginByName(ee, Manager(), Composer(), pluginName, document, base, workDirectory, workDirectoryURL, jsobject); } else { // Call plugin by menu category and index JRI_ExceptionClear(ee); bResult = netscape_plugin_composer_PluginManager_performPlugin(ee, Manager(), Composer(), type, index, document, base, workDirectory, workDirectoryURL, jsobject); } if ( JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); bResult = FALSE; } if ( bResult == FALSE ) { XP_TRACE(("Couldn't perform.")); m_doneFunction = 0; m_doneFunctionArgument = 0; return FALSE; } m_bPluginActive = TRUE; if ( GetBuffer() ){ GetBuffer()->m_pContext->waitingMode = 1; } return TRUE; } struct java_lang_String* CEditorPluginInterface::GetBaseURL(){ if ( GetBuffer() == 0 ) { return 0; } JAVA_EE_OR_RETURN 0; char* pBase = LO_GetBaseURL(GetBuffer()->m_pContext); // an alias. We don't own the result. int32 iBaseLen = XP_STRLEN(pBase); struct java_lang_String* base = (struct java_lang_String*) JRI_NewStringUTF(ee, pBase, iBaseLen); return base; } struct java_lang_String* CEditorPluginInterface::GetDocument(){ if ( GetBuffer() == 0 ) { return 0; } JAVA_EE_OR_RETURN 0; XP_HUGE_CHAR_PTR pDocData = 0; int32 docLength = 0; docLength = GetBuffer()->WriteToBuffer(&pDocData, TRUE); if ( docLength > MAX_STRING ) { DocumentIsTooLarge(docLength, XP_EDT_CP_DOCUMENT_TOO_LARGE_READ); return 0; } int32 unicodeByteLength = 2 * (int32) INTL_TextToUnicodeLen(GetBuffer()->GetDocCharSetID(), (unsigned char*)pDocData, docLength); if ( unicodeByteLength > MAX_STRING ) { DocumentIsTooLarge(unicodeByteLength, XP_EDT_CP_DOCUMENT_TOO_LARGE_READ); return 0; } struct java_lang_String* document = (struct java_lang_String*) intl_makeJavaString2(ee, GetBuffer()->GetDocCharSetID(), pDocData, docLength); if ( pDocData ) { XP_HUGE_FREE(pDocData); } return document; } void CEditorPluginInterface::DocumentIsTooLarge(int32 docLengthInBytes, int msgid){ // Tell the user that the document is too big. char* tmplate = XP_GetString(msgid); if (tmplate) { char* msg = PR_smprintf(tmplate,docLengthInBytes, MAX_STRING); if (msg) { FE_Alert(m_pContext,msg); XP_FREE(msg); } } } void CEditorPluginInterface::GetWorkDirectoryAndURL( struct java_lang_String*& workDirectory, struct java_lang_String*& workDirectoryURL){ workDirectory = 0; workDirectoryURL = 0; if ( GetBuffer() == 0 ) { return; } JAVA_EE_OR_RETURN; // Get the work directory char* pWork = NULL; // We own the storage char* pBase = LO_GetBaseURL(GetBuffer()->m_pContext); // an alias. We don't own the result. int baseURLType = NET_URL_Type(pBase); if (baseURLType == FILE_TYPE_URL) { // Get the file name out of the base URL XP_Bool bValidBase = XP_ConvertUrlToLocalFile(pBase, &pWork); XP_FREE(pWork); pWork = NULL; if ( bValidBase) { // OK, the base file exists. Now we need pWork to hold the directory rather than the // file. char* pTemp = XP_STRDUP(pBase); if ( pTemp != NULL ) { char* pEnd = pTemp + XP_STRLEN(pTemp) - 1; while ( pEnd > pTemp && *pEnd != '/') { pEnd--; } if (* pEnd == '/') { *pEnd = '\0'; XP_ConvertUrlToLocalFile(pTemp, &pWork); } XP_FREE(pTemp); } } } if ( pWork == NULL ) { // If we can't use document current directory, use document temp directory. CEditCommandLog *pLog = CGlobalHistoryGroup::GetGlobalHistoryGroup()->GetLog(GetBuffer()); if (pLog) { char *pxpURL = pLog->GetDocTempDir(); if (pxpURL) { pWork = WH_FileName(pxpURL,xpURL); XP_FREE(pxpURL); } } } if ( pWork != NULL ) { int32 iWorkLen = XP_STRLEN(pWork); workDirectory = (struct java_lang_String*) JRI_NewStringUTF(ee, pWork, iWorkLen); // And what's the URL that corresponds to the work directory? char* pWorkURL = XP_PlatformFileToURL(pWork); int32 iWorkURLLen = XP_STRLEN(pWorkURL); workDirectoryURL = (struct java_lang_String*) JRI_NewStringUTF(ee, pWorkURL, iWorkURLLen); #ifdef DEBUG_rhess fprintf(stderr, " workDir::[ %s ]\n", pWork); fprintf(stderr, " workDirURL::[ %s ]\n", pWorkURL); #endif XP_FREE(pWork); XP_FREE(pWorkURL); } #ifdef DEBUG_rhess else { fprintf(stderr, " workDir::[ NULL ]\n"); fprintf(stderr, " workDirURL::[ NULL ]\n"); } #endif } XP_Bool CEditorPluginInterface::IsPluginActive(){ return m_bPluginActive; } void CEditorPluginInterface::StopPlugin(){ if ( ! PluginsExist() ) return; JAVA_EE_OR_RETURN; JRI_ExceptionClear(ee); netscape_plugin_composer_PluginManager_stopPlugin(ee, Manager(), Composer()); if ( JRI_ExceptionOccurred(ee)){ JRI_ExceptionDescribe(ee); XP_TRACE(("Couldn't stop plugin.")); } m_bPluginActive = FALSE; if ( GetBuffer()){ if ( m_bChangedDocument) { GetBuffer()->EndBatchChanges(); } GetBuffer()->m_pContext->waitingMode = 0; } } void CEditorPluginInterface::PluginCallback(int32 action, struct java_lang_Object* pArgument) { if ( ! PluginsExist() ) return; switch ( action ) { case PLUGIN_FAIL: case PLUGIN_CANCEL: // The plugin has failed. if ( m_bCanCancel ) { PluginFailed((struct java_lang_String*) pArgument); } else { PluginSucceeded(); } break; case PLUGIN_OK: // The plugin has succeeded. PluginSucceeded(); break; case PLUGIN_NEWTEXT: // The plugin has changed the text. NewText((struct java_lang_String*) pArgument); break; default: // Unknown callack XP_TRACE(("Unknown Composer Plugin Callback: %d\n", action)); break; } } void CEditorPluginInterface::PluginFailed(struct java_lang_String* pWhy){ XP_TRACE(("CEditorPluginInterface::PluginFailed.")); m_bPluginActive = FALSE; ImageEncoderFinished(pWhy ? ED_IMAGE_ENCODER_EXCEPTION : ED_IMAGE_ENCODER_USER_CANCELED); if ( m_bImageEncoder ) return; // The user canceled, or the plugin threw an exception. Back out // any change the user may have made to the document. if ( GetBuffer() ){ if (m_bChangedDocument) { GetBuffer()->EndBatchChanges(); } GetBuffer()->m_pContext->waitingMode = 0; if (m_bChangedDocument) { GetBuffer()->Undo(); // After this call, GetBuffer() is deleted. } } } void CEditorPluginInterface::PluginSucceeded(){ XP_TRACE(("CEditorPluginInterface::PluginSucceeded.")); m_bPluginActive = FALSE; ImageEncoderFinished(ED_IMAGE_ENCODER_OK); if ( m_bImageEncoder ) return; if ( GetBuffer() ){ if (m_bChangedDocument) { GetBuffer()->EndBatchChanges(); } GetBuffer()->m_pContext->waitingMode = 0; } } void CEditorPluginInterface::ImageEncoderFinished(EDT_ImageEncoderStatus status){ if ( ! m_doneFunction ) { return; } (*m_doneFunction)(status, m_doneFunctionArgument); m_doneFunction = 0; m_doneFunctionArgument = 0; } void CEditorPluginInterface::NewText(struct java_lang_String* pText){ XP_TRACE(("CEditorPluginInterface::NewText.")); JAVA_EE_OR_RETURN; if ( pText && m_bCanChangeDocument ) { int32 length; int16 csid = 0; if ( GetBuffer() ) { csid = GetBuffer()->GetDocCharSetID(); } char* pElementsAsChar = intl_makeStringFromJava(ee, csid, pText, length); if ( !pElementsAsChar ){ DocumentIsTooLarge(length, XP_EDT_CP_DOCUMENT_TOO_LARGE_WRITE); return; } if ( m_bChangedDocument == FALSE ) { m_bChangedDocument = TRUE; if ( GetBuffer() ) { GetBuffer()->BeginBatchChanges(kPerformPluginCommandID); } } if ( pElementsAsChar ) { if ( GetBuffer() ) { length++; // for '\0' at end. XP_HUGE_CHAR_PTR pElements = (XP_HUGE_CHAR_PTR) XP_HUGE_ALLOC(length); for(int32 i = 0; i < length; i++ ) { pElements[i] = pElementsAsChar[i]; } GetBuffer()->ReadFromBuffer(pElements); // At this point GetBuffer() is deleted. XP_HUGE_FREE(pElements); } else { // Call-back hack for setting the URL during preOpen edt_SetURL(m_doneFunctionArgument, pElementsAsChar); } XP_FREE(pElementsAsChar); } } } CEditBuffer* CEditorPluginInterface::GetBuffer(){ if ( ! m_pContext ) return 0; GET_EDIT_BUF_OR_RETURN_READY_OR_NOT(m_pContext, pEditBuffer) NULL; return pEditBuffer; } #endif // EDITOR_JAVA #endif // EDITOR