Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2020 Joe Drago. All rights reserved. |
2 | | // SPDX-License-Identifier: BSD-2-Clause |
3 | | |
4 | | #include "avif/internal.h" |
5 | | |
6 | | #include <limits.h> |
7 | | #include <stdio.h> |
8 | | #include <string.h> |
9 | | |
10 | | void avifIODestroy(avifIO * io) |
11 | 34.5k | { |
12 | 34.5k | if (io && io->destroy) { |
13 | 17.2k | io->destroy(io); |
14 | 17.2k | } |
15 | 34.5k | } |
16 | | |
17 | | // -------------------------------------------------------------------------------------- |
18 | | // avifIOMemoryReader |
19 | | |
20 | | typedef struct avifIOMemoryReader |
21 | | { |
22 | | avifIO io; // this must be the first member for easy casting to avifIO* |
23 | | avifROData rodata; |
24 | | } avifIOMemoryReader; |
25 | | |
26 | | static avifResult avifIOMemoryReaderRead(struct avifIO * io, uint32_t readFlags, uint64_t offset, size_t size, avifROData * out) |
27 | 104k | { |
28 | | // printf("avifIOMemoryReaderRead offset %" PRIu64 " size %zu\n", offset, size); |
29 | | |
30 | 104k | if (readFlags != 0) { |
31 | | // Unsupported readFlags |
32 | 0 | return AVIF_RESULT_IO_ERROR; |
33 | 0 | } |
34 | | |
35 | 104k | avifIOMemoryReader * reader = (avifIOMemoryReader *)io; |
36 | | |
37 | | // Sanitize/clamp incoming request |
38 | 104k | if (offset > reader->rodata.size) { |
39 | | // The offset is past the end of the buffer. |
40 | 0 | return AVIF_RESULT_IO_ERROR; |
41 | 0 | } |
42 | 104k | uint64_t availableSize = reader->rodata.size - offset; |
43 | 104k | if (size > availableSize) { |
44 | 940 | size = (size_t)availableSize; |
45 | 940 | } |
46 | | |
47 | | // Prevent the offset addition from triggering an undefined behavior |
48 | | // sanitizer error if data is NULL (happens even with offset zero). |
49 | 104k | out->data = offset ? reader->rodata.data + offset : reader->rodata.data; |
50 | 104k | out->size = size; |
51 | 104k | return AVIF_RESULT_OK; |
52 | 104k | } |
53 | | |
54 | | static void avifIOMemoryReaderDestroy(struct avifIO * io) |
55 | 17.2k | { |
56 | 17.2k | avifFree(io); |
57 | 17.2k | } |
58 | | |
59 | | avifIO * avifIOCreateMemoryReader(const uint8_t * data, size_t size) |
60 | 17.2k | { |
61 | 17.2k | avifIOMemoryReader * reader = (avifIOMemoryReader *)avifAlloc(sizeof(avifIOMemoryReader)); |
62 | 17.2k | if (reader == NULL) { |
63 | 0 | return NULL; |
64 | 0 | } |
65 | 17.2k | memset(reader, 0, sizeof(avifIOMemoryReader)); |
66 | 17.2k | reader->io.destroy = avifIOMemoryReaderDestroy; |
67 | 17.2k | reader->io.read = avifIOMemoryReaderRead; |
68 | 17.2k | reader->io.sizeHint = size; |
69 | 17.2k | reader->io.persistent = AVIF_TRUE; |
70 | 17.2k | reader->rodata.data = data; |
71 | 17.2k | reader->rodata.size = size; |
72 | 17.2k | return (avifIO *)reader; |
73 | 17.2k | } |
74 | | |
75 | | // -------------------------------------------------------------------------------------- |
76 | | // avifIOFileReader |
77 | | |
78 | | typedef struct avifIOFileReader |
79 | | { |
80 | | avifIO io; // this must be the first member for easy casting to avifIO* |
81 | | avifRWData buffer; |
82 | | FILE * f; |
83 | | } avifIOFileReader; |
84 | | |
85 | | static avifResult avifIOFileReaderRead(struct avifIO * io, uint32_t readFlags, uint64_t offset, size_t size, avifROData * out) |
86 | 0 | { |
87 | | // printf("avifIOFileReaderRead offset %" PRIu64 " size %zu\n", offset, size); |
88 | |
|
89 | 0 | if (readFlags != 0) { |
90 | | // Unsupported readFlags |
91 | 0 | return AVIF_RESULT_IO_ERROR; |
92 | 0 | } |
93 | | |
94 | 0 | avifIOFileReader * reader = (avifIOFileReader *)io; |
95 | | |
96 | | // Sanitize/clamp incoming request |
97 | 0 | if (offset > reader->io.sizeHint) { |
98 | | // The offset is past the EOF. |
99 | 0 | return AVIF_RESULT_IO_ERROR; |
100 | 0 | } |
101 | 0 | uint64_t availableSize = reader->io.sizeHint - offset; |
102 | 0 | if (size > availableSize) { |
103 | 0 | size = (size_t)availableSize; |
104 | 0 | } |
105 | |
|
106 | 0 | if (size > 0) { |
107 | 0 | if (offset > LONG_MAX) { |
108 | 0 | return AVIF_RESULT_IO_ERROR; |
109 | 0 | } |
110 | 0 | if (reader->buffer.size < size) { |
111 | 0 | AVIF_CHECKRES(avifRWDataRealloc(&reader->buffer, size)); |
112 | 0 | } |
113 | 0 | if (fseek(reader->f, (long)offset, SEEK_SET) != 0) { |
114 | 0 | return AVIF_RESULT_IO_ERROR; |
115 | 0 | } |
116 | 0 | size_t bytesRead = fread(reader->buffer.data, 1, size, reader->f); |
117 | 0 | if (size != bytesRead) { |
118 | 0 | if (ferror(reader->f)) { |
119 | 0 | return AVIF_RESULT_IO_ERROR; |
120 | 0 | } |
121 | 0 | size = bytesRead; |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | 0 | out->data = reader->buffer.data; |
126 | 0 | out->size = size; |
127 | 0 | return AVIF_RESULT_OK; |
128 | 0 | } |
129 | | |
130 | | static void avifIOFileReaderDestroy(struct avifIO * io) |
131 | 0 | { |
132 | 0 | avifIOFileReader * reader = (avifIOFileReader *)io; |
133 | 0 | fclose(reader->f); |
134 | 0 | avifRWDataFree(&reader->buffer); |
135 | 0 | avifFree(io); |
136 | 0 | } |
137 | | |
138 | | avifIO * avifIOCreateFileReader(const char * filename) |
139 | 0 | { |
140 | 0 | FILE * f = fopen(filename, "rb"); |
141 | 0 | if (!f) { |
142 | 0 | return NULL; |
143 | 0 | } |
144 | | |
145 | 0 | fseek(f, 0, SEEK_END); |
146 | 0 | long fileSize = ftell(f); |
147 | 0 | if (fileSize < 0) { |
148 | 0 | fclose(f); |
149 | 0 | return NULL; |
150 | 0 | } |
151 | 0 | fseek(f, 0, SEEK_SET); |
152 | |
|
153 | 0 | avifIOFileReader * reader = (avifIOFileReader *)avifAlloc(sizeof(avifIOFileReader)); |
154 | 0 | if (!reader) { |
155 | 0 | fclose(f); |
156 | 0 | return NULL; |
157 | 0 | } |
158 | 0 | memset(reader, 0, sizeof(avifIOFileReader)); |
159 | 0 | reader->f = f; |
160 | 0 | reader->io.destroy = avifIOFileReaderDestroy; |
161 | 0 | reader->io.read = avifIOFileReaderRead; |
162 | 0 | reader->io.sizeHint = (uint64_t)fileSize; |
163 | 0 | reader->io.persistent = AVIF_FALSE; |
164 | 0 | if (avifRWDataRealloc(&reader->buffer, 1024) != AVIF_RESULT_OK) { |
165 | 0 | avifFree(reader); |
166 | 0 | fclose(f); |
167 | 0 | return NULL; |
168 | 0 | } |
169 | 0 | return (avifIO *)reader; |
170 | 0 | } |