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