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 "SkOSFile.h"
10 #include "SkOnce.h"
11 #include "SkReadBuffer.h"
12 #include "SkStream.h"
13 #include "SkWriteBuffer.h"
14 #include <new>
15 
SkData(const void * ptr,size_t size,ReleaseProc proc,void * context)16 SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
17     fPtr = const_cast<void*>(ptr);
18     fSize = size;
19     fReleaseProc = proc;
20     fReleaseProcContext = context;
21 }
22 
23 /** This constructor means we are inline with our fPtr's contents.
24  *  Thus we set fPtr to point right after this.
25  */
SkData(size_t size)26 SkData::SkData(size_t size) {
27     fPtr = (char*)(this + 1);   // contents are immediately after this
28     fSize = size;
29     fReleaseProc = nullptr;
30     fReleaseProcContext = nullptr;
31 }
32 
~SkData()33 SkData::~SkData() {
34     if (fReleaseProc) {
35         fReleaseProc(fPtr, fReleaseProcContext);
36     }
37 }
38 
equals(const SkData * other) const39 bool SkData::equals(const SkData* other) const {
40     if (nullptr == other) {
41         return false;
42     }
43 
44     return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
45 }
46 
copyRange(size_t offset,size_t length,void * buffer) const47 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
48     size_t available = fSize;
49     if (offset >= available || 0 == length) {
50         return 0;
51     }
52     available -= offset;
53     if (length > available) {
54         length = available;
55     }
56     SkASSERT(length > 0);
57 
58     memcpy(buffer, this->bytes() + offset, length);
59     return length;
60 }
61 
operator delete(void * p)62 void SkData::operator delete(void* p) {
63     ::operator delete(p);
64 }
65 
PrivateNewWithCopy(const void * srcOrNull,size_t length)66 sk_sp<SkData> SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
67     if (0 == length) {
68         return SkData::MakeEmpty();
69     }
70 
71     const size_t actualLength = length + sizeof(SkData);
72     SkASSERT_RELEASE(length < actualLength);  // Check for overflow.
73 
74     void* storage = ::operator new (actualLength);
75     sk_sp<SkData> data(new (storage) SkData(length));
76     if (srcOrNull) {
77         memcpy(data->writable_data(), srcOrNull, length);
78     }
79     return data;
80 }
81 
DummyReleaseProc(const void *,void *)82 void SkData::DummyReleaseProc(const void*, void*) {}
83 
84 ///////////////////////////////////////////////////////////////////////////////
85 
MakeEmpty()86 sk_sp<SkData> SkData::MakeEmpty() {
87     static SkOnce once;
88     static SkData* empty;
89 
90     once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); });
91     return sk_ref_sp(empty);
92 }
93 
94 // assumes fPtr was allocated via sk_malloc
sk_free_releaseproc(const void * ptr,void *)95 static void sk_free_releaseproc(const void* ptr, void*) {
96     sk_free((void*)ptr);
97 }
98 
MakeFromMalloc(const void * data,size_t length)99 sk_sp<SkData> SkData::MakeFromMalloc(const void* data, size_t length) {
100     return sk_sp<SkData>(new SkData(data, length, sk_free_releaseproc, nullptr));
101 }
102 
MakeWithCopy(const void * src,size_t length)103 sk_sp<SkData> SkData::MakeWithCopy(const void* src, size_t length) {
104     SkASSERT(src);
105     return PrivateNewWithCopy(src, length);
106 }
107 
MakeUninitialized(size_t length)108 sk_sp<SkData> SkData::MakeUninitialized(size_t length) {
109     return PrivateNewWithCopy(nullptr, length);
110 }
111 
MakeWithProc(const void * ptr,size_t length,ReleaseProc proc,void * ctx)112 sk_sp<SkData> SkData::MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx) {
113     return sk_sp<SkData>(new SkData(ptr, length, proc, ctx));
114 }
115 
116 // assumes fPtr was allocated with sk_fmmap
sk_mmap_releaseproc(const void * addr,void * ctx)117 static void sk_mmap_releaseproc(const void* addr, void* ctx) {
118     size_t length = reinterpret_cast<size_t>(ctx);
119     sk_fmunmap(addr, length);
120 }
121 
MakeFromFILE(FILE * f)122 sk_sp<SkData> SkData::MakeFromFILE(FILE* f) {
123     size_t size;
124     void* addr = sk_fmmap(f, &size);
125     if (nullptr == addr) {
126         return nullptr;
127     }
128 
129     return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
130 }
131 
MakeFromFileName(const char path[])132 sk_sp<SkData> SkData::MakeFromFileName(const char path[]) {
133     FILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr;
134     if (nullptr == f) {
135         return nullptr;
136     }
137     auto data = MakeFromFILE(f);
138     sk_fclose(f);
139     return data;
140 }
141 
MakeFromFD(int fd)142 sk_sp<SkData> SkData::MakeFromFD(int fd) {
143     size_t size;
144     void* addr = sk_fdmmap(fd, &size);
145     if (nullptr == addr) {
146         return nullptr;
147     }
148     return SkData::MakeWithProc(addr, size, sk_mmap_releaseproc, reinterpret_cast<void*>(size));
149 }
150 
151 // assumes context is a SkData
sk_dataref_releaseproc(const void *,void * context)152 static void sk_dataref_releaseproc(const void*, void* context) {
153     SkData* src = reinterpret_cast<SkData*>(context);
154     src->unref();
155 }
156 
MakeSubset(const SkData * src,size_t offset,size_t length)157 sk_sp<SkData> SkData::MakeSubset(const SkData* src, size_t offset, size_t length) {
158     /*
159         We could, if we wanted/need to, just make a deep copy of src's data,
160         rather than referencing it. This would duplicate the storage (of the
161         subset amount) but would possibly allow src to go out of scope sooner.
162      */
163 
164     size_t available = src->size();
165     if (offset >= available || 0 == length) {
166         return SkData::MakeEmpty();
167     }
168     available -= offset;
169     if (length > available) {
170         length = available;
171     }
172     SkASSERT(length > 0);
173 
174     src->ref(); // this will be balanced in sk_dataref_releaseproc
175     return sk_sp<SkData>(new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
176                                     const_cast<SkData*>(src)));
177 }
178 
MakeWithCString(const char cstr[])179 sk_sp<SkData> SkData::MakeWithCString(const char cstr[]) {
180     size_t size;
181     if (nullptr == cstr) {
182         cstr = "";
183         size = 1;
184     } else {
185         size = strlen(cstr) + 1;
186     }
187     return MakeWithCopy(cstr, size);
188 }
189 
190 ///////////////////////////////////////////////////////////////////////////////
191 
MakeFromStream(SkStream * stream,size_t size)192 sk_sp<SkData> SkData::MakeFromStream(SkStream* stream, size_t size) {
193     sk_sp<SkData> data(SkData::MakeUninitialized(size));
194     if (stream->read(data->writable_data(), size) != size) {
195         return nullptr;
196     }
197     return data;
198 }
199