blob: ff14a8b26f5606bbd576043e6729349bdbdcaf43 [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{
90 SkString tmp;
91 tmp.appendS32(dec);
92 return this->write(tmp.c_str(), tmp.size());
93}
94
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +000095bool SkWStream::writeBigDecAsText(int64_t dec, int minDigits)
96{
97 SkString tmp;
98 tmp.appendS64(dec, minDigits);
99 return this->write(tmp.c_str(), tmp.size());
100}
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{
111 SkString tmp;
112 tmp.appendScalar(value);
113 return this->write(tmp.c_str(), tmp.size());
114}
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) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : NULL;
185}
186
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000187SkFILEStream::SkFILEStream(FILE* file, Ownership ownership)
188 : fFILE((SkFILE*)file)
189 , 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);
202 fFILE = NULL;
203 }
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);
227 fFILE = NULL;
228 }
229 return false;
230}
231
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000232SkStreamAsset* SkFILEStream::duplicate() const {
233 if (NULL == fFILE) {
234 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()) {
242 SkAutoTUnref<SkFILEStream> that(new SkFILEStream(fName.c_str()));
243 if (sk_fidentical(that->fFILE, this->fFILE)) {
244 return that.detach();
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
248 fData.reset(SkData::NewFromFILE(fFILE));
249 if (NULL == fData.get()) {
250 return NULL;
251 }
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 {
268 SkAutoTUnref<SkStreamAsset> that(this->duplicate());
269 that->seek(this->getPosition());
270 return that.detach();
271}
272
273size_t SkFILEStream::getLength() const {
274 return sk_fgetsize(fFILE);
275}
276
277const void* SkFILEStream::getMemoryBase() {
278 if (NULL == fData.get()) {
279 return NULL;
280 }
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
reed@google.com67d0cff2011-06-24 20:06:36 +0000286static SkData* newFromParams(const void* src, size_t size, bool copyData) {
287 if (copyData) {
288 return SkData::NewWithCopy(src, size);
289 } else {
reed33a30502014-09-11 08:42:36 -0700290 return SkData::NewWithoutCopy(src, size);
reed@google.com67d0cff2011-06-24 20:06:36 +0000291 }
292}
293
reed@google.com8a85d0c2011-06-24 19:12:12 +0000294SkMemoryStream::SkMemoryStream() {
295 fData = SkData::NewEmpty();
296 fOffset = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297}
298
299SkMemoryStream::SkMemoryStream(size_t size) {
reed33a30502014-09-11 08:42:36 -0700300 fData = SkData::NewUninitialized(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
scroggo@google.come4904202013-01-09 22:02:58 +0000309SkMemoryStream::SkMemoryStream(SkData* data) {
310 if (NULL == data) {
311 fData = SkData::NewEmpty();
312 } else {
313 fData = data;
314 fData->ref();
315 }
robertphillips@google.comc62b7262013-01-14 18:10:08 +0000316 fOffset = 0;
humper@google.comf515ffc2013-01-07 15:48:19 +0000317}
318
reed@google.com8a85d0c2011-06-24 19:12:12 +0000319SkMemoryStream::~SkMemoryStream() {
320 fData->unref();
321}
322
323void SkMemoryStream::setMemoryOwned(const void* src, size_t size) {
324 fData->unref();
325 fData = SkData::NewFromMalloc(src, size);
326 fOffset = 0;
327}
328
329void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) {
330 fData->unref();
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 {
336 fData->ref();
337 return fData;
338}
339
340SkData* SkMemoryStream::setData(SkData* data) {
scroggo@google.come4904202013-01-09 22:02:58 +0000341 fData->unref();
342 if (NULL == data) {
343 fData = SkData::NewEmpty();
344 } else {
345 fData = data;
346 fData->ref();
347 }
bungeman@google.com10822c62013-11-18 21:29:36 +0000348 fOffset = 0;
reed@google.com8a85d0c2011-06-24 19:12:12 +0000349 return data;
350}
351
352void SkMemoryStream::skipToAlign4() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 // cast to remove unary-minus warning
354 fOffset += -(int)fOffset & 0x03;
355}
356
reed@google.com8a85d0c2011-06-24 19:12:12 +0000357size_t SkMemoryStream::read(void* buffer, size_t size) {
358 size_t dataSize = fData->size();
359
reed@google.com8a85d0c2011-06-24 19:12:12 +0000360 if (size > dataSize - fOffset) {
361 size = dataSize - fOffset;
362 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 if (buffer) {
reed@google.com8a85d0c2011-06-24 19:12:12 +0000364 memcpy(buffer, fData->bytes() + fOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365 }
366 fOffset += size;
367 return size;
368}
369
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000370bool SkMemoryStream::isAtEnd() const {
371 return fOffset == fData->size();
372}
373
374bool SkMemoryStream::rewind() {
375 fOffset = 0;
376 return true;
377}
378
379SkMemoryStream* SkMemoryStream::duplicate() const {
380 return SkNEW_ARGS(SkMemoryStream, (fData));
381}
382
383size_t SkMemoryStream::getPosition() const {
384 return fOffset;
385}
386
387bool SkMemoryStream::seek(size_t position) {
388 fOffset = position > fData->size()
389 ? fData->size()
390 : position;
391 return true;
392}
393
394bool SkMemoryStream::move(long offset) {
395 return this->seek(fOffset + offset);
396}
397
398SkMemoryStream* SkMemoryStream::fork() const {
399 SkAutoTUnref<SkMemoryStream> that(this->duplicate());
400 that->seek(fOffset);
401 return that.detach();
402}
403
404size_t SkMemoryStream::getLength() const {
405 return fData->size();
406}
407
reed@google.com8a85d0c2011-06-24 19:12:12 +0000408const void* SkMemoryStream::getMemoryBase() {
409 return fData->data();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410}
411
reed@google.com8a85d0c2011-06-24 19:12:12 +0000412const void* SkMemoryStream::getAtPos() {
413 return fData->bytes() + fOffset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414}
415
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416/////////////////////////////////////////////////////////////////////////////////////////////////////////
417/////////////////////////////////////////////////////////////////////////////////////////////////////////
418
419SkFILEWStream::SkFILEWStream(const char path[])
420{
421 fFILE = sk_fopen(path, kWrite_SkFILE_Flag);
422}
423
424SkFILEWStream::~SkFILEWStream()
425{
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000426 if (fFILE) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 sk_fclose(fFILE);
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000428 }
429}
430
431size_t SkFILEWStream::bytesWritten() const {
432 return sk_ftell(fFILE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433}
434
435bool SkFILEWStream::write(const void* buffer, size_t size)
436{
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000437 if (fFILE == NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 return false;
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000439 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440
441 if (sk_fwrite(buffer, size, fFILE) != size)
442 {
443 SkDEBUGCODE(SkDebugf("SkFILEWStream failed writing %d bytes\n", size);)
444 sk_fclose(fFILE);
445 fFILE = NULL;
446 return false;
447 }
448 return true;
449}
450
451void SkFILEWStream::flush()
452{
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000453 if (fFILE) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454 sk_fflush(fFILE);
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000455 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456}
457
458////////////////////////////////////////////////////////////////////////
459
460SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size)
461 : fBuffer((char*)buffer), fMaxLength(size), fBytesWritten(0)
462{
463}
464
commit-bot@chromium.orgf1177812014-04-23 19:19:44 +0000465bool SkMemoryWStream::write(const void* buffer, size_t size) {
466 size = SkTMin(size, fMaxLength - fBytesWritten);
467 if (size > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000468 memcpy(fBuffer + fBytesWritten, buffer, size);
469 fBytesWritten += size;
470 return true;
471 }
472 return false;
473}
474
475////////////////////////////////////////////////////////////////////////
476
477#define SkDynamicMemoryWStream_MinBlockSize 256
478
479struct SkDynamicMemoryWStream::Block {
480 Block* fNext;
481 char* fCurr;
482 char* fStop;
483
484 const char* start() const { return (const char*)(this + 1); }
485 char* start() { return (char*)(this + 1); }
486 size_t avail() const { return fStop - fCurr; }
487 size_t written() const { return fCurr - this->start(); }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000488
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489 void init(size_t size)
490 {
491 fNext = NULL;
492 fCurr = this->start();
493 fStop = this->start() + size;
494 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000495
reed@android.com8a1c16f2008-12-17 15:59:43 +0000496 const void* append(const void* data, size_t size)
497 {
498 SkASSERT((size_t)(fStop - fCurr) >= size);
499 memcpy(fCurr, data, size);
500 fCurr += size;
501 return (const void*)((const char*)data + size);
502 }
503};
504
reed@google.com8a85d0c2011-06-24 19:12:12 +0000505SkDynamicMemoryWStream::SkDynamicMemoryWStream()
506 : fHead(NULL), fTail(NULL), fBytesWritten(0), fCopy(NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000507{
508}
509
510SkDynamicMemoryWStream::~SkDynamicMemoryWStream()
511{
512 reset();
513}
514
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515void SkDynamicMemoryWStream::reset()
516{
reed@google.com8a85d0c2011-06-24 19:12:12 +0000517 this->invalidateCopy();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000518
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519 Block* block = fHead;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000520
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 while (block != NULL) {
522 Block* next = block->fNext;
523 sk_free(block);
524 block = next;
525 }
526 fHead = fTail = NULL;
527 fBytesWritten = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528}
529
530bool SkDynamicMemoryWStream::write(const void* buffer, size_t count)
531{
532 if (count > 0) {
reed@google.com8a85d0c2011-06-24 19:12:12 +0000533 this->invalidateCopy();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535 fBytesWritten += count;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000536
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537 size_t size;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000538
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539 if (fTail != NULL && fTail->avail() > 0) {
commit-bot@chromium.orgf1177812014-04-23 19:19:44 +0000540 size = SkTMin(fTail->avail(), count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000541 buffer = fTail->append(buffer, size);
542 SkASSERT(count >= size);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000543 count -= size;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544 if (count == 0)
545 return true;
546 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000547
commit-bot@chromium.orgf1177812014-04-23 19:19:44 +0000548 size = SkTMax<size_t>(count, SkDynamicMemoryWStream_MinBlockSize);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
550 block->init(size);
551 block->append(buffer, count);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000552
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 if (fTail != NULL)
554 fTail->fNext = block;
555 else
556 fHead = fTail = block;
557 fTail = block;
558 }
559 return true;
560}
561
562bool SkDynamicMemoryWStream::write(const void* buffer, size_t offset, size_t count)
563{
reed@google.com8a85d0c2011-06-24 19:12:12 +0000564 if (offset + count > fBytesWritten) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000565 return false; // test does not partially modify
reed@google.com8a85d0c2011-06-24 19:12:12 +0000566 }
567
568 this->invalidateCopy();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000569
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570 Block* block = fHead;
571 while (block != NULL) {
572 size_t size = block->written();
573 if (offset < size) {
574 size_t part = offset + count > size ? size - offset : count;
575 memcpy(block->start() + offset, buffer, part);
576 if (count <= part)
577 return true;
578 count -= part;
579 buffer = (const void*) ((char* ) buffer + part);
580 }
581 offset = offset > size ? offset - size : 0;
582 block = block->fNext;
583 }
584 return false;
585}
586
587bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count)
588{
589 if (offset + count > fBytesWritten)
590 return false; // test does not partially modify
591 Block* block = fHead;
592 while (block != NULL) {
593 size_t size = block->written();
594 if (offset < size) {
595 size_t part = offset + count > size ? size - offset : count;
596 memcpy(buffer, block->start() + offset, part);
597 if (count <= part)
598 return true;
599 count -= part;
600 buffer = (void*) ((char* ) buffer + part);
601 }
602 offset = offset > size ? offset - size : 0;
603 block = block->fNext;
604 }
605 return false;
606}
607
608void SkDynamicMemoryWStream::copyTo(void* dst) const
609{
reed@google.com8a85d0c2011-06-24 19:12:12 +0000610 if (fCopy) {
611 memcpy(dst, fCopy->data(), fBytesWritten);
612 } else {
613 Block* block = fHead;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000614
reed@google.com8a85d0c2011-06-24 19:12:12 +0000615 while (block != NULL) {
616 size_t size = block->written();
617 memcpy(dst, block->start(), size);
618 dst = (void*)((char*)dst + size);
619 block = block->fNext;
620 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000621 }
622}
623
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624void SkDynamicMemoryWStream::padToAlign4()
625{
626 // cast to remove unary-minus warning
627 int padBytes = -(int)fBytesWritten & 0x03;
628 if (padBytes == 0)
629 return;
630 int zero = 0;
631 write(&zero, padBytes);
632}
633
reed@google.com8d0b5772011-06-24 13:07:31 +0000634SkData* SkDynamicMemoryWStream::copyToData() const {
reed@google.com8a85d0c2011-06-24 19:12:12 +0000635 if (NULL == fCopy) {
reed33a30502014-09-11 08:42:36 -0700636 SkData* data = SkData::NewUninitialized(fBytesWritten);
637 // be sure to call copyTo() before we assign to fCopy
638 this->copyTo(data->writable_data());
639 fCopy = data;
reed@google.com8a85d0c2011-06-24 19:12:12 +0000640 }
reed33a30502014-09-11 08:42:36 -0700641 return SkRef(fCopy);
reed@google.com70442a62011-06-23 21:48:04 +0000642}
643
reed@google.com8a85d0c2011-06-24 19:12:12 +0000644void SkDynamicMemoryWStream::invalidateCopy() {
645 if (fCopy) {
646 fCopy->unref();
647 fCopy = NULL;
648 }
649}
650
bungeman@google.com88682b72013-07-19 13:55:41 +0000651class SkBlockMemoryRefCnt : public SkRefCnt {
652public:
653 explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { }
654
655 virtual ~SkBlockMemoryRefCnt() {
656 SkDynamicMemoryWStream::Block* block = fHead;
657 while (block != NULL) {
658 SkDynamicMemoryWStream::Block* next = block->fNext;
659 sk_free(block);
660 block = next;
661 }
662 }
663
664 SkDynamicMemoryWStream::Block* const fHead;
665};
666
667class SkBlockMemoryStream : public SkStreamAsset {
668public:
669 SkBlockMemoryStream(SkDynamicMemoryWStream::Block* head, size_t size)
670 : fBlockMemory(SkNEW_ARGS(SkBlockMemoryRefCnt, (head))), fCurrent(head)
671 , fSize(size) , fOffset(0), fCurrentOffset(0) { }
672
673 SkBlockMemoryStream(SkBlockMemoryRefCnt* headRef, size_t size)
674 : fBlockMemory(SkRef(headRef)), fCurrent(fBlockMemory->fHead)
675 , fSize(size) , fOffset(0), fCurrentOffset(0) { }
676
677 virtual size_t read(void* buffer, size_t rawCount) SK_OVERRIDE {
678 size_t count = rawCount;
679 if (fOffset + count > fSize) {
680 count = fSize - fOffset;
681 }
682 size_t bytesLeftToRead = count;
683 while (fCurrent != NULL) {
684 size_t bytesLeftInCurrent = fCurrent->written() - fCurrentOffset;
bungeman@google.com8d79f962014-03-05 16:26:14 +0000685 size_t bytesFromCurrent = SkTMin(bytesLeftToRead, bytesLeftInCurrent);
bungeman@google.com88682b72013-07-19 13:55:41 +0000686 if (buffer) {
687 memcpy(buffer, fCurrent->start() + fCurrentOffset, bytesFromCurrent);
bungeman@google.com8d79f962014-03-05 16:26:14 +0000688 buffer = SkTAddOffset<void>(buffer, bytesFromCurrent);
bungeman@google.com88682b72013-07-19 13:55:41 +0000689 }
690 if (bytesLeftToRead <= bytesFromCurrent) {
691 fCurrentOffset += bytesFromCurrent;
692 fOffset += count;
693 return count;
694 }
695 bytesLeftToRead -= bytesFromCurrent;
bungeman@google.com88682b72013-07-19 13:55:41 +0000696 fCurrent = fCurrent->fNext;
697 fCurrentOffset = 0;
698 }
699 SkASSERT(false);
700 return 0;
701 }
702
703 virtual bool isAtEnd() const SK_OVERRIDE {
704 return fOffset == fSize;
705 }
706
707 virtual bool rewind() SK_OVERRIDE {
708 fCurrent = fBlockMemory->fHead;
709 fOffset = 0;
710 fCurrentOffset = 0;
711 return true;
712 }
713
714 virtual SkBlockMemoryStream* duplicate() const SK_OVERRIDE {
715 return SkNEW_ARGS(SkBlockMemoryStream, (fBlockMemory.get(), fSize));
716 }
717
718 virtual size_t getPosition() const SK_OVERRIDE {
719 return fOffset;
720 }
721
722 virtual bool seek(size_t position) SK_OVERRIDE {
723 // If possible, skip forward.
724 if (position >= fOffset) {
725 size_t skipAmount = position - fOffset;
726 return this->skip(skipAmount) == skipAmount;
727 }
728 // If possible, move backward within the current block.
729 size_t moveBackAmount = fOffset - position;
730 if (moveBackAmount <= fCurrentOffset) {
731 fCurrentOffset -= moveBackAmount;
732 fOffset -= moveBackAmount;
733 return true;
734 }
735 // Otherwise rewind and move forward.
736 return this->rewind() && this->skip(position) == position;
737 }
738
739 virtual bool move(long offset) SK_OVERRIDE {
740 return seek(fOffset + offset);
741 }
742
743 virtual SkBlockMemoryStream* fork() const SK_OVERRIDE {
744 SkAutoTUnref<SkBlockMemoryStream> that(this->duplicate());
745 that->fCurrent = this->fCurrent;
746 that->fOffset = this->fOffset;
747 that->fCurrentOffset = this->fCurrentOffset;
748 return that.detach();
749 }
750
751 virtual size_t getLength() const SK_OVERRIDE {
752 return fSize;
753 }
754
755 virtual const void* getMemoryBase() SK_OVERRIDE {
756 if (NULL == fBlockMemory->fHead->fNext) {
757 return fBlockMemory->fHead->start();
758 }
759 return NULL;
760 }
761
762private:
763 SkAutoTUnref<SkBlockMemoryRefCnt> const fBlockMemory;
764 SkDynamicMemoryWStream::Block const * fCurrent;
765 size_t const fSize;
766 size_t fOffset;
767 size_t fCurrentOffset;
768};
769
bungeman@google.comc29f3d82013-07-19 22:32:11 +0000770SkStreamAsset* SkDynamicMemoryWStream::detachAsStream() {
bungeman@google.com88682b72013-07-19 13:55:41 +0000771 if (fCopy) {
772 SkMemoryStream* stream = SkNEW_ARGS(SkMemoryStream, (fCopy));
773 this->reset();
774 return stream;
775 }
776 SkBlockMemoryStream* stream = SkNEW_ARGS(SkBlockMemoryStream, (fHead, fBytesWritten));
777 fHead = 0;
778 this->reset();
779 return stream;
780}
781
reed@google.com8a85d0c2011-06-24 19:12:12 +0000782///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783
784void SkDebugWStream::newline()
785{
humper@google.com7af56be2013-01-14 18:49:19 +0000786#if defined(SK_DEBUG) || defined(SK_DEVELOPER)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787 SkDebugf("\n");
commit-bot@chromium.org490fb6b2014-03-06 17:16:26 +0000788 fBytesWritten++;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000789#endif
790}
791
792bool SkDebugWStream::write(const void* buffer, size_t size)
793{
humper@google.com7af56be2013-01-14 18:49:19 +0000794#if defined(SK_DEBUG) || defined(SK_DEVELOPER)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795 char* s = new char[size+1];
796 memcpy(s, buffer, size);
797 s[size] = 0;
798 SkDebugf("%s", s);
799 delete[] s;
commit-bot@chromium.org04386452014-03-06 19:23:51 +0000800 fBytesWritten += size;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801#endif
802 return true;
803}
reed@google.come1575aa2013-03-18 21:08:46 +0000804
805///////////////////////////////////////////////////////////////////////////////
806///////////////////////////////////////////////////////////////////////////////
807
commit-bot@chromium.org9711e442013-04-24 20:03:00 +0000808
809static SkData* mmap_filename(const char path[]) {
810 SkFILE* file = sk_fopen(path, kRead_SkFILE_Flag);
811 if (NULL == file) {
812 return NULL;
reed@google.come1575aa2013-03-18 21:08:46 +0000813 }
skia.committer@gmail.com8eaddb02013-03-19 07:15:10 +0000814
commit-bot@chromium.org9711e442013-04-24 20:03:00 +0000815 SkData* data = SkData::NewFromFILE(file);
816 sk_fclose(file);
817 return data;
reed@google.come1575aa2013-03-18 21:08:46 +0000818}
819
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000820SkStreamAsset* SkStream::NewFromFile(const char path[]) {
commit-bot@chromium.org9711e442013-04-24 20:03:00 +0000821 SkAutoTUnref<SkData> data(mmap_filename(path));
822 if (data.get()) {
823 return SkNEW_ARGS(SkMemoryStream, (data.get()));
reed@google.come1575aa2013-03-18 21:08:46 +0000824 }
skia.committer@gmail.com8eaddb02013-03-19 07:15:10 +0000825
reed@google.come1575aa2013-03-18 21:08:46 +0000826 // If we get here, then our attempt at using mmap failed, so try normal
827 // file access.
828 SkFILEStream* stream = SkNEW_ARGS(SkFILEStream, (path));
829 if (!stream->isValid()) {
830 stream->unref();
831 stream = NULL;
832 }
833 return stream;
834}
halcanary67ec1f82014-06-27 11:36:20 -0700835
836// Declared in SkStreamPriv.h:
837size_t SkCopyStreamToStorage(SkAutoMalloc* storage, SkStream* stream) {
838 SkASSERT(storage != NULL);
839 SkASSERT(stream != NULL);
840
841 if (stream->hasLength()) {
842 const size_t length = stream->getLength();
843 void* dst = storage->reset(length);
844 if (stream->read(dst, length) != length) {
845 return 0;
846 }
847 return length;
848 }
849
850 SkDynamicMemoryWStream tempStream;
851 // Arbitrary buffer size.
852 const size_t bufferSize = 256 * 1024; // 256KB
853 char buffer[bufferSize];
854 SkDEBUGCODE(size_t debugLength = 0;)
855 do {
856 size_t bytesRead = stream->read(buffer, bufferSize);
857 tempStream.write(buffer, bytesRead);
858 SkDEBUGCODE(debugLength += bytesRead);
859 SkASSERT(tempStream.bytesWritten() == debugLength);
860 } while (!stream->isAtEnd());
861 const size_t length = tempStream.bytesWritten();
862 void* dst = storage->reset(length);
863 tempStream.copyTo(dst);
864 return length;
865}
866
867// Declared in SkStreamPriv.h:
868SkData* SkCopyStreamToData(SkStream* stream) {
869 SkASSERT(stream != NULL);
870
871 if (stream->hasLength()) {
reed9594da12014-09-12 12:12:27 -0700872 return SkData::NewFromStream(stream, stream->getLength());
halcanary67ec1f82014-06-27 11:36:20 -0700873 }
874
875 SkDynamicMemoryWStream tempStream;
876 const size_t bufferSize = 4096;
877 char buffer[bufferSize];
878 do {
879 size_t bytesRead = stream->read(buffer, bufferSize);
880 tempStream.write(buffer, bytesRead);
881 } while (!stream->isAtEnd());
882 return tempStream.copyToData();
883}
halcanarye3224822014-07-14 09:12:12 -0700884
885SkStreamRewindable* SkStreamRewindableFromSkStream(SkStream* stream) {
886 if (!stream) {
887 return NULL;
888 }
889 SkAutoTUnref<SkStreamRewindable> dupStream(stream->duplicate());
890 if (dupStream) {
891 return dupStream.detach();
892 }
893 stream->rewind();
894 if (stream->hasLength()) {
895 size_t length = stream->getLength();
896 if (stream->hasPosition()) { // If stream has length, but can't rewind.
897 length -= stream->getPosition();
898 }
reed9594da12014-09-12 12:12:27 -0700899 SkAutoTUnref<SkData> data(SkData::NewFromStream(stream, length));
halcanarye3224822014-07-14 09:12:12 -0700900 return SkNEW_ARGS(SkMemoryStream, (data.get()));
901 }
902 SkDynamicMemoryWStream tempStream;
903 const size_t bufferSize = 4096;
904 char buffer[bufferSize];
905 do {
906 size_t bytesRead = stream->read(buffer, bufferSize);
907 tempStream.write(buffer, bytesRead);
908 } while (!stream->isAtEnd());
909 return tempStream.detachAsStream(); // returns a SkBlockMemoryStream,
910 // cheaper than copying to SkData
911}