text: /**
   * 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
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  #include "InteropUtil.h"
  #include "Clr2JavaImpl.h"
  
  using namespace System::Runtime::InteropServices;
  
  ref class ManagedLog {
    internal:
      static BridgeLogger^ LOGGER = BridgeLogger::GetLogger("<C++>InteropUtil");
  };
  
  const wchar_t* UnicodeCppStringFromJavaString (
    JNIEnv *env,
    jstring javaString) {
    const wchar_t* cppString = NULL;
    if (NULL != javaString) {
      cppString = (const wchar_t* )env->GetStringChars( javaString, 0);
    }
    return cppString;
  }
  
  void ReleaseUnicodeCppString (
    JNIEnv*     env,
    jstring     javaString,
    jchar*      cppString) {
    if (NULL != cppString) {
      env->ReleaseStringChars(javaString, (jchar *)cppString);
    }
  }
  
  String^ ManagedStringFromJavaString (
    JNIEnv *env,
    jstring javaString) {
    if (javaString != NULL) {
      int len = env->GetStringLength(javaString);
      const wchar_t* wcsStr = UnicodeCppStringFromJavaString (env, javaString);
      String^ managedStr = (NULL == wcsStr || 0 == len) ? nullptr : Marshal::PtrToStringUni((IntPtr)(unsigned short*)wcsStr, len);
      ReleaseUnicodeCppString (env, javaString, (jchar*)wcsStr);
      return managedStr;
    }
    return nullptr;
  }
  
  jstring JavaStringFromManagedString(
    JNIEnv *env,
    String^ managedString) {
    pin_ptr<const wchar_t> wch = PtrToStringChars(managedString);
    return env->NewString((const jchar*)wch, managedString->Length);
  }
  
  void HandleClr2JavaError(
    JNIEnv *env,
    String^ errorMessage,
    jobject javaObject) {
    ManagedLog::LOGGER->LogStart("InteropUtil::HandleClr2JavaError");
  
    jclass javaClass = env->GetObjectClass (javaObject);
    jmethodID jmidOnError = env->GetMethodID(javaClass, "onError", "(Ljava/lang/String;)V");
  
    if (jmidOnError == NULL) {
      ManagedLog::LOGGER->Log("jmidOnError is NULL");
      return;
    }
    env -> CallObjectMethod(
      javaObject,
      jmidOnError,
      JavaStringFromManagedString(env, errorMessage));
    ManagedLog::LOGGER->LogStop("InteropUtil::HandleClr2JavaError");
  }
  
  array<byte>^ ManagedByteArrayFromJavaByteArray(
    JNIEnv *env,
    jbyteArray javaByteArray) {
    if (javaByteArray != NULL) {
      byte* bytes = (byte*)env->GetByteArrayElements (javaByteArray, FALSE);
      int len = env->GetArrayLength(javaByteArray);
      array<byte>^  managedByteArray = gcnew array<byte>(len);
      //System::Array
      for (int i = 0; i < len; i++) {
        managedByteArray[i] = bytes[i];
      }
      return managedByteArray;
    }
    return nullptr;
  }
  
  jbyteArray JavaByteArrayFromManagedByteArray(
    JNIEnv *env,
    array<byte>^ managedByteArray) {
    jbyteArray javaByteArray = env->NewByteArray(managedByteArray->Length);
    pin_ptr<Byte> p = &managedByteArray[0];
    env->SetByteArrayRegion(javaByteArray, 0, managedByteArray->Length, (jbyte*) p);
    return javaByteArray;
  }
  
  jlongArray JavaLongArrayFromManagedLongArray(
    JNIEnv *env,
    array<unsigned long long>^ managedLongArray) {
    jlongArray javaLongArray = env->NewLongArray(managedLongArray->Length);
    pin_ptr<unsigned long long> p = &managedLongArray[0];
    env->SetLongArrayRegion(javaLongArray, 0, managedLongArray->Length, (jlong*) p);
    return javaLongArray;
  }
  
  JNIEnv* RetrieveEnv(JavaVM* jvm) {
    JNIEnv *env;
    if (jvm->AttachCurrentThread((void **) &env, NULL) != 0) {
      ManagedLog::LOGGER->Log("cannot attach jni env to current jvm thread.");
      throw;
    }
    return env;
  }
  