1 /*
2 * 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.
6 */
7
8 #include "include/core/SkData.h"
9
10 #include "include/core/SkStream.h"
11 #include "include/private/base/SkAssert.h"
12 #include "include/private/base/SkMalloc.h"
13 #include "include/private/base/SkOnce.h"
14 #include "src/core/SkOSFile.h"
15 #include "src/core/SkStreamPriv.h"
16
17 #include <cstring>
18 #include <new>
19
SkData(const void * ptr,size_t size,ReleaseProc proc,void * context)20 SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context)
21 : fReleaseProc(proc)
22 , fReleaseProcContext(context)
23 , fPtr(ptr)
24 , fSize(size)
25 , fNativeBuffer(nullptr)
26 {}
27
SkData(const void * ptr,size_t size,OH_NativeBuffer * nativeBuffer,ReleaseProc proc,void * context)28 SkData::SkData(const void* ptr, size_t size, OH_NativeBuffer* nativeBuffer, ReleaseProc proc, void* context)
29 : fReleaseProc(proc)
30 , fReleaseProcContext(context)
31 , fPtr(ptr)
32 , fSize(size)
33 , fNativeBuffer(nativeBuffer)
34 {}
35
36 /** This constructor means we are inline with our fPtr's contents.
37 * Thus we set fPtr to point right after this.
38 */
SkData(size_t size)39 SkData::SkData(size_t size)
40 : fReleaseProc(nullptr)
41 , fReleaseProcContext(nullptr)
42 , fPtr((const char*)(this + 1))
43 , fSize(size)
44 , fNativeBuffer(nullptr)
45 {}
46
~SkData()47 SkData::~SkData() {
48 if (fReleaseProc) {
49 fReleaseProc(fPtr, fReleaseProcContext);
50 }
51 }
52
equals(const SkData * other) const53 bool SkData::equals(const SkData* other) const {
54 if (this == other) {
55 return true;
56 }
57 if (nullptr == other) {
58 return false;
59 }
60 return fSize == other->fSize && !sk_careful_memcmp(fPtr, other->fPtr, fSize);
61 }
62
copyRange(size_t offset,size_t length,void * buffer) const63 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
64 size_t available = fSize;
65 if (offset >= available || 0 == length) {
66 return 0;
67 }
68 available -= offset;
69 if (length > available) {
70 length = available;
71 }
72 SkASSERT(length > 0);
73
74 if (buffer) {
75 memcpy(buffer, this->bytes() + offset, length);
76 }
77 return length;
78 }
79
operator delete(void * p)80 void SkData::operator delete(void* p) {
81 ::operator delete(p);
82 }
83
PrivateNewWithCopy(const void * srcOrNull,size_t length)84 sk_sp<SkData> SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
85 if (0 == length) {
86 return SkData::MakeEmpty();
87 }
88
89 const size_t actualLength = length + sizeof(SkData);
90 SkASSERT_RELEASE(length < actualLength); // Check for overflow.
91
92 void* storage = ::operator new (actualLength);
93 sk_sp<SkData> data(new (storage) SkData(length));
94 if (srcOrNull) {
95 memcpy(data->writable_data(), srcOrNull, length);
96 }
97 return data;
98 }
99
NoopReleaseProc(const void *,void *)100 void SkData::NoopReleaseProc(const void*, void*) {}
101
102 ///////////////////////////////////////////////////////////////////////////////
103
MakeEmpty()104 sk_sp<SkData> SkData::MakeEmpty() {
105 static SkOnce once;
106 static SkData* empty;
107
108 once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); });
109 return sk_ref_sp(empty);
110 }
111
112 // assumes fPtr was allocated via sk_malloc
sk_free_releaseproc(const void * ptr,void *)113 static void sk_free_releaseproc(const void* ptr, void*) {
114 sk_free(const_cast<void*>(ptr));
115 }
116
MakeFromMalloc(const void * data,size_t length)117 sk_sp<SkData> SkData::MakeFromMalloc(const void* data, size_t length) {
118 return sk_sp<SkData>(new SkData(data, length, sk_free_releaseproc, nullptr));
119 }
120
MakeWithCopy(const void * src,size_t length)121 sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) {
122 SkASSERT(src);
123 return PrivateNewWithCopy(src, length);
124 }
125
MakeUninitialized(size_t length)126 sk_sp<SkData> SkData::MakeUninitialized(size_t length) {
127 return PrivateNewWithCopy(nullptr, length);
128 }
129
MakeZeroInitialized(size_t length)130 sk_sp<SkData> SkData::MakeZeroInitialized(size_t length) {
131 auto data = MakeUninitialized(length);
132 if (length != 0) {
133 memset(data->writable_data(), 0, data->size());
134 }
135 return data;
136 }
137
MakeWithProc(const void * ptr,size_t length,ReleaseProc proc,void * ctx)138 sk_sp<SkData> SkData::MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx) {
139 return sk_sp<SkData>(new SkData(ptr, length, proc, ctx));
140 }
141
142 // assumes fPtr was allocated with sk_fmmap
sk_mmap_releaseproc(const void * addr,void * ctx)143 static void sk_mmap_releaseproc(const void* addr, void* ctx) {
144 size_t length = reinterpret_cast<size_t>(ctx);
145 sk_fmunmap(addr, length);
146 }
147
MakeFromFILE(FILE * f)148 sk_sp<SkData> SkData::MakeFromFILE(FILE* f) {
149 size_t size;
150 void* addr = sk_fmmap(f, &size);
151 if (nullptr == addr) {
152 return nullptr;
153 }
154
155 return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
156 }
157
MakeFromFileName(const char path[])158 sk_sp<SkData> SkData::MakeFromFileName(const char path[]) {
159 FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr;
160 if (nullptr == f) {
161 return nullptr;
162 }
163 auto data = MakeFromFILE(f);
164 sk_fclose(f);
165 return data;
166 }
167
MakeFromFD(int fd)168 sk_sp<SkData> SkData::MakeFromFD(int fd) {
169 size_t size;
170 void* addr = sk_fdmmap(fd, &size);
171 if (nullptr == addr) {
172 return nullptr;
173 }
174 return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
175 }
176
MakeFromOHNativeBuffer(OH_NativeBuffer * nativeBuffer,size_t size)177 sk_sp<SkData> SkData::MakeFromOHNativeBuffer(OH_NativeBuffer* nativeBuffer, size_t size) {
178 return sk_sp<SkData>(new SkData(nullptr, size, nativeBuffer, nullptr, nullptr));
179 }
180
181 // assumes context is a SkData
sk_dataref_releaseproc(const void *,void * context)182 static void sk_dataref_releaseproc(const void*, void* context) {
183 SkData* src = reinterpret_cast<SkData*>(context);
184 src->unref();
185 }
186
MakeSubset(const SkData * src,size_t offset,size_t length)187 sk_sp<SkData> SkData::MakeSubset(const SkData* src, size_t offset, size_t length) {
188 /*
189 We could, if we wanted/need to, just make a deep copy of src's data,
190 rather than referencing it. This would duplicate the storage (of the
191 subset amount) but would possibly allow src to go out of scope sooner.
192 */
193
194 size_t available = src->size();
195 if (offset >= available || 0 == length) {
196 return SkData::MakeEmpty();
197 }
198 available -= offset;
199 if (length > available) {
200 length = available;
201 }
202 SkASSERT(length > 0);
203
204 src->ref(); // this will be balanced in sk_dataref_releaseproc
205 return sk_sp<SkData>(new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
206 const_cast<SkData*>(src)));
207 }
208
MakeWithCString(const char cstr[])209 sk_sp<SkData> SkData::MakeWithCString(const char cstr[]) {
210 size_t size;
211 if (nullptr == cstr) {
212 cstr = "";
213 size = 1;
214 } else {
215 size = strlen(cstr) + 1;
216 }
217 return MakeWithCopy(cstr, size);
218 }
219
220 ///////////////////////////////////////////////////////////////////////////////
221
MakeFromStream(SkStream * stream,size_t size)222 sk_sp<SkData> SkData::MakeFromStream(SkStream* stream, size_t size) {
223 // reduce the chance of OOM by checking that the stream has enough bytes to read from before
224 // allocating that potentially large buffer.
225 if (StreamRemainingLengthIsBelow(stream, size)) {
226 return nullptr;
227 }
228 sk_sp<SkData> data(SkData::MakeUninitialized(size));
229 if (stream->read(data->writable_data(), size) != size) {
230 return nullptr;
231 }
232 return data;
233 }
234