• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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