blob: abf2b0a9164277d4202dd6158e51362a30d0eabd [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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017#define LOG_TAG "CursorWindow"
18
Mathias Agopian49d2b182012-02-27 18:11:20 -080019#include <androidfw/CursorWindow.h>
Jeff Brown0cde89f2011-10-10 14:50:10 -070020
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060021#include "android-base/logging.h"
Michael Hoisiee28dd9f2024-03-12 18:15:14 +000022#include "android-base/mapped_file.h"
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060023#include "cutils/ashmem.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
Michael Hoisiee28dd9f2024-03-12 18:15:14 +000025using android::base::MappedFile;
26
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027namespace android {
28
Jeff Sharkey539fdff2020-09-23 21:43:23 -060029/**
30 * By default windows are lightweight inline allocations of this size;
31 * they're only inflated to ashmem regions when more space is needed.
32 */
33static constexpr const size_t kInlineSize = 16384;
34
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060035static constexpr const size_t kSlotShift = 4;
36static constexpr const size_t kSlotSizeBytes = 1 << kSlotShift;
37
38CursorWindow::CursorWindow() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039}
40
Jeff Brown0cde89f2011-10-10 14:50:10 -070041CursorWindow::~CursorWindow() {
Jeff Sharkey539fdff2020-09-23 21:43:23 -060042 if (mAshmemFd != -1) {
Michael Hoisiee28dd9f2024-03-12 18:15:14 +000043 mMappedFile.reset();
Jeff Sharkey539fdff2020-09-23 21:43:23 -060044 ::close(mAshmemFd);
45 } else {
46 free(mData);
47 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048}
49
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060050status_t CursorWindow::create(const String8 &name, size_t inflatedSize, CursorWindow **outWindow) {
51 *outWindow = nullptr;
Jeff Sharkey539fdff2020-09-23 21:43:23 -060052
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060053 CursorWindow* window = new CursorWindow();
54 if (!window) goto fail;
Jeff Sharkey539fdff2020-09-23 21:43:23 -060055
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060056 window->mName = name;
57 window->mSize = std::min(kInlineSize, inflatedSize);
58 window->mInflatedSize = inflatedSize;
59 window->mData = malloc(window->mSize);
60 if (!window->mData) goto fail;
61 window->mReadOnly = false;
62
63 window->clear();
64 window->updateSlotsData();
65
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060066 *outWindow = window;
67 return OK;
68
69fail:
70 LOG(ERROR) << "Failed create";
71fail_silent:
Jeff Sharkey539fdff2020-09-23 21:43:23 -060072 delete window;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060073 return UNKNOWN_ERROR;
Jeff Sharkey539fdff2020-09-23 21:43:23 -060074}
75
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060076status_t CursorWindow::maybeInflate() {
77 int ashmemFd = 0;
78 void* newData = nullptr;
Michael Hoisiee28dd9f2024-03-12 18:15:14 +000079 std::unique_ptr<MappedFile> mappedFile;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060080
81 // Bail early when we can't expand any further
82 if (mReadOnly || mSize == mInflatedSize) {
83 return INVALID_OPERATION;
84 }
Jeff Sharkey539fdff2020-09-23 21:43:23 -060085
Jeff Brown0cde89f2011-10-10 14:50:10 -070086 String8 ashmemName("CursorWindow: ");
Jeff Sharkey539fdff2020-09-23 21:43:23 -060087 ashmemName.append(mName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +000089 ashmemFd = ashmem_create_region(ashmemName.c_str(), mInflatedSize);
Jeff Brown0cde89f2011-10-10 14:50:10 -070090 if (ashmemFd < 0) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060091 PLOG(ERROR) << "Failed ashmem_create_region";
92 goto fail_silent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060094
95 if (ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE) < 0) {
96 PLOG(ERROR) << "Failed ashmem_set_prot_region";
97 goto fail_silent;
98 }
99
Michael Hoisiee28dd9f2024-03-12 18:15:14 +0000100 mappedFile = MappedFile::FromFd(ashmemFd, 0, mInflatedSize, PROT_READ | PROT_WRITE);
101 if (mappedFile == nullptr) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600102 PLOG(ERROR) << "Failed mmap";
103 goto fail_silent;
104 }
Michael Hoisiee28dd9f2024-03-12 18:15:14 +0000105 newData = mappedFile->data();
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600106
107 if (ashmem_set_prot_region(ashmemFd, PROT_READ) < 0) {
108 PLOG(ERROR) << "Failed ashmem_set_prot_region";
109 goto fail_silent;
110 }
111
112 {
113 // Migrate existing contents into new ashmem region
Lee Shombertc7e15902023-05-19 15:52:00 -0700114 uint32_t slotsSize = sizeOfSlots();
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600115 uint32_t newSlotsOffset = mInflatedSize - slotsSize;
116 memcpy(static_cast<uint8_t*>(newData),
117 static_cast<uint8_t*>(mData), mAllocOffset);
118 memcpy(static_cast<uint8_t*>(newData) + newSlotsOffset,
119 static_cast<uint8_t*>(mData) + mSlotsOffset, slotsSize);
120
121 free(mData);
122 mAshmemFd = ashmemFd;
123 mData = newData;
124 mSize = mInflatedSize;
125 mSlotsOffset = newSlotsOffset;
Michael Hoisiee28dd9f2024-03-12 18:15:14 +0000126 mMappedFile = std::move(mappedFile);
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600127
128 updateSlotsData();
129 }
130
131 LOG(DEBUG) << "Inflated: " << this->toString();
132 return OK;
133
134fail:
135 LOG(ERROR) << "Failed maybeInflate";
136fail_silent:
Michael Hoisiee28dd9f2024-03-12 18:15:14 +0000137 mappedFile.reset();
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600138 ::close(ashmemFd);
139 return UNKNOWN_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140}
141
Michael Hoisiea8c4d1a2024-10-01 22:54:13 +0000142#ifdef __linux__
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600143status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outWindow) {
144 *outWindow = nullptr;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700145
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600146 CursorWindow* window = new CursorWindow();
147 if (!window) goto fail;
148
149 if (parcel->readString8(&window->mName)) goto fail;
150 if (parcel->readUint32(&window->mNumRows)) goto fail;
151 if (parcel->readUint32(&window->mNumColumns)) goto fail;
152 if (parcel->readUint32(&window->mSize)) goto fail;
153
154 if ((window->mNumRows * window->mNumColumns * kSlotSizeBytes) > window->mSize) {
155 LOG(ERROR) << "Unexpected size " << window->mSize << " for " << window->mNumRows
156 << " rows and " << window->mNumColumns << " columns";
157 goto fail_silent;
158 }
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600159
160 bool isAshmem;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600161 if (parcel->readBool(&isAshmem)) goto fail;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600162 if (isAshmem) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600163 window->mAshmemFd = parcel->readFileDescriptor();
164 if (window->mAshmemFd < 0) {
165 LOG(ERROR) << "Failed readFileDescriptor";
166 goto fail_silent;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700167 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600168
169 window->mAshmemFd = ::fcntl(window->mAshmemFd, F_DUPFD_CLOEXEC, 0);
170 if (window->mAshmemFd < 0) {
171 PLOG(ERROR) << "Failed F_DUPFD_CLOEXEC";
172 goto fail_silent;
173 }
174
Michael Hoisiee28dd9f2024-03-12 18:15:14 +0000175 window->mMappedFile = MappedFile::FromFd(window->mAshmemFd, 0, window->mSize, PROT_READ);
176 if (window->mMappedFile == nullptr) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600177 PLOG(ERROR) << "Failed mmap";
178 goto fail_silent;
179 }
Michael Hoisiee28dd9f2024-03-12 18:15:14 +0000180 window->mData = window->mMappedFile->data();
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600181 } else {
182 window->mAshmemFd = -1;
183
184 if (window->mSize > kInlineSize) {
185 LOG(ERROR) << "Unexpected size " << window->mSize << " for inline window";
186 goto fail_silent;
187 }
188
189 window->mData = malloc(window->mSize);
190 if (!window->mData) goto fail;
191
192 if (parcel->read(window->mData, window->mSize)) goto fail;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700193 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600195 // We just came from a remote source, so we're read-only
196 // and we can't inflate ourselves
197 window->mInflatedSize = window->mSize;
198 window->mReadOnly = true;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600199
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600200 window->updateSlotsData();
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600201
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600202 LOG(DEBUG) << "Created from parcel: " << window->toString();
203 *outWindow = window;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600204 return OK;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600205
206fail:
207 LOG(ERROR) << "Failed createFromParcel";
208fail_silent:
209 delete window;
210 return UNKNOWN_ERROR;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600211}
212
Jeff Brown0cde89f2011-10-10 14:50:10 -0700213status_t CursorWindow::writeToParcel(Parcel* parcel) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600214 LOG(DEBUG) << "Writing to parcel: " << this->toString();
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600215
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600216 if (parcel->writeString8(mName)) goto fail;
217 if (parcel->writeUint32(mNumRows)) goto fail;
218 if (parcel->writeUint32(mNumColumns)) goto fail;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600219 if (mAshmemFd != -1) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600220 if (parcel->writeUint32(mSize)) goto fail;
221 if (parcel->writeBool(true)) goto fail;
222 if (parcel->writeDupFileDescriptor(mAshmemFd)) goto fail;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600223 } else {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600224 // Since we know we're going to be read-only on the remote side,
Lee Shombertc7e15902023-05-19 15:52:00 -0700225 // we can compact ourselves on the wire.
226 size_t slotsSize = sizeOfSlots();
227 size_t compactedSize = sizeInUse();
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600228 if (parcel->writeUint32(compactedSize)) goto fail;
229 if (parcel->writeBool(false)) goto fail;
230 void* dest = parcel->writeInplace(compactedSize);
231 if (!dest) goto fail;
232 memcpy(static_cast<uint8_t*>(dest),
233 static_cast<uint8_t*>(mData), mAllocOffset);
234 memcpy(static_cast<uint8_t*>(dest) + compactedSize - slotsSize,
235 static_cast<uint8_t*>(mData) + mSlotsOffset, slotsSize);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700236 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600237 return OK;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600238
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600239fail:
240 LOG(ERROR) << "Failed writeToParcel";
241fail_silent:
242 return UNKNOWN_ERROR;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700243}
Michael Hoisiea8c4d1a2024-10-01 22:54:13 +0000244#endif
Jeff Brown0cde89f2011-10-10 14:50:10 -0700245
246status_t CursorWindow::clear() {
247 if (mReadOnly) {
248 return INVALID_OPERATION;
249 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600250 mAllocOffset = 0;
251 mSlotsOffset = mSize;
252 mNumRows = 0;
253 mNumColumns = 0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700254 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255}
256
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600257void CursorWindow::updateSlotsData() {
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600258 mSlotsStart = static_cast<uint8_t*>(mData) + mSize - kSlotSizeBytes;
259 mSlotsEnd = static_cast<uint8_t*>(mData) + mSlotsOffset;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600260}
261
262void* CursorWindow::offsetToPtr(uint32_t offset, uint32_t bufferSize = 0) {
263 if (offset > mSize) {
264 LOG(ERROR) << "Offset " << offset
265 << " out of bounds, max value " << mSize;
266 return nullptr;
267 }
268 if (offset + bufferSize > mSize) {
269 LOG(ERROR) << "End offset " << (offset + bufferSize)
270 << " out of bounds, max value " << mSize;
271 return nullptr;
272 }
273 return static_cast<uint8_t*>(mData) + offset;
274}
275
276uint32_t CursorWindow::offsetFromPtr(void* ptr) {
277 return static_cast<uint8_t*>(ptr) - static_cast<uint8_t*>(mData);
278}
279
Jeff Brown0cde89f2011-10-10 14:50:10 -0700280status_t CursorWindow::setNumColumns(uint32_t numColumns) {
281 if (mReadOnly) {
282 return INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600284 uint32_t cur = mNumColumns;
285 if ((cur > 0 || mNumRows > 0) && cur != numColumns) {
286 LOG(ERROR) << "Trying to go from " << cur << " columns to " << numColumns;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700287 return INVALID_OPERATION;
288 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600289 mNumColumns = numColumns;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700290 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291}
292
Jeff Brown0cde89f2011-10-10 14:50:10 -0700293status_t CursorWindow::allocRow() {
294 if (mReadOnly) {
295 return INVALID_OPERATION;
296 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600297 size_t size = mNumColumns * kSlotSizeBytes;
Jeff Sharkeyb2bbdaa2020-10-20 13:19:04 -0600298 int32_t newOffset = mSlotsOffset - size;
299 if (newOffset < (int32_t) mAllocOffset) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600300 maybeInflate();
301 newOffset = mSlotsOffset - size;
Jeff Sharkeyb2bbdaa2020-10-20 13:19:04 -0600302 if (newOffset < (int32_t) mAllocOffset) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600303 return NO_MEMORY;
304 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600306 memset(offsetToPtr(newOffset), 0, size);
307 mSlotsOffset = newOffset;
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600308 updateSlotsData();
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600309 mNumRows++;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700310 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311}
312
Jeff Brown0cde89f2011-10-10 14:50:10 -0700313status_t CursorWindow::freeLastRow() {
314 if (mReadOnly) {
315 return INVALID_OPERATION;
316 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600317 size_t size = mNumColumns * kSlotSizeBytes;
Jeff Sharkeyb2bbdaa2020-10-20 13:19:04 -0600318 size_t newOffset = mSlotsOffset + size;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600319 if (newOffset > mSize) {
320 return NO_MEMORY;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700321 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600322 mSlotsOffset = newOffset;
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600323 updateSlotsData();
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600324 mNumRows--;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700325 return OK;
326}
327
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600328status_t CursorWindow::alloc(size_t size, uint32_t* outOffset) {
329 if (mReadOnly) {
330 return INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600332 size_t alignedSize = (size + 3) & ~3;
Jeff Sharkeyb2bbdaa2020-10-20 13:19:04 -0600333 size_t newOffset = mAllocOffset + alignedSize;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600334 if (newOffset > mSlotsOffset) {
335 maybeInflate();
336 newOffset = mAllocOffset + alignedSize;
337 if (newOffset > mSlotsOffset) {
338 return NO_MEMORY;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600339 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600341 *outOffset = mAllocOffset;
342 mAllocOffset = newOffset;
343 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344}
345
Jeff Brown0cde89f2011-10-10 14:50:10 -0700346CursorWindow::FieldSlot* CursorWindow::getFieldSlot(uint32_t row, uint32_t column) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600347 // This is carefully tuned to use as few cycles as
348 // possible, since this is an extremely hot code path;
349 // see CursorWindow_bench.cpp for more details
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600350 void *result = static_cast<uint8_t*>(mSlotsStart)
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600351 - (((row * mNumColumns) + column) << kSlotShift);
Jeff Sharkeyb2bbdaa2020-10-20 13:19:04 -0600352 if (result < mSlotsEnd || result > mSlotsStart || column >= mNumColumns) {
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600353 LOG(ERROR) << "Failed to read row " << row << ", column " << column
354 << " from a window with " << mNumRows << " rows, " << mNumColumns << " columns";
355 return nullptr;
356 } else {
357 return static_cast<FieldSlot*>(result);
358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359}
360
Jeff Brown0cde89f2011-10-10 14:50:10 -0700361status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) {
362 return putBlobOrString(row, column, value, size, FIELD_TYPE_BLOB);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363}
364
Jeff Brown0cde89f2011-10-10 14:50:10 -0700365status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value,
366 size_t sizeIncludingNull) {
367 return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368}
369
Jeff Brown0cde89f2011-10-10 14:50:10 -0700370status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
371 const void* value, size_t size, int32_t type) {
372 if (mReadOnly) {
373 return INVALID_OPERATION;
374 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375
Jeff Brown0cde89f2011-10-10 14:50:10 -0700376 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700378 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
380
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600381 uint32_t offset;
382 if (alloc(size, &offset)) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700383 return NO_MEMORY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 }
385
Jeff Brown0cde89f2011-10-10 14:50:10 -0700386 memcpy(offsetToPtr(offset), value, size);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600388 fieldSlot = getFieldSlot(row, column);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700389 fieldSlot->type = type;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 fieldSlot->data.buffer.offset = offset;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700391 fieldSlot->data.buffer.size = size;
392 return OK;
393}
394
395status_t CursorWindow::putLong(uint32_t row, uint32_t column, int64_t value) {
396 if (mReadOnly) {
397 return INVALID_OPERATION;
398 }
399
400 FieldSlot* fieldSlot = getFieldSlot(row, column);
401 if (!fieldSlot) {
402 return BAD_VALUE;
403 }
404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 fieldSlot->type = FIELD_TYPE_INTEGER;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700406 fieldSlot->data.l = value;
407 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408}
409
Jeff Brown0cde89f2011-10-10 14:50:10 -0700410status_t CursorWindow::putDouble(uint32_t row, uint32_t column, double value) {
411 if (mReadOnly) {
412 return INVALID_OPERATION;
413 }
414
415 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700417 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 }
419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 fieldSlot->type = FIELD_TYPE_FLOAT;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700421 fieldSlot->data.d = value;
422 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423}
424
Jeff Brown0cde89f2011-10-10 14:50:10 -0700425status_t CursorWindow::putNull(uint32_t row, uint32_t column) {
426 if (mReadOnly) {
427 return INVALID_OPERATION;
428 }
429
430 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700432 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 }
434
435 fieldSlot->type = FIELD_TYPE_NULL;
436 fieldSlot->data.buffer.offset = 0;
437 fieldSlot->data.buffer.size = 0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700438 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439}
440
441}; // namespace android