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
37 namespace android {
38
39 static jfieldID gWindowField;
40 static jfieldID gBufferField;
41 static 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
get_window_from_object(JNIEnv * env,jobject javaWindow)48 CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow)
49 {
50 return GET_WINDOW(env, javaWindow);
51 }
52
native_init_empty(JNIEnv * env,jobject object,jboolean localOnly)53 static 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
71 LOG_WINDOW("native_init_empty: window = %p", window);
72 SET_WINDOW(env, object, window);
73 }
74
native_init_memory(JNIEnv * env,jobject object,jobject memObj)75 static 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
94 LOG_WINDOW("native_init_memory: numRows = %d, numColumns = %d, window = %p", window->getNumRows(), window->getNumColumns(), window);
95 SET_WINDOW(env, object, window);
96 }
97
native_getBinder(JNIEnv * env,jobject object)98 static 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
native_clear(JNIEnv * env,jobject object)111 static void native_clear(JNIEnv * env, jobject object)
112 {
113 CursorWindow * window = GET_WINDOW(env, object);
114 LOG_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
native_close(JNIEnv * env,jobject object)122 static void native_close(JNIEnv * env, jobject object)
123 {
124 CursorWindow * window = GET_WINDOW(env, object);
125 if (window) {
126 LOG_WINDOW("Closing window %p", window);
127 delete window;
128 SET_WINDOW(env, object, 0);
129 }
130 }
131
throwExceptionWithRowCol(JNIEnv * env,jint row,jint column)132 static 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
throwUnknowTypeException(JNIEnv * env,jint type)139 static 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
getLong_native(JNIEnv * env,jobject object,jint row,jint column)146 static jlong getLong_native(JNIEnv * env, jobject object, jint row, jint column)
147 {
148 int32_t err;
149 CursorWindow * window = GET_WINDOW(env, object);
150 LOG_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
getBlob_native(JNIEnv * env,jobject object,jint row,jint column)196 static jbyteArray getBlob_native(JNIEnv* env, jobject object, jint row, jint column)
197 {
198 int32_t err;
199 CursorWindow * window = GET_WINDOW(env, object);
200 LOG_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
isBlob_native(JNIEnv * env,jobject object,jint row,jint column)228 static jboolean isBlob_native(JNIEnv* env, jobject object, jint row, jint column)
229 {
230 int32_t err;
231 CursorWindow * window = GET_WINDOW(env, object);
232 LOG_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
isString_native(JNIEnv * env,jobject object,jint row,jint column)244 static jboolean isString_native(JNIEnv* env, jobject object, jint row, jint column)
245 {
246 int32_t err;
247 CursorWindow * window = GET_WINDOW(env, object);
248 LOG_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
isInteger_native(JNIEnv * env,jobject object,jint row,jint column)260 static jboolean isInteger_native(JNIEnv* env, jobject object, jint row, jint column)
261 {
262 int32_t err;
263 CursorWindow * window = GET_WINDOW(env, object);
264 LOG_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
isFloat_native(JNIEnv * env,jobject object,jint row,jint column)276 static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column)
277 {
278 int32_t err;
279 CursorWindow * window = GET_WINDOW(env, object);
280 LOG_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
getString_native(JNIEnv * env,jobject object,jint row,jint column)292 static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column)
293 {
294 int32_t err;
295 CursorWindow * window = GET_WINDOW(env, object);
296 LOG_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 */
charToJchar(const char * src,jchar * dst,jint bufferSize)350 static 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
copyStringToBuffer_native(JNIEnv * env,jobject object,jint row,jint column,jint bufferSize,jobject buf)364 static 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);
369 LOG_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
getDouble_native(JNIEnv * env,jobject object,jint row,jint column)440 static jdouble getDouble_native(JNIEnv* env, jobject object, jint row, jint column)
441 {
442 int32_t err;
443 CursorWindow * window = GET_WINDOW(env, object);
444 LOG_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
isNull_native(JNIEnv * env,jobject object,jint row,jint column)490 static jboolean isNull_native(JNIEnv* env, jobject object, jint row, jint column)
491 {
492 CursorWindow * window = GET_WINDOW(env, object);
493 LOG_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
getNumRows(JNIEnv * env,jobject object)504 static jint getNumRows(JNIEnv * env, jobject object)
505 {
506 CursorWindow * window = GET_WINDOW(env, object);
507 return window->getNumRows();
508 }
509
setNumColumns(JNIEnv * env,jobject object,jint columnNum)510 static jboolean setNumColumns(JNIEnv * env, jobject object, jint columnNum)
511 {
512 CursorWindow * window = GET_WINDOW(env, object);
513 return window->setNumColumns(columnNum);
514 }
515
allocRow(JNIEnv * env,jobject object)516 static jboolean allocRow(JNIEnv * env, jobject object)
517 {
518 CursorWindow * window = GET_WINDOW(env, object);
519 return window->allocRow() != NULL;
520 }
521
putBlob_native(JNIEnv * env,jobject object,jbyteArray value,jint row,jint col)522 static 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
putString_native(JNIEnv * env,jobject object,jstring value,jint row,jint col)554 static 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
putLong_native(JNIEnv * env,jobject object,jlong value,jint row,jint col)610 static 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
putDouble_native(JNIEnv * env,jobject object,jdouble value,jint row,jint col)623 static 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
putNull_native(JNIEnv * env,jobject object,jint row,jint col)636 static 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
freeLastRow(JNIEnv * env,jobject object)650 static void freeLastRow(JNIEnv * env, jobject object) {
651 CursorWindow * window = GET_WINDOW(env, object);
652 window->freeLastRow();
653 }
654
655 static 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
register_android_database_CursorWindow(JNIEnv * env)684 int 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