• 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 "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