static jbyteArray nativeGetBlob(JNIEnv* env, jclass clazz, jlong windowPtr, jint row, jint column) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window); CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); if (!fieldSlot) { throwExceptionWithRowCol(env, row, column); return NULL; } int32_t type = window->getFieldSlotType(fieldSlot); if (type == CursorWindow::FIELD_TYPE_BLOB || type == CursorWindow::FIELD_TYPE_STRING) { size_t size; const void* value = window->getFieldSlotValueBlob(fieldSlot, &size); jbyteArray byteArray = env->NewByteArray(size); if (!byteArray) { env->ExceptionClear(); throw_sqlite3_exception(env, "Native could not create new byte[]"); return NULL; } env->SetByteArrayRegion(byteArray, 0, size, static_cast<const jbyte*>(value)); return byteArray; } else if (type == CursorWindow::FIELD_TYPE_INTEGER) { throw_sqlite3_exception(env, "INTEGER data in nativeGetBlob "); } else if (type == CursorWindow::FIELD_TYPE_FLOAT) { throw_sqlite3_exception(env, "FLOAT data in nativeGetBlob "); } else if (type == CursorWindow::FIELD_TYPE_NULL) { // do nothing } else { throwUnknownTypeException(env, type); } return NULL; }
static jboolean putBlob_native(JNIEnv * env, jobject object, jbyteArray value, jint row, jint col) { CursorWindow * window = GET_WINDOW(env, object); if (!value) { LOG_WINDOW("How did a null value send to here"); return false; } field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col); if (fieldSlot == NULL) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } jint len = env->GetArrayLength(value); int offset = window->alloc(len); if (!offset) { LOG_WINDOW("Failed allocating %u bytes", len); return false; } jbyte * bytes = env->GetByteArrayElements(value, NULL); window->copyIn(offset, (uint8_t const *)bytes, len); // This must be updated after the call to alloc(), since that // may move the field around in the window fieldSlot->type = FIELD_TYPE_BLOB; fieldSlot->data.buffer.offset = offset; fieldSlot->data.buffer.size = len; env->ReleaseByteArrayElements(value, bytes, JNI_ABORT); LOG_WINDOW("%d,%d is BLOB with %u bytes @ %d", row, col, len, offset); return true; }
static jbyteArray getBlob_native(JNIEnv* env, jobject object, jint row, jint column) { int32_t err; CursorWindow * window = GET_WINDOW(env, object); LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window); field_slot_t field; err = window->read_field_slot(row, column, &field); if (err != 0) { throwExceptionWithRowCol(env, row, column); return NULL; } uint8_t type = field.type; if (type == FIELD_TYPE_BLOB || type == FIELD_TYPE_STRING) { jbyteArray byteArray = env->NewByteArray(field.data.buffer.size); LOG_ASSERT(byteArray, "Native could not create new byte[]"); env->SetByteArrayRegion(byteArray, 0, field.data.buffer.size, (const jbyte*)window->offsetToPtr(field.data.buffer.offset)); return byteArray; } else if (type == FIELD_TYPE_INTEGER) { throw_sqlite3_exception(env, "INTEGER data in getBlob_native "); } else if (type == FIELD_TYPE_FLOAT) { throw_sqlite3_exception(env, "FLOAT data in getBlob_native "); } else if (type == FIELD_TYPE_NULL) { // do nothing } else { throwUnknowTypeException(env, type); } return NULL; }
static void nativeClear(JNIEnv * env, jclass clazz, jlong windowPtr) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); LOG_WINDOW("Clearing window %p", window); status_t status = window->clear(); if (status) { LOG_WINDOW("Could not clear window. error=%d", status); } }
static void native_clear(JNIEnv * env, jobject object) { CursorWindow * window = GET_WINDOW(env, object); LOG_WINDOW("Clearing window %p", window); if (window == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "clear() called after close()"); return; } window->clear(); }
static jboolean putString_native(JNIEnv * env, jobject object, jstring value, jint row, jint col) { CursorWindow * window = GET_WINDOW(env, object); if (!value) { LOG_WINDOW("How did a null value send to here"); return false; } field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col); if (fieldSlot == NULL) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } #if WINDOW_STORAGE_UTF8 int len = env->GetStringUTFLength(value) + 1; char const * valStr = env->GetStringUTFChars(value, NULL); #else int len = env->GetStringLength(value); // GetStringLength return number of chars and one char takes 2 bytes len *= 2; const jchar* valStr = env->GetStringChars(value, NULL); #endif if (!valStr) { LOG_WINDOW("value can't be transfer to UTFChars"); return false; } int offset = window->alloc(len); if (!offset) { LOG_WINDOW("Failed allocating %u bytes", len); #if WINDOW_STORAGE_UTF8 env->ReleaseStringUTFChars(value, valStr); #else env->ReleaseStringChars(value, valStr); #endif return false; } window->copyIn(offset, (uint8_t const *)valStr, len); // This must be updated after the call to alloc(), since that // may move the field around in the window fieldSlot->type = FIELD_TYPE_STRING; fieldSlot->data.buffer.offset = offset; fieldSlot->data.buffer.size = len; LOG_WINDOW("%d,%d is TEXT with %u bytes @ %d", row, col, len, offset); #if WINDOW_STORAGE_UTF8 env->ReleaseStringUTFChars(value, valStr); #else env->ReleaseStringChars(value, valStr); #endif return true; }
static jint nativeGetType(JNIEnv* env, jclass clazz, jlong windowPtr, jint row, jint column) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window); CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); if (!fieldSlot) { return CursorWindow::FIELD_TYPE_NULL; } return window->getFieldSlotType(fieldSlot); }
static jboolean putNull_native(JNIEnv * env, jobject object, jint row, jint col) { CursorWindow * window = GET_WINDOW(env, object); if (!window->putNull(row, col)) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } LOG_WINDOW("%d,%d is NULL", row, col); return true; }
static jobject native_getBinder(JNIEnv * env, jobject object) { CursorWindow * window = GET_WINDOW(env, object); if (window) { sp<IMemory> memory = window->getMemory(); if (memory != NULL) { sp<IBinder> binder = memory->asBinder(); return javaObjectForIBinder(env, binder); } } return NULL; }
static void nativeWriteToParcel(JNIEnv * env, jclass clazz, jlong windowPtr, jobject parcelObj) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); Parcel* parcel = parcelForJavaObject(env, parcelObj); status_t status = window->writeToParcel(parcel); if (status) { String8 msg; msg.appendFormat("Could not write CursorWindow to Parcel due to error %d.", status); jniThrowRuntimeException(env, msg.string()); } }
static jboolean putDouble_native(JNIEnv * env, jobject object, jdouble value, jint row, jint col) { CursorWindow * window = GET_WINDOW(env, object); if (!window->putDouble(row, col, value)) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } LOG_WINDOW("%d,%d is FLOAT %lf", row, col, value); return true; }
static void nativeWriteToParcel(JNIEnv * env, jclass clazz, jint windowPtr, jobject parcelObj) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); Parcel* parcel = parcelForJavaObject(env, parcelObj); status_t status = window->writeToParcel(parcel); if (status) { char buf[100]; snprintf(buf, sizeof(buf), "Could not write CursorWindow to Parcel due to error %d.", status); jniThrowException(env, "java/lang/IllegalStateException", buf); } }
static jboolean putLong_native(JNIEnv * env, jobject object, jlong value, jint row, jint col) { CursorWindow * window = GET_WINDOW(env, object); if (!window->putLong(row, col, value)) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, col, value); return true; }
static jboolean nativePutDouble(JNIEnv* env, jclass clazz, jlong windowPtr, jdouble value, jint row, jint column) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); status_t status = window->putDouble(row, column, value); if (status) { LOG_WINDOW("Failed to put double. error=%d", status); return false; } LOG_WINDOW("%d,%d is FLOAT %lf", row, column, value); return true; }
static jboolean nativePutLong(JNIEnv* env, jclass clazz, jlong windowPtr, jlong value, jint row, jint column) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); status_t status = window->putLong(row, column, value); if (status) { LOG_WINDOW("Failed to put long. error=%d", status); return false; } LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, column, value); return true; }
static jboolean nativePutNull(JNIEnv* env, jclass clazz, jlong windowPtr, jint row, jint column) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); status_t status = window->putNull(row, column); if (status) { LOG_WINDOW("Failed to put null. error=%d", status); return false; } LOG_WINDOW("%d,%d is NULL", row, column); return true; }
static jboolean isNull_native(JNIEnv* env, jobject object, jint row, jint column) { CursorWindow * window = GET_WINDOW(env, object); LOG_WINDOW("Checking for NULL at %d,%d from %p", row, column, window); bool isNull; if (window->getNull(row, column, &isNull)) { return isNull; } //TODO throw execption? return true; }
static jint nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); CursorWindow* window; status_t status = CursorWindow::createFromParcel(parcel, &window); if (status || !window) { LOGE("Could not create CursorWindow from Parcel due to error %d.", status); return 0; } LOG_WINDOW("nativeInitializeFromBinder: numRows = %d, numColumns = %d, window = %p", window->getNumRows(), window->getNumColumns(), window); return reinterpret_cast<jint>(window); }
static jint nativeGetType(JNIEnv* env, jclass clazz, jlong windowPtr, jint row, jint column) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window); CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); if (!fieldSlot) { // FIXME: This is really broken but we have CTS tests that depend // on this legacy behavior. //throwExceptionWithRowCol(env, row, column); return CursorWindow::FIELD_TYPE_NULL; } return window->getFieldSlotType(fieldSlot); }
static jdouble getDouble_native(JNIEnv* env, jobject object, jint row, jint column) { int32_t err; CursorWindow * window = GET_WINDOW(env, object); LOG_WINDOW("Getting double for %d,%d from %p", row, column, window); field_slot_t field; err = window->read_field_slot(row, column, &field); if (err != 0) { throwExceptionWithRowCol(env, row, column); return 0.0; } uint8_t type = field.type; if (type == FIELD_TYPE_FLOAT) { double value; if (window->getDouble(row, column, &value)) { return value; } return 0.0; } else if (type == FIELD_TYPE_STRING) { uint32_t size = field.data.buffer.size; if (size > 0) { double result; jstring data = env->NewString((const jchar*)window->offsetToPtr(field.data.buffer.offset), (jsize)size); const char* utf8data = env->GetStringUTFChars(data, NULL); result = strtod(utf8data, NULL); if(utf8data) env->ReleaseStringUTFChars(data, utf8data); if(data) env->DeleteLocalRef(data); return result; } else { return 0.0; } } else if (type == FIELD_TYPE_INTEGER) { int64_t value; if (window->getLong(row, column, &value)) { return (double) value; } return 0.0; } else if (type == FIELD_TYPE_NULL) { return 0.0; } else if (type == FIELD_TYPE_BLOB) { throw_sqlite3_exception(env, "Unable to convert BLOB to double"); return 0.0; } else { throwUnknowTypeException(env, type); return 0.0; } }
static jint getType_native(JNIEnv* env, jobject object, jint row, jint column) { int32_t err; CursorWindow * window = GET_WINDOW(env, object); LOG_WINDOW("Getting type for %d,%d from %p", row, column, window); field_slot_t field; err = window->read_field_slot(row, column, &field); if (err != 0) { throwExceptionWithRowCol(env, row, column); return NULL; } return field.type; }
static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column) { int32_t err; CursorWindow * window = GET_WINDOW(env, object); LOG_WINDOW("Checking if column is a float for %d,%d from %p", row, column, window); field_slot_t field; err = window->read_field_slot(row, column, &field); if (err != 0) { throwExceptionWithRowCol(env, row, column); return NULL; } return field.type == FIELD_TYPE_FLOAT; }
static jboolean nativePutBlob(JNIEnv* env, jclass clazz, jlong windowPtr, jbyteArray valueObj, jint row, jint column) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); jsize len = env->GetArrayLength(valueObj); void* value = env->GetPrimitiveArrayCritical(valueObj, NULL); status_t status = window->putBlob(row, column, value, len); env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT); if (status) { LOG_WINDOW("Failed to put blob. error=%d", status); return false; } LOG_WINDOW("%d,%d is BLOB with %u bytes", row, column, len); return true; }
status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) { String8 ashmemName("CursorWindow: "); ashmemName.append(name); status_t result; int ashmemFd = ashmem_create_region(ashmemName.string(), size); if (ashmemFd < 0) { ALOG(LOG_ERROR,LOG_TAG,"CursorWindow::create, ashmem_create_region return errno = %d",errno); result = -errno; } else { result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE); if (result >= 0) { void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0); if (data == MAP_FAILED) { ALOG(LOG_ERROR,LOG_TAG,"CursorWindow::create, mmap return errno = %d",errno); result = -errno; } else { result = ashmem_set_prot_region(ashmemFd, PROT_READ); if (result >= 0) { CursorWindow* window = new CursorWindow(name, ashmemFd, data, size, false /*readOnly*/); result = window->clear(); if (!result) { LOG_WINDOW("Created new CursorWindow: freeOffset=%d, " "numRows=%d, numColumns=%d, mSize=%d, mData=%p", window->mHeader->freeOffset, window->mHeader->numRows, window->mHeader->numColumns, window->mSize, window->mData); *outCursorWindow = window; return OK; } ALOG(LOG_ERROR,LOG_TAG,"CursorWindow::create, window->clear return errno = %d",errno); delete window; } else { ALOG(LOG_ERROR,LOG_TAG,"CursorWindow::create, ashmeme_set_prot_region return errno = %d",errno); } } ::munmap(data, size); } ::close(ashmemFd); } *outCursorWindow = NULL; return result; }
static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column) { int i; int32_t err; CursorWindow * window = GET_WINDOW(env, object); LOG_WINDOW("Getting string for %d,%d from %p", row, column, window); field_slot_t field; err = window->read_field_slot(row, column, &field); if (err != 0) { throwExceptionWithRowCol(env, row, column); return NULL; } uint8_t type = field.type; jint size = (jint)field.data.buffer.size; if (type == FIELD_TYPE_NULL) { return NULL; } else if (type == FIELD_TYPE_BLOB) { throw_sqlite3_exception(env, "Unable to convert BLOB to string"); return NULL; } else if (type == FIELD_TYPE_STRING) { jchar * buf = (jchar *)window->offsetToPtr(field.data.buffer.offset); jclass strClass = env->FindClass("java/lang/String"); jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V"); jstring encoding = env->NewStringUTF("UTF-16LE"); jbyteArray bytes = env->NewByteArray(size); env->SetByteArrayRegion(bytes, 0, size, (jbyte*)buf); return (jstring)env->NewObject(strClass, ctorID, bytes, encoding); } else if (type == FIELD_TYPE_INTEGER) { int64_t value; if (window->getLong(row, column, &value)) { char buf[32]; snprintf(buf, sizeof(buf), "%lld", value); return env->NewStringUTF((const char*)buf); } return NULL; } else if (type == FIELD_TYPE_FLOAT) { double value; if (window->getDouble(row, column, &value)) { char buf[32]; snprintf(buf, sizeof(buf), "%g", value); return env->NewStringUTF(buf); } return NULL; } }
static jboolean nativePutString(JNIEnv* env, jclass clazz, jlong windowPtr, jstring valueObj, jint row, jint column) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); size_t sizeIncludingNull = env->GetStringUTFLength(valueObj) + 1; const char* valueStr = env->GetStringUTFChars(valueObj, NULL); if (!valueStr) { LOG_WINDOW("value can't be transferred to UTFChars"); return false; } status_t status = window->putString(row, column, valueStr, sizeIncludingNull); env->ReleaseStringUTFChars(valueObj, valueStr); if (status) { LOG_WINDOW("Failed to put string. error=%d", status); return false; } LOG_WINDOW("%d,%d is TEXT with %u bytes", row, column, sizeIncludingNull); return true; }
static void native_init_empty(JNIEnv * env, jobject object, jboolean localOnly) { uint8_t * data; size_t size; CursorWindow * window; window = new CursorWindow(MAX_WINDOW_SIZE); if (!window) { jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object"); return; } if (!window->initBuffer(localOnly)) { jniThrowException(env, "java/lang/IllegalStateException", "Couldn't init cursor window"); delete window; return; } LOG_WINDOW("native_init_empty: window = %p", window); SET_WINDOW(env, object, window); }
static jdouble nativeGetDouble(JNIEnv* env, jclass clazz, jlong windowPtr, jint row, jint column) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); LOG_WINDOW("Getting double for %d,%d from %p", row, column, window); CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); if (!fieldSlot) { throwExceptionWithRowCol(env, row, column); return 0.0; } int32_t type = window->getFieldSlotType(fieldSlot); if (type == CursorWindow::FIELD_TYPE_FLOAT) { return window->getFieldSlotValueDouble(fieldSlot); } else if (type == CursorWindow::FIELD_TYPE_STRING) { size_t sizeIncludingNull; const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull); return sizeIncludingNull > 1 ? strtod(value, NULL) : 0.0; } else if (type == CursorWindow::FIELD_TYPE_INTEGER) { return jdouble(window->getFieldSlotValueLong(fieldSlot)); } else if (type == CursorWindow::FIELD_TYPE_NULL) { return 0.0; } else if (type == CursorWindow::FIELD_TYPE_BLOB) { throw_sqlite3_exception(env, "Unable to convert BLOB to double"); return 0.0; } else { throwUnknownTypeException(env, type); return 0.0; } }
static void native_init_memory(JNIEnv * env, jobject object, jobject memObj) { sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, memObj)); if (memory == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Couldn't get native binder"); return; } CursorWindow * window = new CursorWindow(); if (!window) { jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object"); return; } if (!window->setMemory(memory)) { jniThrowException(env, "java/lang/RuntimeException", "No memory in memObj"); delete window; return; } LOG_WINDOW("native_init_memory: numRows = %d, numColumns = %d, window = %p", window->getNumRows(), window->getNumColumns(), window); SET_WINDOW(env, object, window); }
static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column) { int32_t err; CursorWindow * window = GET_WINDOW(env, object); LOG_WINDOW("Getting string for %d,%d from %p", row, column, window); field_slot_t field; err = window->read_field_slot(row, column, &field); if (err != 0) { throwExceptionWithRowCol(env, row, column); return NULL; } uint8_t type = field.type; if (type == FIELD_TYPE_STRING) { uint32_t size = field.data.buffer.size; if (size > 0) { #if WINDOW_STORAGE_UTF8 // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1); return env->NewString((jchar const *)utf16.string(), utf16.size()); #else return env->NewString((jchar const *)window->offsetToPtr(field.data.buffer.offset), size / 2); #endif } else { return env->NewStringUTF(""); } } else if (type == FIELD_TYPE_INTEGER) { int64_t value; if (window->getLong(row, column, &value)) { char buf[32]; snprintf(buf, sizeof(buf), "%lld", value); return env->NewStringUTF(buf); } return NULL; } else if (type == FIELD_TYPE_FLOAT) { double value; if (window->getDouble(row, column, &value)) { char buf[32]; //selete the print way by code to impove the precision if (((value > 0.0001) && (value < 1000000)) || ((value < -0.0001) && (value > -1000000))) snprintf(buf, sizeof(buf), "%lf", value); else snprintf(buf, sizeof(buf), "%e", value); return env->NewStringUTF(buf); } return NULL; } else if (type == FIELD_TYPE_NULL) { return NULL; } else if (type == FIELD_TYPE_BLOB) { throw_sqlite3_exception(env, "Unable to convert BLOB to string"); return NULL; } else { throwUnknowTypeException(env, type); return NULL; } }