1 /*
2   Copyright 2021 Northern.tech AS
3 
4   This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8   Free Software Foundation; version 3.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
18 
19   To the extent this program is licensed as part of the Enterprise
20   versions of CFEngine, the applicable Commercial Open Source License
21   (COSL) may apply to this file if you as a licensee so wish it. See
22   included file COSL.txt.
23 */
24 
25 #ifndef CFENGINE_BUFFER_H
26 #define CFENGINE_BUFFER_H
27 
28 #include <compiler.h>
29 #include <stdarg.h> // va_list
30 
31 /**
32   @brief Buffer implementation
33 
34   The buffer structure acts as a byte container. It can contains any bytes and it is not restricted to
35   C strings (by default it acts as a C String).
36 
37   If an error arises while doing something, we do everything we can to restore things to its previous state.
38   Unfortunately not all errors are recoverable. Since we do not have a proper errno system, we just return -1.
39   */
40 
41 typedef enum
42 {
43     BUFFER_BEHAVIOR_CSTRING //<! CString compatibility mode. A '\0' would be interpreted as end of the string, regardless of the size.
44     , BUFFER_BEHAVIOR_BYTEARRAY //<! Byte array mode. A '\0' has no meaning, only the size of the buffer is taken into consideration.
45 } BufferBehavior ;
46 
47 #define DEFAULT_BUFFER_CAPACITY     4096
48 
49 typedef struct
50 {
51     char *buffer;
52     BufferBehavior mode;
53     size_t capacity;
54     size_t used;
55     bool unsafe;
56 } Buffer;
57 
58 
59 typedef bool (*BufferFilterFn)(char item);
60 
61 /**
62   @brief Buffer initialization routine.
63 
64   Initializes the internals of a buffer. By default it is initialized to emulate a C string, but that can be
65   changed at run time if needed. The default size of the buffer is set to DEFAULT_BUFFER_CAPACITY (4096).
66   @return Pointer to initialized Buffer if the initialization was successful,
67           otherwise terminate with message to stderr.
68   */
69 Buffer* BufferNew(void);
70 
71 /**
72   @brief Allocates and setup a buffer with a capacity different than the default capacity.
73   @param initial_capacity Initial capacity of the buffer.
74   @return Pointer to initialized Buffer if the initialization was successful,
75           otherwise terminate with message to stderr.
76   */
77 Buffer *BufferNewWithCapacity(size_t initial_capacity);
78 
79 /**
80   @brief Initializes a buffer based on a const char pointer.
81   @param data Data
82   @param length Length of the data.
83   @return Pointer to initialized Buffer if the initialization was successful,
84           otherwise terminate with message to stderr.
85   @remarks Length is used as a reference only. If a '\0' is found, only so many bytes will be copied.
86   @remarks Only C_STRING behavior is accepted if this constructor is used.
87   */
88 Buffer* BufferNewFrom(const char *data, size_t length);
89 
90 /**
91   @brief Destroys a buffer and frees the memory associated with it.
92   @param buffer Buffer to be destroyed.
93   */
94 void BufferDestroy(Buffer *buffer);
95 
96 /**
97   @brief Destroys a buffer structure returning the its contents.
98   @param buffer Structure to operate on.
99   @return Contents of the buffer.
100   */
101 char *BufferClose(Buffer *buffer);
102 
103 /**
104   @brief Creates a shallow copy of the source buffer.
105   @param source Source buffer.
106   */
107 Buffer *BufferCopy(const Buffer *source);
108 
109 /**
110   @brief Compares two buffers. Uses the same semantic as strcmp.
111   @note If this is called with NULL pointers, it will crash. There is no way around it.
112   @param buffer1
113   @param buffer2
114   @return -1 if buffer1 < buffer2, 0 if buffer1 == buffer2, +1 if buffer1 > buffer2
115   */
116 int BufferCompare(const Buffer *buffer1, const Buffer *buffer2);
117 
118 /**
119   @brief Replaces the current content of the buffer with the given string.
120 
121   In CString mode the content of bytes is copied until length bytes have been copied or a '\0' is found, whatever
122   happens first. In ByteArray mode length bytes are copied regardless of if there are '\0' or not.
123   @note The content of the buffer are overwritten with the new content, it is not possible to access them afterwards.
124   @note For complex data it is preferable to use Printf since that will make sure that all data is represented properly.
125   @note The data will be preserved if this operation fails, although it might be in a detached state.
126   @param buffer Buffer to be used.
127   @param bytes Collection of bytes to be copied into the buffer.
128   @param length Length of the collection of bytes.
129   */
130 void BufferSet(Buffer *buffer, const char *bytes, size_t length);
131 
132 /**
133   @brief This functions allows direct access to the storage inside Buffer.
134   @return Returns the pointer used to store data inside the buffer. The content can be freely modified up to the capacity of the buffer.
135   @remarks This function invalidates the size of the buffer. Mixing calls to this
136   function with other Buffer functions is generally a bad idea.
137   */
138 char *BufferGet(Buffer *buffer);
139 
140 void BufferAppend(Buffer *buffer, const char *bytes, size_t length);
141 
142 /**
143   @brief Appends a char to an existing buffer.
144   @param buffer Structure to operate on.
145   @param byte Char to be added to the buffer.
146   */
147 void BufferAppendChar(Buffer *buffer, char byte);
148 void BufferAppendF(Buffer *buffer, const char *format, ...);
149 void BufferAppendString(Buffer *buffer, const char *str);
150 
151 /**
152   @brief Stores complex data on the buffer.
153 
154   This function uses the same semantic and flags as printf. Internally it might or not call sprintf, so do not depend on obscure
155   sprintf/printf behaviors.
156   @note This function can be used both in CString mode and in ByteArray mode. The only difference is the presence of the final '\0'
157   character.
158   @note The data will be preserved if this operation fails, although it might be in a detached state.
159   @param buffer
160   @param format
161   @return The number of bytes written to the buffer or 0 if the operation needs to be retried. In case of error -1 is returned.
162   */
163 int BufferPrintf(Buffer *buffer, const char *format, ...) FUNC_ATTR_PRINTF(2, 3);
164 
165 /**
166   @brief Stores complex data on the buffer.
167 
168   This function uses the same semantic and flags as printf. Internally it might or not call sprintf, so do not depend on obscure
169   sprintf/printf behaviors.
170 
171   This function uses a va_list instead of variable arguments.
172   @note This function can be used both in CString mode and in ByteArray mode. The only difference is the presence of the final '\0'
173   character.
174   @note The data will be preserved if this operation fails, although it might be in a detached state.
175   @param buffer
176   @param format NB! Make sure to sanitize if taken from user input.
177   @return The number of bytes written to the buffer or 0 if the operation needs to be retried. In case of error -1 is returned.
178   */
179 int BufferVPrintf(Buffer *buffer, const char *format, va_list ap);
180 
181 /**
182   @brief Does a PCRE search and replace on the buffer data.
183 
184   @param buffer
185   @param pattern
186   @param substitute (backreferences allowed)
187   @param options Perl-style gms...
188   @return NULL if successful, an error string otherwise.
189   */
190 const char* BufferSearchAndReplace(Buffer *buffer, const char *pattern, const char *substitute, const char *options);
191 
192 /**
193   @brief Clears the buffer.
194 
195   Clearing the buffer does not mean destroying the data. The data might be still present after this function is called, although
196   it might not be accessible. This function never fails.
197 
198   If a NULL pointer is given it will politely ignore the call.
199   @note This function might trigger a deep copy and a memory allocation if the buffer is shared.
200   @param buffer Buffer to clear.
201   */
202 void BufferClear(Buffer *buffer);
203 
204 /**
205   @brief Returns the size of the buffer.
206   @param buffer
207   @return The size of the buffer, that is the number of bytes contained on it.
208   @note
209   */
210 size_t BufferSize(const Buffer *buffer);
211 
212 /**
213   @param buffer Structure to operate on.
214   @return Returns the capacity of the buffer.
215   */
216 size_t BufferCapacity(const Buffer *buffer);
217 
218 /**
219   @brief Returns the current mode of operation of the buffer.
220   @param buffer The buffer to operate on.
221   @return The current mode of operation.
222   */
223 BufferBehavior BufferMode(const Buffer *buffer);
224 
225 /**
226   @brief Sets the operational mode of the buffer.
227 
228   Although there are no problems changing the operational mode once the buffer is in use, there might be some obscure side effects.
229   The data will not be changed but the interpretation of it will, therefore it might be possible that some data is lost when switching
230   from ByteArray mode to CString mode, since '\0' are allowed in ByteArray mode but not in CString mode.
231   @param buffer The buffer to operate on.
232   @param mode The new mode of operation.
233   */
234 void BufferSetMode(Buffer *buffer, BufferBehavior mode);
235 
236 /**
237   @brief Returns a filtered copy of a Buffer
238 
239   @param buffer The buffer to operate on.
240   @param filter a function to test for inclusion
241   @param invert Whether the test should be inverted
242   */
243 Buffer* BufferFilter(Buffer *buffer, BufferFilterFn filter, const bool invert);
244 
245 /**
246   @brief Filters a Buffer in place
247 
248   @param buffer The buffer to operate on.
249   @param filter a function to test for inclusion
250   @param invert Whether the test should be inverted
251   */
252 void BufferRewrite(Buffer *buffer, BufferFilterFn filter, const bool invert);
253 
254 /**
255   @brief Trim a buffer to be at most max bytes.
256 
257   If the buffer is below the max bytes, nothing happens. Otherwise,
258   it's trimmed to that many bytes. This is not persistent, the buffer
259   could grow beyond the max bytes in the future.
260 
261   @param buffer
262   @param max the maximum number of bytes to trim to
263   */
264 void BufferTrimToMaxLength(Buffer *buffer, size_t max);
265 
266 /**
267   @brief Canonify a buffer in place: replace [^0-9a-zA-Z] with '_'
268 
269   @see CanonifyNameInPlace
270 
271   @param buffer
272   */
273 void BufferCanonify(Buffer *buffer);
274 
275 /**
276   @brief Provides a pointer to the internal data.
277 
278   This is a const pointer and it is not supposed to be used to write data to the buffer, doing so will lead to undefined behavior and
279   most likely segmentation faults. Use the proper functions to write data to the buffer.
280   @param buffer
281   @return A const char pointer to the data contained on the buffer.
282   */
283 const char *BufferData(const Buffer *buffer);
284 
285 #endif
286