blob: dfbd00384975d93a622c7eabeccfaf5d8b091bd0 [file] [log] [blame]
reed@google.com3a31ac12011-06-24 13:11:05 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@google.com3a31ac12011-06-24 13:11:05 +00006 */
7
reed@google.com3a31ac12011-06-24 13:11:05 +00008#include "SkData.h"
commit-bot@chromium.org97de3572014-05-29 20:13:22 +00009#include "SkLazyPtr.h"
10#include "SkOSFile.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
reed9594da12014-09-12 12:12:27 -070012#include "SkStream.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkWriteBuffer.h"
reed@google.com3a31ac12011-06-24 13:11:05 +000014
15SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
reed33a30502014-09-11 08:42:36 -070016 fPtr = const_cast<void*>(ptr);
reed@google.com3a31ac12011-06-24 13:11:05 +000017 fSize = size;
18 fReleaseProc = proc;
19 fReleaseProcContext = context;
20}
21
reed33a30502014-09-11 08:42:36 -070022// This constructor means we are inline with our fPtr's contents. Thus we set fPtr
23// to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc,
24// since we need to handle "delete" ourselves. See internal_displose().
25//
26SkData::SkData(size_t size) {
27 fPtr = (char*)(this + 1); // contents are immediately after this
28 fSize = size;
bsalomon07280312014-11-20 08:02:46 -080029 fReleaseProc = NULL;
reed33a30502014-09-11 08:42:36 -070030 fReleaseProcContext = NULL;
31}
32
reed@google.com3a31ac12011-06-24 13:11:05 +000033SkData::~SkData() {
34 if (fReleaseProc) {
35 fReleaseProc(fPtr, fSize, fReleaseProcContext);
36 }
37}
38
reed@google.comdbc936d2012-06-28 15:40:09 +000039bool SkData::equals(const SkData* other) const {
40 if (NULL == other) {
41 return false;
42 }
43
44 return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
45}
46
reed@google.com3a31ac12011-06-24 13:11:05 +000047size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
48 size_t available = fSize;
49 if (offset >= available || 0 == length) {
50 return 0;
51 }
52 available -= offset;
53 if (length > available) {
54 length = available;
55 }
56 SkASSERT(length > 0);
57
58 memcpy(buffer, this->bytes() + offset, length);
59 return length;
60}
61
reed33a30502014-09-11 08:42:36 -070062SkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
63 if (0 == length) {
64 return SkData::NewEmpty();
65 }
66 char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length);
67 SkData* data = new (storage) SkData(length);
68 if (srcOrNull) {
69 memcpy(data->writable_data(), srcOrNull, length);
70 }
71 return data;
72}
73
reed@google.com3a31ac12011-06-24 13:11:05 +000074///////////////////////////////////////////////////////////////////////////////
75
mtklein148ec592014-10-13 13:17:56 -070076// As a template argument these must have external linkage.
77SkData* sk_new_empty_data() { return new SkData(NULL, 0, NULL, NULL); }
78namespace { void sk_unref_data(SkData* ptr) { return SkSafeUnref(ptr); } }
reed33a30502014-09-11 08:42:36 -070079
mtklein148ec592014-10-13 13:17:56 -070080SK_DECLARE_STATIC_LAZY_PTR(SkData, empty, sk_new_empty_data, sk_unref_data);
commit-bot@chromium.org1f81fd62013-10-23 14:44:08 +000081
reed@google.com3a31ac12011-06-24 13:11:05 +000082SkData* SkData::NewEmpty() {
commit-bot@chromium.org97de3572014-05-29 20:13:22 +000083 return SkRef(empty.get());
reed@google.com3a31ac12011-06-24 13:11:05 +000084}
85
86// assumes fPtr was allocated via sk_malloc
reed@google.com8a85d0c2011-06-24 19:12:12 +000087static void sk_free_releaseproc(const void* ptr, size_t, void*) {
reed@google.com3a31ac12011-06-24 13:11:05 +000088 sk_free((void*)ptr);
89}
90
reed@google.com8a85d0c2011-06-24 19:12:12 +000091SkData* SkData::NewFromMalloc(const void* data, size_t length) {
92 return new SkData(data, length, sk_free_releaseproc, NULL);
93}
94
reed33a30502014-09-11 08:42:36 -070095SkData* SkData::NewWithCopy(const void* src, size_t length) {
96 SkASSERT(src);
97 return PrivateNewWithCopy(src, length);
98}
reed@google.com3a31ac12011-06-24 13:11:05 +000099
reed33a30502014-09-11 08:42:36 -0700100SkData* SkData::NewUninitialized(size_t length) {
101 return PrivateNewWithCopy(NULL, length);
reed@google.com3a31ac12011-06-24 13:11:05 +0000102}
103
104SkData* SkData::NewWithProc(const void* data, size_t length,
reed@google.com8a85d0c2011-06-24 19:12:12 +0000105 ReleaseProc proc, void* context) {
reed@google.com3a31ac12011-06-24 13:11:05 +0000106 return new SkData(data, length, proc, context);
107}
108
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000109// assumes fPtr was allocated with sk_fmmap
110static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
111 sk_fmunmap(addr, length);
112}
113
114SkData* SkData::NewFromFILE(SkFILE* f) {
115 size_t size;
116 void* addr = sk_fmmap(f, &size);
117 if (NULL == addr) {
118 return NULL;
119 }
120
121 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
122}
123
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000124SkData* SkData::NewFromFileName(const char path[]) {
125 SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
126 if (NULL == f) {
127 return NULL;
128 }
129 SkData* data = NewFromFILE(f);
130 sk_fclose(f);
131 return data;
132}
133
bungeman@google.com11c9a552013-06-03 17:10:35 +0000134SkData* SkData::NewFromFD(int fd) {
135 size_t size;
136 void* addr = sk_fdmmap(fd, &size);
137 if (NULL == addr) {
138 return NULL;
139 }
140
141 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
142}
143
reed@google.com3a31ac12011-06-24 13:11:05 +0000144// assumes context is a SkData
145static void sk_dataref_releaseproc(const void*, size_t, void* context) {
146 SkData* src = reinterpret_cast<SkData*>(context);
147 src->unref();
148}
149
150SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
151 /*
152 We could, if we wanted/need to, just make a deep copy of src's data,
153 rather than referencing it. This would duplicate the storage (of the
154 subset amount) but would possibly allow src to go out of scope sooner.
155 */
156
157 size_t available = src->size();
158 if (offset >= available || 0 == length) {
159 return SkData::NewEmpty();
160 }
161 available -= offset;
162 if (length > available) {
163 length = available;
164 }
165 SkASSERT(length > 0);
166
167 src->ref(); // this will be balanced in sk_dataref_releaseproc
168 return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
169 const_cast<SkData*>(src));
170}
171
reed@google.comdbc936d2012-06-28 15:40:09 +0000172SkData* SkData::NewWithCString(const char cstr[]) {
reed@google.comfd59d122012-07-02 20:28:31 +0000173 size_t size;
174 if (NULL == cstr) {
175 cstr = "";
176 size = 1;
reed@google.comdbc936d2012-06-28 15:40:09 +0000177 } else {
reed@google.comfd59d122012-07-02 20:28:31 +0000178 size = strlen(cstr) + 1;
reed@google.comdbc936d2012-06-28 15:40:09 +0000179 }
reed@google.comfd59d122012-07-02 20:28:31 +0000180 return NewWithCopy(cstr, size);
reed@google.comdbc936d2012-06-28 15:40:09 +0000181}
reed9594da12014-09-12 12:12:27 -0700182
183///////////////////////////////////////////////////////////////////////////////
184
185SkData* SkData::NewFromStream(SkStream* stream, size_t size) {
186 SkAutoDataUnref data(SkData::NewUninitialized(size));
187 if (stream->read(data->writable_data(), size) != size) {
188 return NULL;
189 }
190 return data.detach();
191}
192