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 if (actualLength < length) { 68 // we overflowed 69 sk_throw(); 70 } 71 72 void* storage = ::operator new (actualLength); 73 sk_sp<SkData> data(new (storage) SkData(length)); 74 if (srcOrNull) { 75 memcpy(data->writable_data(), srcOrNull, length); 76 } 77 return data; 78 } 79 80 void SkData::DummyReleaseProc(const void*, void*) {} 81 82 /////////////////////////////////////////////////////////////////////////////// 83 84 sk_sp<SkData> SkData::MakeEmpty() { 85 static SkOnce once; 86 static SkData* empty; 87 88 once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); }); 89 return sk_ref_sp(empty); 90 } 91 92 // assumes fPtr was allocated via sk_malloc 93 static void sk_free_releaseproc(const void* ptr, void*) { 94 sk_free((void*)ptr); 95 } 96 97 sk_sp<SkData> SkData::MakeFromMalloc(const void* data, size_t length) { 98 return sk_sp<SkData>(new SkData(data, length, sk_free_releaseproc, nullptr)); 99 } 100 101 sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) { 102 SkASSERT(src); 103 return PrivateNewWithCopy(src, length); 104 } 105 106 sk_sp<SkData> SkData::MakeUninitialized(size_t length) { 107 return PrivateNewWithCopy(nullptr, length); 108 } 109 110 sk_sp<SkData> SkData::MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx) { 111 return sk_sp<SkData>(new SkData(ptr, length, proc, ctx)); 112 } 113 114 // assumes fPtr was allocated with sk_fmmap 115 static void sk_mmap_releaseproc(const void* addr, void* ctx) { 116 size_t length = reinterpret_cast<size_t>(ctx); 117 sk_fmunmap(addr, length); 118 } 119 120 sk_sp<SkData> SkData::MakeFromFILE(FILE* f) { 121 size_t size; 122 void* addr = sk_fmmap(f, &size); 123 if (nullptr == addr) { 124 return nullptr; 125 } 126 127 return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size)); 128 } 129 130 sk_sp<SkData> SkData::MakeFromFileName(const char path[]) { 131 FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr; 132 if (nullptr == f) { 133 return nullptr; 134 } 135 auto data = MakeFromFILE(f); 136 sk_fclose(f); 137 return data; 138 } 139 140 sk_sp<SkData> SkData::MakeFromFD(int fd) { 141 size_t size; 142 void* addr = sk_fdmmap(fd, &size); 143 if (nullptr == addr) { 144 return nullptr; 145 } 146 return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size)); 147 } 148 149 // assumes context is a SkData 150 static void sk_dataref_releaseproc(const void*, void* context) { 151 SkData* src = reinterpret_cast<SkData*>(context); 152 src->unref(); 153 } 154 155 sk_sp<SkData> SkData::MakeSubset(const SkData* src, size_t offset, size_t length) { 156 /* 157 We could, if we wanted/need to, just make a deep copy of src's data, 158 rather than referencing it. This would duplicate the storage (of the 159 subset amount) but would possibly allow src to go out of scope sooner. 160 */ 161 162 size_t available = src->size(); 163 if (offset >= available || 0 == length) { 164 return SkData::MakeEmpty(); 165 } 166 available -= offset; 167 if (length > available) { 168 length = available; 169 } 170 SkASSERT(length > 0); 171 172 src->ref(); // this will be balanced in sk_dataref_releaseproc 173 return sk_sp<SkData>(new SkData(src->bytes() + offset, length, sk_dataref_releaseproc, 174 const_cast<SkData*>(src))); 175 } 176 177 sk_sp<SkData> SkData::MakeWithCString(const char cstr[]) { 178 size_t size; 179 if (nullptr == cstr) { 180 cstr = ""; 181 size = 1; 182 } else { 183 size = strlen(cstr) + 1; 184 } 185 return MakeWithCopy(cstr, size); 186 } 187 188 /////////////////////////////////////////////////////////////////////////////// 189 190 sk_sp<SkData> SkData::MakeFromStream(SkStream* stream, size_t size) { 191 sk_sp<SkData> data(SkData::MakeUninitialized(size)); 192 if (stream->read(data->writable_data(), size) != size) { 193 return nullptr; 194 } 195 return data; 196 } 197