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
153a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
1633a30503d76fdd989358cedd78445ba96bb809ddreed    fPtr = const_cast<void*>(ptr);
173a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fSize = size;
183a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fReleaseProc = proc;
193a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    fReleaseProcContext = context;
203a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
213a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
2233a30503d76fdd989358cedd78445ba96bb809ddreed// This constructor means we are inline with our fPtr's contents. Thus we set fPtr
2333a30503d76fdd989358cedd78445ba96bb809ddreed// to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc,
2433a30503d76fdd989358cedd78445ba96bb809ddreed// since we need to handle "delete" ourselves. See internal_displose().
2533a30503d76fdd989358cedd78445ba96bb809ddreed//
2633a30503d76fdd989358cedd78445ba96bb809ddreedSkData::SkData(size_t size) {
2733a30503d76fdd989358cedd78445ba96bb809ddreed    fPtr = (char*)(this + 1);   // contents are immediately after this
2833a30503d76fdd989358cedd78445ba96bb809ddreed    fSize = size;
29072803144a623f1a59eb73ca5f3ddf45222b5e06bsalomon    fReleaseProc = NULL;
3033a30503d76fdd989358cedd78445ba96bb809ddreed    fReleaseProcContext = NULL;
3133a30503d76fdd989358cedd78445ba96bb809ddreed}
3233a30503d76fdd989358cedd78445ba96bb809ddreed
333a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData::~SkData() {
343a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (fReleaseProc) {
353a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        fReleaseProc(fPtr, fSize, fReleaseProcContext);
363a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
373a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
383a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
39dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.combool SkData::equals(const SkData* other) const {
40dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    if (NULL == other) {
41dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com        return false;
42dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    }
43dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com
44dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
45dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com}
46dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com
473a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comsize_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
483a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    size_t available = fSize;
493a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (offset >= available || 0 == length) {
503a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        return 0;
513a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
523a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    available -= offset;
533a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (length > available) {
543a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        length = available;
553a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
563a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    SkASSERT(length > 0);
573a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
583a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    memcpy(buffer, this->bytes() + offset, length);
593a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    return length;
603a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
613a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
6233a30503d76fdd989358cedd78445ba96bb809ddreedSkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
6333a30503d76fdd989358cedd78445ba96bb809ddreed    if (0 == length) {
6433a30503d76fdd989358cedd78445ba96bb809ddreed        return SkData::NewEmpty();
6533a30503d76fdd989358cedd78445ba96bb809ddreed    }
6633a30503d76fdd989358cedd78445ba96bb809ddreed    char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length);
6733a30503d76fdd989358cedd78445ba96bb809ddreed    SkData* data = new (storage) SkData(length);
6833a30503d76fdd989358cedd78445ba96bb809ddreed    if (srcOrNull) {
6933a30503d76fdd989358cedd78445ba96bb809ddreed        memcpy(data->writable_data(), srcOrNull, length);
7033a30503d76fdd989358cedd78445ba96bb809ddreed    }
7133a30503d76fdd989358cedd78445ba96bb809ddreed    return data;
7233a30503d76fdd989358cedd78445ba96bb809ddreed}
7333a30503d76fdd989358cedd78445ba96bb809ddreed
743a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com///////////////////////////////////////////////////////////////////////////////
753a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
76148ec59001ca7d7e54aec580a048c6dd2a085991mtklein// As a template argument these must have external linkage.
77148ec59001ca7d7e54aec580a048c6dd2a085991mtkleinSkData* sk_new_empty_data() { return new SkData(NULL, 0, NULL, NULL); }
78148ec59001ca7d7e54aec580a048c6dd2a085991mtkleinnamespace { void sk_unref_data(SkData* ptr) { return SkSafeUnref(ptr); } }
7933a30503d76fdd989358cedd78445ba96bb809ddreed
80148ec59001ca7d7e54aec580a048c6dd2a085991mtkleinSK_DECLARE_STATIC_LAZY_PTR(SkData, empty, sk_new_empty_data, sk_unref_data);
811f81fd6546c111e21bc665657e976b9d842192dfcommit-bot@chromium.org
823a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewEmpty() {
8397de357270e54be53acb17e1cb4b4d5e25bacc01commit-bot@chromium.org    return SkRef(empty.get());
843a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
853a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
863a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com// assumes fPtr was allocated via sk_malloc
878a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.comstatic void sk_free_releaseproc(const void* ptr, size_t, void*) {
883a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    sk_free((void*)ptr);
893a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
903a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
918a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.comSkData* SkData::NewFromMalloc(const void* data, size_t length) {
928a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com    return new SkData(data, length, sk_free_releaseproc, NULL);
938a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com}
948a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com
9533a30503d76fdd989358cedd78445ba96bb809ddreedSkData* SkData::NewWithCopy(const void* src, size_t length) {
9633a30503d76fdd989358cedd78445ba96bb809ddreed    SkASSERT(src);
9733a30503d76fdd989358cedd78445ba96bb809ddreed    return PrivateNewWithCopy(src, length);
9833a30503d76fdd989358cedd78445ba96bb809ddreed}
993a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
10033a30503d76fdd989358cedd78445ba96bb809ddreedSkData* SkData::NewUninitialized(size_t length) {
10133a30503d76fdd989358cedd78445ba96bb809ddreed    return PrivateNewWithCopy(NULL, length);
1023a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
1033a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1043a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewWithProc(const void* data, size_t length,
1058a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com                            ReleaseProc proc, void* context) {
1063a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    return new SkData(data, length, proc, context);
1073a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
1083a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1096cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com// assumes fPtr was allocated with sk_fmmap
1106cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comstatic void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
1116cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    sk_fmunmap(addr, length);
1129711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org}
1139711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
1149711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.orgSkData* SkData::NewFromFILE(SkFILE* f) {
1156cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    size_t size;
1166cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    void* addr = sk_fmmap(f, &size);
1179711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org    if (NULL == addr) {
1189711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org        return NULL;
1199711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org    }
1209711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
12111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
12211c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com}
12311c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
124792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.orgSkData* SkData::NewFromFileName(const char path[]) {
125792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
126792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    if (NULL == f) {
127792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org        return NULL;
128792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    }
129792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    SkData* data = NewFromFILE(f);
130792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    sk_fclose(f);
131792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org    return data;
132792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org}
133792bbd14c63f217f2de0e6b2f8df99acb1928eeamike@reedtribe.org
13411c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.comSkData* SkData::NewFromFD(int fd) {
13511c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    size_t size;
13611c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    void* addr = sk_fdmmap(fd, &size);
13711c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (NULL == addr) {
13811c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com        return NULL;
13911c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    }
14011c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
1416cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
1429711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org}
1439711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
1446cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com// assumes context is a SkData
1456cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comstatic void sk_dataref_releaseproc(const void*, size_t, void* context) {
1466cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    SkData* src = reinterpret_cast<SkData*>(context);
1476cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    src->unref();
1489711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org}
1499711e446676e6bf84b3fff916fd1d7537933a110commit-bot@chromium.org
1503a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.comSkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
1513a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    /*
1523a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        We could, if we wanted/need to, just make a deep copy of src's data,
1533a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        rather than referencing it. This would duplicate the storage (of the
1543a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        subset amount) but would possibly allow src to go out of scope sooner.
1553a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com     */
1563a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1573a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    size_t available = src->size();
1583a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (offset >= available || 0 == length) {
1593a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        return SkData::NewEmpty();
1603a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
1613a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    available -= offset;
1623a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    if (length > available) {
1633a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com        length = available;
1643a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    }
1653a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    SkASSERT(length > 0);
1663a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
1673a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    src->ref(); // this will be balanced in sk_dataref_releaseproc
1683a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com    return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
1693a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com                         const_cast<SkData*>(src));
1703a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com}
1713a31ac1cf5d7d37da5a77ce18c43a62bf0781154reed@google.com
172dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.comSkData* SkData::NewWithCString(const char cstr[]) {
173fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com    size_t size;
174fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com    if (NULL == cstr) {
175fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com        cstr = "";
176fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com        size = 1;
177dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    } else {
178fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com        size = strlen(cstr) + 1;
179dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com    }
180fd59d1200073604c0a5dafe14edbb6f3833e1c3dreed@google.com    return NewWithCopy(cstr, size);
181dbc936dff3357f74fc60e124d912a2179b909b0dreed@google.com}
1829594da111dc1c36c1912eb61207aaa54c17ea550reed
1839594da111dc1c36c1912eb61207aaa54c17ea550reed///////////////////////////////////////////////////////////////////////////////
1849594da111dc1c36c1912eb61207aaa54c17ea550reed
1859594da111dc1c36c1912eb61207aaa54c17ea550reedSkData* SkData::NewFromStream(SkStream* stream, size_t size) {
1869594da111dc1c36c1912eb61207aaa54c17ea550reed    SkAutoDataUnref data(SkData::NewUninitialized(size));
1879594da111dc1c36c1912eb61207aaa54c17ea550reed    if (stream->read(data->writable_data(), size) != size) {
1889594da111dc1c36c1912eb61207aaa54c17ea550reed        return NULL;
1899594da111dc1c36c1912eb61207aaa54c17ea550reed    }
1909594da111dc1c36c1912eb61207aaa54c17ea550reed    return data.detach();
1919594da111dc1c36c1912eb61207aaa54c17ea550reed}
1929594da111dc1c36c1912eb61207aaa54c17ea550reed
193