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