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 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 = NULL;
     30     fReleaseProcContext = NULL;
     31 }
     32 
     33 SkData::~SkData() {
     34     if (fReleaseProc) {
     35         fReleaseProc(fPtr, fSize, fReleaseProcContext);
     36     }
     37 }
     38 
     39 bool SkData::equals(const SkData* other) const {
     40     if (NULL == 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     char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length);
     67     SkData* data = new (storage) SkData(length);
     68     if (srcOrNull) {
     69         memcpy(data->writable_data(), srcOrNull, length);
     70     }
     71     return data;
     72 }
     73 
     74 ///////////////////////////////////////////////////////////////////////////////
     75 
     76 // As a template argument these must have external linkage.
     77 SkData* sk_new_empty_data() { return new SkData(NULL, 0, NULL, NULL); }
     78 namespace { void sk_unref_data(SkData* ptr) { return SkSafeUnref(ptr); } }
     79 
     80 SK_DECLARE_STATIC_LAZY_PTR(SkData, empty, sk_new_empty_data, sk_unref_data);
     81 
     82 SkData* SkData::NewEmpty() {
     83     return SkRef(empty.get());
     84 }
     85 
     86 // assumes fPtr was allocated via sk_malloc
     87 static void sk_free_releaseproc(const void* ptr, size_t, void*) {
     88     sk_free((void*)ptr);
     89 }
     90 
     91 SkData* SkData::NewFromMalloc(const void* data, size_t length) {
     92     return new SkData(data, length, sk_free_releaseproc, NULL);
     93 }
     94 
     95 SkData* SkData::NewWithCopy(const void* src, size_t length) {
     96     SkASSERT(src);
     97     return PrivateNewWithCopy(src, length);
     98 }
     99 
    100 SkData* SkData::NewUninitialized(size_t length) {
    101     return PrivateNewWithCopy(NULL, length);
    102 }
    103 
    104 SkData* SkData::NewWithProc(const void* data, size_t length,
    105                             ReleaseProc proc, void* context) {
    106     return new SkData(data, length, proc, context);
    107 }
    108 
    109 // assumes fPtr was allocated with sk_fmmap
    110 static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
    111     sk_fmunmap(addr, length);
    112 }
    113 
    114 SkData* SkData::NewFromFILE(SkFILE* f) {
    115     size_t size;
    116     void* addr = sk_fmmap(f, &size);
    117     if (NULL == addr) {
    118         return NULL;
    119     }
    120 
    121     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
    122 }
    123 
    124 SkData* SkData::NewFromFileName(const char path[]) {
    125     SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
    126     if (NULL == f) {
    127         return NULL;
    128     }
    129     SkData* data = NewFromFILE(f);
    130     sk_fclose(f);
    131     return data;
    132 }
    133 
    134 SkData* SkData::NewFromFD(int fd) {
    135     size_t size;
    136     void* addr = sk_fdmmap(fd, &size);
    137     if (NULL == addr) {
    138         return NULL;
    139     }
    140 
    141     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
    142 }
    143 
    144 // assumes context is a SkData
    145 static void sk_dataref_releaseproc(const void*, size_t, void* context) {
    146     SkData* src = reinterpret_cast<SkData*>(context);
    147     src->unref();
    148 }
    149 
    150 SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
    151     /*
    152         We could, if we wanted/need to, just make a deep copy of src's data,
    153         rather than referencing it. This would duplicate the storage (of the
    154         subset amount) but would possibly allow src to go out of scope sooner.
    155      */
    156 
    157     size_t available = src->size();
    158     if (offset >= available || 0 == length) {
    159         return SkData::NewEmpty();
    160     }
    161     available -= offset;
    162     if (length > available) {
    163         length = available;
    164     }
    165     SkASSERT(length > 0);
    166 
    167     src->ref(); // this will be balanced in sk_dataref_releaseproc
    168     return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
    169                          const_cast<SkData*>(src));
    170 }
    171 
    172 SkData* SkData::NewWithCString(const char cstr[]) {
    173     size_t size;
    174     if (NULL == cstr) {
    175         cstr = "";
    176         size = 1;
    177     } else {
    178         size = strlen(cstr) + 1;
    179     }
    180     return NewWithCopy(cstr, size);
    181 }
    182 
    183 ///////////////////////////////////////////////////////////////////////////////
    184 
    185 SkData* SkData::NewFromStream(SkStream* stream, size_t size) {
    186     SkAutoDataUnref data(SkData::NewUninitialized(size));
    187     if (stream->read(data->writable_data(), size) != size) {
    188         return NULL;
    189     }
    190     return data.detach();
    191 }
    192 
    193