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 "SkOncePtr.h"
11 #include "SkReadBuffer.h"
12 #include "SkStream.h"
13 #include "SkWriteBuffer.h"
14
SkData(const void * ptr,size_t size,ReleaseProc proc,void * context)15 SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
16 fPtr = const_cast<void*>(ptr);
17 fSize = size;
18 fReleaseProc = proc;
19 fReleaseProcContext = context;
20 }
21
22 // This constructor means we are inline with our fPtr's contents. Thus we set fPtr
23 // to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc,
24 // since we need to handle "delete" ourselves. See internal_displose().
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
PrivateNewWithCopy(const void * srcOrNull,size_t length)62 SkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
63 if (0 == length) {
64 return SkData::NewEmpty();
65 }
66
67 const size_t actualLength = length + sizeof(SkData);
68 if (actualLength < length) {
69 // we overflowed
70 sk_throw();
71 }
72
73 char* storage = (char*)sk_malloc_throw(actualLength);
74 SkData* data = new (storage) SkData(length);
75 if (srcOrNull) {
76 memcpy(data->writable_data(), srcOrNull, length);
77 }
78 return data;
79 }
80
81 ///////////////////////////////////////////////////////////////////////////////
82
83 SK_DECLARE_STATIC_ONCE_PTR(SkData, gEmpty);
NewEmpty()84 SkData* SkData::NewEmpty() {
85 return SkRef(gEmpty.get([]{return new SkData(nullptr, 0, nullptr, nullptr); }));
86 }
87
88 // assumes fPtr was allocated via sk_malloc
sk_free_releaseproc(const void * ptr,void *)89 static void sk_free_releaseproc(const void* ptr, void*) {
90 sk_free((void*)ptr);
91 }
92
NewFromMalloc(const void * data,size_t length)93 SkData* SkData::NewFromMalloc(const void* data, size_t length) {
94 return new SkData(data, length, sk_free_releaseproc, nullptr);
95 }
96
NewWithCopy(const void * src,size_t length)97 SkData* SkData::NewWithCopy(const void* src, size_t length) {
98 SkASSERT(src);
99 return PrivateNewWithCopy(src, length);
100 }
101
NewUninitialized(size_t length)102 SkData* SkData::NewUninitialized(size_t length) {
103 return PrivateNewWithCopy(nullptr, length);
104 }
105
NewWithProc(const void * ptr,size_t length,ReleaseProc proc,void * context)106 SkData* SkData::NewWithProc(const void* ptr, size_t length, ReleaseProc proc, void* context) {
107 return new SkData(ptr, length, proc, context);
108 }
109
110 // assumes fPtr was allocated with sk_fmmap
sk_mmap_releaseproc(const void * addr,void * ctx)111 static void sk_mmap_releaseproc(const void* addr, void* ctx) {
112 size_t length = reinterpret_cast<size_t>(ctx);
113 sk_fmunmap(addr, length);
114 }
115
NewFromFILE(FILE * f)116 SkData* SkData::NewFromFILE(FILE* f) {
117 size_t size;
118 void* addr = sk_fmmap(f, &size);
119 if (nullptr == addr) {
120 return nullptr;
121 }
122
123 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
124 }
125
NewFromFileName(const char path[])126 SkData* SkData::NewFromFileName(const char path[]) {
127 FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr;
128 if (nullptr == f) {
129 return nullptr;
130 }
131 SkData* data = NewFromFILE(f);
132 sk_fclose(f);
133 return data;
134 }
135
NewFromFD(int fd)136 SkData* SkData::NewFromFD(int fd) {
137 size_t size;
138 void* addr = sk_fdmmap(fd, &size);
139 if (nullptr == addr) {
140 return nullptr;
141 }
142
143 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, nullptr);
144 }
145
146 // assumes context is a SkData
sk_dataref_releaseproc(const void *,void * context)147 static void sk_dataref_releaseproc(const void*, void* context) {
148 SkData* src = reinterpret_cast<SkData*>(context);
149 src->unref();
150 }
151
NewSubset(const SkData * src,size_t offset,size_t length)152 SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
153 /*
154 We could, if we wanted/need to, just make a deep copy of src's data,
155 rather than referencing it. This would duplicate the storage (of the
156 subset amount) but would possibly allow src to go out of scope sooner.
157 */
158
159 size_t available = src->size();
160 if (offset >= available || 0 == length) {
161 return SkData::NewEmpty();
162 }
163 available -= offset;
164 if (length > available) {
165 length = available;
166 }
167 SkASSERT(length > 0);
168
169 src->ref(); // this will be balanced in sk_dataref_releaseproc
170 return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
171 const_cast<SkData*>(src));
172 }
173
NewWithCString(const char cstr[])174 SkData* SkData::NewWithCString(const char cstr[]) {
175 size_t size;
176 if (nullptr == cstr) {
177 cstr = "";
178 size = 1;
179 } else {
180 size = strlen(cstr) + 1;
181 }
182 return NewWithCopy(cstr, size);
183 }
184
185 ///////////////////////////////////////////////////////////////////////////////
186
NewFromStream(SkStream * stream,size_t size)187 SkData* SkData::NewFromStream(SkStream* stream, size_t size) {
188 SkAutoDataUnref data(SkData::NewUninitialized(size));
189 if (stream->read(data->writable_data(), size) != size) {
190 return nullptr;
191 }
192 return data.detach();
193 }
194
195