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 "SkLazyPtr.h"
10 #include "SkOSFile.h"
11 #include "SkReadBuffer.h"
12 #include "SkStream.h"
13 #include "SkWriteBuffer.h"
14
sk_inplace_sentinel_releaseproc(const void *,size_t,void *)15 static void sk_inplace_sentinel_releaseproc(const void*, size_t, void*) {
16 // we should never get called, as we are just a sentinel
17 sk_throw();
18 }
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 fPtr = const_cast<void*>(ptr);
22 fSize = size;
23 fReleaseProc = proc;
24 fReleaseProcContext = context;
25 }
26
27 // This constructor means we are inline with our fPtr's contents. Thus we set fPtr
28 // to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc,
29 // since we need to handle "delete" ourselves. See internal_displose().
30 //
SkData(size_t size)31 SkData::SkData(size_t size) {
32 fPtr = (char*)(this + 1); // contents are immediately after this
33 fSize = size;
34 fReleaseProc = sk_inplace_sentinel_releaseproc;
35 fReleaseProcContext = NULL;
36 }
37
~SkData()38 SkData::~SkData() {
39 if (fReleaseProc) {
40 fReleaseProc(fPtr, fSize, fReleaseProcContext);
41 }
42 }
43
internal_dispose() const44 void SkData::internal_dispose() const {
45 if (sk_inplace_sentinel_releaseproc == fReleaseProc) {
46 const_cast<SkData*>(this)->fReleaseProc = NULL; // so we don't call it in our destructor
47
48 this->internal_dispose_restore_refcnt_to_1();
49 this->~SkData(); // explicitly call this for refcnt bookkeeping
50
51 sk_free(const_cast<SkData*>(this));
52 } else {
53 this->internal_dispose_restore_refcnt_to_1();
54 SkDELETE(this);
55 }
56 }
57
equals(const SkData * other) const58 bool SkData::equals(const SkData* other) const {
59 if (NULL == other) {
60 return false;
61 }
62
63 return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
64 }
65
copyRange(size_t offset,size_t length,void * buffer) const66 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
67 size_t available = fSize;
68 if (offset >= available || 0 == length) {
69 return 0;
70 }
71 available -= offset;
72 if (length > available) {
73 length = available;
74 }
75 SkASSERT(length > 0);
76
77 memcpy(buffer, this->bytes() + offset, length);
78 return length;
79 }
80
PrivateNewWithCopy(const void * srcOrNull,size_t length)81 SkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
82 if (0 == length) {
83 return SkData::NewEmpty();
84 }
85 char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length);
86 SkData* data = new (storage) SkData(length);
87 if (srcOrNull) {
88 memcpy(data->writable_data(), srcOrNull, length);
89 }
90 return data;
91 }
92
93 ///////////////////////////////////////////////////////////////////////////////
94
NewEmptyImpl()95 SkData* SkData::NewEmptyImpl() {
96 return new SkData(NULL, 0, NULL, NULL);
97 }
98
DeleteEmpty(SkData * ptr)99 void SkData::DeleteEmpty(SkData* ptr) { SkDELETE(ptr); }
100
NewEmpty()101 SkData* SkData::NewEmpty() {
102 SK_DECLARE_STATIC_LAZY_PTR(SkData, empty, NewEmptyImpl, DeleteEmpty);
103 return SkRef(empty.get());
104 }
105
106 // assumes fPtr was allocated via sk_malloc
sk_free_releaseproc(const void * ptr,size_t,void *)107 static void sk_free_releaseproc(const void* ptr, size_t, void*) {
108 sk_free((void*)ptr);
109 }
110
NewFromMalloc(const void * data,size_t length)111 SkData* SkData::NewFromMalloc(const void* data, size_t length) {
112 return new SkData(data, length, sk_free_releaseproc, NULL);
113 }
114
NewWithCopy(const void * src,size_t length)115 SkData* SkData::NewWithCopy(const void* src, size_t length) {
116 SkASSERT(src);
117 return PrivateNewWithCopy(src, length);
118 }
119
NewUninitialized(size_t length)120 SkData* SkData::NewUninitialized(size_t length) {
121 return PrivateNewWithCopy(NULL, length);
122 }
123
NewWithProc(const void * data,size_t length,ReleaseProc proc,void * context)124 SkData* SkData::NewWithProc(const void* data, size_t length,
125 ReleaseProc proc, void* context) {
126 return new SkData(data, length, proc, context);
127 }
128
129 // assumes fPtr was allocated with sk_fmmap
sk_mmap_releaseproc(const void * addr,size_t length,void *)130 static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
131 sk_fmunmap(addr, length);
132 }
133
NewFromFILE(SkFILE * f)134 SkData* SkData::NewFromFILE(SkFILE* f) {
135 size_t size;
136 void* addr = sk_fmmap(f, &size);
137 if (NULL == addr) {
138 return NULL;
139 }
140
141 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
142 }
143
NewFromFileName(const char path[])144 SkData* SkData::NewFromFileName(const char path[]) {
145 SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
146 if (NULL == f) {
147 return NULL;
148 }
149 SkData* data = NewFromFILE(f);
150 sk_fclose(f);
151 return data;
152 }
153
NewFromFD(int fd)154 SkData* SkData::NewFromFD(int fd) {
155 size_t size;
156 void* addr = sk_fdmmap(fd, &size);
157 if (NULL == addr) {
158 return NULL;
159 }
160
161 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
162 }
163
164 // assumes context is a SkData
sk_dataref_releaseproc(const void *,size_t,void * context)165 static void sk_dataref_releaseproc(const void*, size_t, void* context) {
166 SkData* src = reinterpret_cast<SkData*>(context);
167 src->unref();
168 }
169
NewSubset(const SkData * src,size_t offset,size_t length)170 SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
171 /*
172 We could, if we wanted/need to, just make a deep copy of src's data,
173 rather than referencing it. This would duplicate the storage (of the
174 subset amount) but would possibly allow src to go out of scope sooner.
175 */
176
177 size_t available = src->size();
178 if (offset >= available || 0 == length) {
179 return SkData::NewEmpty();
180 }
181 available -= offset;
182 if (length > available) {
183 length = available;
184 }
185 SkASSERT(length > 0);
186
187 src->ref(); // this will be balanced in sk_dataref_releaseproc
188 return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
189 const_cast<SkData*>(src));
190 }
191
NewWithCString(const char cstr[])192 SkData* SkData::NewWithCString(const char cstr[]) {
193 size_t size;
194 if (NULL == cstr) {
195 cstr = "";
196 size = 1;
197 } else {
198 size = strlen(cstr) + 1;
199 }
200 return NewWithCopy(cstr, size);
201 }
202
203 ///////////////////////////////////////////////////////////////////////////////
204
NewFromStream(SkStream * stream,size_t size)205 SkData* SkData::NewFromStream(SkStream* stream, size_t size) {
206 SkAutoDataUnref data(SkData::NewUninitialized(size));
207 if (stream->read(data->writable_data(), size) != size) {
208 return NULL;
209 }
210 return data.detach();
211 }
212
213