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 "SkWriteBuffer.h"
13
SkData(const void * ptr,size_t size,ReleaseProc proc,void * context)14 SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
15 fPtr = ptr;
16 fSize = size;
17 fReleaseProc = proc;
18 fReleaseProcContext = context;
19 }
20
~SkData()21 SkData::~SkData() {
22 if (fReleaseProc) {
23 fReleaseProc(fPtr, fSize, fReleaseProcContext);
24 }
25 }
26
equals(const SkData * other) const27 bool SkData::equals(const SkData* other) const {
28 if (NULL == other) {
29 return false;
30 }
31
32 return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
33 }
34
copyRange(size_t offset,size_t length,void * buffer) const35 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
36 size_t available = fSize;
37 if (offset >= available || 0 == length) {
38 return 0;
39 }
40 available -= offset;
41 if (length > available) {
42 length = available;
43 }
44 SkASSERT(length > 0);
45
46 memcpy(buffer, this->bytes() + offset, length);
47 return length;
48 }
49
50 ///////////////////////////////////////////////////////////////////////////////
51
NewEmptyImpl()52 SkData* SkData::NewEmptyImpl() {
53 return new SkData(NULL, 0, NULL, NULL);
54 }
DeleteEmpty(SkData * ptr)55 void SkData::DeleteEmpty(SkData* ptr) { SkDELETE(ptr); }
56
NewEmpty()57 SkData* SkData::NewEmpty() {
58 SK_DECLARE_STATIC_LAZY_PTR(SkData, empty, NewEmptyImpl, DeleteEmpty);
59 return SkRef(empty.get());
60 }
61
62 // assumes fPtr was allocated via sk_malloc
sk_free_releaseproc(const void * ptr,size_t,void *)63 static void sk_free_releaseproc(const void* ptr, size_t, void*) {
64 sk_free((void*)ptr);
65 }
66
NewFromMalloc(const void * data,size_t length)67 SkData* SkData::NewFromMalloc(const void* data, size_t length) {
68 return new SkData(data, length, sk_free_releaseproc, NULL);
69 }
70
NewWithCopy(const void * data,size_t length)71 SkData* SkData::NewWithCopy(const void* data, size_t length) {
72 if (0 == length) {
73 return SkData::NewEmpty();
74 }
75
76 void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc
77 memcpy(copy, data, length);
78 return new SkData(copy, length, sk_free_releaseproc, NULL);
79 }
80
NewWithProc(const void * data,size_t length,ReleaseProc proc,void * context)81 SkData* SkData::NewWithProc(const void* data, size_t length,
82 ReleaseProc proc, void* context) {
83 return new SkData(data, length, proc, context);
84 }
85
86 // assumes fPtr was allocated with sk_fmmap
sk_mmap_releaseproc(const void * addr,size_t length,void *)87 static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
88 sk_fmunmap(addr, length);
89 }
90
NewFromFILE(SkFILE * f)91 SkData* SkData::NewFromFILE(SkFILE* f) {
92 size_t size;
93 void* addr = sk_fmmap(f, &size);
94 if (NULL == addr) {
95 return NULL;
96 }
97
98 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
99 }
100
NewFromFileName(const char path[])101 SkData* SkData::NewFromFileName(const char path[]) {
102 SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
103 if (NULL == f) {
104 return NULL;
105 }
106 SkData* data = NewFromFILE(f);
107 sk_fclose(f);
108 return data;
109 }
110
NewFromFD(int fd)111 SkData* SkData::NewFromFD(int fd) {
112 size_t size;
113 void* addr = sk_fdmmap(fd, &size);
114 if (NULL == addr) {
115 return NULL;
116 }
117
118 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
119 }
120
121 // assumes context is a SkData
sk_dataref_releaseproc(const void *,size_t,void * context)122 static void sk_dataref_releaseproc(const void*, size_t, void* context) {
123 SkData* src = reinterpret_cast<SkData*>(context);
124 src->unref();
125 }
126
NewSubset(const SkData * src,size_t offset,size_t length)127 SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
128 /*
129 We could, if we wanted/need to, just make a deep copy of src's data,
130 rather than referencing it. This would duplicate the storage (of the
131 subset amount) but would possibly allow src to go out of scope sooner.
132 */
133
134 size_t available = src->size();
135 if (offset >= available || 0 == length) {
136 return SkData::NewEmpty();
137 }
138 available -= offset;
139 if (length > available) {
140 length = available;
141 }
142 SkASSERT(length > 0);
143
144 src->ref(); // this will be balanced in sk_dataref_releaseproc
145 return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
146 const_cast<SkData*>(src));
147 }
148
NewWithCString(const char cstr[])149 SkData* SkData::NewWithCString(const char cstr[]) {
150 size_t size;
151 if (NULL == cstr) {
152 cstr = "";
153 size = 1;
154 } else {
155 size = strlen(cstr) + 1;
156 }
157 return NewWithCopy(cstr, size);
158 }
159