SkData.cpp revision 9594da111dc1c36c1912eb61207aaa54c17ea550
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
15static 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
20SkData::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//
31SkData::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
38SkData::~SkData() {
39    if (fReleaseProc) {
40        fReleaseProc(fPtr, fSize, fReleaseProcContext);
41    }
42}
43
44void 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
58bool 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
66size_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
81SkData* 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
95SkData* SkData::NewEmptyImpl() {
96    return new SkData(NULL, 0, NULL, NULL);
97}
98
99void SkData::DeleteEmpty(SkData* ptr) { SkDELETE(ptr); }
100
101SkData* 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
107static void sk_free_releaseproc(const void* ptr, size_t, void*) {
108    sk_free((void*)ptr);
109}
110
111SkData* SkData::NewFromMalloc(const void* data, size_t length) {
112    return new SkData(data, length, sk_free_releaseproc, NULL);
113}
114
115SkData* SkData::NewWithCopy(const void* src, size_t length) {
116    SkASSERT(src);
117    return PrivateNewWithCopy(src, length);
118}
119
120SkData* SkData::NewUninitialized(size_t length) {
121    return PrivateNewWithCopy(NULL, length);
122}
123
124SkData* 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
130static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
131    sk_fmunmap(addr, length);
132}
133
134SkData* 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
144SkData* 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
154SkData* 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
165static void sk_dataref_releaseproc(const void*, size_t, void* context) {
166    SkData* src = reinterpret_cast<SkData*>(context);
167    src->unref();
168}
169
170SkData* 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
192SkData* 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
205SkData* 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