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