blob: a4c44fb2bc6ca30bac2dc726ff668f87bd5622ec [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkStream.h"
halcanary67ec1f82014-06-27 11:36:20 -070011#include "SkStreamPriv.h"
reed@google.com8d0b5772011-06-24 13:07:31 +000012#include "SkData.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkFixed.h"
14#include "SkString.h"
15#include "SkOSFile.h"
halcanary67ec1f82014-06-27 11:36:20 -070016#include "SkTypes.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
reed@google.com3b429982012-06-26 15:30:08 +000018///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000019
reed@android.com8a1c16f2008-12-17 15:59:43 +000020
21int8_t SkStream::readS8() {
22 int8_t value;
reed@android.com04225dc2009-03-20 04:59:37 +000023 SkDEBUGCODE(size_t len =) this->read(&value, 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000024 SkASSERT(1 == len);
25 return value;
26}
27
28int16_t SkStream::readS16() {
29 int16_t value;
reed@android.com04225dc2009-03-20 04:59:37 +000030 SkDEBUGCODE(size_t len =) this->read(&value, 2);
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 SkASSERT(2 == len);
32 return value;
33}
34
35int32_t SkStream::readS32() {
36 int32_t value;
reed@android.com04225dc2009-03-20 04:59:37 +000037 SkDEBUGCODE(size_t len =) this->read(&value, 4);
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 SkASSERT(4 == len);
39 return value;
40}
41
42SkScalar SkStream::readScalar() {
43 SkScalar value;
reed@android.com04225dc2009-03-20 04:59:37 +000044 SkDEBUGCODE(size_t len =) this->read(&value, sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 SkASSERT(sizeof(SkScalar) == len);
46 return value;
47}
48
reed@google.com19f286b2011-10-18 11:49:52 +000049#define SK_MAX_BYTE_FOR_U8 0xFD
50#define SK_BYTE_SENTINEL_FOR_U16 0xFE
51#define SK_BYTE_SENTINEL_FOR_U32 0xFF
52
reed@android.com8a1c16f2008-12-17 15:59:43 +000053size_t SkStream::readPackedUInt() {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000054 uint8_t byte;
reed@android.com8a1c16f2008-12-17 15:59:43 +000055 if (!this->read(&byte, 1)) {
56 return 0;
57 }
reed@google.com19f286b2011-10-18 11:49:52 +000058 if (SK_BYTE_SENTINEL_FOR_U16 == byte) {
59 return this->readU16();
60 } else if (SK_BYTE_SENTINEL_FOR_U32 == byte) {
61 return this->readU32();
62 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 return byte;
64 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000065}
66
67//////////////////////////////////////////////////////////////////////////////////////
68
69SkWStream::~SkWStream()
70{
71}
72
73void SkWStream::newline()
74{
75 this->write("\n", 1);
76}
77
78void SkWStream::flush()
79{
80}
81
82bool SkWStream::writeText(const char text[])
83{
84 SkASSERT(text);
85 return this->write(text, strlen(text));
86}
87
88bool SkWStream::writeDecAsText(int32_t dec)
89{
halcanaryf0de4232014-11-07 06:07:23 -080090 char buffer[SkStrAppendS32_MaxSize];
91 char* stop = SkStrAppendS32(buffer, dec);
92 return this->write(buffer, stop - buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +000093}
94
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000095bool SkWStream::writeBigDecAsText(int64_t dec, int minDigits)
96{
halcanaryf0de4232014-11-07 06:07:23 -080097 char buffer[SkStrAppendU64_MaxSize];
98 char* stop = SkStrAppendU64(buffer, dec, minDigits);
99 return this->write(buffer, stop - buffer);
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000100}
101
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102bool SkWStream::writeHexAsText(uint32_t hex, int digits)
103{
104 SkString tmp;
105 tmp.appendHex(hex, digits);
106 return this->write(tmp.c_str(), tmp.size());
107}
108
109bool SkWStream::writeScalarAsText(SkScalar value)
110{
halcanaryf0de4232014-11-07 06:07:23 -0800111 char buffer[SkStrAppendScalar_MaxSize];
112 char* stop = SkStrAppendScalar(buffer, value);
113 return this->write(buffer, stop - buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114}
115
116bool SkWStream::write8(U8CPU value) {
117 uint8_t v = SkToU8(value);
118 return this->write(&v, 1);
119}
120
121bool SkWStream::write16(U16CPU value) {
122 uint16_t v = SkToU16(value);
123 return this->write(&v, 2);
124}
125
126bool SkWStream::write32(uint32_t value) {
127 return this->write(&value, 4);
128}
129
130bool SkWStream::writeScalar(SkScalar value) {
131 return this->write(&value, sizeof(value));
132}
133
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000134int SkWStream::SizeOfPackedUInt(size_t value) {
135 if (value <= SK_MAX_BYTE_FOR_U8) {
136 return 1;
137 } else if (value <= 0xFFFF) {
138 return 3;
139 }
140 return 5;
141}
142
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143bool SkWStream::writePackedUInt(size_t value) {
reed@google.com19f286b2011-10-18 11:49:52 +0000144 uint8_t data[5];
145 size_t len = 1;
146 if (value <= SK_MAX_BYTE_FOR_U8) {
147 data[0] = value;
148 len = 1;
149 } else if (value <= 0xFFFF) {
150 uint16_t value16 = value;
151 data[0] = SK_BYTE_SENTINEL_FOR_U16;
152 memcpy(&data[1], &value16, 2);
153 len = 3;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 } else {
commit-bot@chromium.orgf1177812014-04-23 19:19:44 +0000155 uint32_t value32 = SkToU32(value);
reed@google.com19f286b2011-10-18 11:49:52 +0000156 data[0] = SK_BYTE_SENTINEL_FOR_U32;
157 memcpy(&data[1], &value32, 4);
158 len = 5;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 }
reed@google.com19f286b2011-10-18 11:49:52 +0000160 return this->write(data, len);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161}
162
163bool SkWStream::writeStream(SkStream* stream, size_t length) {
164 char scratch[1024];
165 const size_t MAX = sizeof(scratch);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000166
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 while (length != 0) {
168 size_t n = length;
169 if (n > MAX) {
170 n = MAX;
171 }
172 stream->read(scratch, n);
173 if (!this->write(scratch, n)) {
174 return false;
175 }
176 length -= n;
177 }
178 return true;
179}
180
reed@google.com8a85d0c2011-06-24 19:12:12 +0000181///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000183SkFILEStream::SkFILEStream(const char file[]) : fName(file), fOwnership(kCallerPasses_Ownership) {
halcanary96fcdcc2015-08-27 07:41:13 -0700184 fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185}
186
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000187SkFILEStream::SkFILEStream(FILE* file, Ownership ownership)
halcanaryd76be9c2015-11-20 13:47:49 -0800188 : fFILE(file)
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000189 , fOwnership(ownership) {
190}
191
mike@reedtribe.org54d5f832013-03-19 02:12:50 +0000192SkFILEStream::~SkFILEStream() {
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000193 if (fFILE && fOwnership != kCallerRetains_Ownership) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 sk_fclose(fFILE);
mike@reedtribe.org54d5f832013-03-19 02:12:50 +0000195 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196}
197
mike@reedtribe.org54d5f832013-03-19 02:12:50 +0000198void SkFILEStream::setPath(const char path[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 fName.set(path);
mike@reedtribe.org54d5f832013-03-19 02:12:50 +0000200 if (fFILE) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 sk_fclose(fFILE);
halcanary96fcdcc2015-08-27 07:41:13 -0700202 fFILE = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 }
mike@reedtribe.org54d5f832013-03-19 02:12:50 +0000204 if (path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 fFILE = sk_fopen(fName.c_str(), kRead_SkFILE_Flag);
mike@reedtribe.org54d5f832013-03-19 02:12:50 +0000206 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207}
208
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000209size_t SkFILEStream::read(void* buffer, size_t size) {
210 if (fFILE) {
211 return sk_fread(buffer, size, fFILE);
212 }
213 return 0;
214}
215
216bool SkFILEStream::isAtEnd() const {
217 return sk_feof(fFILE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218}
219
mike@reedtribe.org54d5f832013-03-19 02:12:50 +0000220bool SkFILEStream::rewind() {
221 if (fFILE) {
222 if (sk_frewind(fFILE)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 return true;
mike@reedtribe.org54d5f832013-03-19 02:12:50 +0000224 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 // we hit an error
226 sk_fclose(fFILE);
halcanary96fcdcc2015-08-27 07:41:13 -0700227 fFILE = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 }
229 return false;
230}
231
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000232SkStreamAsset* SkFILEStream::duplicate() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700233 if (nullptr == fFILE) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000234 return new SkMemoryStream();
235 }
236
bsalomon49f085d2014-09-05 13:34:00 -0700237 if (fData.get()) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000238 return new SkMemoryStream(fData);
239 }
240
241 if (!fName.isEmpty()) {
scroggoa1193e42015-01-21 12:09:53 -0800242 SkAutoTDelete<SkFILEStream> that(new SkFILEStream(fName.c_str()));
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000243 if (sk_fidentical(that->fFILE, this->fFILE)) {
mtklein18300a32016-03-16 13:53:35 -0700244 return that.release();
mike@reedtribe.org54d5f832013-03-19 02:12:50 +0000245 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 }
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000247
reedfde05112016-03-11 13:02:28 -0800248 fData = SkData::MakeFromFILE(fFILE);
249 if (nullptr == fData) {
halcanary96fcdcc2015-08-27 07:41:13 -0700250 return nullptr;
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000251 }
252 return new SkMemoryStream(fData);
253}
254
255size_t SkFILEStream::getPosition() const {
256 return sk_ftell(fFILE);
257}
258
259bool SkFILEStream::seek(size_t position) {
260 return sk_fseek(fFILE, position);
261}
262
263bool SkFILEStream::move(long offset) {
264 return sk_fmove(fFILE, offset);
265}
266
267SkStreamAsset* SkFILEStream::fork() const {
scroggoa1193e42015-01-21 12:09:53 -0800268 SkAutoTDelete<SkStreamAsset> that(this->duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000269 that->seek(this->getPosition());
mtklein18300a32016-03-16 13:53:35 -0700270 return that.release();
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000271}
272
273size_t SkFILEStream::getLength() const {
274 return sk_fgetsize(fFILE);
275}
276
277const void* SkFILEStream::getMemoryBase() {
halcanary96fcdcc2015-08-27 07:41:13 -0700278 if (nullptr == fData.get()) {
279 return nullptr;
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000280 }
281 return fData->data();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282}
283
reed@google.com8a85d0c2011-06-24 19:12:12 +0000284///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285
reedfde05112016-03-11 13:02:28 -0800286static sk_sp<SkData> newFromParams(const void* src, size_t size, bool copyData) {
reed@google.com67d0cff2011-06-24 20:06:36 +0000287 if (copyData) {
reedfde05112016-03-11 13:02:28 -0800288 return SkData::MakeWithCopy(src, size);
reed@google.com67d0cff2011-06-24 20:06:36 +0000289 } else {
reedfde05112016-03-11 13:02:28 -0800290 return SkData::MakeWithoutCopy(src, size);
reed@google.com67d0cff2011-06-24 20:06:36 +0000291 }
292}
293
reed@google.com8a85d0c2011-06-24 19:12:12 +0000294SkMemoryStream::SkMemoryStream() {
reedfde05112016-03-11 13:02:28 -0800295 fData = SkData::MakeEmpty();
reed@google.com8a85d0c2011-06-24 19:12:12 +0000296 fOffset = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297}
298
299SkMemoryStream::SkMemoryStream(size_t size) {
reedfde05112016-03-11 13:02:28 -0800300 fData = SkData::MakeUninitialized(size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 fOffset = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302}
303
reed@google.com8a85d0c2011-06-24 19:12:12 +0000304SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData) {
reed@google.com67d0cff2011-06-24 20:06:36 +0000305 fData = newFromParams(src, size, copyData);
reed@google.com8a85d0c2011-06-24 19:12:12 +0000306 fOffset = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307}
308
reedfde05112016-03-11 13:02:28 -0800309SkMemoryStream::SkMemoryStream(sk_sp<SkData> data) : fData(std::move(data)) {
310 if (nullptr == fData) {
311 fData = SkData::MakeEmpty();
scroggo@google.come4904202013-01-09 22:02:58 +0000312 }
robertphillips@google.comc62b7262013-01-14 18:10:08 +0000313 fOffset = 0;
humper@google.comf515ffc2013-01-07 15:48:19 +0000314}
315
reedfde05112016-03-11 13:02:28 -0800316SkMemoryStream::SkMemoryStream(SkData* data) {
317 if (nullptr == data) {
318 fData = SkData::MakeEmpty();
319 } else {
320 fData = sk_ref_sp(data);
321 }
322 fOffset = 0;
reed@google.com8a85d0c2011-06-24 19:12:12 +0000323}
324
325void SkMemoryStream::setMemoryOwned(const void* src, size_t size) {
reedfde05112016-03-11 13:02:28 -0800326 fData = SkData::MakeFromMalloc(src, size);
reed@google.com8a85d0c2011-06-24 19:12:12 +0000327 fOffset = 0;
328}
329
330void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) {
reed@google.com67d0cff2011-06-24 20:06:36 +0000331 fData = newFromParams(src, size, copyData);
reed@google.com8a85d0c2011-06-24 19:12:12 +0000332 fOffset = 0;
333}
334
335SkData* SkMemoryStream::copyToData() const {
reedfde05112016-03-11 13:02:28 -0800336 return SkSafeRef(fData.get());
reed@google.com8a85d0c2011-06-24 19:12:12 +0000337}
338
339SkData* SkMemoryStream::setData(SkData* data) {
halcanary96fcdcc2015-08-27 07:41:13 -0700340 if (nullptr == data) {
reedfde05112016-03-11 13:02:28 -0800341 fData = SkData::MakeEmpty();
scroggo@google.come4904202013-01-09 22:02:58 +0000342 } else {
reedfde05112016-03-11 13:02:28 -0800343 fData = sk_ref_sp(data);
scroggo@google.come4904202013-01-09 22:02:58 +0000344 }
bungeman@google.com10822c62013-11-18 21:29:36 +0000345 fOffset = 0;
reed@google.com8a85d0c2011-06-24 19:12:12 +0000346 return data;
347}
348
349void SkMemoryStream::skipToAlign4() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 // cast to remove unary-minus warning
351 fOffset += -(int)fOffset & 0x03;
352}
353
reed@google.com8a85d0c2011-06-24 19:12:12 +0000354size_t SkMemoryStream::read(void* buffer, size_t size) {
355 size_t dataSize = fData->size();
356
reed@google.com8a85d0c2011-06-24 19:12:12 +0000357 if (size > dataSize - fOffset) {
358 size = dataSize - fOffset;
359 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 if (buffer) {
reed@google.com8a85d0c2011-06-24 19:12:12 +0000361 memcpy(buffer, fData->bytes() + fOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 }
363 fOffset += size;
364 return size;
365}
366
scroggod61c3842015-12-07 11:37:13 -0800367size_t SkMemoryStream::peek(void* buffer, size_t size) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700368 SkASSERT(buffer != nullptr);
scroggod61c3842015-12-07 11:37:13 -0800369
370 const size_t currentOffset = fOffset;
scroggo028a4132015-04-02 13:19:51 -0700371 SkMemoryStream* nonConstThis = const_cast<SkMemoryStream*>(this);
scroggod61c3842015-12-07 11:37:13 -0800372 const size_t bytesRead = nonConstThis->read(buffer, size);
373 nonConstThis->fOffset = currentOffset;
374 return bytesRead;
scroggo028a4132015-04-02 13:19:51 -0700375}
376
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000377bool SkMemoryStream::isAtEnd() const {
378 return fOffset == fData->size();
379}
380
381bool SkMemoryStream::rewind() {
382 fOffset = 0;
383 return true;
384}
385
halcanary385fe4d2015-08-26 13:07:48 -0700386SkMemoryStream* SkMemoryStream::duplicate() const { return new SkMemoryStream(fData); }
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000387
388size_t SkMemoryStream::getPosition() const {
389 return fOffset;
390}
391
392bool SkMemoryStream::seek(size_t position) {
393 fOffset = position > fData->size()
394 ? fData->size()
395 : position;
396 return true;
397}
398
399bool SkMemoryStream::move(long offset) {
400 return this->seek(fOffset + offset);
401}
402
403SkMemoryStream* SkMemoryStream::fork() const {
scroggoa1193e42015-01-21 12:09:53 -0800404 SkAutoTDelete<SkMemoryStream> that(this->duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000405 that->seek(fOffset);
mtklein18300a32016-03-16 13:53:35 -0700406 return that.release();
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000407}
408
409size_t SkMemoryStream::getLength() const {
410 return fData->size();
411}
412
reed@google.com8a85d0c2011-06-24 19:12:12 +0000413const void* SkMemoryStream::getMemoryBase() {
414 return fData->data();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415}
416
reed@google.com8a85d0c2011-06-24 19:12:12 +0000417const void* SkMemoryStream::getAtPos() {
418 return fData->bytes() + fOffset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000419}
420
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421/////////////////////////////////////////////////////////////////////////////////////////////////////////
422/////////////////////////////////////////////////////////////////////////////////////////////////////////
423
424SkFILEWStream::SkFILEWStream(const char path[])
425{
426 fFILE = sk_fopen(path, kWrite_SkFILE_Flag);
427}
428
429SkFILEWStream::~SkFILEWStream()
430{
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000431 if (fFILE) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 sk_fclose(fFILE);
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000433 }
434}
435
436size_t SkFILEWStream::bytesWritten() const {
437 return sk_ftell(fFILE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438}
439
440bool SkFILEWStream::write(const void* buffer, size_t size)
441{
halcanary96fcdcc2015-08-27 07:41:13 -0700442 if (fFILE == nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443 return false;
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000444 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445
446 if (sk_fwrite(buffer, size, fFILE) != size)
447 {
448 SkDEBUGCODE(SkDebugf("SkFILEWStream failed writing %d bytes\n", size);)
449 sk_fclose(fFILE);
halcanary96fcdcc2015-08-27 07:41:13 -0700450 fFILE = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451 return false;
452 }
453 return true;
454}
455
456void SkFILEWStream::flush()
457{
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000458 if (fFILE) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459 sk_fflush(fFILE);
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000460 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461}
462
caryclark7471fa42015-12-16 13:41:23 -0800463void SkFILEWStream::fsync()
464{
465 flush();
466 if (fFILE) {
467 sk_fsync(fFILE);
468 }
469}
470
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471////////////////////////////////////////////////////////////////////////
472
473SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size)
474 : fBuffer((char*)buffer), fMaxLength(size), fBytesWritten(0)
475{
476}
477
commit-bot@chromium.orgf1177812014-04-23 19:19:44 +0000478bool SkMemoryWStream::write(const void* buffer, size_t size) {
479 size = SkTMin(size, fMaxLength - fBytesWritten);
480 if (size > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481 memcpy(fBuffer + fBytesWritten, buffer, size);
482 fBytesWritten += size;
483 return true;
484 }
485 return false;
486}
487
488////////////////////////////////////////////////////////////////////////
489
490#define SkDynamicMemoryWStream_MinBlockSize 256
491
492struct SkDynamicMemoryWStream::Block {
493 Block* fNext;
494 char* fCurr;
495 char* fStop;
496
497 const char* start() const { return (const char*)(this + 1); }
498 char* start() { return (char*)(this + 1); }
499 size_t avail() const { return fStop - fCurr; }
500 size_t written() const { return fCurr - this->start(); }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000501
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502 void init(size_t size)
503 {
halcanary96fcdcc2015-08-27 07:41:13 -0700504 fNext = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505 fCurr = this->start();
506 fStop = this->start() + size;
507 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000508
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 const void* append(const void* data, size_t size)
510 {
511 SkASSERT((size_t)(fStop - fCurr) >= size);
512 memcpy(fCurr, data, size);
513 fCurr += size;
514 return (const void*)((const char*)data + size);
515 }
516};
517
reed@google.com8a85d0c2011-06-24 19:12:12 +0000518SkDynamicMemoryWStream::SkDynamicMemoryWStream()
reedfde05112016-03-11 13:02:28 -0800519 : fHead(nullptr), fTail(nullptr), fBytesWritten(0)
520{}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521
522SkDynamicMemoryWStream::~SkDynamicMemoryWStream()
523{
524 reset();
525}
526
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527void SkDynamicMemoryWStream::reset()
528{
reed@google.com8a85d0c2011-06-24 19:12:12 +0000529 this->invalidateCopy();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000530
reed@android.com8a1c16f2008-12-17 15:59:43 +0000531 Block* block = fHead;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000532
halcanary96fcdcc2015-08-27 07:41:13 -0700533 while (block != nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534 Block* next = block->fNext;
535 sk_free(block);
536 block = next;
537 }
halcanary96fcdcc2015-08-27 07:41:13 -0700538 fHead = fTail = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539 fBytesWritten = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540}
541
542bool SkDynamicMemoryWStream::write(const void* buffer, size_t count)
543{
544 if (count > 0) {
reed@google.com8a85d0c2011-06-24 19:12:12 +0000545 this->invalidateCopy();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000546
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547 fBytesWritten += count;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000548
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 size_t size;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000550
halcanary96fcdcc2015-08-27 07:41:13 -0700551 if (fTail != nullptr && fTail->avail() > 0) {
commit-bot@chromium.orgf1177812014-04-23 19:19:44 +0000552 size = SkTMin(fTail->avail(), count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 buffer = fTail->append(buffer, size);
554 SkASSERT(count >= size);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000555 count -= size;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556 if (count == 0)
557 return true;
558 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000559
commit-bot@chromium.orgf1177812014-04-23 19:19:44 +0000560 size = SkTMax<size_t>(count, SkDynamicMemoryWStream_MinBlockSize);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000561 Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
562 block->init(size);
563 block->append(buffer, count);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000564
halcanary96fcdcc2015-08-27 07:41:13 -0700565 if (fTail != nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566 fTail->fNext = block;
567 else
568 fHead = fTail = block;
569 fTail = block;
570 }
571 return true;
572}
573
574bool SkDynamicMemoryWStream::write(const void* buffer, size_t offset, size_t count)
575{
reed@google.com8a85d0c2011-06-24 19:12:12 +0000576 if (offset + count > fBytesWritten) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000577 return false; // test does not partially modify
reed@google.com8a85d0c2011-06-24 19:12:12 +0000578 }
579
580 this->invalidateCopy();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000581
reed@android.com8a1c16f2008-12-17 15:59:43 +0000582 Block* block = fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700583 while (block != nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000584 size_t size = block->written();
585 if (offset < size) {
586 size_t part = offset + count > size ? size - offset : count;
587 memcpy(block->start() + offset, buffer, part);
588 if (count <= part)
589 return true;
590 count -= part;
591 buffer = (const void*) ((char* ) buffer + part);
592 }
593 offset = offset > size ? offset - size : 0;
594 block = block->fNext;
595 }
596 return false;
597}
598
599bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count)
600{
601 if (offset + count > fBytesWritten)
602 return false; // test does not partially modify
603 Block* block = fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700604 while (block != nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000605 size_t size = block->written();
606 if (offset < size) {
607 size_t part = offset + count > size ? size - offset : count;
608 memcpy(buffer, block->start() + offset, part);
609 if (count <= part)
610 return true;
611 count -= part;
612 buffer = (void*) ((char* ) buffer + part);
613 }
614 offset = offset > size ? offset - size : 0;
615 block = block->fNext;
616 }
617 return false;
618}
619
620void SkDynamicMemoryWStream::copyTo(void* dst) const
621{
reed@google.com8a85d0c2011-06-24 19:12:12 +0000622 if (fCopy) {
623 memcpy(dst, fCopy->data(), fBytesWritten);
624 } else {
625 Block* block = fHead;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000626
halcanary96fcdcc2015-08-27 07:41:13 -0700627 while (block != nullptr) {
reed@google.com8a85d0c2011-06-24 19:12:12 +0000628 size_t size = block->written();
629 memcpy(dst, block->start(), size);
630 dst = (void*)((char*)dst + size);
631 block = block->fNext;
632 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633 }
634}
635
halcanary7af21502015-02-23 12:17:59 -0800636void SkDynamicMemoryWStream::writeToStream(SkWStream* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700637 for (Block* block = fHead; block != nullptr; block = block->fNext) {
halcanary7af21502015-02-23 12:17:59 -0800638 dst->write(block->start(), block->written());
639 }
640}
641
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642void SkDynamicMemoryWStream::padToAlign4()
643{
644 // cast to remove unary-minus warning
645 int padBytes = -(int)fBytesWritten & 0x03;
646 if (padBytes == 0)
647 return;
648 int zero = 0;
649 write(&zero, padBytes);
650}
651
reed@google.com8d0b5772011-06-24 13:07:31 +0000652SkData* SkDynamicMemoryWStream::copyToData() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700653 if (nullptr == fCopy) {
reedfde05112016-03-11 13:02:28 -0800654 auto data = SkData::MakeUninitialized(fBytesWritten);
reed33a30502014-09-11 08:42:36 -0700655 // be sure to call copyTo() before we assign to fCopy
656 this->copyTo(data->writable_data());
reedfde05112016-03-11 13:02:28 -0800657 fCopy = std::move(data);
reed@google.com8a85d0c2011-06-24 19:12:12 +0000658 }
reedfde05112016-03-11 13:02:28 -0800659 return SkRef(fCopy.get());
reed@google.com70442a62011-06-23 21:48:04 +0000660}
661
reed@google.com8a85d0c2011-06-24 19:12:12 +0000662void SkDynamicMemoryWStream::invalidateCopy() {
reedfde05112016-03-11 13:02:28 -0800663 fCopy = nullptr;
reed@google.com8a85d0c2011-06-24 19:12:12 +0000664}
665
bungeman@google.com88682b72013-07-19 13:55:41 +0000666class SkBlockMemoryRefCnt : public SkRefCnt {
667public:
668 explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { }
669
670 virtual ~SkBlockMemoryRefCnt() {
671 SkDynamicMemoryWStream::Block* block = fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700672 while (block != nullptr) {
bungeman@google.com88682b72013-07-19 13:55:41 +0000673 SkDynamicMemoryWStream::Block* next = block->fNext;
674 sk_free(block);
675 block = next;
676 }
677 }
678
679 SkDynamicMemoryWStream::Block* const fHead;
680};
681
682class SkBlockMemoryStream : public SkStreamAsset {
683public:
684 SkBlockMemoryStream(SkDynamicMemoryWStream::Block* head, size_t size)
halcanary385fe4d2015-08-26 13:07:48 -0700685 : fBlockMemory(new SkBlockMemoryRefCnt(head))
686 , fCurrent(head)
687 , fSize(size)
688 , fOffset(0)
689 , fCurrentOffset(0) {}
bungeman@google.com88682b72013-07-19 13:55:41 +0000690
691 SkBlockMemoryStream(SkBlockMemoryRefCnt* headRef, size_t size)
692 : fBlockMemory(SkRef(headRef)), fCurrent(fBlockMemory->fHead)
693 , fSize(size) , fOffset(0), fCurrentOffset(0) { }
694
mtklein36352bf2015-03-25 18:17:31 -0700695 size_t read(void* buffer, size_t rawCount) override {
bungeman@google.com88682b72013-07-19 13:55:41 +0000696 size_t count = rawCount;
697 if (fOffset + count > fSize) {
698 count = fSize - fOffset;
699 }
700 size_t bytesLeftToRead = count;
halcanary96fcdcc2015-08-27 07:41:13 -0700701 while (fCurrent != nullptr) {
bungeman@google.com88682b72013-07-19 13:55:41 +0000702 size_t bytesLeftInCurrent = fCurrent->written() - fCurrentOffset;
bungeman@google.com8d79f962014-03-05 16:26:14 +0000703 size_t bytesFromCurrent = SkTMin(bytesLeftToRead, bytesLeftInCurrent);
bungeman@google.com88682b72013-07-19 13:55:41 +0000704 if (buffer) {
705 memcpy(buffer, fCurrent->start() + fCurrentOffset, bytesFromCurrent);
bungeman@google.com8d79f962014-03-05 16:26:14 +0000706 buffer = SkTAddOffset<void>(buffer, bytesFromCurrent);
bungeman@google.com88682b72013-07-19 13:55:41 +0000707 }
708 if (bytesLeftToRead <= bytesFromCurrent) {
709 fCurrentOffset += bytesFromCurrent;
710 fOffset += count;
711 return count;
712 }
713 bytesLeftToRead -= bytesFromCurrent;
bungeman@google.com88682b72013-07-19 13:55:41 +0000714 fCurrent = fCurrent->fNext;
715 fCurrentOffset = 0;
716 }
717 SkASSERT(false);
718 return 0;
719 }
720
mtklein36352bf2015-03-25 18:17:31 -0700721 bool isAtEnd() const override {
bungeman@google.com88682b72013-07-19 13:55:41 +0000722 return fOffset == fSize;
723 }
724
scroggod61c3842015-12-07 11:37:13 -0800725 size_t peek(void* buff, size_t bytesToPeek) const override {
halcanary96fcdcc2015-08-27 07:41:13 -0700726 SkASSERT(buff != nullptr);
scroggod61c3842015-12-07 11:37:13 -0800727
728 bytesToPeek = SkTMin(bytesToPeek, fSize - fOffset);
729
730 size_t bytesLeftToPeek = bytesToPeek;
halcanarye797d0d2015-05-21 08:13:27 -0700731 char* buffer = static_cast<char*>(buff);
732 const SkDynamicMemoryWStream::Block* current = fCurrent;
733 size_t currentOffset = fCurrentOffset;
scroggod61c3842015-12-07 11:37:13 -0800734 while (bytesLeftToPeek) {
halcanarye797d0d2015-05-21 08:13:27 -0700735 SkASSERT(current);
736 size_t bytesFromCurrent =
scroggod61c3842015-12-07 11:37:13 -0800737 SkTMin(current->written() - currentOffset, bytesLeftToPeek);
halcanarye797d0d2015-05-21 08:13:27 -0700738 memcpy(buffer, current->start() + currentOffset, bytesFromCurrent);
scroggod61c3842015-12-07 11:37:13 -0800739 bytesLeftToPeek -= bytesFromCurrent;
halcanarye797d0d2015-05-21 08:13:27 -0700740 buffer += bytesFromCurrent;
741 current = current->fNext;
742 currentOffset = 0;
743 }
scroggod61c3842015-12-07 11:37:13 -0800744 return bytesToPeek;
halcanarye797d0d2015-05-21 08:13:27 -0700745 }
746
mtklein36352bf2015-03-25 18:17:31 -0700747 bool rewind() override {
bungeman@google.com88682b72013-07-19 13:55:41 +0000748 fCurrent = fBlockMemory->fHead;
749 fOffset = 0;
750 fCurrentOffset = 0;
751 return true;
752 }
753
mtklein36352bf2015-03-25 18:17:31 -0700754 SkBlockMemoryStream* duplicate() const override {
halcanary385fe4d2015-08-26 13:07:48 -0700755 return new SkBlockMemoryStream(fBlockMemory.get(), fSize);
bungeman@google.com88682b72013-07-19 13:55:41 +0000756 }
757
mtklein36352bf2015-03-25 18:17:31 -0700758 size_t getPosition() const override {
bungeman@google.com88682b72013-07-19 13:55:41 +0000759 return fOffset;
760 }
761
mtklein36352bf2015-03-25 18:17:31 -0700762 bool seek(size_t position) override {
bungeman@google.com88682b72013-07-19 13:55:41 +0000763 // If possible, skip forward.
764 if (position >= fOffset) {
765 size_t skipAmount = position - fOffset;
766 return this->skip(skipAmount) == skipAmount;
767 }
768 // If possible, move backward within the current block.
769 size_t moveBackAmount = fOffset - position;
770 if (moveBackAmount <= fCurrentOffset) {
771 fCurrentOffset -= moveBackAmount;
772 fOffset -= moveBackAmount;
773 return true;
774 }
775 // Otherwise rewind and move forward.
776 return this->rewind() && this->skip(position) == position;
777 }
778
mtklein36352bf2015-03-25 18:17:31 -0700779 bool move(long offset) override {
bungeman@google.com88682b72013-07-19 13:55:41 +0000780 return seek(fOffset + offset);
781 }
782
mtklein36352bf2015-03-25 18:17:31 -0700783 SkBlockMemoryStream* fork() const override {
scroggoa1193e42015-01-21 12:09:53 -0800784 SkAutoTDelete<SkBlockMemoryStream> that(this->duplicate());
bungeman@google.com88682b72013-07-19 13:55:41 +0000785 that->fCurrent = this->fCurrent;
786 that->fOffset = this->fOffset;
787 that->fCurrentOffset = this->fCurrentOffset;
mtklein18300a32016-03-16 13:53:35 -0700788 return that.release();
bungeman@google.com88682b72013-07-19 13:55:41 +0000789 }
790
mtklein36352bf2015-03-25 18:17:31 -0700791 size_t getLength() const override {
bungeman@google.com88682b72013-07-19 13:55:41 +0000792 return fSize;
793 }
794
mtklein36352bf2015-03-25 18:17:31 -0700795 const void* getMemoryBase() override {
halcanary209c1622015-09-28 07:29:39 -0700796 if (nullptr != fBlockMemory->fHead &&
797 nullptr == fBlockMemory->fHead->fNext) {
bungeman@google.com88682b72013-07-19 13:55:41 +0000798 return fBlockMemory->fHead->start();
799 }
halcanary96fcdcc2015-08-27 07:41:13 -0700800 return nullptr;
bungeman@google.com88682b72013-07-19 13:55:41 +0000801 }
802
803private:
804 SkAutoTUnref<SkBlockMemoryRefCnt> const fBlockMemory;
805 SkDynamicMemoryWStream::Block const * fCurrent;
806 size_t const fSize;
807 size_t fOffset;
808 size_t fCurrentOffset;
809};
810
bungeman@google.comc29f3d82013-07-19 22:32:11 +0000811SkStreamAsset* SkDynamicMemoryWStream::detachAsStream() {
bungeman@google.com88682b72013-07-19 13:55:41 +0000812 if (fCopy) {
halcanary385fe4d2015-08-26 13:07:48 -0700813 SkMemoryStream* stream = new SkMemoryStream(fCopy);
bungeman@google.com88682b72013-07-19 13:55:41 +0000814 this->reset();
815 return stream;
816 }
halcanary385fe4d2015-08-26 13:07:48 -0700817 SkBlockMemoryStream* stream = new SkBlockMemoryStream(fHead, fBytesWritten);
bungeman@google.com88682b72013-07-19 13:55:41 +0000818 fHead = 0;
819 this->reset();
820 return stream;
821}
822
reed@google.com8a85d0c2011-06-24 19:12:12 +0000823///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824
825void SkDebugWStream::newline()
826{
humper@google.com7af56be2013-01-14 18:49:19 +0000827#if defined(SK_DEBUG) || defined(SK_DEVELOPER)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828 SkDebugf("\n");
commit-bot@chromium.org490fb6b2014-03-06 17:16:26 +0000829 fBytesWritten++;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830#endif
831}
832
833bool SkDebugWStream::write(const void* buffer, size_t size)
834{
humper@google.com7af56be2013-01-14 18:49:19 +0000835#if defined(SK_DEBUG) || defined(SK_DEVELOPER)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836 char* s = new char[size+1];
837 memcpy(s, buffer, size);
838 s[size] = 0;
839 SkDebugf("%s", s);
840 delete[] s;
commit-bot@chromium.org04386452014-03-06 19:23:51 +0000841 fBytesWritten += size;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000842#endif
843 return true;
844}
reed@google.come1575aa2013-03-18 21:08:46 +0000845
846///////////////////////////////////////////////////////////////////////////////
847///////////////////////////////////////////////////////////////////////////////
848
commit-bot@chromium.org9711e442013-04-24 20:03:00 +0000849
reedfde05112016-03-11 13:02:28 -0800850static sk_sp<SkData> mmap_filename(const char path[]) {
halcanaryd76be9c2015-11-20 13:47:49 -0800851 FILE* file = sk_fopen(path, kRead_SkFILE_Flag);
halcanary96fcdcc2015-08-27 07:41:13 -0700852 if (nullptr == file) {
853 return nullptr;
reed@google.come1575aa2013-03-18 21:08:46 +0000854 }
skia.committer@gmail.com8eaddb02013-03-19 07:15:10 +0000855
reedfde05112016-03-11 13:02:28 -0800856 auto data = SkData::MakeFromFILE(file);
commit-bot@chromium.org9711e442013-04-24 20:03:00 +0000857 sk_fclose(file);
858 return data;
reed@google.come1575aa2013-03-18 21:08:46 +0000859}
860
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000861SkStreamAsset* SkStream::NewFromFile(const char path[]) {
reedfde05112016-03-11 13:02:28 -0800862 auto data(mmap_filename(path));
863 if (data) {
864 return new SkMemoryStream(std::move(data));
reed@google.come1575aa2013-03-18 21:08:46 +0000865 }
skia.committer@gmail.com8eaddb02013-03-19 07:15:10 +0000866
reed@google.come1575aa2013-03-18 21:08:46 +0000867 // If we get here, then our attempt at using mmap failed, so try normal
868 // file access.
halcanary385fe4d2015-08-26 13:07:48 -0700869 SkFILEStream* stream = new SkFILEStream(path);
reed@google.come1575aa2013-03-18 21:08:46 +0000870 if (!stream->isValid()) {
halcanary385fe4d2015-08-26 13:07:48 -0700871 delete stream;
halcanary96fcdcc2015-08-27 07:41:13 -0700872 stream = nullptr;
reed@google.come1575aa2013-03-18 21:08:46 +0000873 }
874 return stream;
875}
halcanary67ec1f82014-06-27 11:36:20 -0700876
877// Declared in SkStreamPriv.h:
reedfde05112016-03-11 13:02:28 -0800878sk_sp<SkData> SkCopyStreamToData(SkStream* stream) {
halcanary96fcdcc2015-08-27 07:41:13 -0700879 SkASSERT(stream != nullptr);
halcanary67ec1f82014-06-27 11:36:20 -0700880
881 if (stream->hasLength()) {
reedfde05112016-03-11 13:02:28 -0800882 return SkData::MakeFromStream(stream, stream->getLength());
halcanary67ec1f82014-06-27 11:36:20 -0700883 }
884
885 SkDynamicMemoryWStream tempStream;
msarett55343122016-01-27 12:06:22 -0800886 const size_t bufferSize = 4096;
887 char buffer[bufferSize];
888 do {
889 size_t bytesRead = stream->read(buffer, bufferSize);
890 tempStream.write(buffer, bytesRead);
891 } while (!stream->isAtEnd());
reedfde05112016-03-11 13:02:28 -0800892 return sk_sp<SkData>(tempStream.copyToData());
halcanary67ec1f82014-06-27 11:36:20 -0700893}
halcanarye3224822014-07-14 09:12:12 -0700894
halcanary48305e82015-08-18 13:30:25 -0700895bool SkStreamCopy(SkWStream* out, SkStream* input) {
896 const char* base = static_cast<const char*>(input->getMemoryBase());
897 if (base && input->hasPosition() && input->hasLength()) {
898 // Shortcut that avoids the while loop.
899 size_t position = input->getPosition();
900 size_t length = input->getLength();
901 SkASSERT(length >= position);
902 return out->write(&base[position], length - position);
903 }
904 char scratch[4096];
905 size_t count;
906 while (true) {
907 count = input->read(scratch, sizeof(scratch));
908 if (0 == count) {
909 return true;
910 }
911 if (!out->write(scratch, count)) {
912 return false;
913 }
914 }
915}