| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2006-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 <utils/Log.h> | 
|  | 21 | #include <binder/CursorWindow.h> | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 22 |  | 
|  | 23 | #include <cutils/ashmem.h> | 
|  | 24 | #include <sys/mman.h> | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 25 |  | 
|  | 26 | #include <assert.h> | 
|  | 27 | #include <string.h> | 
|  | 28 | #include <stdlib.h> | 
|  | 29 |  | 
|  | 30 | namespace android { | 
|  | 31 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 32 | CursorWindow::CursorWindow(const String8& name, int ashmemFd, | 
|  | 33 | void* data, size_t size, bool readOnly) : | 
|  | 34 | mName(name), mAshmemFd(ashmemFd), mData(data), mSize(size), mReadOnly(readOnly) { | 
|  | 35 | mHeader = static_cast<Header*>(mData); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 36 | } | 
|  | 37 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 38 | CursorWindow::~CursorWindow() { | 
|  | 39 | ::munmap(mData, mSize); | 
|  | 40 | ::close(mAshmemFd); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 41 | } | 
|  | 42 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 43 | status_t CursorWindow::create(const String8& name, size_t size, bool localOnly, | 
|  | 44 | CursorWindow** outCursorWindow) { | 
|  | 45 | String8 ashmemName("CursorWindow: "); | 
|  | 46 | ashmemName.append(name); | 
|  | 47 | ashmemName.append(localOnly ? " (local)" : " (remote)"); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 48 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 49 | status_t result; | 
|  | 50 | int ashmemFd = ashmem_create_region(ashmemName.string(), size); | 
|  | 51 | if (ashmemFd < 0) { | 
|  | 52 | result = -errno; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 53 | } else { | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 54 | result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE); | 
|  | 55 | if (result >= 0) { | 
|  | 56 | void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0); | 
|  | 57 | if (data == MAP_FAILED) { | 
|  | 58 | result = -errno; | 
|  | 59 | } else { | 
|  | 60 | result = ashmem_set_prot_region(ashmemFd, PROT_READ); | 
|  | 61 | if (result >= 0) { | 
|  | 62 | CursorWindow* window = new CursorWindow(name, ashmemFd, | 
|  | 63 | data, size, false /*readOnly*/); | 
|  | 64 | result = window->clear(); | 
|  | 65 | if (!result) { | 
|  | 66 | LOG_WINDOW("Created new CursorWindow: freeOffset=%d, " | 
|  | 67 | "numRows=%d, numColumns=%d, mSize=%d, mData=%p", | 
|  | 68 | window->mHeader->freeOffset, | 
|  | 69 | window->mHeader->numRows, | 
|  | 70 | window->mHeader->numColumns, | 
|  | 71 | window->mSize, window->mData); | 
|  | 72 | *outCursorWindow = window; | 
|  | 73 | return OK; | 
|  | 74 | } | 
|  | 75 | delete window; | 
|  | 76 | } | 
|  | 77 | } | 
|  | 78 | ::munmap(data, size); | 
|  | 79 | } | 
|  | 80 | ::close(ashmemFd); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 81 | } | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 82 | *outCursorWindow = NULL; | 
|  | 83 | return result; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 84 | } | 
|  | 85 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 86 | status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) { | 
|  | 87 | String8 name = parcel->readString8(); | 
|  | 88 |  | 
|  | 89 | status_t result; | 
|  | 90 | int ashmemFd = parcel->readFileDescriptor(); | 
|  | 91 | if (ashmemFd == int(BAD_TYPE)) { | 
|  | 92 | result = BAD_TYPE; | 
|  | 93 | } else { | 
|  | 94 | ssize_t size = ashmem_get_size_region(ashmemFd); | 
|  | 95 | if (size < 0) { | 
|  | 96 | result = UNKNOWN_ERROR; | 
|  | 97 | } else { | 
|  | 98 | int dupAshmemFd = ::dup(ashmemFd); | 
|  | 99 | if (dupAshmemFd < 0) { | 
|  | 100 | result = -errno; | 
|  | 101 | } else { | 
|  | 102 | void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0); | 
|  | 103 | if (data == MAP_FAILED) { | 
|  | 104 | result = -errno; | 
|  | 105 | } else { | 
|  | 106 | CursorWindow* window = new CursorWindow(name, dupAshmemFd, | 
|  | 107 | data, size, true /*readOnly*/); | 
|  | 108 | LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, " | 
|  | 109 | "numRows=%d, numColumns=%d, mSize=%d, mData=%p", | 
|  | 110 | window->mHeader->freeOffset, | 
|  | 111 | window->mHeader->numRows, | 
|  | 112 | window->mHeader->numColumns, | 
|  | 113 | window->mSize, window->mData); | 
|  | 114 | *outCursorWindow = window; | 
|  | 115 | return OK; | 
|  | 116 | } | 
|  | 117 | ::close(dupAshmemFd); | 
|  | 118 | } | 
|  | 119 | } | 
|  | 120 | } | 
|  | 121 | *outCursorWindow = NULL; | 
|  | 122 | return result; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 123 | } | 
|  | 124 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 125 | status_t CursorWindow::writeToParcel(Parcel* parcel) { | 
|  | 126 | status_t status = parcel->writeString8(mName); | 
|  | 127 | if (!status) { | 
|  | 128 | status = parcel->writeDupFileDescriptor(mAshmemFd); | 
|  | 129 | } | 
|  | 130 | return status; | 
|  | 131 | } | 
|  | 132 |  | 
|  | 133 | status_t CursorWindow::clear() { | 
|  | 134 | if (mReadOnly) { | 
|  | 135 | return INVALID_OPERATION; | 
|  | 136 | } | 
|  | 137 |  | 
|  | 138 | mHeader->freeOffset = sizeof(Header) + sizeof(RowSlotChunk); | 
|  | 139 | mHeader->firstChunkOffset = sizeof(Header); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 140 | mHeader->numRows = 0; | 
|  | 141 | mHeader->numColumns = 0; | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 142 |  | 
|  | 143 | RowSlotChunk* firstChunk = static_cast<RowSlotChunk*>(offsetToPtr(mHeader->firstChunkOffset)); | 
|  | 144 | firstChunk->nextChunkOffset = 0; | 
|  | 145 | return OK; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 146 | } | 
|  | 147 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 148 | status_t CursorWindow::setNumColumns(uint32_t numColumns) { | 
|  | 149 | if (mReadOnly) { | 
|  | 150 | return INVALID_OPERATION; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 151 | } | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 152 |  | 
|  | 153 | uint32_t cur = mHeader->numColumns; | 
|  | 154 | if ((cur > 0 || mHeader->numRows > 0) && cur != numColumns) { | 
|  | 155 | LOGE("Trying to go from %d columns to %d", cur, numColumns); | 
|  | 156 | return INVALID_OPERATION; | 
|  | 157 | } | 
|  | 158 | mHeader->numColumns = numColumns; | 
|  | 159 | return OK; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 160 | } | 
|  | 161 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 162 | status_t CursorWindow::allocRow() { | 
|  | 163 | if (mReadOnly) { | 
|  | 164 | return INVALID_OPERATION; | 
|  | 165 | } | 
|  | 166 |  | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 167 | // Fill in the row slot | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 168 | RowSlot* rowSlot = allocRowSlot(); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 169 | if (rowSlot == NULL) { | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 170 | return NO_MEMORY; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 171 | } | 
|  | 172 |  | 
|  | 173 | // Allocate the slots for the field directory | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 174 | size_t fieldDirSize = mHeader->numColumns * sizeof(FieldSlot); | 
|  | 175 | uint32_t fieldDirOffset = alloc(fieldDirSize, true /*aligned*/); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 176 | if (!fieldDirOffset) { | 
|  | 177 | mHeader->numRows--; | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 178 | LOG_WINDOW("The row failed, so back out the new row accounting " | 
|  | 179 | "from allocRowSlot %d", mHeader->numRows); | 
|  | 180 | return NO_MEMORY; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 181 | } | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 182 | FieldSlot* fieldDir = static_cast<FieldSlot*>(offsetToPtr(fieldDirOffset)); | 
|  | 183 | memset(fieldDir, 0, fieldDirSize); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 184 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 185 | LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n", | 
|  | 186 | mHeader->numRows - 1, offsetFromPtr(rowSlot), fieldDirSize, fieldDirOffset); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 187 | rowSlot->offset = fieldDirOffset; | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 188 | return OK; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 189 | } | 
|  | 190 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 191 | status_t CursorWindow::freeLastRow() { | 
|  | 192 | if (mReadOnly) { | 
|  | 193 | return INVALID_OPERATION; | 
|  | 194 | } | 
|  | 195 |  | 
|  | 196 | if (mHeader->numRows > 0) { | 
|  | 197 | mHeader->numRows--; | 
|  | 198 | } | 
|  | 199 | return OK; | 
|  | 200 | } | 
|  | 201 |  | 
|  | 202 | uint32_t CursorWindow::alloc(size_t size, bool aligned) { | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 203 | uint32_t padding; | 
|  | 204 | if (aligned) { | 
|  | 205 | // 4 byte alignment | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 206 | padding = (~mHeader->freeOffset + 1) & 3; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 207 | } else { | 
|  | 208 | padding = 0; | 
|  | 209 | } | 
|  | 210 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 211 | uint32_t offset = mHeader->freeOffset + padding; | 
|  | 212 | uint32_t nextFreeOffset = offset + size; | 
|  | 213 | if (nextFreeOffset > mSize) { | 
|  | 214 | LOGE("Window is full: requested allocation %d bytes, " | 
|  | 215 | "free space %d bytes, window size %d bytes", | 
|  | 216 | size, freeSpace(), mSize); | 
|  | 217 | return 0; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 218 | } | 
|  | 219 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 220 | mHeader->freeOffset = nextFreeOffset; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 221 | return offset; | 
|  | 222 | } | 
|  | 223 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 224 | CursorWindow::RowSlot* CursorWindow::getRowSlot(uint32_t row) { | 
|  | 225 | uint32_t chunkPos = row; | 
|  | 226 | RowSlotChunk* chunk = static_cast<RowSlotChunk*>( | 
|  | 227 | offsetToPtr(mHeader->firstChunkOffset)); | 
|  | 228 | while (chunkPos >= ROW_SLOT_CHUNK_NUM_ROWS) { | 
|  | 229 | chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset)); | 
|  | 230 | chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 231 | } | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 232 | return &chunk->slots[chunkPos]; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 233 | } | 
|  | 234 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 235 | CursorWindow::RowSlot* CursorWindow::allocRowSlot() { | 
|  | 236 | uint32_t chunkPos = mHeader->numRows; | 
|  | 237 | RowSlotChunk* chunk = static_cast<RowSlotChunk*>( | 
|  | 238 | offsetToPtr(mHeader->firstChunkOffset)); | 
|  | 239 | while (chunkPos > ROW_SLOT_CHUNK_NUM_ROWS) { | 
|  | 240 | chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset)); | 
|  | 241 | chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS; | 
|  | 242 | } | 
|  | 243 | if (chunkPos == ROW_SLOT_CHUNK_NUM_ROWS) { | 
|  | 244 | if (!chunk->nextChunkOffset) { | 
|  | 245 | chunk->nextChunkOffset = alloc(sizeof(RowSlotChunk), true /*aligned*/); | 
|  | 246 | if (!chunk->nextChunkOffset) { | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 247 | return NULL; | 
|  | 248 | } | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 249 | } | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 250 | chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset)); | 
|  | 251 | chunk->nextChunkOffset = 0; | 
|  | 252 | chunkPos = 0; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 253 | } | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 254 | mHeader->numRows += 1; | 
|  | 255 | return &chunk->slots[chunkPos]; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 256 | } | 
|  | 257 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 258 | CursorWindow::FieldSlot* CursorWindow::getFieldSlot(uint32_t row, uint32_t column) { | 
|  | 259 | if (row >= mHeader->numRows || column >= mHeader->numColumns) { | 
|  | 260 | LOGE("Failed to read row %d, column %d from a CursorWindow which " | 
|  | 261 | "has %d rows, %d columns.", | 
|  | 262 | row, column, mHeader->numRows, mHeader->numColumns); | 
|  | 263 | return NULL; | 
|  | 264 | } | 
|  | 265 | RowSlot* rowSlot = getRowSlot(row); | 
|  | 266 | if (!rowSlot) { | 
|  | 267 | LOGE("Failed to find rowSlot for row %d.", row); | 
|  | 268 | return NULL; | 
|  | 269 | } | 
|  | 270 | FieldSlot* fieldDir = static_cast<FieldSlot*>(offsetToPtr(rowSlot->offset)); | 
|  | 271 | return &fieldDir[column]; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 272 | } | 
|  | 273 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 274 | status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) { | 
|  | 275 | return putBlobOrString(row, column, value, size, FIELD_TYPE_BLOB); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 276 | } | 
|  | 277 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 278 | status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value, | 
|  | 279 | size_t sizeIncludingNull) { | 
|  | 280 | return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 281 | } | 
|  | 282 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 283 | status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column, | 
|  | 284 | const void* value, size_t size, int32_t type) { | 
|  | 285 | if (mReadOnly) { | 
|  | 286 | return INVALID_OPERATION; | 
|  | 287 | } | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 288 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 289 | FieldSlot* fieldSlot = getFieldSlot(row, column); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 290 | if (!fieldSlot) { | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 291 | return BAD_VALUE; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 292 | } | 
|  | 293 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 294 | uint32_t offset = alloc(size); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 295 | if (!offset) { | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 296 | return NO_MEMORY; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 297 | } | 
|  | 298 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 299 | memcpy(offsetToPtr(offset), value, size); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 300 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 301 | fieldSlot->type = type; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 302 | fieldSlot->data.buffer.offset = offset; | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 303 | fieldSlot->data.buffer.size = size; | 
|  | 304 | return OK; | 
|  | 305 | } | 
|  | 306 |  | 
|  | 307 | status_t CursorWindow::putLong(uint32_t row, uint32_t column, int64_t value) { | 
|  | 308 | if (mReadOnly) { | 
|  | 309 | return INVALID_OPERATION; | 
|  | 310 | } | 
|  | 311 |  | 
|  | 312 | FieldSlot* fieldSlot = getFieldSlot(row, column); | 
|  | 313 | if (!fieldSlot) { | 
|  | 314 | return BAD_VALUE; | 
|  | 315 | } | 
|  | 316 |  | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 317 | fieldSlot->type = FIELD_TYPE_INTEGER; | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 318 | fieldSlot->data.l = value; | 
|  | 319 | return OK; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 320 | } | 
|  | 321 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 322 | status_t CursorWindow::putDouble(uint32_t row, uint32_t column, double value) { | 
|  | 323 | if (mReadOnly) { | 
|  | 324 | return INVALID_OPERATION; | 
|  | 325 | } | 
|  | 326 |  | 
|  | 327 | FieldSlot* fieldSlot = getFieldSlot(row, column); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 328 | if (!fieldSlot) { | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 329 | return BAD_VALUE; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 330 | } | 
|  | 331 |  | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 332 | fieldSlot->type = FIELD_TYPE_FLOAT; | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 333 | fieldSlot->data.d = value; | 
|  | 334 | return OK; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 335 | } | 
|  | 336 |  | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 337 | status_t CursorWindow::putNull(uint32_t row, uint32_t column) { | 
|  | 338 | if (mReadOnly) { | 
|  | 339 | return INVALID_OPERATION; | 
|  | 340 | } | 
|  | 341 |  | 
|  | 342 | FieldSlot* fieldSlot = getFieldSlot(row, column); | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 343 | if (!fieldSlot) { | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 344 | return BAD_VALUE; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 345 | } | 
|  | 346 |  | 
|  | 347 | fieldSlot->type = FIELD_TYPE_NULL; | 
|  | 348 | fieldSlot->data.buffer.offset = 0; | 
|  | 349 | fieldSlot->data.buffer.size = 0; | 
| Jeff Brown | ec4e006 | 2011-10-10 14:50:10 -0700 | [diff] [blame] | 350 | return OK; | 
| Mike Lockwood | 244a765 | 2010-05-27 17:04:23 -0400 | [diff] [blame] | 351 | } | 
|  | 352 |  | 
|  | 353 | }; // namespace android |