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