android_database_CursorWindow.cpp revision 03d9490758c9318cee6d14d3cc5007556dce92d0
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#undef LOG_TAG 18#define LOG_TAG "CursorWindow" 19 20#include <jni.h> 21#include <JNIHelp.h> 22#include <android_runtime/AndroidRuntime.h> 23 24#include <utils/Log.h> 25#include <utils/String8.h> 26#include <utils/String16.h> 27 28#include <stdio.h> 29#include <string.h> 30#include <unistd.h> 31 32#include "CursorWindow.h" 33#include "sqlite3_exception.h" 34#include "android_util_Binder.h" 35 36 37namespace android { 38 39static jfieldID gWindowField; 40static jfieldID gBufferField; 41static jfieldID gSizeCopiedField; 42 43#define GET_WINDOW(env, object) ((CursorWindow *)env->GetIntField(object, gWindowField)) 44#define SET_WINDOW(env, object, window) (env->SetIntField(object, gWindowField, (int)window)) 45#define SET_BUFFER(env, object, buf) (env->SetObjectField(object, gBufferField, buf)) 46#define SET_SIZE_COPIED(env, object, size) (env->SetIntField(object, gSizeCopiedField, size)) 47 48CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow) 49{ 50 return GET_WINDOW(env, javaWindow); 51} 52 53static void native_init_empty(JNIEnv * env, jobject object, jboolean localOnly) 54{ 55 uint8_t * data; 56 size_t size; 57 CursorWindow * window; 58 59 window = new CursorWindow(MAX_WINDOW_SIZE); 60 if (!window) { 61 jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object"); 62 return; 63 } 64 65 if (!window->initBuffer(localOnly)) { 66 jniThrowException(env, "java/lang/IllegalStateException", "Couldn't init cursor window"); 67 delete window; 68 return; 69 } 70 71LOG_WINDOW("native_init_empty: window = %p", window); 72 SET_WINDOW(env, object, window); 73} 74 75static void native_init_memory(JNIEnv * env, jobject object, jobject memObj) 76{ 77 sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, memObj)); 78 if (memory == NULL) { 79 jniThrowException(env, "java/lang/IllegalStateException", "Couldn't get native binder"); 80 return; 81 } 82 83 CursorWindow * window = new CursorWindow(); 84 if (!window) { 85 jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object"); 86 return; 87 } 88 if (!window->setMemory(memory)) { 89 jniThrowException(env, "java/lang/RuntimeException", "No memory in memObj"); 90 delete window; 91 return; 92 } 93 94LOG_WINDOW("native_init_memory: numRows = %d, numColumns = %d, window = %p", window->getNumRows(), window->getNumColumns(), window); 95 SET_WINDOW(env, object, window); 96} 97 98static jobject native_getBinder(JNIEnv * env, jobject object) 99{ 100 CursorWindow * window = GET_WINDOW(env, object); 101 if (window) { 102 sp<IMemory> memory = window->getMemory(); 103 if (memory != NULL) { 104 sp<IBinder> binder = memory->asBinder(); 105 return javaObjectForIBinder(env, binder); 106 } 107 } 108 return NULL; 109} 110 111static void native_clear(JNIEnv * env, jobject object) 112{ 113 CursorWindow * window = GET_WINDOW(env, object); 114LOG_WINDOW("Clearing window %p", window); 115 if (window == NULL) { 116 jniThrowException(env, "java/lang/IllegalStateException", "clear() called after close()"); 117 return; 118 } 119 window->clear(); 120} 121 122static void native_close(JNIEnv * env, jobject object) 123{ 124 CursorWindow * window = GET_WINDOW(env, object); 125 if (window) { 126LOG_WINDOW("Closing window %p", window); 127 delete window; 128 SET_WINDOW(env, object, 0); 129 } 130} 131 132static void throwExceptionWithRowCol(JNIEnv * env, jint row, jint column) 133{ 134 char buf[100]; 135 snprintf(buf, sizeof(buf), "get field slot from row %d col %d failed", row, column); 136 jniThrowException(env, "java/lang/IllegalStateException", buf); 137} 138 139static void throwUnknowTypeException(JNIEnv * env, jint type) 140{ 141 char buf[80]; 142 snprintf(buf, sizeof(buf), "UNKNOWN type %d", type); 143 jniThrowException(env, "java/lang/IllegalStateException", buf); 144} 145 146static jlong getLong_native(JNIEnv * env, jobject object, jint row, jint column) 147{ 148 int32_t err; 149 CursorWindow * window = GET_WINDOW(env, object); 150LOG_WINDOW("Getting long for %d,%d from %p", row, column, window); 151 152 field_slot_t field; 153 err = window->read_field_slot(row, column, &field); 154 if (err != 0) { 155 throwExceptionWithRowCol(env, row, column); 156 return 0; 157 } 158 159 uint8_t type = field.type; 160 if (type == FIELD_TYPE_INTEGER) { 161 int64_t value; 162 if (window->getLong(row, column, &value)) { 163 return value; 164 } 165 return 0; 166 } else if (type == FIELD_TYPE_STRING) { 167 uint32_t size = field.data.buffer.size; 168 if (size > 0) { 169#if WINDOW_STORAGE_UTF8 170 return strtoll((char const *)window->offsetToPtr(field.data.buffer.offset), NULL, 0); 171#else 172 String8 ascii((char16_t *) window->offsetToPtr(field.data.buffer.offset), size / 2); 173 char const * str = ascii.string(); 174 return strtoll(str, NULL, 0); 175#endif 176 } else { 177 return 0; 178 } 179 } else if (type == FIELD_TYPE_FLOAT) { 180 double value; 181 if (window->getDouble(row, column, &value)) { 182 return value; 183 } 184 return 0; 185 } else if (type == FIELD_TYPE_NULL) { 186 return 0; 187 } else if (type == FIELD_TYPE_BLOB) { 188 throw_sqlite3_exception(env, "Unable to convert BLOB to long"); 189 return 0; 190 } else { 191 throwUnknowTypeException(env, type); 192 return 0; 193 } 194} 195 196static jbyteArray getBlob_native(JNIEnv* env, jobject object, jint row, jint column) 197{ 198 int32_t err; 199 CursorWindow * window = GET_WINDOW(env, object); 200LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window); 201 202 field_slot_t field; 203 err = window->read_field_slot(row, column, &field); 204 if (err != 0) { 205 throwExceptionWithRowCol(env, row, column); 206 return NULL; 207 } 208 209 uint8_t type = field.type; 210 if (type == FIELD_TYPE_BLOB || type == FIELD_TYPE_STRING) { 211 jbyteArray byteArray = env->NewByteArray(field.data.buffer.size); 212 LOG_ASSERT(byteArray, "Native could not create new byte[]"); 213 env->SetByteArrayRegion(byteArray, 0, field.data.buffer.size, 214 (const jbyte*)window->offsetToPtr(field.data.buffer.offset)); 215 return byteArray; 216 } else if (type == FIELD_TYPE_INTEGER) { 217 throw_sqlite3_exception(env, "INTEGER data in getBlob_native "); 218 } else if (type == FIELD_TYPE_FLOAT) { 219 throw_sqlite3_exception(env, "FLOAT data in getBlob_native "); 220 } else if (type == FIELD_TYPE_NULL) { 221 // do nothing 222 } else { 223 throwUnknowTypeException(env, type); 224 } 225 return NULL; 226} 227 228static jboolean isBlob_native(JNIEnv* env, jobject object, jint row, jint column) 229{ 230 int32_t err; 231 CursorWindow * window = GET_WINDOW(env, object); 232LOG_WINDOW("Checking if column is a blob or null for %d,%d from %p", row, column, window); 233 234 field_slot_t field; 235 err = window->read_field_slot(row, column, &field); 236 if (err != 0) { 237 throwExceptionWithRowCol(env, row, column); 238 return NULL; 239 } 240 241 return field.type == FIELD_TYPE_BLOB || field.type == FIELD_TYPE_NULL; 242} 243 244static jboolean isString_native(JNIEnv* env, jobject object, jint row, jint column) 245{ 246 int32_t err; 247 CursorWindow * window = GET_WINDOW(env, object); 248LOG_WINDOW("Checking if column is a string or null for %d,%d from %p", row, column, window); 249 250 field_slot_t field; 251 err = window->read_field_slot(row, column, &field); 252 if (err != 0) { 253 throwExceptionWithRowCol(env, row, column); 254 return NULL; 255 } 256 257 return field.type == FIELD_TYPE_STRING || field.type == FIELD_TYPE_NULL; 258} 259 260static jboolean isInteger_native(JNIEnv* env, jobject object, jint row, jint column) 261{ 262 int32_t err; 263 CursorWindow * window = GET_WINDOW(env, object); 264LOG_WINDOW("Checking if column is an integer for %d,%d from %p", row, column, window); 265 266 field_slot_t field; 267 err = window->read_field_slot(row, column, &field); 268 if (err != 0) { 269 throwExceptionWithRowCol(env, row, column); 270 return NULL; 271 } 272 273 return field.type == FIELD_TYPE_INTEGER; 274} 275 276static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column) 277{ 278 int32_t err; 279 CursorWindow * window = GET_WINDOW(env, object); 280LOG_WINDOW("Checking if column is a float for %d,%d from %p", row, column, window); 281 282 field_slot_t field; 283 err = window->read_field_slot(row, column, &field); 284 if (err != 0) { 285 throwExceptionWithRowCol(env, row, column); 286 return NULL; 287 } 288 289 return field.type == FIELD_TYPE_FLOAT; 290} 291 292static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column) 293{ 294 int32_t err; 295 CursorWindow * window = GET_WINDOW(env, object); 296LOG_WINDOW("Getting string for %d,%d from %p", row, column, window); 297 298 field_slot_t field; 299 err = window->read_field_slot(row, column, &field); 300 if (err != 0) { 301 throwExceptionWithRowCol(env, row, column); 302 return NULL; 303 } 304 305 uint8_t type = field.type; 306 if (type == FIELD_TYPE_STRING) { 307 uint32_t size = field.data.buffer.size; 308 if (size > 0) { 309#if WINDOW_STORAGE_UTF8 310 // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string 311 String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1); 312 return env->NewString((jchar const *)utf16.string(), utf16.size()); 313#else 314 return env->NewString((jchar const *)window->offsetToPtr(field.data.buffer.offset), size / 2); 315#endif 316 } else { 317 return env->NewStringUTF(""); 318 } 319 } else if (type == FIELD_TYPE_INTEGER) { 320 int64_t value; 321 if (window->getLong(row, column, &value)) { 322 char buf[32]; 323 snprintf(buf, sizeof(buf), "%lld", value); 324 return env->NewStringUTF(buf); 325 } 326 return NULL; 327 } else if (type == FIELD_TYPE_FLOAT) { 328 double value; 329 if (window->getDouble(row, column, &value)) { 330 char buf[32]; 331 snprintf(buf, sizeof(buf), "%g", value); 332 return env->NewStringUTF(buf); 333 } 334 return NULL; 335 } else if (type == FIELD_TYPE_NULL) { 336 return NULL; 337 } else if (type == FIELD_TYPE_BLOB) { 338 throw_sqlite3_exception(env, "Unable to convert BLOB to string"); 339 return NULL; 340 } else { 341 throwUnknowTypeException(env, type); 342 return NULL; 343 } 344} 345 346/** 347 * Use this only to convert characters that are known to be within the 348 * 0-127 range for direct conversion to UTF-16 349 */ 350static jint charToJchar(const char* src, jchar* dst, jint bufferSize) 351{ 352 int32_t len = strlen(src); 353 354 if (bufferSize < len) { 355 len = bufferSize; 356 } 357 358 for (int i = 0; i < len; i++) { 359 *dst++ = (*src++ & 0x7F); 360 } 361 return len; 362} 363 364static jcharArray copyStringToBuffer_native(JNIEnv* env, jobject object, jint row, 365 jint column, jint bufferSize, jobject buf) 366{ 367 int32_t err; 368 CursorWindow * window = GET_WINDOW(env, object); 369LOG_WINDOW("Copying string for %d,%d from %p", row, column, window); 370 371 field_slot_t field; 372 err = window->read_field_slot(row, column, &field); 373 if (err != 0) { 374 jniThrowException(env, "java/lang/IllegalStateException", "Unable to get field slot"); 375 return NULL; 376 } 377 378 jcharArray buffer = (jcharArray)env->GetObjectField(buf, gBufferField); 379 if (buffer == NULL) { 380 jniThrowException(env, "java/lang/IllegalStateException", "buf should not be null"); 381 return NULL; 382 } 383 jchar* dst = env->GetCharArrayElements(buffer, NULL); 384 uint8_t type = field.type; 385 uint32_t sizeCopied = 0; 386 jcharArray newArray = NULL; 387 if (type == FIELD_TYPE_STRING) { 388 uint32_t size = field.data.buffer.size; 389 if (size > 0) { 390#if WINDOW_STORAGE_UTF8 391 // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string 392 String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1); 393 int32_t strSize = utf16.size(); 394 if (strSize > bufferSize || dst == NULL) { 395 newArray = env->NewCharArray(strSize); 396 env->SetCharArrayRegion(newArray, 0, strSize, (jchar const *)utf16.string()); 397 } else { 398 memcpy(dst, (jchar const *)utf16.string(), strSize * 2); 399 } 400 sizeCopied = strSize; 401#else 402 sizeCopied = size/2 + size % 2; 403 if (size > bufferSize * 2 || dst == NULL) { 404 newArray = env->NewCharArray(sizeCopied); 405 memcpy(newArray, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size); 406 } else { 407 memcpy(dst, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size); 408 } 409#endif 410 } 411 } else if (type == FIELD_TYPE_INTEGER) { 412 int64_t value; 413 if (window->getLong(row, column, &value)) { 414 char buf[32]; 415 int len; 416 snprintf(buf, sizeof(buf), "%lld", value); 417 jchar* dst = env->GetCharArrayElements(buffer, NULL); 418 sizeCopied = charToJchar(buf, dst, bufferSize); 419 } 420 } else if (type == FIELD_TYPE_FLOAT) { 421 double value; 422 if (window->getDouble(row, column, &value)) { 423 char tempbuf[32]; 424 snprintf(tempbuf, sizeof(tempbuf), "%g", value); 425 jchar* dst = env->GetCharArrayElements(buffer, NULL); 426 sizeCopied = charToJchar(tempbuf, dst, bufferSize); 427 } 428 } else if (type == FIELD_TYPE_NULL) { 429 } else if (type == FIELD_TYPE_BLOB) { 430 throw_sqlite3_exception(env, "Unable to convert BLOB to string"); 431 } else { 432 LOGE("Unknown field type %d", type); 433 throw_sqlite3_exception(env, "UNKNOWN type in copyStringToBuffer_native()"); 434 } 435 SET_SIZE_COPIED(env, buf, sizeCopied); 436 env->ReleaseCharArrayElements(buffer, dst, JNI_OK); 437 return newArray; 438} 439 440static jdouble getDouble_native(JNIEnv* env, jobject object, jint row, jint column) 441{ 442 int32_t err; 443 CursorWindow * window = GET_WINDOW(env, object); 444LOG_WINDOW("Getting double for %d,%d from %p", row, column, window); 445 446 field_slot_t field; 447 err = window->read_field_slot(row, column, &field); 448 if (err != 0) { 449 throwExceptionWithRowCol(env, row, column); 450 return 0.0; 451 } 452 453 uint8_t type = field.type; 454 if (type == FIELD_TYPE_FLOAT) { 455 double value; 456 if (window->getDouble(row, column, &value)) { 457 return value; 458 } 459 return 0.0; 460 } else if (type == FIELD_TYPE_STRING) { 461 uint32_t size = field.data.buffer.size; 462 if (size > 0) { 463#if WINDOW_STORAGE_UTF8 464 return strtod((char const *)window->offsetToPtr(field.data.buffer.offset), NULL); 465#else 466 String8 ascii((char16_t *) window->offsetToPtr(field.data.buffer.offset), size / 2); 467 char const * str = ascii.string(); 468 return strtod(str, NULL); 469#endif 470 } else { 471 return 0.0; 472 } 473 } else if (type == FIELD_TYPE_INTEGER) { 474 int64_t value; 475 if (window->getLong(row, column, &value)) { 476 return (double) value; 477 } 478 return 0.0; 479 } else if (type == FIELD_TYPE_NULL) { 480 return 0.0; 481 } else if (type == FIELD_TYPE_BLOB) { 482 throw_sqlite3_exception(env, "Unable to convert BLOB to double"); 483 return 0.0; 484 } else { 485 throwUnknowTypeException(env, type); 486 return 0.0; 487 } 488} 489 490static jboolean isNull_native(JNIEnv* env, jobject object, jint row, jint column) 491{ 492 CursorWindow * window = GET_WINDOW(env, object); 493LOG_WINDOW("Checking for NULL at %d,%d from %p", row, column, window); 494 495 bool isNull; 496 if (window->getNull(row, column, &isNull)) { 497 return isNull; 498 } 499 500 //TODO throw execption? 501 return true; 502} 503 504static jint getNumRows(JNIEnv * env, jobject object) 505{ 506 CursorWindow * window = GET_WINDOW(env, object); 507 return window->getNumRows(); 508} 509 510static jboolean setNumColumns(JNIEnv * env, jobject object, jint columnNum) 511{ 512 CursorWindow * window = GET_WINDOW(env, object); 513 return window->setNumColumns(columnNum); 514} 515 516static jboolean allocRow(JNIEnv * env, jobject object) 517{ 518 CursorWindow * window = GET_WINDOW(env, object); 519 return window->allocRow() != NULL; 520} 521 522static jboolean putBlob_native(JNIEnv * env, jobject object, jbyteArray value, jint row, jint col) 523{ 524 CursorWindow * window = GET_WINDOW(env, object); 525 if (!value) { 526 LOG_WINDOW("How did a null value send to here"); 527 return false; 528 } 529 field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col); 530 if (fieldSlot == NULL) { 531 LOG_WINDOW(" getFieldSlotWithCheck error "); 532 return false; 533 } 534 535 jint len = env->GetArrayLength(value); 536 int offset = window->alloc(len); 537 if (!offset) { 538 LOG_WINDOW("Failed allocating %u bytes", len); 539 return false; 540 } 541 jbyte * bytes = env->GetByteArrayElements(value, NULL); 542 window->copyIn(offset, (uint8_t const *)bytes, len); 543 544 // This must be updated after the call to alloc(), since that 545 // may move the field around in the window 546 fieldSlot->type = FIELD_TYPE_BLOB; 547 fieldSlot->data.buffer.offset = offset; 548 fieldSlot->data.buffer.size = len; 549 env->ReleaseByteArrayElements(value, bytes, JNI_ABORT); 550 LOG_WINDOW("%d,%d is BLOB with %u bytes @ %d", row, col, len, offset); 551 return true; 552} 553 554static jboolean putString_native(JNIEnv * env, jobject object, jstring value, jint row, jint col) 555{ 556 CursorWindow * window = GET_WINDOW(env, object); 557 if (!value) { 558 LOG_WINDOW("How did a null value send to here"); 559 return false; 560 } 561 field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col); 562 if (fieldSlot == NULL) { 563 LOG_WINDOW(" getFieldSlotWithCheck error "); 564 return false; 565 } 566 567#if WINDOW_STORAGE_UTF8 568 int len = env->GetStringUTFLength(value) + 1; 569 char const * valStr = env->GetStringUTFChars(value, NULL); 570#else 571 int len = env->GetStringLength(value); 572 // GetStringLength return number of chars and one char takes 2 bytes 573 len *= 2; 574 const jchar* valStr = env->GetStringChars(value, NULL); 575#endif 576 if (!valStr) { 577 LOG_WINDOW("value can't be transfer to UTFChars"); 578 return false; 579 } 580 581 int offset = window->alloc(len); 582 if (!offset) { 583 LOG_WINDOW("Failed allocating %u bytes", len); 584#if WINDOW_STORAGE_UTF8 585 env->ReleaseStringUTFChars(value, valStr); 586#else 587 env->ReleaseStringChars(value, valStr); 588#endif 589 return false; 590 } 591 592 window->copyIn(offset, (uint8_t const *)valStr, len); 593 594 // This must be updated after the call to alloc(), since that 595 // may move the field around in the window 596 fieldSlot->type = FIELD_TYPE_STRING; 597 fieldSlot->data.buffer.offset = offset; 598 fieldSlot->data.buffer.size = len; 599 600 LOG_WINDOW("%d,%d is TEXT with %u bytes @ %d", row, col, len, offset); 601#if WINDOW_STORAGE_UTF8 602 env->ReleaseStringUTFChars(value, valStr); 603#else 604 env->ReleaseStringChars(value, valStr); 605#endif 606 607 return true; 608} 609 610static jboolean putLong_native(JNIEnv * env, jobject object, jlong value, jint row, jint col) 611{ 612 CursorWindow * window = GET_WINDOW(env, object); 613 if (!window->putLong(row, col, value)) { 614 LOG_WINDOW(" getFieldSlotWithCheck error "); 615 return false; 616 } 617 618 LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, col, value); 619 620 return true; 621} 622 623static jboolean putDouble_native(JNIEnv * env, jobject object, jdouble value, jint row, jint col) 624{ 625 CursorWindow * window = GET_WINDOW(env, object); 626 if (!window->putDouble(row, col, value)) { 627 LOG_WINDOW(" getFieldSlotWithCheck error "); 628 return false; 629 } 630 631 LOG_WINDOW("%d,%d is FLOAT %lf", row, col, value); 632 633 return true; 634} 635 636static jboolean putNull_native(JNIEnv * env, jobject object, jint row, jint col) 637{ 638 CursorWindow * window = GET_WINDOW(env, object); 639 if (!window->putNull(row, col)) { 640 LOG_WINDOW(" getFieldSlotWithCheck error "); 641 return false; 642 } 643 644 LOG_WINDOW("%d,%d is NULL", row, col); 645 646 return true; 647} 648 649// free the last row 650static void freeLastRow(JNIEnv * env, jobject object) { 651 CursorWindow * window = GET_WINDOW(env, object); 652 window->freeLastRow(); 653} 654 655static JNINativeMethod sMethods[] = 656{ 657 /* name, signature, funcPtr */ 658 {"native_init", "(Z)V", (void *)native_init_empty}, 659 {"native_init", "(Landroid/os/IBinder;)V", (void *)native_init_memory}, 660 {"native_getBinder", "()Landroid/os/IBinder;", (void *)native_getBinder}, 661 {"native_clear", "()V", (void *)native_clear}, 662 {"close_native", "()V", (void *)native_close}, 663 {"getLong_native", "(II)J", (void *)getLong_native}, 664 {"getBlob_native", "(II)[B", (void *)getBlob_native}, 665 {"isBlob_native", "(II)Z", (void *)isBlob_native}, 666 {"getString_native", "(II)Ljava/lang/String;", (void *)getString_native}, 667 {"copyStringToBuffer_native", "(IIILandroid/database/CharArrayBuffer;)[C", (void *)copyStringToBuffer_native}, 668 {"getDouble_native", "(II)D", (void *)getDouble_native}, 669 {"isNull_native", "(II)Z", (void *)isNull_native}, 670 {"getNumRows_native", "()I", (void *)getNumRows}, 671 {"setNumColumns_native", "(I)Z", (void *)setNumColumns}, 672 {"allocRow_native", "()Z", (void *)allocRow}, 673 {"putBlob_native", "([BII)Z", (void *)putBlob_native}, 674 {"putString_native", "(Ljava/lang/String;II)Z", (void *)putString_native}, 675 {"putLong_native", "(JII)Z", (void *)putLong_native}, 676 {"putDouble_native", "(DII)Z", (void *)putDouble_native}, 677 {"freeLastRow_native", "()V", (void *)freeLastRow}, 678 {"putNull_native", "(II)Z", (void *)putNull_native}, 679 {"isString_native", "(II)Z", (void *)isString_native}, 680 {"isFloat_native", "(II)Z", (void *)isFloat_native}, 681 {"isInteger_native", "(II)Z", (void *)isInteger_native}, 682}; 683 684int register_android_database_CursorWindow(JNIEnv * env) 685{ 686 jclass clazz; 687 688 clazz = env->FindClass("android/database/CursorWindow"); 689 if (clazz == NULL) { 690 LOGE("Can't find android/database/CursorWindow"); 691 return -1; 692 } 693 694 gWindowField = env->GetFieldID(clazz, "nWindow", "I"); 695 696 if (gWindowField == NULL) { 697 LOGE("Error locating fields"); 698 return -1; 699 } 700 701 clazz = env->FindClass("android/database/CharArrayBuffer"); 702 if (clazz == NULL) { 703 LOGE("Can't find android/database/CharArrayBuffer"); 704 return -1; 705 } 706 707 gBufferField = env->GetFieldID(clazz, "data", "[C"); 708 709 if (gBufferField == NULL) { 710 LOGE("Error locating fields data in CharArrayBuffer"); 711 return -1; 712 } 713 714 gSizeCopiedField = env->GetFieldID(clazz, "sizeCopied", "I"); 715 716 if (gSizeCopiedField == NULL) { 717 LOGE("Error locating fields sizeCopied in CharArrayBuffer"); 718 return -1; 719 } 720 721 return AndroidRuntime::registerNativeMethods(env, "android/database/CursorWindow", 722 sMethods, NELEM(sMethods)); 723} 724 725} // namespace android 726