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 "SkFlattenableBuffers.h" 10 #include "SkOSFile.h" 11 #include "SkOnce.h" 12 13 SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) { 14 fPtr = ptr; 15 fSize = size; 16 fReleaseProc = proc; 17 fReleaseProcContext = context; 18 } 19 20 SkData::~SkData() { 21 if (fReleaseProc) { 22 fReleaseProc(fPtr, fSize, fReleaseProcContext); 23 } 24 } 25 26 bool SkData::equals(const SkData* other) const { 27 if (NULL == other) { 28 return false; 29 } 30 31 return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize); 32 } 33 34 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const { 35 size_t available = fSize; 36 if (offset >= available || 0 == length) { 37 return 0; 38 } 39 available -= offset; 40 if (length > available) { 41 length = available; 42 } 43 SkASSERT(length > 0); 44 45 memcpy(buffer, this->bytes() + offset, length); 46 return length; 47 } 48 49 /////////////////////////////////////////////////////////////////////////////// 50 51 void SkData::NewEmptyImpl(SkData** empty) { 52 *empty = new SkData(NULL, 0, NULL, NULL); 53 } 54 55 SkData* SkData::NewEmpty() { 56 static SkData* gEmptyRef; 57 SK_DECLARE_STATIC_ONCE(once); 58 SkOnce(&once, SkData::NewEmptyImpl, &gEmptyRef); 59 gEmptyRef->ref(); 60 return gEmptyRef; 61 } 62 63 // assumes fPtr was allocated via sk_malloc 64 static void sk_free_releaseproc(const void* ptr, size_t, void*) { 65 sk_free((void*)ptr); 66 } 67 68 SkData* SkData::NewFromMalloc(const void* data, size_t length) { 69 return new SkData(data, length, sk_free_releaseproc, NULL); 70 } 71 72 SkData* SkData::NewWithCopy(const void* data, size_t length) { 73 if (0 == length) { 74 return SkData::NewEmpty(); 75 } 76 77 void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc 78 memcpy(copy, data, length); 79 return new SkData(copy, length, sk_free_releaseproc, NULL); 80 } 81 82 SkData* SkData::NewWithProc(const void* data, size_t length, 83 ReleaseProc proc, void* context) { 84 return new SkData(data, length, proc, context); 85 } 86 87 // assumes fPtr was allocated with sk_fmmap 88 static void sk_mmap_releaseproc(const void* addr, size_t length, void*) { 89 sk_fmunmap(addr, length); 90 } 91 92 SkData* SkData::NewFromFILE(SkFILE* f) { 93 size_t size; 94 void* addr = sk_fmmap(f, &size); 95 if (NULL == addr) { 96 return NULL; 97 } 98 99 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL); 100 } 101 102 SkData* SkData::NewFromFileName(const char path[]) { 103 SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL; 104 if (NULL == f) { 105 return NULL; 106 } 107 SkData* data = NewFromFILE(f); 108 sk_fclose(f); 109 return data; 110 } 111 112 SkData* SkData::NewFromFD(int fd) { 113 size_t size; 114 void* addr = sk_fdmmap(fd, &size); 115 if (NULL == addr) { 116 return NULL; 117 } 118 119 return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL); 120 } 121 122 // assumes context is a SkData 123 static void sk_dataref_releaseproc(const void*, size_t, void* context) { 124 SkData* src = reinterpret_cast<SkData*>(context); 125 src->unref(); 126 } 127 128 SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) { 129 /* 130 We could, if we wanted/need to, just make a deep copy of src's data, 131 rather than referencing it. This would duplicate the storage (of the 132 subset amount) but would possibly allow src to go out of scope sooner. 133 */ 134 135 size_t available = src->size(); 136 if (offset >= available || 0 == length) { 137 return SkData::NewEmpty(); 138 } 139 available -= offset; 140 if (length > available) { 141 length = available; 142 } 143 SkASSERT(length > 0); 144 145 src->ref(); // this will be balanced in sk_dataref_releaseproc 146 return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc, 147 const_cast<SkData*>(src)); 148 } 149 150 SkData* SkData::NewWithCString(const char cstr[]) { 151 size_t size; 152 if (NULL == cstr) { 153 cstr = ""; 154 size = 1; 155 } else { 156 size = strlen(cstr) + 1; 157 } 158 return NewWithCopy(cstr, size); 159 } 160