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