1 | /* |
2 | * Copyright 2006 The Android Open Source Project |
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 | #ifndef SkStream_DEFINED |
9 | #define SkStream_DEFINED |
10 | |
11 | #include "include/core/SkData.h" |
12 | #include "include/core/SkRefCnt.h" |
13 | #include "include/core/SkScalar.h" |
14 | #include "include/private/SkTo.h" |
15 | |
16 | #include <memory.h> |
17 | |
18 | class SkStream; |
19 | class SkStreamRewindable; |
20 | class SkStreamSeekable; |
21 | class SkStreamAsset; |
22 | class SkStreamMemory; |
23 | |
24 | /** |
25 | * SkStream -- abstraction for a source of bytes. Subclasses can be backed by |
26 | * memory, or a file, or something else. |
27 | * |
28 | * NOTE: |
29 | * |
30 | * Classic "streams" APIs are sort of async, in that on a request for N |
31 | * bytes, they may return fewer than N bytes on a given call, in which case |
32 | * the caller can "try again" to get more bytes, eventually (modulo an error) |
33 | * receiving their total N bytes. |
34 | * |
35 | * Skia streams behave differently. They are effectively synchronous, and will |
36 | * always return all N bytes of the request if possible. If they return fewer |
37 | * (the read() call returns the number of bytes read) then that means there is |
38 | * no more data (at EOF or hit an error). The caller should *not* call again |
39 | * in hopes of fulfilling more of the request. |
40 | */ |
41 | class SK_API SkStream { |
42 | public: |
43 | virtual ~SkStream() {} |
44 | SkStream() {} |
45 | |
46 | /** |
47 | * Attempts to open the specified file as a stream, returns nullptr on failure. |
48 | */ |
49 | static std::unique_ptr<SkStreamAsset> MakeFromFile(const char path[]); |
50 | |
51 | /** Reads or skips size number of bytes. |
52 | * If buffer == NULL, skip size bytes, return how many were skipped. |
53 | * If buffer != NULL, copy size bytes into buffer, return how many were copied. |
54 | * @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer |
55 | * @param size the number of bytes to skip or copy |
56 | * @return the number of bytes actually read. |
57 | */ |
58 | virtual size_t read(void* buffer, size_t size) = 0; |
59 | |
60 | /** Skip size number of bytes. |
61 | * @return the actual number bytes that could be skipped. |
62 | */ |
63 | size_t skip(size_t size) { |
64 | return this->read(nullptr, size); |
65 | } |
66 | |
67 | /** |
68 | * Attempt to peek at size bytes. |
69 | * If this stream supports peeking, copy min(size, peekable bytes) into |
70 | * buffer, and return the number of bytes copied. |
71 | * If the stream does not support peeking, or cannot peek any bytes, |
72 | * return 0 and leave buffer unchanged. |
73 | * The stream is guaranteed to be in the same visible state after this |
74 | * call, regardless of success or failure. |
75 | * @param buffer Must not be NULL, and must be at least size bytes. Destination |
76 | * to copy bytes. |
77 | * @param size Number of bytes to copy. |
78 | * @return The number of bytes peeked/copied. |
79 | */ |
80 | virtual size_t peek(void* /*buffer*/, size_t /*size*/) const { return 0; } |
81 | |
82 | /** Returns true when all the bytes in the stream have been read. |
83 | * This may return true early (when there are no more bytes to be read) |
84 | * or late (after the first unsuccessful read). |
85 | */ |
86 | virtual bool isAtEnd() const = 0; |
87 | |
88 | bool SK_WARN_UNUSED_RESULT readS8(int8_t*); |
89 | bool SK_WARN_UNUSED_RESULT readS16(int16_t*); |
90 | bool SK_WARN_UNUSED_RESULT readS32(int32_t*); |
91 | |
92 | bool SK_WARN_UNUSED_RESULT readU8(uint8_t* i) { return this->readS8((int8_t*)i); } |
93 | bool SK_WARN_UNUSED_RESULT readU16(uint16_t* i) { return this->readS16((int16_t*)i); } |
94 | bool SK_WARN_UNUSED_RESULT readU32(uint32_t* i) { return this->readS32((int32_t*)i); } |
95 | |
96 | bool SK_WARN_UNUSED_RESULT readBool(bool* b) { |
97 | uint8_t i; |
98 | if (!this->readU8(&i)) { return false; } |
99 | *b = (i != 0); |
100 | return true; |
101 | } |
102 | bool SK_WARN_UNUSED_RESULT readScalar(SkScalar*); |
103 | bool SK_WARN_UNUSED_RESULT readPackedUInt(size_t*); |
104 | |
105 | //SkStreamRewindable |
106 | /** Rewinds to the beginning of the stream. Returns true if the stream is known |
107 | * to be at the beginning after this call returns. |
108 | */ |
109 | virtual bool rewind() { return false; } |
110 | |
111 | /** Duplicates this stream. If this cannot be done, returns NULL. |
112 | * The returned stream will be positioned at the beginning of its data. |
113 | */ |
114 | std::unique_ptr<SkStream> duplicate() const { |
115 | return std::unique_ptr<SkStream>(this->onDuplicate()); |
116 | } |
117 | /** Duplicates this stream. If this cannot be done, returns NULL. |
118 | * The returned stream will be positioned the same as this stream. |
119 | */ |
120 | std::unique_ptr<SkStream> fork() const { |
121 | return std::unique_ptr<SkStream>(this->onFork()); |
122 | } |
123 | |
124 | //SkStreamSeekable |
125 | /** Returns true if this stream can report it's current position. */ |
126 | virtual bool hasPosition() const { return false; } |
127 | /** Returns the current position in the stream. If this cannot be done, returns 0. */ |
128 | virtual size_t getPosition() const { return 0; } |
129 | |
130 | /** Seeks to an absolute position in the stream. If this cannot be done, returns false. |
131 | * If an attempt is made to seek past the end of the stream, the position will be set |
132 | * to the end of the stream. |
133 | */ |
134 | virtual bool seek(size_t /*position*/) { return false; } |
135 | |
136 | /** Seeks to an relative offset in the stream. If this cannot be done, returns false. |
137 | * If an attempt is made to move to a position outside the stream, the position will be set |
138 | * to the closest point within the stream (beginning or end). |
139 | */ |
140 | virtual bool move(long /*offset*/) { return false; } |
141 | |
142 | //SkStreamAsset |
143 | /** Returns true if this stream can report it's total length. */ |
144 | virtual bool hasLength() const { return false; } |
145 | /** Returns the total length of the stream. If this cannot be done, returns 0. */ |
146 | virtual size_t getLength() const { return 0; } |
147 | |
148 | //SkStreamMemory |
149 | /** Returns the starting address for the data. If this cannot be done, returns NULL. */ |
150 | //TODO: replace with virtual const SkData* getData() |
151 | virtual const void* getMemoryBase() { return nullptr; } |
152 | |
153 | private: |
154 | virtual SkStream* onDuplicate() const { return nullptr; } |
155 | virtual SkStream* onFork() const { return nullptr; } |
156 | |
157 | SkStream(SkStream&&) = delete; |
158 | SkStream(const SkStream&) = delete; |
159 | SkStream& operator=(SkStream&&) = delete; |
160 | SkStream& operator=(const SkStream&) = delete; |
161 | }; |
162 | |
163 | /** SkStreamRewindable is a SkStream for which rewind and duplicate are required. */ |
164 | class SK_API SkStreamRewindable : public SkStream { |
165 | public: |
166 | bool rewind() override = 0; |
167 | std::unique_ptr<SkStreamRewindable> duplicate() const { |
168 | return std::unique_ptr<SkStreamRewindable>(this->onDuplicate()); |
169 | } |
170 | private: |
171 | SkStreamRewindable* onDuplicate() const override = 0; |
172 | }; |
173 | |
174 | /** SkStreamSeekable is a SkStreamRewindable for which position, seek, move, and fork are required. */ |
175 | class SK_API SkStreamSeekable : public SkStreamRewindable { |
176 | public: |
177 | std::unique_ptr<SkStreamSeekable> duplicate() const { |
178 | return std::unique_ptr<SkStreamSeekable>(this->onDuplicate()); |
179 | } |
180 | |
181 | bool hasPosition() const override { return true; } |
182 | size_t getPosition() const override = 0; |
183 | bool seek(size_t position) override = 0; |
184 | bool move(long offset) override = 0; |
185 | |
186 | std::unique_ptr<SkStreamSeekable> fork() const { |
187 | return std::unique_ptr<SkStreamSeekable>(this->onFork()); |
188 | } |
189 | private: |
190 | SkStreamSeekable* onDuplicate() const override = 0; |
191 | SkStreamSeekable* onFork() const override = 0; |
192 | }; |
193 | |
194 | /** SkStreamAsset is a SkStreamSeekable for which getLength is required. */ |
195 | class SK_API SkStreamAsset : public SkStreamSeekable { |
196 | public: |
197 | bool hasLength() const override { return true; } |
198 | size_t getLength() const override = 0; |
199 | |
200 | std::unique_ptr<SkStreamAsset> duplicate() const { |
201 | return std::unique_ptr<SkStreamAsset>(this->onDuplicate()); |
202 | } |
203 | std::unique_ptr<SkStreamAsset> fork() const { |
204 | return std::unique_ptr<SkStreamAsset>(this->onFork()); |
205 | } |
206 | private: |
207 | SkStreamAsset* onDuplicate() const override = 0; |
208 | SkStreamAsset* onFork() const override = 0; |
209 | }; |
210 | |
211 | /** SkStreamMemory is a SkStreamAsset for which getMemoryBase is required. */ |
212 | class SK_API SkStreamMemory : public SkStreamAsset { |
213 | public: |
214 | const void* getMemoryBase() override = 0; |
215 | |
216 | std::unique_ptr<SkStreamMemory> duplicate() const { |
217 | return std::unique_ptr<SkStreamMemory>(this->onDuplicate()); |
218 | } |
219 | std::unique_ptr<SkStreamMemory> fork() const { |
220 | return std::unique_ptr<SkStreamMemory>(this->onFork()); |
221 | } |
222 | private: |
223 | SkStreamMemory* onDuplicate() const override = 0; |
224 | SkStreamMemory* onFork() const override = 0; |
225 | }; |
226 | |
227 | class SK_API SkWStream { |
228 | public: |
229 | virtual ~SkWStream(); |
230 | SkWStream() {} |
231 | |
232 | /** Called to write bytes to a SkWStream. Returns true on success |
233 | @param buffer the address of at least size bytes to be written to the stream |
234 | @param size The number of bytes in buffer to write to the stream |
235 | @return true on success |
236 | */ |
237 | virtual bool write(const void* buffer, size_t size) = 0; |
238 | virtual void flush(); |
239 | |
240 | virtual size_t bytesWritten() const = 0; |
241 | |
242 | // helpers |
243 | |
244 | bool write8(U8CPU value) { |
245 | uint8_t v = SkToU8(value); |
246 | return this->write(&v, 1); |
247 | } |
248 | bool write16(U16CPU value) { |
249 | uint16_t v = SkToU16(value); |
250 | return this->write(&v, 2); |
251 | } |
252 | bool write32(uint32_t v) { |
253 | return this->write(&v, 4); |
254 | } |
255 | |
256 | bool writeText(const char text[]) { |
257 | SkASSERT(text); |
258 | return this->write(text, strlen(text)); |
259 | } |
260 | |
261 | bool newline() { return this->write("\n" , strlen("\n" )); } |
262 | |
263 | bool writeDecAsText(int32_t); |
264 | bool writeBigDecAsText(int64_t, int minDigits = 0); |
265 | bool writeHexAsText(uint32_t, int minDigits = 0); |
266 | bool writeScalarAsText(SkScalar); |
267 | |
268 | bool writeBool(bool v) { return this->write8(v); } |
269 | bool writeScalar(SkScalar); |
270 | bool writePackedUInt(size_t); |
271 | |
272 | bool writeStream(SkStream* input, size_t length); |
273 | |
274 | /** |
275 | * This returns the number of bytes in the stream required to store |
276 | * 'value'. |
277 | */ |
278 | static int SizeOfPackedUInt(size_t value); |
279 | |
280 | private: |
281 | SkWStream(const SkWStream&) = delete; |
282 | SkWStream& operator=(const SkWStream&) = delete; |
283 | }; |
284 | |
285 | class SK_API SkNullWStream : public SkWStream { |
286 | public: |
287 | SkNullWStream() : fBytesWritten(0) {} |
288 | |
289 | bool write(const void* , size_t n) override { fBytesWritten += n; return true; } |
290 | void flush() override {} |
291 | size_t bytesWritten() const override { return fBytesWritten; } |
292 | |
293 | private: |
294 | size_t fBytesWritten; |
295 | }; |
296 | |
297 | //////////////////////////////////////////////////////////////////////////////////////// |
298 | |
299 | #include <stdio.h> |
300 | |
301 | /** A stream that wraps a C FILE* file stream. */ |
302 | class SK_API SkFILEStream : public SkStreamAsset { |
303 | public: |
304 | /** Initialize the stream by calling sk_fopen on the specified path. |
305 | * This internal stream will be closed in the destructor. |
306 | */ |
307 | explicit SkFILEStream(const char path[] = nullptr); |
308 | |
309 | /** Initialize the stream with an existing C FILE stream. |
310 | * The current position of the C FILE stream will be considered the |
311 | * beginning of the SkFILEStream. |
312 | * The C FILE stream will be closed in the destructor. |
313 | */ |
314 | explicit SkFILEStream(FILE* file); |
315 | |
316 | ~SkFILEStream() override; |
317 | |
318 | static std::unique_ptr<SkFILEStream> Make(const char path[]) { |
319 | std::unique_ptr<SkFILEStream> stream(new SkFILEStream(path)); |
320 | return stream->isValid() ? std::move(stream) : nullptr; |
321 | } |
322 | |
323 | /** Returns true if the current path could be opened. */ |
324 | bool isValid() const { return fFILE != nullptr; } |
325 | |
326 | /** Close this SkFILEStream. */ |
327 | void close(); |
328 | |
329 | size_t read(void* buffer, size_t size) override; |
330 | bool isAtEnd() const override; |
331 | |
332 | bool rewind() override; |
333 | std::unique_ptr<SkStreamAsset> duplicate() const { |
334 | return std::unique_ptr<SkStreamAsset>(this->onDuplicate()); |
335 | } |
336 | |
337 | size_t getPosition() const override; |
338 | bool seek(size_t position) override; |
339 | bool move(long offset) override; |
340 | |
341 | std::unique_ptr<SkStreamAsset> fork() const { |
342 | return std::unique_ptr<SkStreamAsset>(this->onFork()); |
343 | } |
344 | |
345 | size_t getLength() const override; |
346 | |
347 | private: |
348 | explicit SkFILEStream(std::shared_ptr<FILE>, size_t size, size_t offset); |
349 | explicit SkFILEStream(std::shared_ptr<FILE>, size_t size, size_t offset, size_t originalOffset); |
350 | |
351 | SkStreamAsset* onDuplicate() const override; |
352 | SkStreamAsset* onFork() const override; |
353 | |
354 | std::shared_ptr<FILE> fFILE; |
355 | // My own council will I keep on sizes and offsets. |
356 | size_t fSize; |
357 | size_t fOffset; |
358 | size_t fOriginalOffset; |
359 | |
360 | typedef SkStreamAsset INHERITED; |
361 | }; |
362 | |
363 | class SK_API SkMemoryStream : public SkStreamMemory { |
364 | public: |
365 | SkMemoryStream(); |
366 | |
367 | /** We allocate (and free) the memory. Write to it via getMemoryBase() */ |
368 | SkMemoryStream(size_t length); |
369 | |
370 | /** If copyData is true, the stream makes a private copy of the data. */ |
371 | SkMemoryStream(const void* data, size_t length, bool copyData = false); |
372 | |
373 | /** Creates the stream to read from the specified data */ |
374 | SkMemoryStream(sk_sp<SkData> data); |
375 | |
376 | /** Returns a stream with a copy of the input data. */ |
377 | static std::unique_ptr<SkMemoryStream> MakeCopy(const void* data, size_t length); |
378 | |
379 | /** Returns a stream with a bare pointer reference to the input data. */ |
380 | static std::unique_ptr<SkMemoryStream> MakeDirect(const void* data, size_t length); |
381 | |
382 | /** Returns a stream with a shared reference to the input data. */ |
383 | static std::unique_ptr<SkMemoryStream> Make(sk_sp<SkData> data); |
384 | |
385 | /** Resets the stream to the specified data and length, |
386 | just like the constructor. |
387 | if copyData is true, the stream makes a private copy of the data |
388 | */ |
389 | virtual void setMemory(const void* data, size_t length, |
390 | bool copyData = false); |
391 | /** Replace any memory buffer with the specified buffer. The caller |
392 | must have allocated data with sk_malloc or sk_realloc, since it |
393 | will be freed with sk_free. |
394 | */ |
395 | void setMemoryOwned(const void* data, size_t length); |
396 | |
397 | sk_sp<SkData> asData() const { return fData; } |
398 | void setData(sk_sp<SkData> data); |
399 | |
400 | void skipToAlign4(); |
401 | const void* getAtPos(); |
402 | |
403 | size_t read(void* buffer, size_t size) override; |
404 | bool isAtEnd() const override; |
405 | |
406 | size_t peek(void* buffer, size_t size) const override; |
407 | |
408 | bool rewind() override; |
409 | |
410 | std::unique_ptr<SkMemoryStream> duplicate() const { |
411 | return std::unique_ptr<SkMemoryStream>(this->onDuplicate()); |
412 | } |
413 | |
414 | size_t getPosition() const override; |
415 | bool seek(size_t position) override; |
416 | bool move(long offset) override; |
417 | |
418 | std::unique_ptr<SkMemoryStream> fork() const { |
419 | return std::unique_ptr<SkMemoryStream>(this->onFork()); |
420 | } |
421 | |
422 | size_t getLength() const override; |
423 | |
424 | const void* getMemoryBase() override; |
425 | |
426 | private: |
427 | SkMemoryStream* onDuplicate() const override; |
428 | SkMemoryStream* onFork() const override; |
429 | |
430 | sk_sp<SkData> fData; |
431 | size_t fOffset; |
432 | |
433 | typedef SkStreamMemory INHERITED; |
434 | }; |
435 | |
436 | ///////////////////////////////////////////////////////////////////////////////////////////// |
437 | |
438 | class SK_API SkFILEWStream : public SkWStream { |
439 | public: |
440 | SkFILEWStream(const char path[]); |
441 | ~SkFILEWStream() override; |
442 | |
443 | /** Returns true if the current path could be opened. |
444 | */ |
445 | bool isValid() const { return fFILE != nullptr; } |
446 | |
447 | bool write(const void* buffer, size_t size) override; |
448 | void flush() override; |
449 | void fsync(); |
450 | size_t bytesWritten() const override; |
451 | |
452 | private: |
453 | FILE* fFILE; |
454 | |
455 | typedef SkWStream INHERITED; |
456 | }; |
457 | |
458 | class SK_API SkDynamicMemoryWStream : public SkWStream { |
459 | public: |
460 | SkDynamicMemoryWStream() = default; |
461 | SkDynamicMemoryWStream(SkDynamicMemoryWStream&&); |
462 | SkDynamicMemoryWStream& operator=(SkDynamicMemoryWStream&&); |
463 | ~SkDynamicMemoryWStream() override; |
464 | |
465 | bool write(const void* buffer, size_t size) override; |
466 | size_t bytesWritten() const override; |
467 | |
468 | bool read(void* buffer, size_t offset, size_t size); |
469 | |
470 | /** More efficient version of read(dst, 0, bytesWritten()). */ |
471 | void copyTo(void* dst) const; |
472 | bool writeToStream(SkWStream* dst) const; |
473 | |
474 | /** Equivalent to copyTo() followed by reset(), but may save memory use. */ |
475 | void copyToAndReset(void* dst); |
476 | |
477 | /** Equivalent to writeToStream() followed by reset(), but may save memory use. */ |
478 | bool writeToAndReset(SkWStream* dst); |
479 | |
480 | /** Equivalent to writeToStream() followed by reset(), but may save memory use. |
481 | When the dst is also a SkDynamicMemoryWStream, the implementation is constant time. */ |
482 | bool writeToAndReset(SkDynamicMemoryWStream* dst); |
483 | |
484 | /** Prepend this stream to dst, resetting this. */ |
485 | void prependToAndReset(SkDynamicMemoryWStream* dst); |
486 | |
487 | /** Return the contents as SkData, and then reset the stream. */ |
488 | sk_sp<SkData> detachAsData(); |
489 | |
490 | /** Reset, returning a reader stream with the current content. */ |
491 | std::unique_ptr<SkStreamAsset> detachAsStream(); |
492 | |
493 | /** Reset the stream to its original, empty, state. */ |
494 | void reset(); |
495 | void padToAlign4(); |
496 | private: |
497 | struct Block; |
498 | Block* fHead = nullptr; |
499 | Block* fTail = nullptr; |
500 | size_t fBytesWrittenBeforeTail = 0; |
501 | |
502 | #ifdef SK_DEBUG |
503 | void validate() const; |
504 | #else |
505 | void validate() const {} |
506 | #endif |
507 | |
508 | // For access to the Block type. |
509 | friend class SkBlockMemoryStream; |
510 | friend class SkBlockMemoryRefCnt; |
511 | |
512 | typedef SkWStream INHERITED; |
513 | }; |
514 | |
515 | #endif |
516 | |