michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkData.h" michael@0: #include "SkReadBuffer.h" michael@0: #include "SkWriteBuffer.h" michael@0: #include "SkOSFile.h" michael@0: #include "SkOnce.h" michael@0: michael@0: SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) { michael@0: fPtr = ptr; michael@0: fSize = size; michael@0: fReleaseProc = proc; michael@0: fReleaseProcContext = context; michael@0: } michael@0: michael@0: SkData::~SkData() { michael@0: if (fReleaseProc) { michael@0: fReleaseProc(fPtr, fSize, fReleaseProcContext); michael@0: } michael@0: } michael@0: michael@0: bool SkData::equals(const SkData* other) const { michael@0: if (NULL == other) { michael@0: return false; michael@0: } michael@0: michael@0: return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize); michael@0: } michael@0: michael@0: size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const { michael@0: size_t available = fSize; michael@0: if (offset >= available || 0 == length) { michael@0: return 0; michael@0: } michael@0: available -= offset; michael@0: if (length > available) { michael@0: length = available; michael@0: } michael@0: SkASSERT(length > 0); michael@0: michael@0: memcpy(buffer, this->bytes() + offset, length); michael@0: return length; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static SkData* gEmptyDataRef = NULL; michael@0: static void cleanup_gEmptyDataRef() { gEmptyDataRef->unref(); } michael@0: michael@0: void SkData::NewEmptyImpl(int) { michael@0: gEmptyDataRef = new SkData(NULL, 0, NULL, NULL); michael@0: } michael@0: michael@0: SkData* SkData::NewEmpty() { michael@0: SK_DECLARE_STATIC_ONCE(once); michael@0: SkOnce(&once, SkData::NewEmptyImpl, 0, cleanup_gEmptyDataRef); michael@0: gEmptyDataRef->ref(); michael@0: return gEmptyDataRef; michael@0: } michael@0: michael@0: // assumes fPtr was allocated via sk_malloc michael@0: static void sk_free_releaseproc(const void* ptr, size_t, void*) { michael@0: sk_free((void*)ptr); michael@0: } michael@0: michael@0: SkData* SkData::NewFromMalloc(const void* data, size_t length) { michael@0: return new SkData(data, length, sk_free_releaseproc, NULL); michael@0: } michael@0: michael@0: SkData* SkData::NewWithCopy(const void* data, size_t length) { michael@0: if (0 == length) { michael@0: return SkData::NewEmpty(); michael@0: } michael@0: michael@0: void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc michael@0: memcpy(copy, data, length); michael@0: return new SkData(copy, length, sk_free_releaseproc, NULL); michael@0: } michael@0: michael@0: SkData* SkData::NewWithProc(const void* data, size_t length, michael@0: ReleaseProc proc, void* context) { michael@0: return new SkData(data, length, proc, context); michael@0: } michael@0: michael@0: // assumes fPtr was allocated with sk_fmmap michael@0: static void sk_mmap_releaseproc(const void* addr, size_t length, void*) { michael@0: sk_fmunmap(addr, length); michael@0: } michael@0: michael@0: SkData* SkData::NewFromFILE(SkFILE* f) { michael@0: size_t size; michael@0: void* addr = sk_fmmap(f, &size); michael@0: if (NULL == addr) { michael@0: return NULL; michael@0: } michael@0: michael@0: return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL); michael@0: } michael@0: michael@0: SkData* SkData::NewFromFileName(const char path[]) { michael@0: SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL; michael@0: if (NULL == f) { michael@0: return NULL; michael@0: } michael@0: SkData* data = NewFromFILE(f); michael@0: sk_fclose(f); michael@0: return data; michael@0: } michael@0: michael@0: SkData* SkData::NewFromFD(int fd) { michael@0: size_t size; michael@0: void* addr = sk_fdmmap(fd, &size); michael@0: if (NULL == addr) { michael@0: return NULL; michael@0: } michael@0: michael@0: return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL); michael@0: } michael@0: michael@0: // assumes context is a SkData michael@0: static void sk_dataref_releaseproc(const void*, size_t, void* context) { michael@0: SkData* src = reinterpret_cast(context); michael@0: src->unref(); michael@0: } michael@0: michael@0: SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) { michael@0: /* michael@0: We could, if we wanted/need to, just make a deep copy of src's data, michael@0: rather than referencing it. This would duplicate the storage (of the michael@0: subset amount) but would possibly allow src to go out of scope sooner. michael@0: */ michael@0: michael@0: size_t available = src->size(); michael@0: if (offset >= available || 0 == length) { michael@0: return SkData::NewEmpty(); michael@0: } michael@0: available -= offset; michael@0: if (length > available) { michael@0: length = available; michael@0: } michael@0: SkASSERT(length > 0); michael@0: michael@0: src->ref(); // this will be balanced in sk_dataref_releaseproc michael@0: return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc, michael@0: const_cast(src)); michael@0: } michael@0: michael@0: SkData* SkData::NewWithCString(const char cstr[]) { michael@0: size_t size; michael@0: if (NULL == cstr) { michael@0: cstr = ""; michael@0: size = 1; michael@0: } else { michael@0: size = strlen(cstr) + 1; michael@0: } michael@0: return NewWithCopy(cstr, size); michael@0: }