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