xref: /third_party/skia/src/core/SkData.cpp (revision cb93a386)
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
16SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context)
17    : fReleaseProc(proc)
18    , fReleaseProcContext(context)
19    , fPtr(ptr)
20    , fSize(size)
21    , fNativeBuffer(nullptr)
22{}
23
24SkData::SkData(const void* ptr, size_t size, OH_NativeBuffer* nativeBuffer, ReleaseProc proc, void* context)
25    : fReleaseProc(proc)
26    , fReleaseProcContext(context)
27    , fPtr(ptr)
28    , fSize(size)
29    , fNativeBuffer(nativeBuffer)
30{}
31
32/** This constructor means we are inline with our fPtr's contents.
33 *  Thus we set fPtr to point right after this.
34 */
35SkData::SkData(size_t size)
36    : fReleaseProc(nullptr)
37    , fReleaseProcContext(nullptr)
38    , fPtr((const char*)(this + 1))
39    , fSize(size)
40    , fNativeBuffer(nullptr)
41{}
42
43SkData::~SkData() {
44    if (fReleaseProc) {
45        fReleaseProc(fPtr, fReleaseProcContext);
46    }
47}
48
49bool SkData::equals(const SkData* other) const {
50    if (this == other) {
51        return true;
52    }
53    if (nullptr == other) {
54        return false;
55    }
56    return fSize == other->fSize && !sk_careful_memcmp(fPtr, other->fPtr, fSize);
57}
58
59size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
60    size_t available = fSize;
61    if (offset >= available || 0 == length) {
62        return 0;
63    }
64    available -= offset;
65    if (length > available) {
66        length = available;
67    }
68    SkASSERT(length > 0);
69
70    memcpy(buffer, this->bytes() + offset, length);
71    return length;
72}
73
74void SkData::operator delete(void* p) {
75    ::operator delete(p);
76}
77
78sk_sp<SkData> SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
79    if (0 == length) {
80        return SkData::MakeEmpty();
81    }
82
83    const size_t actualLength = length + sizeof(SkData);
84    SkASSERT_RELEASE(length < actualLength);  // Check for overflow.
85
86    void* storage = ::operator new (actualLength);
87    sk_sp<SkData> data(new (storage) SkData(length));
88    if (srcOrNull) {
89        memcpy(data->writable_data(), srcOrNull, length);
90    }
91    return data;
92}
93
94void SkData::NoopReleaseProc(const void*, void*) {}
95
96///////////////////////////////////////////////////////////////////////////////
97
98sk_sp<SkData> SkData::MakeEmpty() {
99    static SkOnce once;
100    static SkData* empty;
101
102    once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); });
103    return sk_ref_sp(empty);
104}
105
106// assumes fPtr was allocated via sk_malloc
107static void sk_free_releaseproc(const void* ptr, void*) {
108    sk_free((void*)ptr);
109}
110
111sk_sp<SkData> SkData::MakeFromMalloc(const void* data, size_t length) {
112    return sk_sp<SkData>(new SkData(data, length, sk_free_releaseproc, nullptr));
113}
114
115sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) {
116    SkASSERT(src);
117    return PrivateNewWithCopy(src, length);
118}
119
120sk_sp<SkData> SkData::MakeUninitialized(size_t length) {
121    return PrivateNewWithCopy(nullptr, length);
122}
123
124sk_sp<SkData> SkData::MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx) {
125    return sk_sp<SkData>(new SkData(ptr, length, proc, ctx));
126}
127
128// assumes fPtr was allocated with sk_fmmap
129static void sk_mmap_releaseproc(const void* addr, void* ctx) {
130    size_t length = reinterpret_cast<size_t>(ctx);
131    sk_fmunmap(addr, length);
132}
133
134sk_sp<SkData> SkData::MakeFromFILE(FILE* f) {
135    size_t size;
136    void* addr = sk_fmmap(f, &size);
137    if (nullptr == addr) {
138        return nullptr;
139    }
140
141    return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
142}
143
144sk_sp<SkData> SkData::MakeFromFileName(const char path[]) {
145    FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr;
146    if (nullptr == f) {
147        return nullptr;
148    }
149    auto data = MakeFromFILE(f);
150    sk_fclose(f);
151    return data;
152}
153
154sk_sp<SkData> SkData::MakeFromFD(int fd) {
155    size_t size;
156    void* addr = sk_fdmmap(fd, &size);
157    if (nullptr == addr) {
158        return nullptr;
159    }
160    return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
161}
162
163sk_sp<SkData> SkData::MakeFromOHNativeBuffer(OH_NativeBuffer* nativeBuffer, size_t size) {
164    return sk_sp<SkData>(new SkData(nullptr, size, nativeBuffer, nullptr, nullptr));
165}
166
167// assumes context is a SkData
168static void sk_dataref_releaseproc(const void*, void* context) {
169    SkData* src = reinterpret_cast<SkData*>(context);
170    src->unref();
171}
172
173sk_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
195sk_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
208sk_sp<SkData> SkData::MakeFromStream(SkStream* stream, size_t size) {
209    sk_sp<SkData> data(SkData::MakeUninitialized(size));
210    if (stream->read(data->writable_data(), size) != size) {
211        return nullptr;
212    }
213    return data;
214}
215