Home | History | Annotate | Download | only in core
      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 "SkLazyPtr.h"
     10 #include "SkOSFile.h"
     11 #include "SkReadBuffer.h"
     12 #include "SkStream.h"
     13 #include "SkWriteBuffer.h"
     14 
     15 static void sk_inplace_sentinel_releaseproc(const void*, size_t, void*) {
     16     // we should never get called, as we are just a sentinel
     17     sk_throw();
     18 }
     19 
     20 SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
     21     fPtr = const_cast<void*>(ptr);
     22     fSize = size;
     23     fReleaseProc = proc;
     24     fReleaseProcContext = context;
     25 }
     26 
     27 // This constructor means we are inline with our fPtr's contents. Thus we set fPtr
     28 // to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc,
     29 // since we need to handle "delete" ourselves. See internal_displose().
     30 //
     31 SkData::SkData(size_t size) {
     32     fPtr = (char*)(this + 1);   // contents are immediately after this
     33     fSize = size;
     34     fReleaseProc = sk_inplace_sentinel_releaseproc;
     35     fReleaseProcContext = NULL;
     36 }
     37 
     38 SkData::~SkData() {
     39     if (fReleaseProc) {
     40         fReleaseProc(fPtr, fSize, fReleaseProcContext);
     41     }
     42 }
     43 
     44 void SkData::internal_dispose() const {
     45     if (sk_inplace_sentinel_releaseproc == fReleaseProc) {
     46         const_cast<SkData*>(this)->fReleaseProc = NULL;    // so we don't call it in our destructor
     47 
     48         this->internal_dispose_restore_refcnt_to_1();
     49         this->~SkData();        // explicitly call this for refcnt bookkeeping
     50 
     51         sk_free(const_cast<SkData*>(this));
     52     } else {
     53         this->internal_dispose_restore_refcnt_to_1();
     54         SkDELETE(this);
     55     }
     56 }
     57 
     58 bool SkData::equals(const SkData* other) const {
     59     if (NULL == other) {
     60         return false;
     61     }
     62 
     63     return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
     64 }
     65 
     66 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
     67     size_t available = fSize;
     68     if (offset >= available || 0 == length) {
     69         return 0;
     70     }
     71     available -= offset;
     72     if (length > available) {
     73         length = available;
     74     }
     75     SkASSERT(length > 0);
     76 
     77     memcpy(buffer, this->bytes() + offset, length);
     78     return length;
     79 }
     80 
     81 SkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
     82     if (0 == length) {
     83         return SkData::NewEmpty();
     84     }
     85     char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length);
     86     SkData* data = new (storage) SkData(length);
     87     if (srcOrNull) {
     88         memcpy(data->writable_data(), srcOrNull, length);
     89     }
     90     return data;
     91 }
     92 
     93 ///////////////////////////////////////////////////////////////////////////////
     94 
     95 SkData* SkData::NewEmptyImpl() {
     96     return new SkData(NULL, 0, NULL, NULL);
     97 }
     98 
     99 void SkData::DeleteEmpty(SkData* ptr) { SkDELETE(ptr); }
    100 
    101 SkData* SkData::NewEmpty() {
    102     SK_DECLARE_STATIC_LAZY_PTR(SkData, empty, NewEmptyImpl, DeleteEmpty);
    103     return SkRef(empty.get());
    104 }
    105 
    106 // assumes fPtr was allocated via sk_malloc
    107 static void sk_free_releaseproc(const void* ptr, size_t, void*) {
    108     sk_free((void*)ptr);
    109 }
    110 
    111 SkData* SkData::NewFromMalloc(const void* data, size_t length) {
    112     return new SkData(data, length, sk_free_releaseproc, NULL);
    113 }
    114 
    115 SkData* SkData::NewWithCopy(const void* src, size_t length) {
    116     SkASSERT(src);
    117     return PrivateNewWithCopy(src, length);
    118 }
    119 
    120 SkData* SkData::NewUninitialized(size_t length) {
    121     return PrivateNewWithCopy(NULL, length);
    122 }
    123 
    124 SkData* SkData::NewWithProc(const void* data, size_t length,
    125                             ReleaseProc proc, void* context) {
    126     return new SkData(data, length, proc, context);
    127 }
    128 
    129 // assumes fPtr was allocated with sk_fmmap
    130 static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
    131     sk_fmunmap(addr, length);
    132 }
    133 
    134 SkData* SkData::NewFromFILE(SkFILE* f) {
    135     size_t size;
    136     void* addr = sk_fmmap(f, &size);
    137     if (NULL == addr) {
    138         return NULL;
    139     }
    140 
    141     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
    142 }
    143 
    144 SkData* SkData::NewFromFileName(const char path[]) {
    145     SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
    146     if (NULL == f) {
    147         return NULL;
    148     }
    149     SkData* data = NewFromFILE(f);
    150     sk_fclose(f);
    151     return data;
    152 }
    153 
    154 SkData* SkData::NewFromFD(int fd) {
    155     size_t size;
    156     void* addr = sk_fdmmap(fd, &size);
    157     if (NULL == addr) {
    158         return NULL;
    159     }
    160 
    161     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
    162 }
    163 
    164 // assumes context is a SkData
    165 static void sk_dataref_releaseproc(const void*, size_t, void* context) {
    166     SkData* src = reinterpret_cast<SkData*>(context);
    167     src->unref();
    168 }
    169 
    170 SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
    171     /*
    172         We could, if we wanted/need to, just make a deep copy of src's data,
    173         rather than referencing it. This would duplicate the storage (of the
    174         subset amount) but would possibly allow src to go out of scope sooner.
    175      */
    176 
    177     size_t available = src->size();
    178     if (offset >= available || 0 == length) {
    179         return SkData::NewEmpty();
    180     }
    181     available -= offset;
    182     if (length > available) {
    183         length = available;
    184     }
    185     SkASSERT(length > 0);
    186 
    187     src->ref(); // this will be balanced in sk_dataref_releaseproc
    188     return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
    189                          const_cast<SkData*>(src));
    190 }
    191 
    192 SkData* SkData::NewWithCString(const char cstr[]) {
    193     size_t size;
    194     if (NULL == cstr) {
    195         cstr = "";
    196         size = 1;
    197     } else {
    198         size = strlen(cstr) + 1;
    199     }
    200     return NewWithCopy(cstr, size);
    201 }
    202 
    203 ///////////////////////////////////////////////////////////////////////////////
    204 
    205 SkData* SkData::NewFromStream(SkStream* stream, size_t size) {
    206     SkAutoDataUnref data(SkData::NewUninitialized(size));
    207     if (stream->read(data->writable_data(), size) != size) {
    208         return NULL;
    209     }
    210     return data.detach();
    211 }
    212 
    213