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 memcpy(buffer, this->bytes() + offset, length);
61 return length;
62 }
63
operator delete(void * p)64 void SkData::operator delete(void* p) {
65 ::operator delete(p);
66 }
67
PrivateNewWithCopy(const void * srcOrNull,size_t length)68 sk_sp<SkData> SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
69 if (0 == length) {
70 return SkData::MakeEmpty();
71 }
72
73 const size_t actualLength = length + sizeof(SkData);
74 SkASSERT_RELEASE(length < actualLength); // Check for overflow.
75
76 void* storage = ::operator new (actualLength);
77 sk_sp<SkData> data(new (storage) SkData(length));
78 if (srcOrNull) {
79 memcpy(data->writable_data(), srcOrNull, length);
80 }
81 return data;
82 }
83
NoopReleaseProc(const void *,void *)84 void SkData::NoopReleaseProc(const void*, void*) {}
85
86 ///////////////////////////////////////////////////////////////////////////////
87
MakeEmpty()88 sk_sp<SkData> SkData::MakeEmpty() {
89 static SkOnce once;
90 static SkData* empty;
91
92 once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); });
93 return sk_ref_sp(empty);
94 }
95
96 // assumes fPtr was allocated via sk_malloc
sk_free_releaseproc(const void * ptr,void *)97 static void sk_free_releaseproc(const void* ptr, void*) {
98 sk_free((void*)ptr);
99 }
100
MakeFromMalloc(const void * data,size_t length)101 sk_sp<SkData> SkData::MakeFromMalloc(const void* data, size_t length) {
102 return sk_sp<SkData>(new SkData(data, length, sk_free_releaseproc, nullptr));
103 }
104
MakeWithCopy(const void * src,size_t length)105 sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) {
106 SkASSERT(src);
107 return PrivateNewWithCopy(src, length);
108 }
109
MakeUninitialized(size_t length)110 sk_sp<SkData> SkData::MakeUninitialized(size_t length) {
111 return PrivateNewWithCopy(nullptr, length);
112 }
113
MakeWithProc(const void * ptr,size_t length,ReleaseProc proc,void * ctx)114 sk_sp<SkData> SkData::MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx) {
115 return sk_sp<SkData>(new SkData(ptr, length, proc, ctx));
116 }
117
118 // assumes fPtr was allocated with sk_fmmap
sk_mmap_releaseproc(const void * addr,void * ctx)119 static void sk_mmap_releaseproc(const void* addr, void* ctx) {
120 size_t length = reinterpret_cast<size_t>(ctx);
121 sk_fmunmap(addr, length);
122 }
123
MakeFromFILE(FILE * f)124 sk_sp<SkData> SkData::MakeFromFILE(FILE* f) {
125 size_t size;
126 void* addr = sk_fmmap(f, &size);
127 if (nullptr == addr) {
128 return nullptr;
129 }
130
131 return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
132 }
133
MakeFromFileName(const char path[])134 sk_sp<SkData> SkData::MakeFromFileName(const char path[]) {
135 FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr;
136 if (nullptr == f) {
137 return nullptr;
138 }
139 auto data = MakeFromFILE(f);
140 sk_fclose(f);
141 return data;
142 }
143
MakeFromFD(int fd)144 sk_sp<SkData> SkData::MakeFromFD(int fd) {
145 size_t size;
146 void* addr = sk_fdmmap(fd, &size);
147 if (nullptr == addr) {
148 return nullptr;
149 }
150 return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
151 }
152
153 // assumes context is a SkData
sk_dataref_releaseproc(const void *,void * context)154 static void sk_dataref_releaseproc(const void*, void* context) {
155 SkData* src = reinterpret_cast<SkData*>(context);
156 src->unref();
157 }
158
MakeSubset(const SkData * src,size_t offset,size_t length)159 sk_sp<SkData> SkData::MakeSubset(const SkData* src, size_t offset, size_t length) {
160 /*
161 We could, if we wanted/need to, just make a deep copy of src's data,
162 rather than referencing it. This would duplicate the storage (of the
163 subset amount) but would possibly allow src to go out of scope sooner.
164 */
165
166 size_t available = src->size();
167 if (offset >= available || 0 == length) {
168 return SkData::MakeEmpty();
169 }
170 available -= offset;
171 if (length > available) {
172 length = available;
173 }
174 SkASSERT(length > 0);
175
176 src->ref(); // this will be balanced in sk_dataref_releaseproc
177 return sk_sp<SkData>(new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
178 const_cast<SkData*>(src)));
179 }
180
MakeWithCString(const char cstr[])181 sk_sp<SkData> SkData::MakeWithCString(const char cstr[]) {
182 size_t size;
183 if (nullptr == cstr) {
184 cstr = "";
185 size = 1;
186 } else {
187 size = strlen(cstr) + 1;
188 }
189 return MakeWithCopy(cstr, size);
190 }
191
192 ///////////////////////////////////////////////////////////////////////////////
193
MakeFromStream(SkStream * stream,size_t size)194 sk_sp<SkData> SkData::MakeFromStream(SkStream* stream, size_t size) {
195 sk_sp<SkData> data(SkData::MakeUninitialized(size));
196 if (stream->read(data->writable_data(), size) != size) {
197 return nullptr;
198 }
199 return data;
200 }
201