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 "SkOncePtr.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. Thus we set fPtr 23 // to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc, 24 // since we need to handle "delete" ourselves. See internal_displose(). 25 // 26 SkData::SkData(size_t size) { 27 fPtr = (char*)(this + 1); // contents are immediately after this 28 fSize = size; 29 fReleaseProc = nullptr; 30 fReleaseProcContext = nullptr; 31 } 32 33 SkData::~SkData() { 34 if (fReleaseProc) { 35 fReleaseProc(fPtr, fReleaseProcContext); 36 } 37 } 38 39 bool SkData::equals(const SkData* other) const { 40 if (nullptr == other) { 41 return false; 42 } 43 44 return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize); 45 } 46 47 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const { 48 size_t available = fSize; 49 if (offset >= available || 0 == length) { 50 return 0; 51 } 52 available -= offset; 53 if (length > available) { 54 length = available; 55 } 56 SkASSERT(length > 0); 57 58 memcpy(buffer, this->bytes() + offset, length); 59 return length; 60 } 61 62 SkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) { 63 if (0 == length) { 64 return SkData::NewEmpty(); 65 } 66 67 const size_t actualLength = length + sizeof(SkData); 68 if (actualLength < length) { 69 // we overflowed 70 sk_throw(); 71 } 72 73 char* storage = (char*)sk_malloc_throw(actualLength); 74 SkData* data = new (storage) SkData(length); 75 if (srcOrNull) { 76 memcpy(data->writable_data(), srcOrNull, length); 77 } 78 return data; 79 } 80 81 /////////////////////////////////////////////////////////////////////////////// 82 83 SK_DECLARE_STATIC_ONCE_PTR(SkData, gEmpty); 84 SkData* SkData::NewEmpty() { 85 return SkRef(gEmpty.get([]{return new SkData(nullptr, 0, nullptr, nullptr); })); 86 } 87 88 // assumes fPtr was allocated via sk_malloc 89 static void sk_free_releaseproc(const void* ptr, void*) { 90 sk_free((void*)ptr); 91 } 92 93 SkData* SkData::NewFromMalloc(const void* data, size_t length) { 94 return new SkData(data, length, sk_free_releaseproc, nullptr); 95 } 96 97 SkData* SkData::NewWithCopy(const void* src, size_t length) { 98 SkASSERT(src); 99 return PrivateNewWithCopy(src, length); 100 } 101 102 SkData* SkData::NewUninitialized(size_t length) { 103 return PrivateNewWithCopy(nullptr, length); 104 } 105 106 SkData* SkData::NewWithProc(const void* ptr, size_t length, ReleaseProc proc, void* context) { 107 return new SkData(ptr, length, proc, context); 108 } 109 110 // assumes fPtr was allocated with sk_fmmap 111 static void sk_mmap_releaseproc(const void* addr, void* ctx) { 112 size_t length = reinterpret_cast<size_t>(ctx); 113 sk_fmunmap(addr, length); 114 } 115 116 SkData* SkData::NewFromFILE(FILE* f) { 117 size_t size; 118 void* addr = sk_fmmap(f, &size); 119 if (nullptr == addr) { 120 return nullptr; 121 } 122 123 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size)); 124 } 125 126 SkData* SkData::NewFromFileName(const char path[]) { 127 FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr; 128 if (nullptr == f) { 129 return nullptr; 130 } 131 SkData* data = NewFromFILE(f); 132 sk_fclose(f); 133 return data; 134 } 135 136 SkData* SkData::NewFromFD(int fd) { 137 size_t size; 138 void* addr = sk_fdmmap(fd, &size); 139 if (nullptr == addr) { 140 return nullptr; 141 } 142 143 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, nullptr); 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 SkData* SkData::NewSubset(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::NewEmpty(); 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 new SkData(src->bytes() + offset, length, sk_dataref_releaseproc, 171 const_cast<SkData*>(src)); 172 } 173 174 SkData* SkData::NewWithCString(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 NewWithCopy(cstr, size); 183 } 184 185 /////////////////////////////////////////////////////////////////////////////// 186 187 SkData* SkData::NewFromStream(SkStream* stream, size_t size) { 188 SkAutoDataUnref data(SkData::NewUninitialized(size)); 189 if (stream->read(data->writable_data(), size) != size) { 190 return nullptr; 191 } 192 return data.detach(); 193 } 194 195