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