blob: 71c8e1f6121f7256c58c5569fe17484d724b392f [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2007 The Android Open Source Project
3 *
Mark Salyzyn00adb862014-03-19 11:00:06 -07004 * 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007 *
Mark Salyzyn00adb862014-03-19 11:00:06 -07008 * http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009 *
Mark Salyzyn00adb862014-03-19 11:00:06 -070010 * 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014 * limitations under the License.
15 */
16
17#undef LOG_TAG
18#define LOG_TAG "CursorWindow"
19
Mathias Agopian49d2b182012-02-27 18:11:20 -080020#include <androidfw/CursorWindow.h>
Jeff Brown9d3b1a42013-07-01 19:07:15 -070021#include <binder/Parcel.h>
22#include <utils/Log.h>
Jeff Brown0cde89f2011-10-10 14:50:10 -070023
24#include <cutils/ashmem.h>
25#include <sys/mman.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026
27#include <assert.h>
28#include <string.h>
29#include <stdlib.h>
30
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031namespace android {
32
Jeff Sharkey539fdff2020-09-23 21:43:23 -060033/**
34 * By default windows are lightweight inline allocations of this size;
35 * they're only inflated to ashmem regions when more space is needed.
36 */
37static constexpr const size_t kInlineSize = 16384;
38
39CursorWindow::CursorWindow(const String8& name, int ashmemFd, void* data, size_t size,
40 size_t inflatedSize, bool readOnly) :
41 mName(name), mAshmemFd(ashmemFd), mData(data), mSize(size),
42 mInflatedSize(inflatedSize), mReadOnly(readOnly) {
Jeff Brown0cde89f2011-10-10 14:50:10 -070043 mHeader = static_cast<Header*>(mData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044}
45
Jeff Brown0cde89f2011-10-10 14:50:10 -070046CursorWindow::~CursorWindow() {
Jeff Sharkey539fdff2020-09-23 21:43:23 -060047 if (mAshmemFd != -1) {
48 ::munmap(mData, mSize);
49 ::close(mAshmemFd);
50 } else {
51 free(mData);
52 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053}
54
Jeff Sharkey539fdff2020-09-23 21:43:23 -060055status_t CursorWindow::create(const String8& name, size_t inflatedSize,
56 CursorWindow** outCursorWindow) {
57 *outCursorWindow = nullptr;
58
59 size_t size = std::min(kInlineSize, inflatedSize);
60 void* data = calloc(size, 1);
61 if (!data) return NO_MEMORY;
62
63 CursorWindow* window = new CursorWindow(name, -1, data, size,
64 inflatedSize, false /*readOnly*/);
65 status_t result = window->clear();
66 if (!result) {
67 LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
68 "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
69 window->mHeader->freeOffset,
70 window->mHeader->numRows,
71 window->mHeader->numColumns,
72 window->mSize, window->mData);
73 *outCursorWindow = window;
74 return OK;
75 }
76 delete window;
77 return result;
78}
79
80status_t CursorWindow::inflate() {
81 // Shortcut when we can't expand any further
82 if (mSize == mInflatedSize) return INVALID_OPERATION;
83
Jeff Brown0cde89f2011-10-10 14:50:10 -070084 String8 ashmemName("CursorWindow: ");
Jeff Sharkey539fdff2020-09-23 21:43:23 -060085 ashmemName.append(mName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
Jeff Brown0cde89f2011-10-10 14:50:10 -070087 status_t result;
Jeff Sharkey539fdff2020-09-23 21:43:23 -060088 int ashmemFd = ashmem_create_region(ashmemName.string(), mInflatedSize);
Jeff Brown0cde89f2011-10-10 14:50:10 -070089 if (ashmemFd < 0) {
90 result = -errno;
Makoto Onuki2276cea2019-04-02 14:05:05 -070091 ALOGE("CursorWindow: ashmem_create_region() failed: errno=%d.", errno);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 } else {
Jeff Brown0cde89f2011-10-10 14:50:10 -070093 result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
Makoto Onuki2276cea2019-04-02 14:05:05 -070094 if (result < 0) {
95 ALOGE("CursorWindow: ashmem_set_prot_region() failed: errno=%d",errno);
96 } else {
Jeff Sharkey539fdff2020-09-23 21:43:23 -060097 void* data = ::mmap(NULL, mInflatedSize, PROT_READ | PROT_WRITE,
98 MAP_SHARED, ashmemFd, 0);
Jeff Brown0cde89f2011-10-10 14:50:10 -070099 if (data == MAP_FAILED) {
100 result = -errno;
Makoto Onuki2276cea2019-04-02 14:05:05 -0700101 ALOGE("CursorWindow: mmap() failed: errno=%d.", errno);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700102 } else {
103 result = ashmem_set_prot_region(ashmemFd, PROT_READ);
Makoto Onuki2276cea2019-04-02 14:05:05 -0700104 if (result < 0) {
105 ALOGE("CursorWindow: ashmem_set_prot_region() failed: errno=%d.", errno);
106 } else {
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600107 // Move inline contents into new ashmem region
108 memcpy(data, mData, mSize);
109 free(mData);
110 mAshmemFd = ashmemFd;
111 mData = data;
112 mHeader = static_cast<Header*>(mData);
113 mSize = mInflatedSize;
114 LOG_WINDOW("Inflated CursorWindow: freeOffset=%d, "
115 "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
116 mHeader->freeOffset,
117 mHeader->numRows,
118 mHeader->numColumns,
119 mSize, mData);
120 return OK;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700121 }
122 }
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600123 ::munmap(data, mInflatedSize);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700124 }
125 ::close(ashmemFd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700127 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128}
129
Jeff Brown0cde89f2011-10-10 14:50:10 -0700130status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600131 *outCursorWindow = nullptr;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700132
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600133 String8 name;
134 status_t result = parcel->readString8(&name);
135 if (result) return result;
136
137 bool isAshmem;
138 result = parcel->readBool(&isAshmem);
139 if (result) return result;
140
141 if (isAshmem) {
142 return createFromParcelAshmem(parcel, name, outCursorWindow);
143 } else {
144 return createFromParcelInline(parcel, name, outCursorWindow);
145 }
146}
147
148status_t CursorWindow::createFromParcelAshmem(Parcel* parcel, String8& name,
149 CursorWindow** outCursorWindow) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700150 status_t result;
Makoto Onuki2276cea2019-04-02 14:05:05 -0700151 int actualSize;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700152 int ashmemFd = parcel->readFileDescriptor();
153 if (ashmemFd == int(BAD_TYPE)) {
154 result = BAD_TYPE;
Makoto Onuki2276cea2019-04-02 14:05:05 -0700155 ALOGE("CursorWindow: readFileDescriptor() failed");
Jeff Brown0cde89f2011-10-10 14:50:10 -0700156 } else {
157 ssize_t size = ashmem_get_size_region(ashmemFd);
158 if (size < 0) {
159 result = UNKNOWN_ERROR;
Makoto Onuki2276cea2019-04-02 14:05:05 -0700160 ALOGE("CursorWindow: ashmem_get_size_region() failed: errno=%d.", errno);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700161 } else {
Nick Kraleviche104df92019-01-14 14:03:36 -0800162 int dupAshmemFd = ::fcntl(ashmemFd, F_DUPFD_CLOEXEC, 0);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700163 if (dupAshmemFd < 0) {
164 result = -errno;
Makoto Onuki2276cea2019-04-02 14:05:05 -0700165 ALOGE("CursorWindow: fcntl() failed: errno=%d.", errno);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700166 } else {
Fyodor Kupolov45e2e952017-02-13 18:35:12 -0800167 // the size of the ashmem descriptor can be modified between ashmem_get_size_region
168 // call and mmap, so we'll check again immediately after memory is mapped
Jeff Brown0cde89f2011-10-10 14:50:10 -0700169 void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
170 if (data == MAP_FAILED) {
171 result = -errno;
Makoto Onuki2276cea2019-04-02 14:05:05 -0700172 ALOGE("CursorWindow: mmap() failed: errno=%d.", errno);
173 } else if ((actualSize = ashmem_get_size_region(dupAshmemFd)) != size) {
Fyodor Kupolov45e2e952017-02-13 18:35:12 -0800174 ::munmap(data, size);
175 result = BAD_VALUE;
Makoto Onuki2276cea2019-04-02 14:05:05 -0700176 ALOGE("CursorWindow: ashmem_get_size_region() returned %d, expected %d"
177 " errno=%d",
178 actualSize, (int) size, errno);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700179 } else {
180 CursorWindow* window = new CursorWindow(name, dupAshmemFd,
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600181 data, size, size, true /*readOnly*/);
182 LOG_WINDOW("Created CursorWindow from ashmem parcel: freeOffset=%d, "
Daniel Santiago Rivera4ca1cc92019-04-30 08:57:46 -0700183 "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
Jeff Brown0cde89f2011-10-10 14:50:10 -0700184 window->mHeader->freeOffset,
185 window->mHeader->numRows,
186 window->mHeader->numColumns,
187 window->mSize, window->mData);
188 *outCursorWindow = window;
189 return OK;
190 }
191 ::close(dupAshmemFd);
192 }
193 }
194 }
195 *outCursorWindow = NULL;
196 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197}
198
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600199status_t CursorWindow::createFromParcelInline(Parcel* parcel, String8& name,
200 CursorWindow** outCursorWindow) {
201 uint32_t sentSize;
202 status_t result = parcel->readUint32(&sentSize);
203 if (result) return result;
204 if (sentSize > kInlineSize) return NO_MEMORY;
205
206 void* data = calloc(sentSize, 1);
207 if (!data) return NO_MEMORY;
208
209 result = parcel->read(data, sentSize);
210 if (result) return result;
211
212 CursorWindow* window = new CursorWindow(name, -1, data, sentSize,
213 sentSize, true /*readOnly*/);
214 LOG_WINDOW("Created CursorWindow from inline parcel: freeOffset=%d, "
215 "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
216 window->mHeader->freeOffset,
217 window->mHeader->numRows,
218 window->mHeader->numColumns,
219 window->mSize, window->mData);
220 *outCursorWindow = window;
221 return OK;
222}
223
Jeff Brown0cde89f2011-10-10 14:50:10 -0700224status_t CursorWindow::writeToParcel(Parcel* parcel) {
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600225 LOG_WINDOW("Writing CursorWindow: freeOffset=%d, "
226 "numRows=%d, numColumns=%d, mSize=%zu, mData=%p",
227 mHeader->freeOffset,
228 mHeader->numRows,
229 mHeader->numColumns,
230 mSize, mData);
231
232 status_t result = parcel->writeString8(mName);
233 if (result) return result;
234
235 if (mAshmemFd != -1) {
236 result = parcel->writeBool(true);
237 if (result) return result;
238 return writeToParcelAshmem(parcel);
239 } else {
240 result = parcel->writeBool(false);
241 if (result) return result;
242 return writeToParcelInline(parcel);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700243 }
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600244}
245
246status_t CursorWindow::writeToParcelAshmem(Parcel* parcel) {
247 return parcel->writeDupFileDescriptor(mAshmemFd);
248}
249
250status_t CursorWindow::writeToParcelInline(Parcel* parcel) {
251 status_t result = parcel->writeUint32(mHeader->freeOffset);
252 if (result) return result;
253
254 return parcel->write(mData, mHeader->freeOffset);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700255}
256
257status_t CursorWindow::clear() {
258 if (mReadOnly) {
259 return INVALID_OPERATION;
260 }
261
262 mHeader->freeOffset = sizeof(Header) + sizeof(RowSlotChunk);
263 mHeader->firstChunkOffset = sizeof(Header);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 mHeader->numRows = 0;
265 mHeader->numColumns = 0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700266
267 RowSlotChunk* firstChunk = static_cast<RowSlotChunk*>(offsetToPtr(mHeader->firstChunkOffset));
268 firstChunk->nextChunkOffset = 0;
269 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270}
271
Jeff Brown0cde89f2011-10-10 14:50:10 -0700272status_t CursorWindow::setNumColumns(uint32_t numColumns) {
273 if (mReadOnly) {
274 return INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700276
277 uint32_t cur = mHeader->numColumns;
278 if ((cur > 0 || mHeader->numRows > 0) && cur != numColumns) {
Steve Block3762c312012-01-06 19:20:56 +0000279 ALOGE("Trying to go from %d columns to %d", cur, numColumns);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700280 return INVALID_OPERATION;
281 }
282 mHeader->numColumns = numColumns;
283 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284}
285
Jeff Brown0cde89f2011-10-10 14:50:10 -0700286status_t CursorWindow::allocRow() {
287 if (mReadOnly) {
288 return INVALID_OPERATION;
289 }
290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 // Fill in the row slot
Jeff Brown0cde89f2011-10-10 14:50:10 -0700292 RowSlot* rowSlot = allocRowSlot();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 if (rowSlot == NULL) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700294 return NO_MEMORY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 }
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600296 uint32_t rowSlotOffset = offsetFromPtr(rowSlot);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297
298 // Allocate the slots for the field directory
Jeff Brown0cde89f2011-10-10 14:50:10 -0700299 size_t fieldDirSize = mHeader->numColumns * sizeof(FieldSlot);
300 uint32_t fieldDirOffset = alloc(fieldDirSize, true /*aligned*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 if (!fieldDirOffset) {
302 mHeader->numRows--;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700303 LOG_WINDOW("The row failed, so back out the new row accounting "
304 "from allocRowSlot %d", mHeader->numRows);
305 return NO_MEMORY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700307 FieldSlot* fieldDir = static_cast<FieldSlot*>(offsetToPtr(fieldDirOffset));
308 memset(fieldDir, 0, fieldDirSize);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309
Daniel Santiago Rivera4ca1cc92019-04-30 08:57:46 -0700310 LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %zu bytes at offset %u\n",
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600311 mHeader->numRows - 1, rowSlotOffset, fieldDirSize, fieldDirOffset);
312 rowSlot = static_cast<RowSlot*>(offsetToPtr(rowSlotOffset));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 rowSlot->offset = fieldDirOffset;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700314 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315}
316
Jeff Brown0cde89f2011-10-10 14:50:10 -0700317status_t CursorWindow::freeLastRow() {
318 if (mReadOnly) {
319 return INVALID_OPERATION;
320 }
321
322 if (mHeader->numRows > 0) {
323 mHeader->numRows--;
324 }
325 return OK;
326}
327
328uint32_t CursorWindow::alloc(size_t size, bool aligned) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 uint32_t padding;
330 if (aligned) {
331 // 4 byte alignment
Jeff Brown0cde89f2011-10-10 14:50:10 -0700332 padding = (~mHeader->freeOffset + 1) & 3;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 } else {
334 padding = 0;
335 }
336
Jeff Brown0cde89f2011-10-10 14:50:10 -0700337 uint32_t offset = mHeader->freeOffset + padding;
338 uint32_t nextFreeOffset = offset + size;
339 if (nextFreeOffset > mSize) {
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600340 // Try inflating to ashmem before finally giving up
341 inflate();
342 if (nextFreeOffset > mSize) {
343 ALOGW("Window is full: requested allocation %zu bytes, "
344 "free space %zu bytes, window size %zu bytes",
345 size, freeSpace(), mSize);
346 return 0;
347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 }
349
Jeff Brown0cde89f2011-10-10 14:50:10 -0700350 mHeader->freeOffset = nextFreeOffset;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 return offset;
352}
353
Jeff Brown0cde89f2011-10-10 14:50:10 -0700354CursorWindow::RowSlot* CursorWindow::getRowSlot(uint32_t row) {
355 uint32_t chunkPos = row;
356 RowSlotChunk* chunk = static_cast<RowSlotChunk*>(
357 offsetToPtr(mHeader->firstChunkOffset));
358 while (chunkPos >= ROW_SLOT_CHUNK_NUM_ROWS) {
359 chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset));
360 chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700362 return &chunk->slots[chunkPos];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363}
364
Jeff Brown0cde89f2011-10-10 14:50:10 -0700365CursorWindow::RowSlot* CursorWindow::allocRowSlot() {
366 uint32_t chunkPos = mHeader->numRows;
367 RowSlotChunk* chunk = static_cast<RowSlotChunk*>(
368 offsetToPtr(mHeader->firstChunkOffset));
369 while (chunkPos > ROW_SLOT_CHUNK_NUM_ROWS) {
370 chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset));
371 chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS;
372 }
373 if (chunkPos == ROW_SLOT_CHUNK_NUM_ROWS) {
374 if (!chunk->nextChunkOffset) {
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600375 uint32_t chunkOffset = offsetFromPtr(chunk);
376 uint32_t newChunk = alloc(sizeof(RowSlotChunk), true /*aligned*/);
377 chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunkOffset));
378 chunk->nextChunkOffset = newChunk;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700379 if (!chunk->nextChunkOffset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 return NULL;
381 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700383 chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset));
384 chunk->nextChunkOffset = 0;
385 chunkPos = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700387 mHeader->numRows += 1;
388 return &chunk->slots[chunkPos];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389}
390
Jeff Brown0cde89f2011-10-10 14:50:10 -0700391CursorWindow::FieldSlot* CursorWindow::getFieldSlot(uint32_t row, uint32_t column) {
392 if (row >= mHeader->numRows || column >= mHeader->numColumns) {
Steve Block3762c312012-01-06 19:20:56 +0000393 ALOGE("Failed to read row %d, column %d from a CursorWindow which "
Jeff Brown0cde89f2011-10-10 14:50:10 -0700394 "has %d rows, %d columns.",
395 row, column, mHeader->numRows, mHeader->numColumns);
396 return NULL;
397 }
398 RowSlot* rowSlot = getRowSlot(row);
399 if (!rowSlot) {
Steve Block3762c312012-01-06 19:20:56 +0000400 ALOGE("Failed to find rowSlot for row %d.", row);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700401 return NULL;
402 }
403 FieldSlot* fieldDir = static_cast<FieldSlot*>(offsetToPtr(rowSlot->offset));
404 return &fieldDir[column];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405}
406
Jeff Brown0cde89f2011-10-10 14:50:10 -0700407status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) {
408 return putBlobOrString(row, column, value, size, FIELD_TYPE_BLOB);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409}
410
Jeff Brown0cde89f2011-10-10 14:50:10 -0700411status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value,
412 size_t sizeIncludingNull) {
413 return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414}
415
Jeff Brown0cde89f2011-10-10 14:50:10 -0700416status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
417 const void* value, size_t size, int32_t type) {
418 if (mReadOnly) {
419 return INVALID_OPERATION;
420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421
Jeff Brown0cde89f2011-10-10 14:50:10 -0700422 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700424 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 }
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600426 uint32_t fieldSlotOffset = offsetFromPtr(fieldSlot);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427
Jeff Brown0cde89f2011-10-10 14:50:10 -0700428 uint32_t offset = alloc(size);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 if (!offset) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700430 return NO_MEMORY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 }
432
Jeff Brown0cde89f2011-10-10 14:50:10 -0700433 memcpy(offsetToPtr(offset), value, size);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600435 fieldSlot = static_cast<FieldSlot*>(offsetToPtr(fieldSlotOffset));
Jeff Brown0cde89f2011-10-10 14:50:10 -0700436 fieldSlot->type = type;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 fieldSlot->data.buffer.offset = offset;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700438 fieldSlot->data.buffer.size = size;
439 return OK;
440}
441
442status_t CursorWindow::putLong(uint32_t row, uint32_t column, int64_t value) {
443 if (mReadOnly) {
444 return INVALID_OPERATION;
445 }
446
447 FieldSlot* fieldSlot = getFieldSlot(row, column);
448 if (!fieldSlot) {
449 return BAD_VALUE;
450 }
451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 fieldSlot->type = FIELD_TYPE_INTEGER;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700453 fieldSlot->data.l = value;
454 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455}
456
Jeff Brown0cde89f2011-10-10 14:50:10 -0700457status_t CursorWindow::putDouble(uint32_t row, uint32_t column, double value) {
458 if (mReadOnly) {
459 return INVALID_OPERATION;
460 }
461
462 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700464 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 }
466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 fieldSlot->type = FIELD_TYPE_FLOAT;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700468 fieldSlot->data.d = value;
469 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470}
471
Jeff Brown0cde89f2011-10-10 14:50:10 -0700472status_t CursorWindow::putNull(uint32_t row, uint32_t column) {
473 if (mReadOnly) {
474 return INVALID_OPERATION;
475 }
476
477 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700479 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 }
481
482 fieldSlot->type = FIELD_TYPE_NULL;
483 fieldSlot->data.buffer.offset = 0;
484 fieldSlot->data.buffer.size = 0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700485 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486}
487
488}; // namespace android