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 | |
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 | */ |
26 | SkData::SkData(size_t size) |
27 | : fReleaseProc(nullptr) |
28 | , fReleaseProcContext(nullptr) |
29 | , fPtr((const char*)(this + 1)) |
30 | , fSize(size) |
31 | {} |
32 | |
33 | SkData::~SkData() { |
34 | if (fReleaseProc) { |
35 | fReleaseProc(fPtr, fReleaseProcContext); |
36 | } |
37 | } |
38 | |
39 | 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 | |
49 | 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 | |
64 | void SkData::operator delete(void* p) { |
65 | ::operator delete(p); |
66 | } |
67 | |
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 | |
84 | void SkData::DummyReleaseProc(const void*, void*) {} |
85 | |
86 | /////////////////////////////////////////////////////////////////////////////// |
87 | |
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 |
97 | static void sk_free_releaseproc(const void* ptr, void*) { |
98 | sk_free((void*)ptr); |
99 | } |
100 | |
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 | |
105 | sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) { |
106 | SkASSERT(src); |
107 | return PrivateNewWithCopy(src, length); |
108 | } |
109 | |
110 | sk_sp<SkData> SkData::MakeUninitialized(size_t length) { |
111 | return PrivateNewWithCopy(nullptr, length); |
112 | } |
113 | |
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 |
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 | |
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 | |
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 | |
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 |
154 | static void sk_dataref_releaseproc(const void*, void* context) { |
155 | SkData* src = reinterpret_cast<SkData*>(context); |
156 | src->unref(); |
157 | } |
158 | |
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 | |
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 | |
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 | |