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"
129594da111dc1c36c1912eb61207aaa54c17ea550reed#include "SkStream.h"
138b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
143a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1533a30503d76fdd989358cedd78445ba96bb809ddreedstatic void sk_inplace_sentinel_releaseproc(const void*, size_t, void*) {
1633a30503d76fdd989358cedd78445ba96bb809ddreed    // we should never get called, as we are just a sentinel
1733a30503d76fdd989358cedd78445ba96bb809ddreed    sk_throw();
1833a30503d76fdd989358cedd78445ba96bb809ddreed}
1933a30503d76fdd989358cedd78445ba96bb809ddreed
203a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
2133a30503d76fdd989358cedd78445ba96bb809ddreed    fPtr = const_cast<void*>(ptr);
223a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fSize = size;
233a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fReleaseProc = proc;
243a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fReleaseProcContext = context;
253a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
263a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
2733a30503d76fdd989358cedd78445ba96bb809ddreed// This constructor means we are inline with our fPtr's contents. Thus we set fPtr
2833a30503d76fdd989358cedd78445ba96bb809ddreed// to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc,
2933a30503d76fdd989358cedd78445ba96bb809ddreed// since we need to handle "delete" ourselves. See internal_displose().
3033a30503d76fdd989358cedd78445ba96bb809ddreed//
3133a30503d76fdd989358cedd78445ba96bb809ddreedSkData::SkData(size_t size) {
3233a30503d76fdd989358cedd78445ba96bb809ddreed    fPtr = (char*)(this + 1);   // contents are immediately after this
3333a30503d76fdd989358cedd78445ba96bb809ddreed    fSize = size;
3433a30503d76fdd989358cedd78445ba96bb809ddreed    fReleaseProc = sk_inplace_sentinel_releaseproc;
3533a30503d76fdd989358cedd78445ba96bb809ddreed    fReleaseProcContext = NULL;
3633a30503d76fdd989358cedd78445ba96bb809ddreed}
3733a30503d76fdd989358cedd78445ba96bb809ddreed
383a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData::~SkData() {
393a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (fReleaseProc) {
403a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        fReleaseProc(fPtr, fSize, fReleaseProcContext);
413a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
423a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
433a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
4433a30503d76fdd989358cedd78445ba96bb809ddreedvoid SkData::internal_dispose() const {
4533a30503d76fdd989358cedd78445ba96bb809ddreed    if (sk_inplace_sentinel_releaseproc == fReleaseProc) {
4633a30503d76fdd989358cedd78445ba96bb809ddreed        const_cast<SkData*>(this)->fReleaseProc = NULL;    // so we don't call it in our destructor
4733a30503d76fdd989358cedd78445ba96bb809ddreed
4833a30503d76fdd989358cedd78445ba96bb809ddreed        this->internal_dispose_restore_refcnt_to_1();
4933a30503d76fdd989358cedd78445ba96bb809ddreed        this->~SkData();        // explicitly call this for refcnt bookkeeping
5033a30503d76fdd989358cedd78445ba96bb809ddreed
5133a30503d76fdd989358cedd78445ba96bb809ddreed        sk_free(const_cast<SkData*>(this));
5233a30503d76fdd989358cedd78445ba96bb809ddreed    } else {
5333a30503d76fdd989358cedd78445ba96bb809ddreed        this->internal_dispose_restore_refcnt_to_1();
5433a30503d76fdd989358cedd78445ba96bb809ddreed        SkDELETE(this);
5533a30503d76fdd989358cedd78445ba96bb809ddreed    }
5633a30503d76fdd989358cedd78445ba96bb809ddreed}
5733a30503d76fdd989358cedd78445ba96bb809ddreed
58dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.combool SkData::equals(const SkData* other) const {
59dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    if (NULL == other) {
60dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com        return false;
61dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    }
62dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com
63dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
64dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com}
65dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com
663a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comsize_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
673a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    size_t available = fSize;
683a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (offset >= available || 0 == length) {
693a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        return 0;
703a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
713a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    available -= offset;
723a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (length > available) {
733a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        length = available;
743a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
753a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    SkASSERT(length > 0);
763a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
773a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    memcpy(buffer, this->bytes() + offset, length);
783a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    return length;
793a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
803a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
8133a30503d76fdd989358cedd78445ba96bb809ddreedSkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
8233a30503d76fdd989358cedd78445ba96bb809ddreed    if (0 == length) {
8333a30503d76fdd989358cedd78445ba96bb809ddreed        return SkData::NewEmpty();
8433a30503d76fdd989358cedd78445ba96bb809ddreed    }
8533a30503d76fdd989358cedd78445ba96bb809ddreed    char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length);
8633a30503d76fdd989358cedd78445ba96bb809ddreed    SkData* data = new (storage) SkData(length);
8733a30503d76fdd989358cedd78445ba96bb809ddreed    if (srcOrNull) {
8833a30503d76fdd989358cedd78445ba96bb809ddreed        memcpy(data->writable_data(), srcOrNull, length);
8933a30503d76fdd989358cedd78445ba96bb809ddreed    }
9033a30503d76fdd989358cedd78445ba96bb809ddreed    return data;
9133a30503d76fdd989358cedd78445ba96bb809ddreed}
9233a30503d76fdd989358cedd78445ba96bb809ddreed
933a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com///////////////////////////////////////////////////////////////////////////////
943a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
9597de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.orgSkData* SkData::NewEmptyImpl() {
9697de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.org    return new SkData(NULL, 0, NULL, NULL);
971f81fd6546c111e21bc665657e976b9d842192dfcommit-bot@chromium.org}
9833a30503d76fdd989358cedd78445ba96bb809ddreed
9997de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.orgvoid SkData::DeleteEmpty(SkData* ptr) { SkDELETE(ptr); }
1001f81fd6546c111e21bc665657e976b9d842192dfcommit-bot@chromium.org
1013a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewEmpty() {
10297de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.org    SK_DECLARE_STATIC_LAZY_PTR(SkData, empty, NewEmptyImpl, DeleteEmpty);
10397de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.org    return SkRef(empty.get());
1043a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
1053a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1063a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com// assumes fPtr was allocated via sk_malloc
1078a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.comstatic void sk_free_releaseproc(const void* ptr, size_t, void*) {
1083a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    sk_free((void*)ptr);
1093a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
1103a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1118a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.comSkData* SkData::NewFromMalloc(const void* data, size_t length) {
1128a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com    return new SkData(data, length, sk_free_releaseproc, NULL);
1138a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com}
1148a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com
11533a30503d76fdd989358cedd78445ba96bb809ddreedSkData* SkData::NewWithCopy(const void* src, size_t length) {
11633a30503d76fdd989358cedd78445ba96bb809ddreed    SkASSERT(src);
11733a30503d76fdd989358cedd78445ba96bb809ddreed    return PrivateNewWithCopy(src, length);
11833a30503d76fdd989358cedd78445ba96bb809ddreed}
1193a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
12033a30503d76fdd989358cedd78445ba96bb809ddreedSkData* SkData::NewUninitialized(size_t length) {
12133a30503d76fdd989358cedd78445ba96bb809ddreed    return PrivateNewWithCopy(NULL, length);
1223a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
1233a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1243a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewWithProc(const void* data, size_t length,
1258a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com                            ReleaseProc proc, void* context) {
1263a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    return new SkData(data, length, proc, context);
1273a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
1283a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1296cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com// assumes fPtr was allocated with sk_fmmap
1306cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comstatic void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
1316cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    sk_fmunmap(addr, length);
1329711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org}
1339711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
1349711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.orgSkData* SkData::NewFromFILE(SkFILE* f) {
1356cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    size_t size;
1366cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    void* addr = sk_fmmap(f, &size);
1379711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org    if (NULL == addr) {
1389711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org        return NULL;
1399711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org    }
1409711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
14111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
14211c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com}
14311c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
144792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.orgSkData* SkData::NewFromFileName(const char path[]) {
145792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
146792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    if (NULL == f) {
147792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org        return NULL;
148792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    }
149792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    SkData* data = NewFromFILE(f);
150792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    sk_fclose(f);
151792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    return data;
152792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org}
153792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org
15411c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.comSkData* SkData::NewFromFD(int fd) {
15511c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    size_t size;
15611c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    void* addr = sk_fdmmap(fd, &size);
15711c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (NULL == addr) {
15811c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com        return NULL;
15911c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    }
16011c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
1616cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
1629711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org}
1639711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
1646cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com// assumes context is a SkData
1656cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comstatic void sk_dataref_releaseproc(const void*, size_t, void* context) {
1666cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    SkData* src = reinterpret_cast<SkData*>(context);
1676cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    src->unref();
1689711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org}
1699711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
1703a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
1713a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    /*
1723a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        We could, if we wanted/need to, just make a deep copy of src's data,
1733a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        rather than referencing it. This would duplicate the storage (of the
1743a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        subset amount) but would possibly allow src to go out of scope sooner.
1753a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com     */
1763a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1773a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    size_t available = src->size();
1783a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (offset >= available || 0 == length) {
1793a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        return SkData::NewEmpty();
1803a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
1813a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    available -= offset;
1823a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (length > available) {
1833a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        length = available;
1843a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
1853a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    SkASSERT(length > 0);
1863a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1873a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    src->ref(); // this will be balanced in sk_dataref_releaseproc
1883a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
1893a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com                         const_cast<SkData*>(src));
1903a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
1913a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
192dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.comSkData* SkData::NewWithCString(const char cstr[]) {
193fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com    size_t size;
194fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com    if (NULL == cstr) {
195fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com        cstr = "";
196fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com        size = 1;
197dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    } else {
198fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com        size = strlen(cstr) + 1;
199dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    }
200fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com    return NewWithCopy(cstr, size);
201dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com}
2029594da111dc1c36c1912eb61207aaa54c17ea550reed
2039594da111dc1c36c1912eb61207aaa54c17ea550reed///////////////////////////////////////////////////////////////////////////////
2049594da111dc1c36c1912eb61207aaa54c17ea550reed
2059594da111dc1c36c1912eb61207aaa54c17ea550reedSkData* SkData::NewFromStream(SkStream* stream, size_t size) {
2069594da111dc1c36c1912eb61207aaa54c17ea550reed    SkAutoDataUnref data(SkData::NewUninitialized(size));
2079594da111dc1c36c1912eb61207aaa54c17ea550reed    if (stream->read(data->writable_data(), size) != size) {
2089594da111dc1c36c1912eb61207aaa54c17ea550reed        return NULL;
2099594da111dc1c36c1912eb61207aaa54c17ea550reed    }
2109594da111dc1c36c1912eb61207aaa54c17ea550reed    return data.detach();
2119594da111dc1c36c1912eb61207aaa54c17ea550reed}
2129594da111dc1c36c1912eb61207aaa54c17ea550reed
213