1 /* 2 * Copyright (C) 2006 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 #ifndef _ANDROID__DATABASE_WINDOW_H 18 #define _ANDROID__DATABASE_WINDOW_H 19 20 #include <inttypes.h> 21 #include <stddef.h> 22 #include <stdint.h> 23 24 #include <binder/Parcel.h> 25 #include <log/log.h> 26 #include <utils/String8.h> 27 28 #if LOG_NDEBUG 29 30 #define IF_LOG_WINDOW() if (false) 31 #define LOG_WINDOW(...) 32 33 #else 34 35 #define IF_LOG_WINDOW() IF_ALOG(LOG_DEBUG, "CursorWindow") 36 #define LOG_WINDOW(...) ALOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__) 37 38 #endif 39 40 namespace android { 41 42 /** 43 * This class stores a set of rows from a database in a buffer. The begining of the 44 * window has first chunk of RowSlots, which are offsets to the row directory, followed by 45 * an offset to the next chunk in a linked-list of additional chunk of RowSlots in case 46 * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a 47 * FieldSlot per column, which has the size, offset, and type of the data for that field. 48 * Note that the data types come from sqlite3.h. 49 * 50 * Strings are stored in UTF-8. 51 */ 52 class CursorWindow { 53 CursorWindow(const String8& name, int ashmemFd, 54 void* data, size_t size, bool readOnly); 55 56 public: 57 /* Field types. */ 58 enum { 59 FIELD_TYPE_NULL = 0, 60 FIELD_TYPE_INTEGER = 1, 61 FIELD_TYPE_FLOAT = 2, 62 FIELD_TYPE_STRING = 3, 63 FIELD_TYPE_BLOB = 4, 64 }; 65 66 /* Opaque type that describes a field slot. */ 67 struct FieldSlot { 68 private: 69 int32_t type; 70 union { 71 double d; 72 int64_t l; 73 struct { 74 uint32_t offset; 75 uint32_t size; 76 } buffer; 77 } data; 78 79 friend class CursorWindow; 80 } __attribute((packed)); 81 82 ~CursorWindow(); 83 84 static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow); 85 static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow); 86 87 status_t writeToParcel(Parcel* parcel); 88 name()89 inline String8 name() { return mName; } size()90 inline size_t size() { return mSize; } freeSpace()91 inline size_t freeSpace() { return mSize - mHeader->freeOffset; } getNumRows()92 inline uint32_t getNumRows() { return mHeader->numRows; } getNumColumns()93 inline uint32_t getNumColumns() { return mHeader->numColumns; } 94 95 status_t clear(); 96 status_t setNumColumns(uint32_t numColumns); 97 98 /** 99 * Allocate a row slot and its directory. 100 * The row is initialized will null entries for each field. 101 */ 102 status_t allocRow(); 103 status_t freeLastRow(); 104 105 status_t putBlob(uint32_t row, uint32_t column, const void* value, size_t size); 106 status_t putString(uint32_t row, uint32_t column, const char* value, size_t sizeIncludingNull); 107 status_t putLong(uint32_t row, uint32_t column, int64_t value); 108 status_t putDouble(uint32_t row, uint32_t column, double value); 109 status_t putNull(uint32_t row, uint32_t column); 110 111 /** 112 * Gets the field slot at the specified row and column. 113 * Returns null if the requested row or column is not in the window. 114 */ 115 FieldSlot* getFieldSlot(uint32_t row, uint32_t column); 116 getFieldSlotType(FieldSlot * fieldSlot)117 inline int32_t getFieldSlotType(FieldSlot* fieldSlot) { 118 return fieldSlot->type; 119 } 120 getFieldSlotValueLong(FieldSlot * fieldSlot)121 inline int64_t getFieldSlotValueLong(FieldSlot* fieldSlot) { 122 return fieldSlot->data.l; 123 } 124 getFieldSlotValueDouble(FieldSlot * fieldSlot)125 inline double getFieldSlotValueDouble(FieldSlot* fieldSlot) { 126 return fieldSlot->data.d; 127 } 128 getFieldSlotValueString(FieldSlot * fieldSlot,size_t * outSizeIncludingNull)129 inline const char* getFieldSlotValueString(FieldSlot* fieldSlot, 130 size_t* outSizeIncludingNull) { 131 *outSizeIncludingNull = fieldSlot->data.buffer.size; 132 return static_cast<char*>(offsetToPtr( 133 fieldSlot->data.buffer.offset, fieldSlot->data.buffer.size)); 134 } 135 getFieldSlotValueBlob(FieldSlot * fieldSlot,size_t * outSize)136 inline const void* getFieldSlotValueBlob(FieldSlot* fieldSlot, size_t* outSize) { 137 *outSize = fieldSlot->data.buffer.size; 138 return offsetToPtr(fieldSlot->data.buffer.offset, fieldSlot->data.buffer.size); 139 } 140 141 private: 142 static const size_t ROW_SLOT_CHUNK_NUM_ROWS = 100; 143 144 struct Header { 145 // Offset of the lowest unused byte in the window. 146 uint32_t freeOffset; 147 148 // Offset of the first row slot chunk. 149 uint32_t firstChunkOffset; 150 151 uint32_t numRows; 152 uint32_t numColumns; 153 }; 154 155 struct RowSlot { 156 uint32_t offset; 157 }; 158 159 struct RowSlotChunk { 160 RowSlot slots[ROW_SLOT_CHUNK_NUM_ROWS]; 161 uint32_t nextChunkOffset; 162 }; 163 164 String8 mName; 165 int mAshmemFd; 166 void* mData; 167 size_t mSize; 168 bool mReadOnly; 169 Header* mHeader; 170 171 inline void* offsetToPtr(uint32_t offset, uint32_t bufferSize = 0) { 172 if (offset >= mSize) { 173 ALOGE("Offset %" PRIu32 " out of bounds, max value %zu", offset, mSize); 174 return NULL; 175 } 176 if (offset + bufferSize > mSize) { 177 ALOGE("End offset %" PRIu32 " out of bounds, max value %zu", 178 offset + bufferSize, mSize); 179 return NULL; 180 } 181 return static_cast<uint8_t*>(mData) + offset; 182 } 183 offsetFromPtr(void * ptr)184 inline uint32_t offsetFromPtr(void* ptr) { 185 return static_cast<uint8_t*>(ptr) - static_cast<uint8_t*>(mData); 186 } 187 188 /** 189 * Allocate a portion of the window. Returns the offset 190 * of the allocation, or 0 if there isn't enough space. 191 * If aligned is true, the allocation gets 4 byte alignment. 192 */ 193 uint32_t alloc(size_t size, bool aligned = false); 194 195 RowSlot* getRowSlot(uint32_t row); 196 RowSlot* allocRowSlot(); 197 198 status_t putBlobOrString(uint32_t row, uint32_t column, 199 const void* value, size_t size, int32_t type); 200 }; 201 202 }; // namespace android 203 204 #endif 205