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