aboutsummaryrefslogtreecommitdiff
path: root/include/io/istream.h
blob: f091aa1061c9494a8d1d09596d96e7c5c86a8fe2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
 * istream.h
 *
 * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
 */
#ifndef IO_ISTREAM_H
#define IO_ISTREAM_H

#include "sqfs/predef.h"
#include "io/ostream.h"

/**
 * @struct istream_t
 *
 * @extends sqfs_object_t
 *
 * @brief A sequential, read-only data stream.
 */
typedef struct istream_t {
	sqfs_object_t base;

	size_t buffer_used;
	const sqfs_u8 *buffer;

	int (*precache)(struct istream_t *strm);

	const char *(*get_filename)(struct istream_t *strm);
} istream_t;

enum {
	ISTREAM_LINE_LTRIM = 0x01,
	ISTREAM_LINE_RTRIM = 0x02,
	ISTREAM_LINE_SKIP_EMPTY = 0x04,
};

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Read a line of text from an input stream
 *
 * @memberof istream_t
 *
 * The line returned is allocated using malloc and must subsequently be
 * freed when it is no longer needed. The line itself is always null-terminated
 * and never includes the line break characters (LF or CR-LF).
 *
 * If the flag @ref ISTREAM_LINE_LTRIM is set, leading white space characters
 * are removed. If the flag @ref ISTREAM_LINE_RTRIM is set, trailing white space
 * characters are remvoed.
 *
 * If the flag @ref ISTREAM_LINE_SKIP_EMPTY is set and a line is discovered to
 * be empty (after the optional trimming), the function discards the empty line
 * and retries. The given line_num pointer is used to increment the line
 * number.
 *
 * @param strm A pointer to an input stream.
 * @param out Returns a pointer to a line on success.
 * @param line_num This is incremented if lines are skipped.
 * @param flags A combination of flags controling the functions behaviour.
 *
 * @return Zero on success, a negative value on error, a positive value if
 *         end-of-file was reached without reading any data.
 */
SQFS_INTERNAL int istream_get_line(istream_t *strm, char **out,
				   size_t *line_num, int flags);

/**
 * @brief Read data from an input stream
 *
 * @memberof istream_t
 *
 * @param strm A pointer to an input stream.
 * @param data A buffer to read into.
 * @param size The number of bytes to read into the buffer.
 *
 * @return The number of bytes actually read on success, -1 on failure,
 *         0 on end-of-file.
 */
SQFS_INTERNAL sqfs_s32 istream_read(istream_t *strm, void *data, size_t size);

/**
 * @brief Adjust and refill the internal buffer of an input stream
 *
 * @memberof istream_t
 *
 * This function resets the buffer offset of an input stream (moving any unread
 * data up front if it has to) and calls an internal callback of the input
 * stream to fill the rest of the buffer to the extent possible.
 *
 * @param strm A pointer to an input stream.
 *
 * @return 0 on success, -1 on failure.
 */
SQFS_INLINE int istream_precache(istream_t *strm)
{
	return strm->precache(strm);
}

/**
 * @brief Get the underlying filename of an input stream.
 *
 * @memberof istream_t
 *
 * @param strm The input stream to get the filename from.
 *
 * @return A string holding the underlying filename.
 */
SQFS_INLINE const char *istream_get_filename(istream_t *strm)
{
	return strm->get_filename(strm);
}

/**
 * @brief Peek into the data buffered in an istream
 *
 * @memberof istream_t
 *
 * If the internal buffer is empty, the function tries to fetch more, which can
 * block, and returns a positive return code if there is no more data to be
 * read. Since this and other functions can alter the buffer pointer and
 * contents, do not store the pointers returned here across function calls.
 *
 * Higher level functions like @ref istream_read, providing a Unix read() style
 * API are built on top of this primitive.
 *
 * @param strm A pointer to an istream_t implementation.
 * @param out Returns a pointer into an internal buffer on success.
 * @param size Returns the number of bytes available in the buffer.
 *
 * @return Zero on success, a negative error code on failure,
 *         a postive number on EOF.
 */
SQFS_INLINE int istream_get_buffered_data(istream_t *strm, const sqfs_u8 **out,
					  size_t *size)
{
	if (strm->buffer_used == 0) {
		int ret = strm->precache(strm);
		if (ret)
			return ret;
		if (strm->buffer_used == 0)
			return 1;
	}

	*out = strm->buffer;
	*size = strm->buffer_used;
	return 0;
}

/**
 * @brief Mark a section of the internal buffer of an istream as used
 *
 * @memberof istream_t
 *
 * This marks the first `count` bytes of the internal buffer as used,
 * forcing @ref istream_get_buffered_data to return data afterwards
 * and potentially to load more data.
 *
 * @param strm A pointer to an istream_t implementation.
 * @param count The number of bytes used up.
 *
 * @return Zero on success, a negative error code on failure.
 */
SQFS_INLINE int istream_advance_buffer(istream_t *strm, size_t count)
{
	if (count >= strm->buffer_used) {
		strm->buffer += strm->buffer_used;
		strm->buffer_used = 0;
		return strm->precache(strm);
	}

	strm->buffer += count;
	strm->buffer_used -= count;
	return 0;
}

/**
 * @brief Skip over a number of bytes in an input stream.
 *
 * @memberof istream_t
 *
 * @param strm A pointer to an input stream.
 * @param size The number of bytes to seek forward.
 *
 * @return Zero on success, -1 on failure.
 */
SQFS_INTERNAL int istream_skip(istream_t *strm, sqfs_u64 size);

/**
 * @brief Dump data from an input stream to an output stream
 *
 * @memberof istream_t
 *
 * @param in A pointer to an input stream to read from.
 * @param out A pointer to an output stream to append to.
 * @param size The number of bytes to copy over.
 *
 * @return The number of bytes copied on success, -1 on failure,
 *         0 on end-of-file.
 */
SQFS_INTERNAL sqfs_s32 istream_splice(istream_t *in, ostream_t *out,
				      sqfs_u32 size);

#ifdef __cplusplus
}
#endif

#endif /* IO_ISTREAM_H */