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