aboutsummaryrefslogtreecommitdiff
path: root/include/io/istream.h
blob: 8e8689179bd98ba52879bb3e5e224608fed25bff (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
/* 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;

	int (*get_buffered_data)(struct istream_t *strm, const sqfs_u8 **out,
				 size_t *size, size_t want);

	void (*advance_buffer)(struct istream_t *strm, size_t count);

	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 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.
 * @param want A number of bytes that the reader would like to have. If there is
 *             less than this available, the implementation can choose to do a
 *             blocking precache.
 *
 * @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, size_t want)
{
	return strm->get_buffered_data(strm, out, size, want);
}

/**
 * @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 try to load more data.
 *
 * @param strm A pointer to an istream_t implementation.
 * @param count The number of bytes used up.
 */
SQFS_INLINE void istream_advance_buffer(istream_t *strm, size_t count)
{
	strm->advance_buffer(strm, count);
}

/**
 * @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 */