• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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