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