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 {}
22
23 /** This constructor means we are inline with our fPtr's contents.
24 * Thus we set fPtr to point right after this.
25 */
SkData(size_t size)26 SkData::SkData(size_t size)
27 : fReleaseProc(nullptr)
28 , fReleaseProcContext(nullptr)
29 , fPtr((const char*)(this + 1))
30 , fSize(size)
31 {}
32
~SkData()33 SkData::~SkData() {
34 if (fReleaseProc) {
35 fReleaseProc(fPtr, fReleaseProcContext);
36 }
37 }
38
equals(const SkData * other) const39 bool SkData::equals(const SkData* other) const {
40 if (this == other) {
41 return true;
42 }
43 if (nullptr == other) {
44 return false;
45 }
46 return fSize == other->fSize && !sk_careful_memcmp(fPtr, other->fPtr, fSize);
47 }
48
copyRange(size_t offset,size_t length,void * buffer) const49 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
50 size_t available = fSize;
51 if (offset >= available || 0 == length) {
52 return 0;
53 }
54 available -= offset;
55 if (length > available) {
56 length = available;
57 }
58 SkASSERT(length > 0);
59
60 if (buffer) {
61 memcpy(buffer, this->bytes() + offset, length);
62 }
63 return length;
64 }
65
operator delete(void * p)66 void SkData::operator delete(void* p) {
67 ::operator delete(p);
68 }
69
PrivateNewWithCopy(const void * srcOrNull,size_t length)70 sk_sp<SkData> SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
71 if (0 == length) {
72 return SkData::MakeEmpty();
73 }
74
75 const size_t actualLength = length + sizeof(SkData);
76 SkASSERT_RELEASE(length < actualLength); // Check for overflow.
77
78 void* storage = ::operator new (actualLength);
79 sk_sp<SkData> data(new (storage) SkData(length));
80 if (srcOrNull) {
81 memcpy(data->writable_data(), srcOrNull, length);
82 }
83 return data;
84 }
85
NoopReleaseProc(const void *,void *)86 void SkData::NoopReleaseProc(const void*, void*) {}
87
88 ///////////////////////////////////////////////////////////////////////////////
89
MakeEmpty()90 sk_sp<SkData> SkData::MakeEmpty() {
91 static SkOnce once;
92 static SkData* empty;
93
94 once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); });
95 return sk_ref_sp(empty);
96 }
97
98 // assumes fPtr was allocated via sk_malloc
sk_free_releaseproc(const void * ptr,void *)99 static void sk_free_releaseproc(const void* ptr, void*) {
100 sk_free((void*)ptr);
101 }
102
MakeFromMalloc(const void * data,size_t length)103 sk_sp<SkData> SkData::MakeFromMalloc(const void* data, size_t length) {
104 return sk_sp<SkData>(new SkData(data, length, sk_free_releaseproc, nullptr));
105 }
106
MakeWithCopy(const void * src,size_t length)107 sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) {
108 SkASSERT(src);
109 return PrivateNewWithCopy(src, length);
110 }
111
MakeUninitialized(size_t length)112 sk_sp<SkData> SkData::MakeUninitialized(size_t length) {
113 return PrivateNewWithCopy(nullptr, length);
114 }
115
MakeZeroInitialized(size_t length)116 sk_sp<SkData> SkData::MakeZeroInitialized(size_t length) {
117 auto data = MakeUninitialized(length);
118 if (length != 0) {
119 memset(data->writable_data(), 0, data->size());
120 }
121 return data;
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
163 // assumes context is a SkData
sk_dataref_releaseproc(const void *,void * context)164 static void sk_dataref_releaseproc(const void*, void* context) {
165 SkData* src = reinterpret_cast<SkData*>(context);
166 src->unref();
167 }
168
MakeSubset(const SkData * src,size_t offset,size_t length)169 sk_sp<SkData> SkData::MakeSubset(const SkData* src, size_t offset, size_t length) {
170 /*
171 We could, if we wanted/need to, just make a deep copy of src's data,
172 rather than referencing it. This would duplicate the storage (of the
173 subset amount) but would possibly allow src to go out of scope sooner.
174 */
175
176 size_t available = src->size();
177 if (offset >= available || 0 == length) {
178 return SkData::MakeEmpty();
179 }
180 available -= offset;
181 if (length > available) {
182 length = available;
183 }
184 SkASSERT(length > 0);
185
186 src->ref(); // this will be balanced in sk_dataref_releaseproc
187 return sk_sp<SkData>(new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
188 const_cast<SkData*>(src)));
189 }
190
MakeWithCString(const char cstr[])191 sk_sp<SkData> SkData::MakeWithCString(const char cstr[]) {
192 size_t size;
193 if (nullptr == cstr) {
194 cstr = "";
195 size = 1;
196 } else {
197 size = strlen(cstr) + 1;
198 }
199 return MakeWithCopy(cstr, size);
200 }
201
202 ///////////////////////////////////////////////////////////////////////////////
203
MakeFromStream(SkStream * stream,size_t size)204 sk_sp<SkData> SkData::MakeFromStream(SkStream* stream, size_t size) {
205 sk_sp<SkData> data(SkData::MakeUninitialized(size));
206 if (stream->read(data->writable_data(), size) != size) {
207 return nullptr;
208 }
209 return data;
210 }
211