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 "SkOncePtr.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 = nullptr;
     30     fReleaseProcContext = nullptr;
     31 }
     32 
     33 SkData::~SkData() {
     34     if (fReleaseProc) {
     35         fReleaseProc(fPtr, fReleaseProcContext);
     36     }
     37 }
     38 
     39 bool SkData::equals(const SkData* other) const {
     40     if (nullptr == 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 
     67     const size_t actualLength = length + sizeof(SkData);
     68     if (actualLength < length) {
     69         // we overflowed
     70         sk_throw();
     71     }
     72 
     73     char* storage = (char*)sk_malloc_throw(actualLength);
     74     SkData* data = new (storage) SkData(length);
     75     if (srcOrNull) {
     76         memcpy(data->writable_data(), srcOrNull, length);
     77     }
     78     return data;
     79 }
     80 
     81 ///////////////////////////////////////////////////////////////////////////////
     82 
     83 SK_DECLARE_STATIC_ONCE_PTR(SkData, gEmpty);
     84 SkData* SkData::NewEmpty() {
     85     return SkRef(gEmpty.get([]{return new SkData(nullptr, 0, nullptr, nullptr); }));
     86 }
     87 
     88 // assumes fPtr was allocated via sk_malloc
     89 static void sk_free_releaseproc(const void* ptr, void*) {
     90     sk_free((void*)ptr);
     91 }
     92 
     93 SkData* SkData::NewFromMalloc(const void* data, size_t length) {
     94     return new SkData(data, length, sk_free_releaseproc, nullptr);
     95 }
     96 
     97 SkData* SkData::NewWithCopy(const void* src, size_t length) {
     98     SkASSERT(src);
     99     return PrivateNewWithCopy(src, length);
    100 }
    101 
    102 SkData* SkData::NewUninitialized(size_t length) {
    103     return PrivateNewWithCopy(nullptr, length);
    104 }
    105 
    106 SkData* SkData::NewWithProc(const void* ptr, size_t length, ReleaseProc proc, void* context) {
    107     return new SkData(ptr, length, proc, context);
    108 }
    109 
    110 // assumes fPtr was allocated with sk_fmmap
    111 static void sk_mmap_releaseproc(const void* addr, void* ctx) {
    112     size_t length = reinterpret_cast<size_t>(ctx);
    113     sk_fmunmap(addr, length);
    114 }
    115 
    116 SkData* SkData::NewFromFILE(FILE* f) {
    117     size_t size;
    118     void* addr = sk_fmmap(f, &size);
    119     if (nullptr == addr) {
    120         return nullptr;
    121     }
    122 
    123     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
    124 }
    125 
    126 SkData* SkData::NewFromFileName(const char path[]) {
    127     FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr;
    128     if (nullptr == f) {
    129         return nullptr;
    130     }
    131     SkData* data = NewFromFILE(f);
    132     sk_fclose(f);
    133     return data;
    134 }
    135 
    136 SkData* SkData::NewFromFD(int fd) {
    137     size_t size;
    138     void* addr = sk_fdmmap(fd, &size);
    139     if (nullptr == addr) {
    140         return nullptr;
    141     }
    142 
    143     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, nullptr);
    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 SkData* SkData::NewSubset(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::NewEmpty();
    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 new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
    171                          const_cast<SkData*>(src));
    172 }
    173 
    174 SkData* SkData::NewWithCString(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 NewWithCopy(cstr, size);
    183 }
    184 
    185 ///////////////////////////////////////////////////////////////////////////////
    186 
    187 SkData* SkData::NewFromStream(SkStream* stream, size_t size) {
    188     SkAutoDataUnref data(SkData::NewUninitialized(size));
    189     if (stream->read(data->writable_data(), size) != size) {
    190         return nullptr;
    191     }
    192     return data.detach();
    193 }
    194 
    195