19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#undef LOG_TAG
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "CursorWindow"
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20853940331ff2be48ed3e63f459845e5e43d0a131Mark Salyzyn#include <inttypes.h>
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <jni.h>
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <JNIHelp.h>
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/String8.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/String16.h>
283bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown#include <utils/Unicode.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdio.h>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h>
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <unistd.h>
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449d2b1864c3dfec6faff74d67cb2527a8f1af5a8Mathias Agopian#include <androidfw/CursorWindow.h>
35d84e1ce0b535128f03416145554fb405f9fade3eJeff Sharkey#include "android_os_Parcel.h"
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "android_util_Binder.h"
37e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include "android_database_SQLiteCommon.h"
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39987f79f60bb1f0a4bcd3ef22e57301c743f0b94fAndreas Gampe#include "core_jni_helpers.h"
40987f79f60bb1f0a4bcd3ef22e57301c743f0b94fAndreas Gampe
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
433bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic struct {
443bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jfieldID data;
453bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jfieldID sizeCopied;
463bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown} gCharArrayBufferClassInfo;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
483bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jstring gEmptyString;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
503bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void throwExceptionWithRowCol(JNIEnv* env, jint row, jint column) {
513bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    String8 msg;
523bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    msg.appendFormat("Couldn't read row %d, col %d from CursorWindow.  "
533bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            "Make sure the Cursor is initialized correctly before accessing data from it.",
543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            row, column);
553bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jniThrowException(env, "java/lang/IllegalStateException", msg.string());
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void throwUnknownTypeException(JNIEnv * env, jint type) {
593bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    String8 msg;
603bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    msg.appendFormat("UNKNOWN type %d", type);
613bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jniThrowException(env, "java/lang/IllegalStateException", msg.string());
623bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
64738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jlong nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
650cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    String8 name;
665a05c23f3d6a1a895bf5917aacd8bd9a5302ba00Jeff Brown    const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
675a05c23f3d6a1a895bf5917aacd8bd9a5302ba00Jeff Brown    name.setTo(nameStr);
685a05c23f3d6a1a895bf5917aacd8bd9a5302ba00Jeff Brown    env->ReleaseStringUTFChars(nameObj, nameStr);
690cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
700cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow* window;
715e5d6d8ba04d7579df840cda055cd5dfa9d7666fJeff Brown    status_t status = CursorWindow::create(name, cursorWindowSize, &window);
720cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status || !window) {
733762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
740cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                name.string(), cursorWindowSize, status);
753bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
783bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("nativeInitializeEmpty: window = %p", window);
79738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    return reinterpret_cast<jlong>(window);
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
82738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jlong nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
830cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    Parcel* parcel = parcelForJavaObject(env, parcelObj);
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
850cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow* window;
860cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = CursorWindow::createFromParcel(parcel, &window);
870cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status || !window) {
883762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Could not create CursorWindow from Parcel due to error %d.", status);
893bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
923bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("nativeInitializeFromBinder: numRows = %d, numColumns = %d, window = %p",
933bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            window->getNumRows(), window->getNumColumns(), window);
94738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    return reinterpret_cast<jlong>(window);
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
97738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic void nativeDispose(JNIEnv* env, jclass clazz, jlong windowPtr) {
983bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
993bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (window) {
1003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        LOG_WINDOW("Closing window %p", window);
1013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        delete window;
1023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
1033bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
1043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
105738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jstring nativeGetName(JNIEnv* env, jclass clazz, jlong windowPtr) {
106650de3dcfcbc7635da3c070410ef1dc4027ae464Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
107650de3dcfcbc7635da3c070410ef1dc4027ae464Jeff Brown    return env->NewStringUTF(window->name().string());
108650de3dcfcbc7635da3c070410ef1dc4027ae464Jeff Brown}
109650de3dcfcbc7635da3c070410ef1dc4027ae464Jeff Brown
110738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic void nativeWriteToParcel(JNIEnv * env, jclass clazz, jlong windowPtr,
1110cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        jobject parcelObj) {
1123bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1130cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    Parcel* parcel = parcelForJavaObject(env, parcelObj);
1140cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
1150cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->writeToParcel(parcel);
1160cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
1170cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        String8 msg;
1180cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        msg.appendFormat("Could not write CursorWindow to Parcel due to error %d.", status);
1190cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        jniThrowRuntimeException(env, msg.string());
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
123738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic void nativeClear(JNIEnv * env, jclass clazz, jlong windowPtr) {
1243bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1253bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Clearing window %p", window);
1260cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->clear();
1270cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
1280cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Could not clear window. error=%d", status);
1290cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    }
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
132738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jint nativeGetNumRows(JNIEnv* env, jclass clazz, jlong windowPtr) {
1333bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1343bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    return window->getNumRows();
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
137738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jboolean nativeSetNumColumns(JNIEnv* env, jclass clazz, jlong windowPtr,
1383bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint columnNum) {
1393bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1400cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->setNumColumns(columnNum);
1410cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    return status == OK;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
144738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jboolean nativeAllocRow(JNIEnv* env, jclass clazz, jlong windowPtr) {
1453bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1460cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->allocRow();
1470cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    return status == OK;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
150738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic void nativeFreeLastRow(JNIEnv* env, jclass clazz, jlong windowPtr) {
1513bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1523bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    window->freeLastRow();
1533bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
155738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jint nativeGetType(JNIEnv* env, jclass clazz, jlong windowPtr,
1563bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
1573bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1600cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
1613bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
162aa32c30b81134fc7ebd9408f4757d1dc4410f338Jeff Brown        // FIXME: This is really broken but we have CTS tests that depend
163aa32c30b81134fc7ebd9408f4757d1dc4410f338Jeff Brown        // on this legacy behavior.
164aa32c30b81134fc7ebd9408f4757d1dc4410f338Jeff Brown        //throwExceptionWithRowCol(env, row, column);
1650cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        return CursorWindow::FIELD_TYPE_NULL;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1670cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    return window->getFieldSlotType(fieldSlot);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
170738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jbyteArray nativeGetBlob(JNIEnv* env, jclass clazz, jlong windowPtr,
1713bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
1723bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1733bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1750cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
1763bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throwExceptionWithRowCol(env, row, column);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1810cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
1820cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_BLOB || type == CursorWindow::FIELD_TYPE_STRING) {
1830cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t size;
1840cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const void* value = window->getFieldSlotValueBlob(fieldSlot, &size);
1853bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jbyteArray byteArray = env->NewByteArray(size);
186e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori        if (!byteArray) {
1873bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            env->ExceptionClear();
188e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori            throw_sqlite3_exception(env, "Native could not create new byte[]");
189e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori            return NULL;
190e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori        }
1910cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        env->SetByteArrayRegion(byteArray, 0, size, static_cast<const jbyte*>(value));
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return byteArray;
1930cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
1943bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throw_sqlite3_exception(env, "INTEGER data in nativeGetBlob ");
1950cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
1963bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throw_sqlite3_exception(env, "FLOAT data in nativeGetBlob ");
1970cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // do nothing
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
2003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
205738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jstring nativeGetString(JNIEnv* env, jclass clazz, jlong windowPtr,
2063bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
2073bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
2083bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2100cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
2113bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throwExceptionWithRowCol(env, row, column);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2160cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
2170cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_STRING) {
2180cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t sizeIncludingNull;
2190cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
2200cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        if (sizeIncludingNull <= 1) {
221715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown            return gEmptyString;
222715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        }
223715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        // Convert to UTF-16 here instead of calling NewStringUTF.  NewStringUTF
224715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        // doesn't like UTF-8 strings with high codepoints.  It actually expects
225715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        // Modified UTF-8 with encoded surrogate pairs.
2260cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        String16 utf16(value, sizeIncludingNull - 1);
227715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        return env->NewString(reinterpret_cast<const jchar*>(utf16.string()), utf16.size());
2280cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
2293bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        int64_t value = window->getFieldSlotValueLong(fieldSlot);
2303bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        char buf[32];
231853940331ff2be48ed3e63f459845e5e43d0a131Mark Salyzyn        snprintf(buf, sizeof(buf), "%" PRId64, value);
2323bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return env->NewStringUTF(buf);
2330cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
2343bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        double value = window->getFieldSlotValueDouble(fieldSlot);
2353bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        char buf[32];
2363bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        snprintf(buf, sizeof(buf), "%g", value);
2373bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return env->NewStringUTF(buf);
2380cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
2400cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, "Unable to convert BLOB to string");
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
2443bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2493bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jcharArray allocCharArrayBuffer(JNIEnv* env, jobject bufferObj, size_t size) {
2503bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jcharArray dataObj = jcharArray(env->GetObjectField(bufferObj,
2513bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            gCharArrayBufferClassInfo.data));
2523bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (dataObj && size) {
2533bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jsize capacity = env->GetArrayLength(dataObj);
2543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        if (size_t(capacity) < size) {
2553bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            env->DeleteLocalRef(dataObj);
2563bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            dataObj = NULL;
2573bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
2583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
2593bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!dataObj) {
2603bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jsize capacity = size;
2613bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        if (capacity < 64) {
2623bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            capacity = 64;
2633bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
2643bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        dataObj = env->NewCharArray(capacity); // might throw OOM
2653bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        if (dataObj) {
2663bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            env->SetObjectField(bufferObj, gCharArrayBufferClassInfo.data, dataObj);
2673bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
2683bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
2693bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    return dataObj;
2703bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2723bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void fillCharArrayBufferUTF(JNIEnv* env, jobject bufferObj,
2733bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        const char* str, size_t len) {
2743bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    ssize_t size = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str), len);
2753bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (size < 0) {
2763bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        size = 0; // invalid UTF8 string
2773bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
2783bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, size);
2793bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (dataObj) {
2803bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        if (size) {
2813bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL));
282d0ff68da6a606602235fb8749473999e3d1bde53Jeff Brown            utf8_to_utf16_no_null_terminator(reinterpret_cast<const uint8_t*>(str), len,
2833bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown                    reinterpret_cast<char16_t*>(data));
2843bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            env->ReleasePrimitiveArrayCritical(dataObj, data, 0);
2853bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
2863bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, size);
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2883bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2903bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void clearCharArrayBuffer(JNIEnv* env, jobject bufferObj) {
2913bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, 0);
2923bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (dataObj) {
2933bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, 0);
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2953bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
29603d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana
297738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic void nativeCopyStringToBuffer(JNIEnv* env, jclass clazz, jlong windowPtr,
2983bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column, jobject bufferObj) {
2993bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
3003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
3013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
3020cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
3033bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
3043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwExceptionWithRowCol(env, row, column);
3053bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return;
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3073bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
3080cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
3090cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_STRING) {
3100cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t sizeIncludingNull;
3110cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
3120cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        if (sizeIncludingNull > 1) {
3130cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            fillCharArrayBufferUTF(env, bufferObj, value, sizeIncludingNull - 1);
3143bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        } else {
3153bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            clearCharArrayBuffer(env, bufferObj);
3163bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
3170cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
3183bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        int64_t value = window->getFieldSlotValueLong(fieldSlot);
3193bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        char buf[32];
320853940331ff2be48ed3e63f459845e5e43d0a131Mark Salyzyn        snprintf(buf, sizeof(buf), "%" PRId64, value);
3213bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
3220cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
3233bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        double value = window->getFieldSlotValueDouble(fieldSlot);
3243bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        char buf[32];
3253bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        snprintf(buf, sizeof(buf), "%g", value);
3263bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
3270cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
3283bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        clearCharArrayBuffer(env, bufferObj);
3290cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, "Unable to convert BLOB to string");
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
3323bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
336738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jlong nativeGetLong(JNIEnv* env, jclass clazz, jlong windowPtr,
3373bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
3383bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
3393bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Getting long for %d,%d from %p", row, column, window);
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3410cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
3423bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
3433bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwExceptionWithRowCol(env, row, column);
3443bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
3453bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
3463bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
3470cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
3480cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_INTEGER) {
3493bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return window->getFieldSlotValueLong(fieldSlot);
3500cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_STRING) {
3510cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t sizeIncludingNull;
3520cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
3530cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        return sizeIncludingNull > 1 ? strtoll(value, NULL, 0) : 0L;
3540cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
3553bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return jlong(window->getFieldSlotValueDouble(fieldSlot));
3560cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
3573bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
3580cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
3593bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throw_sqlite3_exception(env, "Unable to convert BLOB to long");
3603bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
3613bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    } else {
3623bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
3633bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
3643bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
3653bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
3663bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
367738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jdouble nativeGetDouble(JNIEnv* env, jclass clazz, jlong windowPtr,
3683bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
3693bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
3703bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Getting double for %d,%d from %p", row, column, window);
3713bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
3720cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
3733bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throwExceptionWithRowCol(env, row, column);
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0.0;
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3780cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
3790cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_FLOAT) {
3803bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return window->getFieldSlotValueDouble(fieldSlot);
3810cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_STRING) {
3820cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t sizeIncludingNull;
3830cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
3840cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        return sizeIncludingNull > 1 ? strtod(value, NULL) : 0.0;
3850cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
3863bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return jdouble(window->getFieldSlotValueLong(fieldSlot));
3870cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0.0;
3890cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, "Unable to convert BLOB to double");
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0.0;
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
3933bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0.0;
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
398738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jboolean nativePutBlob(JNIEnv* env, jclass clazz, jlong windowPtr,
3993bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jbyteArray valueObj, jint row, jint column) {
4003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
4013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jsize len = env->GetArrayLength(valueObj);
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4033bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    void* value = env->GetPrimitiveArrayCritical(valueObj, NULL);
4040cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putBlob(row, column, value, len);
4053bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT);
4063bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
4070cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4080cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put blob. error=%d", status);
4090cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        return false;
4100cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    }
4110cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
4120cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    LOG_WINDOW("%d,%d is BLOB with %u bytes", row, column, len);
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
416738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jboolean nativePutString(JNIEnv* env, jclass clazz, jlong windowPtr,
4173bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jstring valueObj, jint row, jint column) {
4183bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4200cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    size_t sizeIncludingNull = env->GetStringUTFLength(valueObj) + 1;
4213bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    const char* valueStr = env->GetStringUTFChars(valueObj, NULL);
4223bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!valueStr) {
4230cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("value can't be transferred to UTFChars");
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4260cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putString(row, column, valueStr, sizeIncludingNull);
4270cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    env->ReleaseStringUTFChars(valueObj, valueStr);
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4290cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4300cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put string. error=%d", status);
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4340cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    LOG_WINDOW("%d,%d is TEXT with %u bytes", row, column, sizeIncludingNull);
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
438738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jboolean nativePutLong(JNIEnv* env, jclass clazz, jlong windowPtr,
4393bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jlong value, jint row, jint column) {
4403bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
4410cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putLong(row, column, value);
4420cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
4430cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4440cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put long. error=%d", status);
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4483bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, column, value);
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
452738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jboolean nativePutDouble(JNIEnv* env, jclass clazz, jlong windowPtr,
4533bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jdouble value, jint row, jint column) {
4543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
4550cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putDouble(row, column, value);
4560cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
4570cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4580cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put double. error=%d", status);
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4623bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("%d,%d is FLOAT %lf", row, column, value);
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
466738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhatstatic jboolean nativePutNull(JNIEnv* env, jclass clazz, jlong windowPtr,
4673bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
4683bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
4690cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putNull(row, column);
4700cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
4710cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4720cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put null. error=%d", status);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4763bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("%d,%d is NULL", row, column);
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
48076f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod sMethods[] =
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4823bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    /* name, signature, funcPtr */
483738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeCreate", "(Ljava/lang/String;I)J",
4840cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            (void*)nativeCreate },
485738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeCreateFromParcel", "(Landroid/os/Parcel;)J",
4860cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            (void*)nativeCreateFromParcel },
487738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeDispose", "(J)V",
4883bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeDispose },
489738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
4900cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            (void*)nativeWriteToParcel },
491738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeGetName", "(J)Ljava/lang/String;",
492650de3dcfcbc7635da3c070410ef1dc4027ae464Jeff Brown            (void*)nativeGetName },
493738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeClear", "(J)V",
4943bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeClear },
495738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeGetNumRows", "(J)I",
4963bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetNumRows },
497738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeSetNumColumns", "(JI)Z",
4983bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeSetNumColumns },
499738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeAllocRow", "(J)Z",
5003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeAllocRow },
501738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeFreeLastRow", "(J)V",
5023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeFreeLastRow },
503738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeGetType", "(JII)I",
5043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetType },
505738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeGetBlob", "(JII)[B",
5063bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetBlob },
507738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeGetString", "(JII)Ljava/lang/String;",
5083bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetString },
509738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeGetLong", "(JII)J",
5103bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetLong },
511738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeGetDouble", "(JII)D",
5123bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetDouble },
513738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativeCopyStringToBuffer", "(JIILandroid/database/CharArrayBuffer;)V",
5143bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeCopyStringToBuffer },
515738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativePutBlob", "(J[BII)Z",
5163bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutBlob },
517738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativePutString", "(JLjava/lang/String;II)Z",
5183bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutString },
519738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativePutLong", "(JJII)Z",
5203bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutLong },
521738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativePutDouble", "(JDII)Z",
5223bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutDouble },
523738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat    { "nativePutNull", "(JII)Z",
5243bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutNull },
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
527987f79f60bb1f0a4bcd3ef22e57301c743f0b94fAndreas Gampeint register_android_database_CursorWindow(JNIEnv* env)
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
529987f79f60bb1f0a4bcd3ef22e57301c743f0b94fAndreas Gampe    jclass clazz = FindClassOrDie(env, "android/database/CharArrayBuffer");
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
531987f79f60bb1f0a4bcd3ef22e57301c743f0b94fAndreas Gampe    gCharArrayBufferClassInfo.data = GetFieldIDOrDie(env, clazz, "data", "[C");
532987f79f60bb1f0a4bcd3ef22e57301c743f0b94fAndreas Gampe    gCharArrayBufferClassInfo.sizeCopied = GetFieldIDOrDie(env, clazz, "sizeCopied", "I");
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
534987f79f60bb1f0a4bcd3ef22e57301c743f0b94fAndreas Gampe    gEmptyString = MakeGlobalRefOrDie(env, env->NewStringUTF(""));
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
536987f79f60bb1f0a4bcd3ef22e57301c743f0b94fAndreas Gampe    return RegisterMethodsOrDie(env, "android/database/CursorWindow", sMethods, NELEM(sMethods));
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} // namespace android
540