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