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