|
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 "SkReadBuffer.h" |
|
10 #include "SkWriteBuffer.h" |
|
11 #include "SkOSFile.h" |
|
12 #include "SkOnce.h" |
|
13 |
|
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 |
|
21 SkData::~SkData() { |
|
22 if (fReleaseProc) { |
|
23 fReleaseProc(fPtr, fSize, fReleaseProcContext); |
|
24 } |
|
25 } |
|
26 |
|
27 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 |
|
35 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 |
|
52 static SkData* gEmptyDataRef = NULL; |
|
53 static void cleanup_gEmptyDataRef() { gEmptyDataRef->unref(); } |
|
54 |
|
55 void SkData::NewEmptyImpl(int) { |
|
56 gEmptyDataRef = new SkData(NULL, 0, NULL, NULL); |
|
57 } |
|
58 |
|
59 SkData* SkData::NewEmpty() { |
|
60 SK_DECLARE_STATIC_ONCE(once); |
|
61 SkOnce(&once, SkData::NewEmptyImpl, 0, cleanup_gEmptyDataRef); |
|
62 gEmptyDataRef->ref(); |
|
63 return gEmptyDataRef; |
|
64 } |
|
65 |
|
66 // assumes fPtr was allocated via sk_malloc |
|
67 static void sk_free_releaseproc(const void* ptr, size_t, void*) { |
|
68 sk_free((void*)ptr); |
|
69 } |
|
70 |
|
71 SkData* SkData::NewFromMalloc(const void* data, size_t length) { |
|
72 return new SkData(data, length, sk_free_releaseproc, NULL); |
|
73 } |
|
74 |
|
75 SkData* SkData::NewWithCopy(const void* data, size_t length) { |
|
76 if (0 == length) { |
|
77 return SkData::NewEmpty(); |
|
78 } |
|
79 |
|
80 void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc |
|
81 memcpy(copy, data, length); |
|
82 return new SkData(copy, length, sk_free_releaseproc, NULL); |
|
83 } |
|
84 |
|
85 SkData* SkData::NewWithProc(const void* data, size_t length, |
|
86 ReleaseProc proc, void* context) { |
|
87 return new SkData(data, length, proc, context); |
|
88 } |
|
89 |
|
90 // assumes fPtr was allocated with sk_fmmap |
|
91 static void sk_mmap_releaseproc(const void* addr, size_t length, void*) { |
|
92 sk_fmunmap(addr, length); |
|
93 } |
|
94 |
|
95 SkData* SkData::NewFromFILE(SkFILE* f) { |
|
96 size_t size; |
|
97 void* addr = sk_fmmap(f, &size); |
|
98 if (NULL == addr) { |
|
99 return NULL; |
|
100 } |
|
101 |
|
102 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL); |
|
103 } |
|
104 |
|
105 SkData* SkData::NewFromFileName(const char path[]) { |
|
106 SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL; |
|
107 if (NULL == f) { |
|
108 return NULL; |
|
109 } |
|
110 SkData* data = NewFromFILE(f); |
|
111 sk_fclose(f); |
|
112 return data; |
|
113 } |
|
114 |
|
115 SkData* SkData::NewFromFD(int fd) { |
|
116 size_t size; |
|
117 void* addr = sk_fdmmap(fd, &size); |
|
118 if (NULL == addr) { |
|
119 return NULL; |
|
120 } |
|
121 |
|
122 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL); |
|
123 } |
|
124 |
|
125 // assumes context is a SkData |
|
126 static void sk_dataref_releaseproc(const void*, size_t, void* context) { |
|
127 SkData* src = reinterpret_cast<SkData*>(context); |
|
128 src->unref(); |
|
129 } |
|
130 |
|
131 SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) { |
|
132 /* |
|
133 We could, if we wanted/need to, just make a deep copy of src's data, |
|
134 rather than referencing it. This would duplicate the storage (of the |
|
135 subset amount) but would possibly allow src to go out of scope sooner. |
|
136 */ |
|
137 |
|
138 size_t available = src->size(); |
|
139 if (offset >= available || 0 == length) { |
|
140 return SkData::NewEmpty(); |
|
141 } |
|
142 available -= offset; |
|
143 if (length > available) { |
|
144 length = available; |
|
145 } |
|
146 SkASSERT(length > 0); |
|
147 |
|
148 src->ref(); // this will be balanced in sk_dataref_releaseproc |
|
149 return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc, |
|
150 const_cast<SkData*>(src)); |
|
151 } |
|
152 |
|
153 SkData* SkData::NewWithCString(const char cstr[]) { |
|
154 size_t size; |
|
155 if (NULL == cstr) { |
|
156 cstr = ""; |
|
157 size = 1; |
|
158 } else { |
|
159 size = strlen(cstr) + 1; |
|
160 } |
|
161 return NewWithCopy(cstr, size); |
|
162 } |