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 "SkFlattenableBuffers.h"
     10 #include "SkOSFile.h"
     11 
     12 SK_DEFINE_INST_COUNT(SkData)
     13 
     14 SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
     15     fPtr = ptr;
     16     fSize = size;
     17     fReleaseProc = proc;
     18     fReleaseProcContext = context;
     19 }
     20 
     21 SkData::~SkData() {
     22     if (fReleaseProc) {
     23         fReleaseProc(fPtr, fSize, fReleaseProcContext);
     24     }
     25 }
     26 
     27 bool SkData::equals(const SkData* other) const {
     28     if (NULL == other) {
     29         return false;
     30     }
     31 
     32     return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
     33 }
     34 
     35 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
     36     size_t available = fSize;
     37     if (offset >= available || 0 == length) {
     38         return 0;
     39     }
     40     available -= offset;
     41     if (length > available) {
     42         length = available;
     43     }
     44     SkASSERT(length > 0);
     45 
     46     memcpy(buffer, this->bytes() + offset, length);
     47     return length;
     48 }
     49 
     50 ///////////////////////////////////////////////////////////////////////////////
     51 
     52 SkData* SkData::NewEmpty() {
     53     static SkData* gEmptyRef;
     54     if (NULL == gEmptyRef) {
     55         gEmptyRef = new SkData(NULL, 0, NULL, NULL);
     56     }
     57     gEmptyRef->ref();
     58     return gEmptyRef;
     59 }
     60 
     61 // assumes fPtr was allocated via sk_malloc
     62 static void sk_free_releaseproc(const void* ptr, size_t, void*) {
     63     sk_free((void*)ptr);
     64 }
     65 
     66 SkData* SkData::NewFromMalloc(const void* data, size_t length) {
     67     return new SkData(data, length, sk_free_releaseproc, NULL);
     68 }
     69 
     70 SkData* SkData::NewWithCopy(const void* data, size_t length) {
     71     if (0 == length) {
     72         return SkData::NewEmpty();
     73     }
     74 
     75     void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc
     76     memcpy(copy, data, length);
     77     return new SkData(copy, length, sk_free_releaseproc, NULL);
     78 }
     79 
     80 SkData* SkData::NewWithProc(const void* data, size_t length,
     81                             ReleaseProc proc, void* context) {
     82     return new SkData(data, length, proc, context);
     83 }
     84 
     85 // assumes fPtr was allocated with sk_fmmap
     86 static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
     87     sk_fmunmap(addr, length);
     88 }
     89 
     90 SkData* SkData::NewFromFILE(SkFILE* f) {
     91     size_t size;
     92     void* addr = sk_fmmap(f, &size);
     93     if (NULL == addr) {
     94         return NULL;
     95     }
     96 
     97     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
     98 }
     99 
    100 SkData* SkData::NewFromFileName(const char path[]) {
    101     SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
    102     if (NULL == f) {
    103         return NULL;
    104     }
    105     SkData* data = NewFromFILE(f);
    106     sk_fclose(f);
    107     return data;
    108 }
    109 
    110 SkData* SkData::NewFromFD(int fd) {
    111     size_t size;
    112     void* addr = sk_fdmmap(fd, &size);
    113     if (NULL == addr) {
    114         return NULL;
    115     }
    116 
    117     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
    118 }
    119 
    120 // assumes context is a SkData
    121 static void sk_dataref_releaseproc(const void*, size_t, void* context) {
    122     SkData* src = reinterpret_cast<SkData*>(context);
    123     src->unref();
    124 }
    125 
    126 SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
    127     /*
    128         We could, if we wanted/need to, just make a deep copy of src's data,
    129         rather than referencing it. This would duplicate the storage (of the
    130         subset amount) but would possibly allow src to go out of scope sooner.
    131      */
    132 
    133     size_t available = src->size();
    134     if (offset >= available || 0 == length) {
    135         return SkData::NewEmpty();
    136     }
    137     available -= offset;
    138     if (length > available) {
    139         length = available;
    140     }
    141     SkASSERT(length > 0);
    142 
    143     src->ref(); // this will be balanced in sk_dataref_releaseproc
    144     return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
    145                          const_cast<SkData*>(src));
    146 }
    147 
    148 SkData* SkData::NewWithCString(const char cstr[]) {
    149     size_t size;
    150     if (NULL == cstr) {
    151         cstr = "";
    152         size = 1;
    153     } else {
    154         size = strlen(cstr) + 1;
    155     }
    156     return NewWithCopy(cstr, size);
    157 }
    158 
    159 ///////////////////////////////////////////////////////////////////////////////
    160 
    161 void SkData::flatten(SkFlattenableWriteBuffer& buffer) const {
    162     buffer.writeByteArray(fPtr, fSize);
    163 }
    164 
    165 SkData::SkData(SkFlattenableReadBuffer& buffer) {
    166     fSize = buffer.getArrayCount();
    167     fReleaseProcContext = NULL;
    168 
    169     if (fSize > 0) {
    170         fPtr = sk_malloc_throw(fSize);
    171         fReleaseProc = sk_free_releaseproc;
    172     } else {
    173         fPtr = NULL;
    174         fReleaseProc = NULL;
    175     }
    176 
    177     buffer.readByteArray(const_cast<void*>(fPtr));
    178 }
    179 
    180 ///////////////////////////////////////////////////////////////////////////////
    181 ///////////////////////////////////////////////////////////////////////////////
    182 
    183 #include "SkDataSet.h"
    184 #include "SkFlattenable.h"
    185 #include "SkStream.h"
    186 
    187 static SkData* dupdata(SkData* data) {
    188     if (data) {
    189         data->ref();
    190     } else {
    191         data = SkData::NewEmpty();
    192     }
    193     return data;
    194 }
    195 
    196 static SkData* findValue(const char key[], const SkDataSet::Pair array[], int n) {
    197     for (int i = 0; i < n; ++i) {
    198         if (!strcmp(key, array[i].fKey)) {
    199             return array[i].fValue;
    200         }
    201     }
    202     return NULL;
    203 }
    204 
    205 static SkDataSet::Pair* allocatePairStorage(int count, size_t storage) {
    206     size_t size = count * sizeof(SkDataSet::Pair) + storage;
    207     return (SkDataSet::Pair*)sk_malloc_throw(size);
    208 }
    209 
    210 SkDataSet::SkDataSet(const char key[], SkData* value) {
    211     size_t keyLen = strlen(key);
    212 
    213     fCount = 1;
    214     fKeySize = keyLen + 1;
    215     fPairs = allocatePairStorage(1, keyLen + 1);
    216 
    217     fPairs[0].fKey = (char*)(fPairs + 1);
    218     memcpy(const_cast<char*>(fPairs[0].fKey), key, keyLen + 1);
    219 
    220     fPairs[0].fValue = dupdata(value);
    221 }
    222 
    223 SkDataSet::SkDataSet(const Pair array[], int count) {
    224     if (count < 1) {
    225         fCount = 0;
    226         fKeySize = 0;
    227         fPairs = NULL;
    228         return;
    229     }
    230 
    231     int i;
    232     size_t keySize = 0;
    233     for (i = 0; i < count; ++i) {
    234         keySize += strlen(array[i].fKey) + 1;
    235     }
    236 
    237     Pair* pairs = fPairs = allocatePairStorage(count, keySize);
    238     char* keyStorage = (char*)(pairs + count);
    239 
    240     keySize = 0;    // reset this, so we can compute the size for unique keys
    241     int uniqueCount = 0;
    242     for (int i = 0; i < count; ++i) {
    243         if (!findValue(array[i].fKey, pairs, uniqueCount)) {
    244             size_t len = strlen(array[i].fKey);
    245             memcpy(keyStorage, array[i].fKey, len + 1);
    246             pairs[uniqueCount].fKey = keyStorage;
    247             keyStorage += len + 1;
    248             keySize += len + 1;
    249 
    250             pairs[uniqueCount].fValue = dupdata(array[i].fValue);
    251             uniqueCount += 1;
    252         }
    253     }
    254     fCount = uniqueCount;
    255     fKeySize = keySize;
    256 }
    257 
    258 SkDataSet::~SkDataSet() {
    259     for (int i = 0; i < fCount; ++i) {
    260         fPairs[i].fValue->unref();
    261     }
    262     sk_free(fPairs);    // this also frees the key storage
    263 }
    264 
    265 SkData* SkDataSet::find(const char key[]) const {
    266     return findValue(key, fPairs, fCount);
    267 }
    268 
    269 void SkDataSet::writeToStream(SkWStream* stream) const {
    270     stream->write32(fCount);
    271     if (fCount > 0) {
    272         stream->write32(fKeySize);
    273         // our first key points to all the key storage
    274         stream->write(fPairs[0].fKey, fKeySize);
    275         for (int i = 0; i < fCount; ++i) {
    276             stream->writeData(fPairs[i].fValue);
    277         }
    278     }
    279 }
    280 
    281 void SkDataSet::flatten(SkFlattenableWriteBuffer& buffer) const {
    282     buffer.writeInt(fCount);
    283     if (fCount > 0) {
    284         buffer.writeByteArray(fPairs[0].fKey, fKeySize);
    285         for (int i = 0; i < fCount; ++i) {
    286             buffer.writeFlattenable(fPairs[i].fValue);
    287         }
    288     }
    289 }
    290 
    291 SkDataSet::SkDataSet(SkStream* stream) {
    292     fCount = stream->readU32();
    293     if (fCount > 0) {
    294         fKeySize = stream->readU32();
    295         fPairs = allocatePairStorage(fCount, fKeySize);
    296         char* keyStorage = (char*)(fPairs + fCount);
    297 
    298         stream->read(keyStorage, fKeySize);
    299 
    300         for (int i = 0; i < fCount; ++i) {
    301             fPairs[i].fKey = keyStorage;
    302             keyStorage += strlen(keyStorage) + 1;
    303             fPairs[i].fValue = stream->readData();
    304         }
    305     } else {
    306         fKeySize = 0;
    307         fPairs = NULL;
    308     }
    309 }
    310 
    311 SkDataSet::SkDataSet(SkFlattenableReadBuffer& buffer) {
    312     fCount = buffer.readInt();
    313     if (fCount > 0) {
    314         fKeySize = buffer.getArrayCount();
    315         fPairs = allocatePairStorage(fCount, fKeySize);
    316         char* keyStorage = (char*)(fPairs + fCount);
    317 
    318         buffer.readByteArray(keyStorage);
    319 
    320         for (int i = 0; i < fCount; ++i) {
    321             fPairs[i].fKey = keyStorage;
    322             keyStorage += strlen(keyStorage) + 1;
    323             fPairs[i].fValue = buffer.readFlattenableT<SkData>();
    324         }
    325     } else {
    326         fKeySize = 0;
    327         fPairs = NULL;
    328     }
    329 }
    330 
    331 SkDataSet* SkDataSet::NewEmpty() {
    332     static SkDataSet* gEmptySet;
    333     if (NULL == gEmptySet) {
    334         gEmptySet = SkNEW_ARGS(SkDataSet, (NULL, 0));
    335     }
    336     gEmptySet->ref();
    337     return gEmptySet;
    338 }
    339