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 "SkOSFile.h"
     10 #include "SkOnce.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.
     23  *  Thus we set fPtr to point right after this.
     24  */
     25 SkData::SkData(size_t size) {
     26     fPtr = (char*)(this + 1);   // contents are immediately after this
     27     fSize = size;
     28     fReleaseProc = nullptr;
     29     fReleaseProcContext = nullptr;
     30 }
     31 
     32 SkData::~SkData() {
     33     if (fReleaseProc) {
     34         fReleaseProc(fPtr, fReleaseProcContext);
     35     }
     36 }
     37 
     38 bool SkData::equals(const SkData* other) const {
     39     if (nullptr == other) {
     40         return false;
     41     }
     42 
     43     return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
     44 }
     45 
     46 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
     47     size_t available = fSize;
     48     if (offset >= available || 0 == length) {
     49         return 0;
     50     }
     51     available -= offset;
     52     if (length > available) {
     53         length = available;
     54     }
     55     SkASSERT(length > 0);
     56 
     57     memcpy(buffer, this->bytes() + offset, length);
     58     return length;
     59 }
     60 
     61 sk_sp<SkData> SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
     62     if (0 == length) {
     63         return SkData::MakeEmpty();
     64     }
     65 
     66     const size_t actualLength = length + sizeof(SkData);
     67     SkASSERT_RELEASE(length < actualLength);  // Check for overflow.
     68 
     69     void* storage = ::operator new (actualLength);
     70     sk_sp<SkData> data(new (storage) SkData(length));
     71     if (srcOrNull) {
     72         memcpy(data->writable_data(), srcOrNull, length);
     73     }
     74     return data;
     75 }
     76 
     77 void SkData::DummyReleaseProc(const void*, void*) {}
     78 
     79 ///////////////////////////////////////////////////////////////////////////////
     80 
     81 sk_sp<SkData> SkData::MakeEmpty() {
     82     static SkOnce once;
     83     static SkData* empty;
     84 
     85     once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); });
     86     return sk_ref_sp(empty);
     87 }
     88 
     89 // assumes fPtr was allocated via sk_malloc
     90 static void sk_free_releaseproc(const void* ptr, void*) {
     91     sk_free((void*)ptr);
     92 }
     93 
     94 sk_sp<SkData> SkData::MakeFromMalloc(const void* data, size_t length) {
     95     return sk_sp<SkData>(new SkData(data, length, sk_free_releaseproc, nullptr));
     96 }
     97 
     98 sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) {
     99     SkASSERT(src);
    100     return PrivateNewWithCopy(src, length);
    101 }
    102 
    103 sk_sp<SkData> SkData::MakeUninitialized(size_t length) {
    104     return PrivateNewWithCopy(nullptr, length);
    105 }
    106 
    107 sk_sp<SkData> SkData::MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx) {
    108     return sk_sp<SkData>(new SkData(ptr, length, proc, ctx));
    109 }
    110 
    111 // assumes fPtr was allocated with sk_fmmap
    112 static void sk_mmap_releaseproc(const void* addr, void* ctx) {
    113     size_t length = reinterpret_cast<size_t>(ctx);
    114     sk_fmunmap(addr, length);
    115 }
    116 
    117 sk_sp<SkData> SkData::MakeFromFILE(FILE* f) {
    118     size_t size;
    119     void* addr = sk_fmmap(f, &size);
    120     if (nullptr == addr) {
    121         return nullptr;
    122     }
    123 
    124     return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
    125 }
    126 
    127 sk_sp<SkData> SkData::MakeFromFileName(const char path[]) {
    128     FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr;
    129     if (nullptr == f) {
    130         return nullptr;
    131     }
    132     auto data = MakeFromFILE(f);
    133     sk_fclose(f);
    134     return data;
    135 }
    136 
    137 sk_sp<SkData> SkData::MakeFromFD(int fd) {
    138     size_t size;
    139     void* addr = sk_fdmmap(fd, &size);
    140     if (nullptr == addr) {
    141         return nullptr;
    142     }
    143     return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
    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 sk_sp<SkData> SkData::MakeSubset(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::MakeEmpty();
    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 sk_sp<SkData>(new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
    171                                     const_cast<SkData*>(src)));
    172 }
    173 
    174 sk_sp<SkData> SkData::MakeWithCString(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 MakeWithCopy(cstr, size);
    183 }
    184 
    185 ///////////////////////////////////////////////////////////////////////////////
    186 
    187 sk_sp<SkData> SkData::MakeFromStream(SkStream* stream, size_t size) {
    188     sk_sp<SkData> data(SkData::MakeUninitialized(size));
    189     if (stream->read(data->writable_data(), size) != size) {
    190         return nullptr;
    191     }
    192     return data;
    193 }
    194