1 /* 2 * Copyright (C) 2023 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 package android.database; 17 18 import android.database.sqlite.SQLiteException; 19 import android.os.Parcel; 20 import android.ravenwood.annotation.RavenwoodKeepWholeClass; 21 import android.util.Base64; 22 23 import java.text.DecimalFormat; 24 import java.text.ParsePosition; 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.HashMap; 28 import java.util.List; 29 30 @RavenwoodKeepWholeClass 31 class CursorWindow_ravenwood { 32 33 private static final HashMap<Long, CursorWindow_ravenwood> sInstances = new HashMap<>(); 34 private static long sNextId = 1; 35 36 private String mName; 37 private int mColumnNum; 38 private static class Row { 39 String[] mFields; 40 int[] mTypes; 41 } 42 43 private final List<Row> mRows = new ArrayList<>(); 44 nativeCreate(String name, int cursorWindowSize)45 public static long nativeCreate(String name, int cursorWindowSize) { 46 CursorWindow_ravenwood instance = new CursorWindow_ravenwood(); 47 instance.mName = name; 48 long instanceId = sNextId++; 49 sInstances.put(instanceId, instance); 50 return instanceId; 51 } 52 nativeDispose(long windowPtr)53 public static void nativeDispose(long windowPtr) { 54 sInstances.remove(windowPtr); 55 } 56 nativeGetName(long windowPtr)57 public static String nativeGetName(long windowPtr) { 58 return sInstances.get(windowPtr).mName; 59 } 60 nativeSetNumColumns(long windowPtr, int columnNum)61 public static boolean nativeSetNumColumns(long windowPtr, int columnNum) { 62 sInstances.get(windowPtr).mColumnNum = columnNum; 63 return true; 64 } 65 nativeGetNumRows(long windowPtr)66 public static int nativeGetNumRows(long windowPtr) { 67 return sInstances.get(windowPtr).mRows.size(); 68 } 69 nativeAllocRow(long windowPtr)70 public static boolean nativeAllocRow(long windowPtr) { 71 CursorWindow_ravenwood instance = sInstances.get(windowPtr); 72 Row row = new Row(); 73 row.mFields = new String[instance.mColumnNum]; 74 row.mTypes = new int[instance.mColumnNum]; 75 Arrays.fill(row.mTypes, Cursor.FIELD_TYPE_NULL); 76 instance.mRows.add(row); 77 return true; 78 } 79 put(long windowPtr, String value, int type, int row, int column)80 private static boolean put(long windowPtr, String value, int type, int row, int column) { 81 CursorWindow_ravenwood instance = sInstances.get(windowPtr); 82 if (row >= instance.mRows.size() || column >= instance.mColumnNum) { 83 return false; 84 } 85 Row r = instance.mRows.get(row); 86 r.mFields[column] = value; 87 r.mTypes[column] = type; 88 return true; 89 } 90 nativeGetType(long windowPtr, int row, int column)91 public static int nativeGetType(long windowPtr, int row, int column) { 92 CursorWindow_ravenwood instance = sInstances.get(windowPtr); 93 if (row >= instance.mRows.size() || column >= instance.mColumnNum) { 94 return Cursor.FIELD_TYPE_NULL; 95 } 96 97 return instance.mRows.get(row).mTypes[column]; 98 } 99 nativePutString(long windowPtr, String value, int row, int column)100 public static boolean nativePutString(long windowPtr, String value, 101 int row, int column) { 102 return put(windowPtr, value, Cursor.FIELD_TYPE_STRING, row, column); 103 } 104 nativeGetString(long windowPtr, int row, int column)105 public static String nativeGetString(long windowPtr, int row, int column) { 106 CursorWindow_ravenwood instance = sInstances.get(windowPtr); 107 if (row >= instance.mRows.size() || column >= instance.mColumnNum) { 108 return null; 109 } 110 111 return instance.mRows.get(row).mFields[column]; 112 } 113 nativePutLong(long windowPtr, long value, int row, int column)114 public static boolean nativePutLong(long windowPtr, long value, int row, int column) { 115 return put(windowPtr, Long.toString(value), Cursor.FIELD_TYPE_INTEGER, row, column); 116 } 117 nativeGetLong(long windowPtr, int row, int column)118 public static long nativeGetLong(long windowPtr, int row, int column) { 119 String value = nativeGetString(windowPtr, row, column); 120 if (value == null) { 121 return 0; 122 } 123 124 Number number = new DecimalFormat().parse(value, new ParsePosition(0)); 125 return number == null ? 0 : number.longValue(); 126 } 127 nativePutDouble(long windowPtr, double value, int row, int column)128 public static boolean nativePutDouble(long windowPtr, double value, int row, int column) { 129 return put(windowPtr, Double.toString(value), Cursor.FIELD_TYPE_FLOAT, row, column); 130 } 131 nativeGetDouble(long windowPtr, int row, int column)132 public static double nativeGetDouble(long windowPtr, int row, int column) { 133 String value = nativeGetString(windowPtr, row, column); 134 if (value == null) { 135 return 0; 136 } 137 138 Number number = new DecimalFormat().parse(value, new ParsePosition(0)); 139 return number == null ? 0 : number.doubleValue(); 140 } 141 nativePutBlob(long windowPtr, byte[] value, int row, int column)142 public static boolean nativePutBlob(long windowPtr, byte[] value, int row, int column) { 143 return put(windowPtr, value == null ? null : Base64.encodeToString(value, 0), 144 Cursor.FIELD_TYPE_BLOB, row, column); 145 } 146 nativeGetBlob(long windowPtr, int row, int column)147 public static byte[] nativeGetBlob(long windowPtr, int row, int column) { 148 int type = nativeGetType(windowPtr, row, column); 149 switch (type) { 150 case Cursor.FIELD_TYPE_BLOB: { 151 String value = nativeGetString(windowPtr, row, column); 152 return value == null ? null : Base64.decode(value, 0); 153 } 154 case Cursor.FIELD_TYPE_STRING: { 155 String value = nativeGetString(windowPtr, row, column); 156 return value == null ? null : value.getBytes(); 157 } 158 case Cursor.FIELD_TYPE_FLOAT: 159 throw new SQLiteException(); 160 case Cursor.FIELD_TYPE_INTEGER: 161 throw new SQLiteException(); 162 case Cursor.FIELD_TYPE_NULL: 163 default: 164 return null; 165 } 166 } 167 nativeWriteToParcel(long windowPtr, Parcel parcel)168 public static void nativeWriteToParcel(long windowPtr, Parcel parcel) { 169 CursorWindow_ravenwood window = sInstances.get(windowPtr); 170 parcel.writeString(window.mName); 171 parcel.writeInt(window.mColumnNum); 172 parcel.writeInt(window.mRows.size()); 173 for (int row = 0; row < window.mRows.size(); row++) { 174 parcel.writeStringArray(window.mRows.get(row).mFields); 175 parcel.writeIntArray(window.mRows.get(row).mTypes); 176 } 177 } 178 nativeCreateFromParcel(Parcel parcel)179 public static long nativeCreateFromParcel(Parcel parcel) { 180 long windowPtr = nativeCreate(null, 0); 181 CursorWindow_ravenwood window = sInstances.get(windowPtr); 182 window.mName = parcel.readString(); 183 window.mColumnNum = parcel.readInt(); 184 int rowCount = parcel.readInt(); 185 for (int row = 0; row < rowCount; row++) { 186 Row r = new Row(); 187 r.mFields = parcel.createStringArray(); 188 r.mTypes = parcel.createIntArray(); 189 window.mRows.add(r); 190 } 191 return windowPtr; 192 } 193 } 194