/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include /* On Windows, jpipe.dll must not have static dependencies on any other URE DLLs (sal3.dll, uwinapi.dll), as Java System.LoadLibrary could otherwise not load it. Therefore, on Windows, this code goes into a jpipx.dll that the jpipe.dll wrapper loads with LoadLibraryEx(LOAD_WITH_ALTERED_SEARCH_PATH). The function names in this wrapped code are truncated from the long JNICALL names, as JNICALL causes some "@N" with different numeric values for N (and probably different across 32 and 64 bit) to be added to the symbol names, which the calls to GetProcAddress in wrapper/wrapper.c would otherwise have to take into account. */ /*****************************************************************************/ /* exception macros */ static void ThrowException(JNIEnv * env, char const * type, char const * msg) { jclass c; (*env)->ExceptionClear(env); c = (*env)->FindClass(env, type); if (c == NULL) { (*env)->ExceptionClear(env); (*env)->FatalError(env, "JNI FindClass failed"); } if ((*env)->ThrowNew(env, c, msg) != 0) { (*env)->ExceptionClear(env); (*env)->FatalError(env, "JNI ThrowNew failed"); } } /*****************************************************************************/ /* helper functions prototypes */ static oslPipe getPipe(JNIEnv * env, jobject obj_this); static rtl_uString * jstring2ustring(JNIEnv * env, jstring jstr); /*****************************************************************************/ /* get pipe */ static oslPipe getPipe(JNIEnv * env, jobject obj_this) { jclass tclass; jfieldID fid; tclass = (*env)->GetObjectClass(env, obj_this); if (tclass == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot find class"); return NULL; } fid = (*env)->GetFieldID(env, tclass, "_nPipeHandle", "J"); if (fid == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot find field"); return NULL; } return (oslPipe) SAL_INT_CAST( sal_IntPtr, (*env)->GetLongField(env, obj_this, fid)); } /*****************************************************************************/ /* convert jstring to rtl_uString */ static rtl_uString * jstring2ustring(JNIEnv * env, jstring jstr) { const char * cstr; rtl_uString * ustr = NULL; cstr = (*env)->GetStringUTFChars(env, jstr, NULL); rtl_uString_newFromAscii(&ustr, cstr); (*env)->ReleaseStringUTFChars(env, jstr, cstr); return ustr; } /*****************************************************************************/ /* * Class: com_sun_star_lib_connections_pipe_PipeConnection * Method: connect * Signature: (Lcom/sun/star/beans/NativeService;)V */ SAL_DLLPUBLIC_EXPORT void #if defined(_WIN32) PipeConnection_create #else JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_createJNI #endif (JNIEnv * env, jobject obj_this, jstring name) { enum { START = 0, INMONITOR, GOTNAME, CREATED }; short state = START; jclass tclass; jfieldID fid; oslSecurity psec = osl_getCurrentSecurity(); oslPipe npipe = NULL; rtl_uString * pname = NULL; if ((*env)->MonitorEnter(env, obj_this) != 0) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot synchronize on the object"); goto error; } state = INMONITOR; /* check connection state */ npipe = getPipe(env, obj_this); if ((*env)->ExceptionOccurred(env) != NULL) goto error; if (npipe != NULL) { ThrowException(env, "com/sun/star/io/IOException", "native pipe is already connected"); goto error; } /* save the pipe name */ tclass = (*env)->GetObjectClass(env, obj_this); if (tclass == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot find class"); goto error; } fid = (*env)->GetFieldID(env, tclass, "_aDescription", "Ljava/lang/String;"); if (fid == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot find field"); goto error; } (*env)->SetObjectField(env, obj_this, fid, (jobject)name); /* convert pipe name to rtl_uString */ pname = jstring2ustring(env, name); if (pname == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot convert name"); goto error; } state = GOTNAME; /* try to connect */ npipe = osl_createPipe(pname, osl_Pipe_OPEN, psec); if (npipe == NULL) { ThrowException(env, "java/lang/RuntimeException", "cannot create native pipe"); goto error; } state = CREATED; /* save the pipe */ tclass = (*env)->GetObjectClass(env, obj_this); if (tclass == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot find class"); goto error; } fid = (*env)->GetFieldID(env, tclass, "_nPipeHandle", "J"); if (fid == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot find field"); goto error; } (*env)->SetLongField( env, obj_this, fid, SAL_INT_CAST(jlong, (sal_IntPtr) npipe)); /* done */ rtl_uString_release(pname); (*env)->MonitorExit(env, obj_this); osl_freeSecurityHandle(psec); return; error: switch (state) { case CREATED: osl_closePipe(npipe); osl_releasePipe(npipe); /* fall through */ case GOTNAME: rtl_uString_release(pname); /* fall through */ case INMONITOR: (*env)->MonitorExit(env, obj_this); /* fall through */ case START: osl_freeSecurityHandle(psec); default: break; } return; } /*****************************************************************************/ /* * Class: com_sun_star_lib_connections_pipe_PipeConnection * Method: closeJNI * Signature: ()V */ SAL_DLLPUBLIC_EXPORT void #if defined(_WIN32) PipeConnection_close #else JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_closeJNI #endif (JNIEnv * env, jobject obj_this) { enum { START = 0, INMONITOR }; short state = START; oslPipe npipe; /* native pipe */ jclass tclass; /* this class */ jfieldID fid; /* a field identifier */ if ((*env)->MonitorEnter(env, obj_this) != 0) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot synchronize on the object"); goto error; } state = INMONITOR; /* check connection state */ npipe = getPipe(env, obj_this); if ((*env)->ExceptionOccurred(env) != NULL) goto error; if (npipe == NULL) { ThrowException(env, "com/sun/star/io/IOException", "native pipe is not connected"); goto error; } /* remove the reference to the pipe */ tclass = (*env)->GetObjectClass(env, obj_this); if (tclass == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot find class"); goto error; } fid = (*env)->GetFieldID(env, tclass, "_nPipeHandle", "J"); if (fid == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot find field"); goto error; } (*env)->SetLongField(env, obj_this, fid, (jlong)0); /* release the pipe */ osl_closePipe(npipe); osl_releasePipe(npipe); /* done */ (*env)->MonitorExit(env, obj_this); return; error: switch (state) { case INMONITOR: (*env)->MonitorExit(env, obj_this); case START: default: break; } return; } /*****************************************************************************/ /* * Class: com_sun_star_lib_connections_pipe_PipeConnection * Method: readJNI * Signature: ([[BI)I */ SAL_DLLPUBLIC_EXPORT jint #if defined(_WIN32) PipeConnection_read #else JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_readJNI #endif (JNIEnv * env, jobject obj_this, jobjectArray buffer, jint len) { enum { START = 0, INMONITOR, ACQUIRED, GOTBUFFER }; short state = START; oslPipe npipe; /* native pipe */ void * nbuff = NULL; /* native read buffer */ jbyteArray bytes; /* java read buffer */ jint nread; /* number of bytes has been read */ /* enter monitor */ if ((*env)->MonitorEnter(env, obj_this) != 0) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot synchronize on the object"); goto error; } state = INMONITOR; /* check connection state */ npipe = getPipe(env, obj_this); if ((*env)->ExceptionOccurred(env) != NULL) goto error; if (npipe == NULL) { ThrowException(env, "com/sun/star/io/IOException", "native pipe is not connected"); goto error; } /* acquire pipe */ osl_acquirePipe( npipe ); state = ACQUIRED; /* allocate a buffer */ if ((nbuff = malloc(len)) == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe out of memory"); goto error; } state = GOTBUFFER; /* exit monitor */ (*env)->MonitorExit(env, obj_this); /* reading */ nread = osl_readPipe(npipe, nbuff, len); /* enter monitor again */ if ((*env)->MonitorEnter(env, obj_this) != 0) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot synchronize on the object"); goto error; } /* copy buffer */ if (nread >= 0) { bytes = (*env)->NewByteArray(env, len); if (bytes == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe out of memory"); goto error; } /* save the data */ (*env)->SetByteArrayRegion(env, bytes, 0, len, nbuff); (*env)->SetObjectArrayElement(env, buffer, 0, bytes); (*env)->DeleteLocalRef(env, bytes); } /* done */ free(nbuff); if ( state >= ACQUIRED ) osl_releasePipe( npipe ); /* exit monitor */ (*env)->MonitorExit(env, obj_this); return nread; error: switch (state) { case GOTBUFFER: free(nbuff); /* fall-through */ case INMONITOR: (*env)->MonitorExit(env, obj_this); case START: default: break; } return -1; } /*****************************************************************************/ /* * Class: com_sun_star_lib_connections_pipe_PipeConnection * Method: writeJNI * Signature: ([B)V */ SAL_DLLPUBLIC_EXPORT void #if defined(_WIN32) PipeConnection_write #else JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_writeJNI #endif (JNIEnv * env, jobject obj_this, jbyteArray buffer) { enum { START = 0, INMONITOR, GOTBUFFER }; short state = START; oslPipe npipe; /* native pipe */ sal_Int32 count; /* number of bytes has been written */ jsize nwrite; /* number of bytes to write */ jbyte * nbuff = NULL; /* native buffer */ if ((*env)->MonitorEnter(env, obj_this) != 0) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot synchronize on the object"); goto error; } state = INMONITOR; /* check connection state */ npipe = getPipe(env, obj_this); if ((*env)->ExceptionOccurred(env) != NULL) goto error; if (npipe == NULL) { ThrowException(env, "com/sun/star/io/IOException", "native pipe is not connected"); goto error; } nwrite = (*env)->GetArrayLength(env, buffer); if (nwrite > 0) { nbuff = (*env)->GetByteArrayElements(env, buffer, NULL); if (nbuff == NULL) { ThrowException(env, "java/lang/RuntimeException", "native pipe out of memory"); goto error; } state = GOTBUFFER; (*env)->MonitorExit(env, obj_this); /* writing */ count = osl_writePipe(npipe, nbuff, nwrite); if ((*env)->MonitorEnter(env, obj_this) != 0) { ThrowException(env, "java/lang/RuntimeException", "native pipe cannot synchronize on the object"); goto error; } if (count != nwrite) { ThrowException(env, "com/sun/star/io/IOException", "native pipe: failed to write"); goto error; } } /* done */ (*env)->ReleaseByteArrayElements(env, buffer, nbuff, JNI_ABORT); (*env)->MonitorExit(env, obj_this); return; error: switch (state) { case GOTBUFFER: (*env)->ReleaseByteArrayElements(env, buffer, nbuff, JNI_ABORT); /* fall through */ case INMONITOR: (*env)->MonitorExit(env, obj_this); case START: default: break; } return; } /*****************************************************************************/ /* * Class: com_sun_star_lib_connections_pipe_PipeConnection * Method: flushJNI * Signature: ()V */ SAL_DLLPUBLIC_EXPORT void #if defined(_WIN32) PipeConnection_flush #else JNICALL Java_com_sun_star_lib_connections_pipe_PipeConnection_flushJNI #endif (JNIEnv * env, jobject obj_this) { (void) env; /* not used */ (void) obj_this; /* not used */ return; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */