• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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     : 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  */
SkData(size_t size)26 SkData::SkData(size_t size)
27     : fReleaseProc(nullptr)
28     , fReleaseProcContext(nullptr)
29     , fPtr((const char*)(this + 1))
30     , fSize(size)
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 (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 
copyRange(size_t offset,size_t length,void * buffer) const49 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     if (buffer) {
61         memcpy(buffer, this->bytes() + offset, length);
62     }
63     return length;
64 }
65 
operator delete(void * p)66 void SkData::operator delete(void* p) {
67     ::operator delete(p);
68 }
69 
PrivateNewWithCopy(const void * srcOrNull,size_t length)70 sk_sp<SkData> SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
71     if (0 == length) {
72         return SkData::MakeEmpty();
73     }
74 
75     const size_t actualLength = length + sizeof(SkData);
76     SkASSERT_RELEASE(length < actualLength);  // Check for overflow.
77 
78     void* storage = ::operator new (actualLength);
79     sk_sp<SkData> data(new (storage) SkData(length));
80     if (srcOrNull) {
81         memcpy(data->writable_data(), srcOrNull, length);
82     }
83     return data;
84 }
85 
NoopReleaseProc(const void *,void *)86 void SkData::NoopReleaseProc(const void*, void*) {}
87 
88 ///////////////////////////////////////////////////////////////////////////////
89 
MakeEmpty()90 sk_sp<SkData> SkData::MakeEmpty() {
91     static SkOnce once;
92     static SkData* empty;
93 
94     once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); });
95     return sk_ref_sp(empty);
96 }
97 
98 // assumes fPtr was allocated via sk_malloc
sk_free_releaseproc(const void * ptr,void *)99 static void sk_free_releaseproc(const void* ptr, void*) {
100     sk_free((void*)ptr);
101 }
102 
MakeFromMalloc(const void * data,size_t length)103 sk_sp<SkData> SkData::MakeFromMalloc(const void* data, size_t length) {
104     return sk_sp<SkData>(new SkData(data, length, sk_free_releaseproc, nullptr));
105 }
106 
MakeWithCopy(const void * src,size_t length)107 sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) {
108     SkASSERT(src);
109     return PrivateNewWithCopy(src, length);
110 }
111 
MakeUninitialized(size_t length)112 sk_sp<SkData> SkData::MakeUninitialized(size_t length) {
113     return PrivateNewWithCopy(nullptr, length);
114 }
115 
MakeZeroInitialized(size_t length)116 sk_sp<SkData> SkData::MakeZeroInitialized(size_t length) {
117     auto data = MakeUninitialized(length);
118     if (length != 0) {
119         memset(data->writable_data(), 0, data->size());
120     }
121     return data;
122 }
123 
MakeWithProc(const void * ptr,size_t length,ReleaseProc proc,void * ctx)124 sk_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
sk_mmap_releaseproc(const void * addr,void * ctx)129 static 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 
MakeFromFILE(FILE * f)134 sk_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 
MakeFromFileName(const char path[])144 sk_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 
MakeFromFD(int fd)154 sk_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 
163 // assumes context is a SkData
sk_dataref_releaseproc(const void *,void * context)164 static void sk_dataref_releaseproc(const void*, void* context) {
165     SkData* src = reinterpret_cast<SkData*>(context);
166     src->unref();
167 }
168 
MakeSubset(const SkData * src,size_t offset,size_t length)169 sk_sp<SkData> SkData::MakeSubset(const SkData* src, size_t offset, size_t length) {
170     /*
171         We could, if we wanted/need to, just make a deep copy of src's data,
172         rather than referencing it. This would duplicate the storage (of the
173         subset amount) but would possibly allow src to go out of scope sooner.
174      */
175 
176     size_t available = src->size();
177     if (offset >= available || 0 == length) {
178         return SkData::MakeEmpty();
179     }
180     available -= offset;
181     if (length > available) {
182         length = available;
183     }
184     SkASSERT(length > 0);
185 
186     src->ref(); // this will be balanced in sk_dataref_releaseproc
187     return sk_sp<SkData>(new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
188                                     const_cast<SkData*>(src)));
189 }
190 
MakeWithCString(const char cstr[])191 sk_sp<SkData> SkData::MakeWithCString(const char cstr[]) {
192     size_t size;
193     if (nullptr == cstr) {
194         cstr = "";
195         size = 1;
196     } else {
197         size = strlen(cstr) + 1;
198     }
199     return MakeWithCopy(cstr, size);
200 }
201 
202 ///////////////////////////////////////////////////////////////////////////////
203 
MakeFromStream(SkStream * stream,size_t size)204 sk_sp<SkData> SkData::MakeFromStream(SkStream* stream, size_t size) {
205     sk_sp<SkData> data(SkData::MakeUninitialized(size));
206     if (stream->read(data->writable_data(), size) != size) {
207         return nullptr;
208     }
209     return data;
210 }
211