1 /* 2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "JavaInputStreamCallbacks.h" 27 #include "JniUtils.h" 28 #include <Common/VSMemory.h> 29 #if TARGET_OS_LINUX 30 #include <stdlib.h> 31 #include <string.h> 32 #endif // TARGET_OS_LINUX 33 34 jfieldID CJavaInputStreamCallbacks::m_BufferFID = 0; 35 jmethodID CJavaInputStreamCallbacks::m_NeedBufferMID = 0; 36 jmethodID CJavaInputStreamCallbacks::m_ReadNextBlockMID = 0; 37 jmethodID CJavaInputStreamCallbacks::m_ReadBlockMID = 0; 38 jmethodID CJavaInputStreamCallbacks::m_IsSeekableMID = 0; 39 jmethodID CJavaInputStreamCallbacks::m_IsRandomAccessMID = 0; 40 jmethodID CJavaInputStreamCallbacks::m_SeekMID = 0; 41 jmethodID CJavaInputStreamCallbacks::m_CloseConnectionMID = 0; 42 jmethodID CJavaInputStreamCallbacks::m_PropertyMID = 0; 43 jmethodID CJavaInputStreamCallbacks::m_GetStreamSizeMID = 0; 44 45 CJavaInputStreamCallbacks::CJavaInputStreamCallbacks() 46 : m_ConnectionHolder(0) 47 {} 48 49 CJavaInputStreamCallbacks::~CJavaInputStreamCallbacks() 50 {} 51 52 bool CJavaInputStreamCallbacks::Init(JNIEnv *env, jobject jLocator) 53 { 54 env->GetJavaVM(&m_jvm); 55 CJavaEnvironment javaEnv(m_jvm); 56 57 static jmethodID createConnectionHolder = 0; 58 if (0 == createConnectionHolder) 59 { 60 jclass klass = env->GetObjectClass(jLocator); 61 createConnectionHolder = env->GetMethodID(klass, "createConnectionHolder", "()Lcom/sun/media/jfxmedia/locator/ConnectionHolder;"); 62 env->DeleteLocalRef(klass); 63 } 64 65 m_ConnectionHolder = env->NewGlobalRef(env->CallObjectMethod(jLocator, createConnectionHolder)); 66 if (NULL == m_ConnectionHolder) 67 { 68 javaEnv.reportException(); 69 return false; 70 } 71 72 static bool methodIDsInitialized = false; 73 if (!methodIDsInitialized) 74 { 75 // Get the parent abstract class. It's wrong to get method ids from the concrete implementation 76 // because it crashes jvm when it tries to call virtual methods. 77 // See https://javafx-jira.kenai.com/browse/RT-37115 78 jclass klass = env->FindClass("com/sun/media/jfxmedia/locator/ConnectionHolder"); 79 80 m_BufferFID = env->GetFieldID(klass, "buffer", "Ljava/nio/ByteBuffer;"); 81 m_NeedBufferMID = env->GetMethodID(klass, "needBuffer", "()Z"); 82 m_ReadNextBlockMID = env->GetMethodID(klass, "readNextBlock", "()I"); 83 m_ReadBlockMID = env->GetMethodID(klass, "readBlock", "(JI)I"); 84 m_IsSeekableMID = env->GetMethodID(klass, "isSeekable", "()Z"); 85 m_IsRandomAccessMID = env->GetMethodID(klass, "isRandomAccess", "()Z"); 86 m_SeekMID = env->GetMethodID(klass, "seek", "(J)J"); 87 m_CloseConnectionMID = env->GetMethodID(klass, "closeConnection", "()V"); 88 m_PropertyMID = env->GetMethodID(klass, "property", "(II)I"); 89 m_GetStreamSizeMID = env->GetMethodID(klass, "getStreamSize", "()I"); 90 91 methodIDsInitialized = true; 92 env->DeleteLocalRef(klass); 93 } 94 95 javaEnv.reportException(); 96 return true; 97 } 98 99 bool CJavaInputStreamCallbacks::NeedBuffer() 100 { 101 bool result = false; 102 CJavaEnvironment javaEnv(m_jvm); 103 JNIEnv *pEnv = javaEnv.getEnvironment(); 104 if (m_ConnectionHolder && pEnv) 105 { 106 result = (pEnv->CallBooleanMethod(m_ConnectionHolder, m_NeedBufferMID) == JNI_TRUE); 107 javaEnv.reportException(); 108 } 109 110 return result; 111 } 112 113 int CJavaInputStreamCallbacks::ReadNextBlock() 114 { 115 int result = -1; 116 CJavaEnvironment javaEnv(m_jvm); 117 JNIEnv *pEnv = javaEnv.getEnvironment(); 118 119 if (m_ConnectionHolder && pEnv) { 120 result = pEnv->CallIntMethod(m_ConnectionHolder, m_ReadNextBlockMID); 121 if (javaEnv.clearException()) { 122 result = -2; 123 } 124 } 125 126 return result; 127 } 128 129 int CJavaInputStreamCallbacks::ReadBlock(int64_t position, int size) 130 { 131 int result = -1; 132 CJavaEnvironment javaEnv(m_jvm); 133 JNIEnv *pEnv = javaEnv.getEnvironment(); 134 135 if (m_ConnectionHolder && pEnv) 136 { 137 result = pEnv->CallIntMethod(m_ConnectionHolder, m_ReadBlockMID, position, size); 138 if (javaEnv.clearException()) { 139 result = -2; 140 } 141 } 142 143 return result; 144 } 145 146 void CJavaInputStreamCallbacks::CopyBlock(void* destination, int size) 147 { 148 CJavaEnvironment javaEnv(m_jvm); 149 JNIEnv *pEnv = javaEnv.getEnvironment(); 150 if (m_ConnectionHolder && pEnv) 151 { 152 jobject buffer = pEnv->GetObjectField(m_ConnectionHolder, m_BufferFID); 153 void *data = pEnv->GetDirectBufferAddress(buffer); 154 155 memcpy(destination, data, size); 156 pEnv->DeleteLocalRef(buffer); 157 } 158 } 159 160 bool CJavaInputStreamCallbacks::IsSeekable() 161 { 162 CJavaEnvironment javaEnv(m_jvm); 163 JNIEnv *pEnv = javaEnv.getEnvironment(); 164 bool result = false; 165 166 if (m_ConnectionHolder && pEnv) 167 { 168 result = (pEnv->CallBooleanMethod(m_ConnectionHolder, m_IsSeekableMID) == JNI_TRUE); 169 javaEnv.reportException(); 170 } 171 172 return result; 173 } 174 175 bool CJavaInputStreamCallbacks::IsRandomAccess() 176 { 177 CJavaEnvironment javaEnv(m_jvm); 178 JNIEnv *pEnv = javaEnv.getEnvironment(); 179 bool result = false; 180 181 if (m_ConnectionHolder && pEnv) 182 { 183 result = (pEnv->CallBooleanMethod(m_ConnectionHolder, m_IsRandomAccessMID) == JNI_TRUE); 184 javaEnv.reportException(); 185 } 186 187 return result; 188 } 189 190 int64_t CJavaInputStreamCallbacks::Seek(int64_t position) 191 { 192 CJavaEnvironment javaEnv(m_jvm); 193 JNIEnv *pEnv = javaEnv.getEnvironment(); 194 jlong result = -1; 195 196 if (m_ConnectionHolder && pEnv) 197 { 198 result = pEnv->CallLongMethod(m_ConnectionHolder, m_SeekMID, (jlong)position); 199 javaEnv.reportException(); 200 } 201 202 return (int64_t)result; 203 } 204 205 void CJavaInputStreamCallbacks::CloseConnection() 206 { 207 CJavaEnvironment javaEnv(m_jvm); 208 JNIEnv *pEnv = javaEnv.getEnvironment(); 209 if (m_ConnectionHolder && pEnv) 210 { 211 pEnv->CallVoidMethod(m_ConnectionHolder, m_CloseConnectionMID); 212 javaEnv.reportException(); 213 pEnv->DeleteGlobalRef(m_ConnectionHolder); 214 m_ConnectionHolder = NULL; 215 } 216 } 217 218 int CJavaInputStreamCallbacks::Property(int prop, int value) 219 { 220 CJavaEnvironment javaEnv(m_jvm); 221 JNIEnv *pEnv = javaEnv.getEnvironment(); 222 int result = 0; 223 224 if (m_ConnectionHolder && pEnv) 225 { 226 result = pEnv->CallIntMethod(m_ConnectionHolder, m_PropertyMID, (jint)prop, (jint)value); 227 javaEnv.reportException(); 228 } 229 230 return result; 231 } 232 233 int CJavaInputStreamCallbacks::GetStreamSize() 234 { 235 CJavaEnvironment javaEnv(m_jvm); 236 JNIEnv *pEnv = javaEnv.getEnvironment(); 237 int result = 0; 238 239 if (m_ConnectionHolder && pEnv) 240 { 241 result = pEnv->CallIntMethod(m_ConnectionHolder, m_GetStreamSizeMID); 242 javaEnv.reportException(); 243 } 244 245 return result; 246 }