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 "include/core/SkData.h" 9#include "include/core/SkStream.h" 10#include "include/private/SkOnce.h" 11#include "src/core/SkOSFile.h" 12#include "src/core/SkReadBuffer.h" 13#include "src/core/SkWriteBuffer.h" 14#include <new> 15 16SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) 17 : fReleaseProc(proc) 18 , fReleaseProcContext(context) 19 , fPtr(ptr) 20 , fSize(size) 21 , fNativeBuffer(nullptr) 22{} 23 24SkData::SkData(const void* ptr, size_t size, OH_NativeBuffer* nativeBuffer, ReleaseProc proc, void* context) 25 : fReleaseProc(proc) 26 , fReleaseProcContext(context) 27 , fPtr(ptr) 28 , fSize(size) 29 , fNativeBuffer(nativeBuffer) 30{} 31 32/** This constructor means we are inline with our fPtr's contents. 33 * Thus we set fPtr to point right after this. 34 */ 35SkData::SkData(size_t size) 36 : fReleaseProc(nullptr) 37 , fReleaseProcContext(nullptr) 38 , fPtr((const char*)(this + 1)) 39 , fSize(size) 40 , fNativeBuffer(nullptr) 41{} 42 43SkData::~SkData() { 44 if (fReleaseProc) { 45 fReleaseProc(fPtr, fReleaseProcContext); 46 } 47} 48 49bool SkData::equals(const SkData* other) const { 50 if (this == other) { 51 return true; 52 } 53 if (nullptr == other) { 54 return false; 55 } 56 return fSize == other->fSize && !sk_careful_memcmp(fPtr, other->fPtr, fSize); 57} 58 59size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const { 60 size_t available = fSize; 61 if (offset >= available || 0 == length) { 62 return 0; 63 } 64 available -= offset; 65 if (length > available) { 66 length = available; 67 } 68 SkASSERT(length > 0); 69 70 memcpy(buffer, this->bytes() + offset, length); 71 return length; 72} 73 74void SkData::operator delete(void* p) { 75 ::operator delete(p); 76} 77 78sk_sp<SkData> SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) { 79 if (0 == length) { 80 return SkData::MakeEmpty(); 81 } 82 83 const size_t actualLength = length + sizeof(SkData); 84 SkASSERT_RELEASE(length < actualLength); // Check for overflow. 85 86 void* storage = ::operator new (actualLength); 87 sk_sp<SkData> data(new (storage) SkData(length)); 88 if (srcOrNull) { 89 memcpy(data->writable_data(), srcOrNull, length); 90 } 91 return data; 92} 93 94void SkData::NoopReleaseProc(const void*, void*) {} 95 96/////////////////////////////////////////////////////////////////////////////// 97 98sk_sp<SkData> SkData::MakeEmpty() { 99 static SkOnce once; 100 static SkData* empty; 101 102 once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); }); 103 return sk_ref_sp(empty); 104} 105 106// assumes fPtr was allocated via sk_malloc 107static void sk_free_releaseproc(const void* ptr, void*) { 108 sk_free((void*)ptr); 109} 110 111sk_sp<SkData> SkData::MakeFromMalloc(const void* data, size_t length) { 112 return sk_sp<SkData>(new SkData(data, length, sk_free_releaseproc, nullptr)); 113} 114 115sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) { 116 SkASSERT(src); 117 return PrivateNewWithCopy(src, length); 118} 119 120sk_sp<SkData> SkData::MakeUninitialized(size_t length) { 121 return PrivateNewWithCopy(nullptr, length); 122} 123 124sk_sp<SkData> SkData::MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx) { 125 return sk_sp<SkData>(new SkData(ptr, length, proc, ctx)); 126} 127 128// assumes fPtr was allocated with sk_fmmap 129static void sk_mmap_releaseproc(const void* addr, void* ctx) { 130 size_t length = reinterpret_cast<size_t>(ctx); 131 sk_fmunmap(addr, length); 132} 133 134sk_sp<SkData> SkData::MakeFromFILE(FILE* f) { 135 size_t size; 136 void* addr = sk_fmmap(f, &size); 137 if (nullptr == addr) { 138 return nullptr; 139 } 140 141 return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size)); 142} 143 144sk_sp<SkData> SkData::MakeFromFileName(const char path[]) { 145 FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr; 146 if (nullptr == f) { 147 return nullptr; 148 } 149 auto data = MakeFromFILE(f); 150 sk_fclose(f); 151 return data; 152} 153 154sk_sp<SkData> SkData::MakeFromFD(int fd) { 155 size_t size; 156 void* addr = sk_fdmmap(fd, &size); 157 if (nullptr == addr) { 158 return nullptr; 159 } 160 return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size)); 161} 162 163sk_sp<SkData> SkData::MakeFromOHNativeBuffer(OH_NativeBuffer* nativeBuffer, size_t size) { 164 return sk_sp<SkData>(new SkData(nullptr, size, nativeBuffer, nullptr, nullptr)); 165} 166 167// assumes context is a SkData 168static void sk_dataref_releaseproc(const void*, void* context) { 169 SkData* src = reinterpret_cast<SkData*>(context); 170 src->unref(); 171} 172 173sk_sp<SkData> SkData::MakeSubset(const SkData* src, size_t offset, size_t length) { 174 /* 175 We could, if we wanted/need to, just make a deep copy of src's data, 176 rather than referencing it. This would duplicate the storage (of the 177 subset amount) but would possibly allow src to go out of scope sooner. 178 */ 179 180 size_t available = src->size(); 181 if (offset >= available || 0 == length) { 182 return SkData::MakeEmpty(); 183 } 184 available -= offset; 185 if (length > available) { 186 length = available; 187 } 188 SkASSERT(length > 0); 189 190 src->ref(); // this will be balanced in sk_dataref_releaseproc 191 return sk_sp<SkData>(new SkData(src->bytes() + offset, length, sk_dataref_releaseproc, 192 const_cast<SkData*>(src))); 193} 194 195sk_sp<SkData> SkData::MakeWithCString(const char cstr[]) { 196 size_t size; 197 if (nullptr == cstr) { 198 cstr = ""; 199 size = 1; 200 } else { 201 size = strlen(cstr) + 1; 202 } 203 return MakeWithCopy(cstr, size); 204} 205 206/////////////////////////////////////////////////////////////////////////////// 207 208sk_sp<SkData> SkData::MakeFromStream(SkStream* stream, size_t size) { 209 sk_sp<SkData> data(SkData::MakeUninitialized(size)); 210 if (stream->read(data->writable_data(), size) != size) { 211 return nullptr; 212 } 213 return data; 214} 215