1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
63a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com */
73a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
83a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com#include "SkData.h"
997de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.org#include "SkLazyPtr.h"
1097de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.org#include "SkOSFile.h"
118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
133a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
143a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
153a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fPtr = ptr;
163a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fSize = size;
173a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fReleaseProc = proc;
183a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fReleaseProcContext = context;
193a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
203a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
213a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData::~SkData() {
223a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (fReleaseProc) {
233a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        fReleaseProc(fPtr, fSize, fReleaseProcContext);
243a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
253a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
263a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
27dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.combool SkData::equals(const SkData* other) const {
28dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    if (NULL == other) {
29dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com        return false;
30dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    }
31dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com
32dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
33dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com}
34dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com
353a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comsize_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
363a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    size_t available = fSize;
373a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (offset >= available || 0 == length) {
383a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        return 0;
393a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
403a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    available -= offset;
413a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (length > available) {
423a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        length = available;
433a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
443a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    SkASSERT(length > 0);
453a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
463a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    memcpy(buffer, this->bytes() + offset, length);
473a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    return length;
483a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
493a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
503a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com///////////////////////////////////////////////////////////////////////////////
513a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
5297de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.orgSkData* SkData::NewEmptyImpl() {
5397de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.org    return new SkData(NULL, 0, NULL, NULL);
541f81fd6546c111e21bc665657e976b9d842192dfcommit-bot@chromium.org}
5597de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.orgvoid SkData::DeleteEmpty(SkData* ptr) { SkDELETE(ptr); }
561f81fd6546c111e21bc665657e976b9d842192dfcommit-bot@chromium.org
573a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewEmpty() {
5897de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.org    SK_DECLARE_STATIC_LAZY_PTR(SkData, empty, NewEmptyImpl, DeleteEmpty);
5997de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.org    return SkRef(empty.get());
603a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
613a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
623a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com// assumes fPtr was allocated via sk_malloc
638a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.comstatic void sk_free_releaseproc(const void* ptr, size_t, void*) {
643a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    sk_free((void*)ptr);
653a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
663a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
678a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.comSkData* SkData::NewFromMalloc(const void* data, size_t length) {
688a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com    return new SkData(data, length, sk_free_releaseproc, NULL);
698a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com}
708a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com
713a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewWithCopy(const void* data, size_t length) {
723a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (0 == length) {
733a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        return SkData::NewEmpty();
743a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
753a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
768a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com    void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc
773a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    memcpy(copy, data, length);
788a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com    return new SkData(copy, length, sk_free_releaseproc, NULL);
793a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
803a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
813a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewWithProc(const void* data, size_t length,
828a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com                            ReleaseProc proc, void* context) {
833a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    return new SkData(data, length, proc, context);
843a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
853a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
866cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com// assumes fPtr was allocated with sk_fmmap
876cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comstatic void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
886cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    sk_fmunmap(addr, length);
899711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org}
909711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
919711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.orgSkData* SkData::NewFromFILE(SkFILE* f) {
926cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    size_t size;
936cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    void* addr = sk_fmmap(f, &size);
949711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org    if (NULL == addr) {
959711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org        return NULL;
969711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org    }
979711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
9811c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
9911c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com}
10011c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
101792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.orgSkData* SkData::NewFromFileName(const char path[]) {
102792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
103792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    if (NULL == f) {
104792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org        return NULL;
105792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    }
106792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    SkData* data = NewFromFILE(f);
107792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    sk_fclose(f);
108792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    return data;
109792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org}
110792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org
11111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.comSkData* SkData::NewFromFD(int fd) {
11211c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    size_t size;
11311c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    void* addr = sk_fdmmap(fd, &size);
11411c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (NULL == addr) {
11511c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com        return NULL;
11611c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    }
11711c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
1186cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
1199711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org}
1209711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
1216cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com// assumes context is a SkData
1226cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comstatic void sk_dataref_releaseproc(const void*, size_t, void* context) {
1236cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    SkData* src = reinterpret_cast<SkData*>(context);
1246cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    src->unref();
1259711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org}
1269711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
1273a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
1283a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    /*
1293a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        We could, if we wanted/need to, just make a deep copy of src's data,
1303a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        rather than referencing it. This would duplicate the storage (of the
1313a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        subset amount) but would possibly allow src to go out of scope sooner.
1323a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com     */
1333a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1343a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    size_t available = src->size();
1353a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (offset >= available || 0 == length) {
1363a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        return SkData::NewEmpty();
1373a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
1383a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    available -= offset;
1393a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (length > available) {
1403a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        length = available;
1413a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
1423a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    SkASSERT(length > 0);
1433a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1443a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    src->ref(); // this will be balanced in sk_dataref_releaseproc
1453a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
1463a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com                         const_cast<SkData*>(src));
1473a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
1483a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
149dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.comSkData* SkData::NewWithCString(const char cstr[]) {
150fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com    size_t size;
151fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com    if (NULL == cstr) {
152fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com        cstr = "";
153fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com        size = 1;
154dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    } else {
155fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com        size = strlen(cstr) + 1;
156dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    }
157fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com    return NewWithCopy(cstr, size);
158dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com}
159