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 "SkLazyPtr.h"
10#include "SkOSFile.h"
11#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
13
14SkData::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
21SkData::~SkData() {
22    if (fReleaseProc) {
23        fReleaseProc(fPtr, fSize, fReleaseProcContext);
24    }
25}
26
27bool 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
35size_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
52SkData* SkData::NewEmptyImpl() {
53    return new SkData(NULL, 0, NULL, NULL);
54}
55void SkData::DeleteEmpty(SkData* ptr) { SkDELETE(ptr); }
56
57SkData* SkData::NewEmpty() {
58    SK_DECLARE_STATIC_LAZY_PTR(SkData, empty, NewEmptyImpl, DeleteEmpty);
59    return SkRef(empty.get());
60}
61
62// assumes fPtr was allocated via sk_malloc
63static void sk_free_releaseproc(const void* ptr, size_t, void*) {
64    sk_free((void*)ptr);
65}
66
67SkData* SkData::NewFromMalloc(const void* data, size_t length) {
68    return new SkData(data, length, sk_free_releaseproc, NULL);
69}
70
71SkData* SkData::NewWithCopy(const void* data, size_t length) {
72    if (0 == length) {
73        return SkData::NewEmpty();
74    }
75
76    void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc
77    memcpy(copy, data, length);
78    return new SkData(copy, length, sk_free_releaseproc, NULL);
79}
80
81SkData* SkData::NewWithProc(const void* data, size_t length,
82                            ReleaseProc proc, void* context) {
83    return new SkData(data, length, proc, context);
84}
85
86// assumes fPtr was allocated with sk_fmmap
87static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
88    sk_fmunmap(addr, length);
89}
90
91SkData* SkData::NewFromFILE(SkFILE* f) {
92    size_t size;
93    void* addr = sk_fmmap(f, &size);
94    if (NULL == addr) {
95        return NULL;
96    }
97
98    return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
99}
100
101SkData* SkData::NewFromFileName(const char path[]) {
102    SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
103    if (NULL == f) {
104        return NULL;
105    }
106    SkData* data = NewFromFILE(f);
107    sk_fclose(f);
108    return data;
109}
110
111SkData* SkData::NewFromFD(int fd) {
112    size_t size;
113    void* addr = sk_fdmmap(fd, &size);
114    if (NULL == addr) {
115        return NULL;
116    }
117
118    return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
119}
120
121// assumes context is a SkData
122static void sk_dataref_releaseproc(const void*, size_t, void* context) {
123    SkData* src = reinterpret_cast<SkData*>(context);
124    src->unref();
125}
126
127SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
128    /*
129        We could, if we wanted/need to, just make a deep copy of src's data,
130        rather than referencing it. This would duplicate the storage (of the
131        subset amount) but would possibly allow src to go out of scope sooner.
132     */
133
134    size_t available = src->size();
135    if (offset >= available || 0 == length) {
136        return SkData::NewEmpty();
137    }
138    available -= offset;
139    if (length > available) {
140        length = available;
141    }
142    SkASSERT(length > 0);
143
144    src->ref(); // this will be balanced in sk_dataref_releaseproc
145    return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
146                         const_cast<SkData*>(src));
147}
148
149SkData* SkData::NewWithCString(const char cstr[]) {
150    size_t size;
151    if (NULL == cstr) {
152        cstr = "";
153        size = 1;
154    } else {
155        size = strlen(cstr) + 1;
156    }
157    return NewWithCopy(cstr, size);
158}
159