blob: 54cefeccbb22f3457b2f250ef8a655e458419613 [file] [log] [blame]
Joe Dragobe4cbb92020-09-21 12:14:05 -07001// Copyright 2020 Joe Drago. All rights reserved.
2// SPDX-License-Identifier: BSD-2-Clause
3
4#include "avif/internal.h"
5
6#include <stdio.h>
7#include <string.h>
8
9void avifIODestroy(avifIO * io)
10{
11 if (io && io->destroy) {
12 io->destroy(io);
13 }
14}
15
16// --------------------------------------------------------------------------------------
17// avifIOMemoryReader
18
19typedef struct avifIOMemoryReader
20{
21 avifIO io; // this must be the first member for easy casting to avifIO*
22 avifROData rodata;
23} avifIOMemoryReader;
24
25static avifResult avifIOMemoryReaderRead(struct avifIO * io, uint32_t readFlags, uint64_t offset, uint64_t size, avifROData * out)
26{
27 // printf("avifIOMemoryReaderRead offset %zu size %zu\n", offset, size);
28
29 (void)readFlags;
30
31 avifIOMemoryReader * reader = (avifIOMemoryReader *)io;
32
33 // Sanitize/clamp incoming request
34 if (offset >= reader->rodata.size) {
35 offset = 0;
36 size = 0;
37 }
38 if ((offset + size) > reader->rodata.size) {
39 size = reader->rodata.size - offset;
40 }
41
42 out->data = reader->rodata.data + offset;
43 out->size = size;
44 return AVIF_RESULT_OK;
45}
46
47static void avifIOMemoryReaderDestroy(struct avifIO * io)
48{
49 avifFree(io);
50}
51
52avifIO * avifIOCreateMemoryReader(const uint8_t * data, size_t size)
53{
54 avifIOMemoryReader * reader = avifAlloc(sizeof(avifIOMemoryReader));
55 memset(reader, 0, sizeof(avifIOMemoryReader));
56 reader->io.destroy = avifIOMemoryReaderDestroy;
57 reader->io.read = avifIOMemoryReaderRead;
Joe Drago0675bef2020-09-21 13:03:41 -070058 reader->io.sizeHint = size;
Joe Dragobe4cbb92020-09-21 12:14:05 -070059 reader->io.persistent = AVIF_TRUE;
60 reader->rodata.data = data;
61 reader->rodata.size = size;
62 return (avifIO *)reader;
63}
64
65// --------------------------------------------------------------------------------------
66// avifIOFileReader
67
68typedef struct avifIOFileReader
69{
70 avifIO io; // this must be the first member for easy casting to avifIO*
71 avifRWData buffer;
72 FILE * f;
Joe Dragobe4cbb92020-09-21 12:14:05 -070073} avifIOFileReader;
74
75static avifResult avifIOFileReaderRead(struct avifIO * io, uint32_t readFlags, uint64_t offset, uint64_t size, avifROData * out)
76{
77 // printf("avifIOFileReaderRead offset %zu size %zu\n", offset, size);
78
79 (void)readFlags;
80
81 avifIOFileReader * reader = (avifIOFileReader *)io;
82 if (!reader->f) {
83 return AVIF_RESULT_IO_ERROR;
84 }
85
Joe Drago0675bef2020-09-21 13:03:41 -070086 if (offset < reader->io.sizeHint) {
87 uint64_t availableSize = reader->io.sizeHint - offset;
Joe Dragobe4cbb92020-09-21 12:14:05 -070088 if (size > availableSize) {
89 size = availableSize;
90 }
91 } else {
92 // The offset is past the EOF.
93 size = 0;
94 }
95
96 if (size > 0) {
97 if (reader->buffer.size < size) {
98 avifRWDataRealloc(&reader->buffer, size);
99 }
100 if (fseek(reader->f, (long)offset, SEEK_SET) != 0) {
101 return AVIF_RESULT_IO_ERROR;
102 }
103 size_t bytesRead = fread(reader->buffer.data, 1, size, reader->f);
104 if (size != bytesRead) {
105 size = bytesRead;
106 }
107 }
108
109 out->data = reader->buffer.data;
110 out->size = size;
111 return AVIF_RESULT_OK;
112}
113
114static void avifIOFileReaderDestroy(struct avifIO * io)
115{
116 avifIOFileReader * reader = (avifIOFileReader *)io;
Derek Buitenhuis16104712020-09-23 17:46:45 +0100117 if (reader->f) {
Joe Dragobe4cbb92020-09-21 12:14:05 -0700118 fclose(reader->f);
119 }
120 avifRWDataFree(&reader->buffer);
121 avifFree(io);
122}
123
Derek Buitenhuis16104712020-09-23 17:46:45 +0100124avifIO * avifIOCreateFileReader(const char * filename)
Joe Dragobe4cbb92020-09-21 12:14:05 -0700125{
Derek Buitenhuis16104712020-09-23 17:46:45 +0100126 FILE * f = fopen(filename, "rb");
Joe Dragobe4cbb92020-09-21 12:14:05 -0700127 if (!f) {
128 return NULL;
129 }
130
131 fseek(f, 0, SEEK_END);
132 size_t fileSize = (size_t)ftell(f);
133 fseek(f, 0, SEEK_SET);
134
135 avifIOFileReader * reader = avifAlloc(sizeof(avifIOFileReader));
136 memset(reader, 0, sizeof(avifIOFileReader));
137 reader->f = f;
Joe Dragobe4cbb92020-09-21 12:14:05 -0700138 reader->io.destroy = avifIOFileReaderDestroy;
139 reader->io.read = avifIOFileReaderRead;
Joe Drago0675bef2020-09-21 13:03:41 -0700140 reader->io.sizeHint = fileSize;
Joe Dragobe4cbb92020-09-21 12:14:05 -0700141 reader->io.persistent = AVIF_FALSE;
142 avifRWDataRealloc(&reader->buffer, 1024);
143 return (avifIO *)reader;
144}