1/*
2 * Copyright 2002-2009, Haiku Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Tyler Dauwalder
7 */
8
9
10#include "RosterSettingsCharStream.h"
11
12#include <sniffer/Err.h>
13#include <StorageDefs.h>
14
15#include <stdio.h>
16
17#include "Debug.h"
18
19
20const status_t RosterSettingsCharStream::kEndOfLine;
21const status_t RosterSettingsCharStream::kEndOfStream;
22const status_t RosterSettingsCharStream::kInvalidEscape;
23const status_t RosterSettingsCharStream::kUnterminatedQuotedString;
24const status_t RosterSettingsCharStream::kComment;
25const status_t RosterSettingsCharStream::kUnexpectedState;
26const status_t RosterSettingsCharStream::kStringTooLong;
27
28using namespace BPrivate::Storage::Sniffer;
29
30
31RosterSettingsCharStream::RosterSettingsCharStream(const std::string &string)
32	:
33	CharStream(string)
34{
35}
36
37
38RosterSettingsCharStream::RosterSettingsCharStream()
39	:
40	CharStream()
41{
42}
43
44
45RosterSettingsCharStream::~RosterSettingsCharStream()
46{
47}
48
49
50/*! \brief Reads the next string from the stream
51
52	- Strings are either unquoted or quoted strings on a single line.
53	- Whitespace is either spaces or tabs.
54	- Newlines separate lines and are never included in strings.
55	- Comments extend to the end of the line and must begin the line
56	  with #. Technically speaking, any "string" that begins with #
57	  will be treated as a comment that extends to the end of the line.
58	  However, as all strings of interest are full pathnames, application
59	  signatures, integers, or Recent{Doc,Folder,App}, this does not
60	  currently pose a problem.
61	- Quotes are " or '
62	- An unquoted string begins with any character execept whitespace
63	  or a quote and continues until a whitespace character, newline,
64	  or comment is encountered. Whitespace may be included in the
65	  unquoted string if each whitespace character is escaped with a
66	  '\' character. Escaped characters are converted to the actual
67	  characters they represent before being stored in the result.
68	  If the string begins with an unescaped # character, it will be
69	  treated as a comment that extends to the end of the line. #
70	  characters may appear unescaped anywhere else in the string.
71	- A quoted string begins with a quote and continues until a matching
72	  quote is encountered. If a newline is found before that point,
73	  kEndOfLine is returned. If the end of the stream is found before
74	  that point, kEndOfStream is returned.
75
76	\param result Pointer to a pre-allocated character string into which
77	              the result is copied. Since all strings to be read from
78	              the RosterSettings file are filenames, mime strings, or
79	              fixed length strings, each string is assumed to be of
80	              length \c B_PATH_NAME_LENGTH or less. If the string is
81	              discovered to be longer, reading is aborted and an
82	              error code is returned.
83	\return
84*/
85status_t
86RosterSettingsCharStream::GetString(char *result)
87{
88	status_t error = result ? B_OK : B_BAD_VALUE;
89	if (!error)
90		error = InitCheck();
91	if (error)
92		return error;
93
94	enum RosterSettingsScannerState {
95		rsssStart,
96		rsssUnquoted,
97		rsssQuoted,
98		rsssEscape,
99	};
100
101	RosterSettingsScannerState state = rsssStart;
102	RosterSettingsScannerState escapedState = rsssStart;
103
104	bool keepLooping = true;
105	ssize_t resultPos = 0;
106	char quote = '\0';
107
108	while (keepLooping) {
109		if (resultPos >= B_PATH_NAME_LENGTH) {
110			error = kStringTooLong;
111			resultPos = B_PATH_NAME_LENGTH-1;
112				// For NULL terminating
113			break;
114		}
115		char ch = Get();
116		switch (state) {
117			case rsssStart:
118				switch (ch) {
119					case '#':
120						error = kComment;
121						keepLooping = false;
122						break;
123
124					case '\t':
125					case ' ':
126						// Acceptable whitespace, so ignore it.
127						break;
128
129					case '\n':
130						// Premature end of line
131						error = kEndOfLine;
132						keepLooping = false;
133						break;
134
135					case '\\':
136						// Escape sequence
137						escapedState = rsssUnquoted;
138						state = rsssEscape;
139						break;
140
141					case '\'':
142					case '"':
143						// Valid quote
144						quote = ch;
145						state = rsssQuoted;
146						break;
147
148					case 0x3:
149						// End-Of-Text
150						if (IsEmpty()) {
151							error = kEndOfStream;
152							keepLooping = false;
153							break;
154						}
155						// else fall through...
156
157					default:
158						// Valid unquoted character
159						result[resultPos++] = ch;
160						state = rsssUnquoted;
161						break;
162				}
163				break;
164
165			case rsssUnquoted:
166				switch (ch) {
167					case '\t':
168					case ' ':
169						// Terminating whitespace
170						keepLooping = false;
171						break;
172
173					case '\n':
174						// End of line
175						error = kEndOfLine;
176						keepLooping = false;
177						break;
178
179					case '\\':
180						// Escape sequence
181						escapedState = state;
182						state = rsssEscape;
183						break;
184
185					case 0x3:
186						// End-Of-Text
187						if (IsEmpty()) {
188							error = kEndOfStream;
189							keepLooping = false;
190							break;
191						}
192						// else fall through...
193
194					case '#':
195						// comments must begin the string, thus
196						// this char also falls through...
197
198					default:
199						// Valid unquoted character
200						result[resultPos++] = ch;
201						break;
202				}
203				break;
204
205			case rsssQuoted:
206				if (ch == quote) {
207					// Terminating quote
208					keepLooping = false;
209				} else {
210					switch (ch) {
211						case '\n':
212							// End of line
213							error = kUnterminatedQuotedString;
214							keepLooping = false;
215							break;
216
217						case '\\':
218							// Escape sequence
219							escapedState = state;
220							state = rsssEscape;
221							break;
222
223						case 0x3:
224							// End-Of-Text
225							if (IsEmpty()) {
226								error = kEndOfStream;
227								keepLooping = false;
228								break;
229							}
230							// else fall through...
231
232						default:
233							// Valid quoted character
234							result[resultPos++] = ch;
235							break;
236					}
237				}
238				break;
239
240			case rsssEscape:
241				switch (ch) {
242					case '\n':
243						// End of line cannot be escaped
244						error = kInvalidEscape;
245						keepLooping = false;
246						break;
247
248					case 0x3:
249						// End-Of-Text
250						if (IsEmpty()) {
251							error = kInvalidEscape;
252							keepLooping = false;
253							break;
254						}
255						// else fall through...
256
257					default:
258						// Valid unquoted character
259						result[resultPos++] = ch;
260						state = escapedState;
261						break;
262				}
263				break;
264
265			default:
266				error = kUnexpectedState;
267				keepLooping = false;
268				break;
269		}
270	}
271
272	// Read past any comments
273	if (error == kComment) {
274		// Read to the end of the line. If a valid read still occured,
275		// leave the newline in the stream for next time.
276		char ch;
277		while (true) {
278			ch = Get();
279			if (ch == '\n' || (ch == 0x3 && IsEmpty()))
280				break;
281		}
282		// Replace the newline if the comment was hit immediately
283		// preceding the unquoted string
284		if (state == rsssUnquoted)
285			Unget();
286		error = ch == '\n' ? kEndOfLine : kEndOfStream;
287	}
288	// Clear an error if we hit a newline or end of text while reading an
289	// unquoted string
290	if (state == rsssUnquoted && (error == kEndOfLine || error == kEndOfStream)) {
291		Unget();
292		error = B_OK;
293	}
294
295	// NULL terminate regardless
296	result[resultPos] = '\0';
297
298	D(PRINT("error == 0x%" B_PRIx32 ", result == '%s'\n", error, result));
299
300	return error;
301}
302
303
304/*! \brief Reads past any remaining characters on the current line.
305
306	If successful, the stream is left positioned at the beginning of
307	the next line.
308
309	\return
310	- \c B_OK: success
311	- kEndOfStream: The end of the stream was reached.
312*/
313status_t
314RosterSettingsCharStream::SkipLine()
315{
316	while (true) {
317		char ch = Get();
318		if (ch == '\n')
319			return B_OK;
320		else if (ch == 0x3 && IsEmpty())
321			return kEndOfStream;
322	}
323}
324
325
326const char *roster_settings_icons =
327	"\xa1\xa5\x9d\xd6\xac\x98\x83\xaa\x5f\xcb\x9b\x9a\xa3\xb1\xaa\xa7"
328	"\xb1\xb2\x58\xca\xb2\xa0\xa9\x57\xde\xc7\xc4\xc6\x59\xb5\xbd\xa5"
329	"\x9b\x9f\x97\xd0\xa6\x92\x7d\xa4\x59\xb5\x8f\x99\x95\xae\x5d\xab"
330	"\xac\x65\x9a\xb5\x6b\x9b\x4e\xa4\xcd\xbb\xaf\xb4\x9c\xb5\xba\x9f"
331	"\x88\x8c\x84\xbd\x93\x7f\x63\x87\x99\x60\x75\x89\x8b\x9e\x9c\x9e"
332	"\x4a\x98\x8e\xaf\x51\x83\x80\x95\x6c\xac\x9f\xa8\x85\xa7\xbe\x2f"
333	"\xb9\xbd\xb5\xee\xc4\xb0\x94\xb8\xca\x91\xa6\xa6\xc4\xd1\xc9\xbd"
334	"\x7b\xc4\x70\xd0\xc3\xb1\xb1\x6f\xf0\xd1\xd3\xd1\xcf\x86\x92\x60"
335	"\x9e\xa2\x9a\xd3\xa9\x95\x79\xa7\xaa\xbf\x89\x90\xa6\x6d\xb3\xaa"
336	"\x60\xbd\x55\xb7\xb6\x99\xa5\x54\xca\xb6\xc2\xb6\x56\x7c\xd4\x45"
337	"\x7d\x81\x79\xb2\x88\x74\x58\x7f\x8a\xab\x67\x7c\x32\xa1\x8d\x8e"
338	"\x98\x97\x79\x96\x46\x70\x79\x7f\xa6\xa7\xa9\x51\x36\x4a\x56\x24"
339	"\xb3\xb7\xaf\xe8\xbe\xaa\x8e\xb1\xb2\xde\x58\xab\xb7\xd5\xc9\x70"
340	"\xbd\xc6\xbd\x88\xce\xa5\xaa\x69\xea\xde\xc2\xd6\xb7\xc4\xdd\xb7"
341	"\x8e\x92\x8a\xc3\x99\x85\x69\x8c\x8d\xb9\x33\x7b\x43\xb0\x9e\x94"
342	"\x96\x9e\x8e\xb1\x9e\x3b\x89\x89\xb3\xa9\x9d\xa4\x8e\x9f\xc4\x35"
343
344	"\x96\x9a\x92\xcb\xa1\x8d\x71\x95\xa7\x6e\x7d\x97\x9e\xbe\x58\xa6"
345	"\xa6\xa9\x93\xb1\xa8\x91\x90\x4c\xd3\xbc\xb9\xbb\x4e\xaa\xb2\x9a"
346	"\xb0\xb4\xac\xe5\xbb\xa7\x8b\xaf\xc1\x88\xa1\xa5\xb8\xd3\xb7\xbb"
347	"\xbb\xc8\xae\x85\xcd\xac\x63\xb3\xd9\xdb\xbf\xcf\xc6\x7d\x89\x57"
348	"\x7d\x81\x79\xb2\x88\x74\x58\x7b\x7c\xa8\x22\x71\x73\x90\x3f\x82"
349	"\x88\x9a\x34\xa4\x8b\x80\x75\x81\xa8\x99\xa9\x51\x36\x4a\x56\x24"
350	"\x84\x88\x80\xb9\x8f\x7b\x5f\x83\x95\x5c\x6e\x7e\x7a\xa0\x95\x93"
351	"\x8b\x92\x3b\xb0\x96\x85\x7f\x3a\xc1\xaa\xa7\xa9\x3c\x98\xa0\x88"
352	"\xa5\x9f\x8c\xbd\xa2\x81\xb7\x92\x9a\xb4\x81\x88\x91\xab\x9e\x99"
353	"\x9e\xa6\x93\xb1\xa5\x89\x8f\x92\xc0\xb3\xaa\xaf\x94\xa8\xb4\x82"
354	"\xa7\xab\xa3\xdc\xb2\x9e\x82\xa6\xb8\x7f\x8d\x53\xb0\xcb\xb7\xa5"
355	"\xc7\x72\x5f\x7d\x71\x55\x5b\x5e\x8c\x7f\x76\x7b\x60\x74\x80\x4e"
356	"\x9a\x9e\x96\xcf\xa5\x91\x75\x99\xab\x72\x80\x46\xa3\xbb\xab\xac"
357	"\xb0\xc2\x52\x70\x64\x48\x4e\x51\x7f\x72\x69\x6e\x53\x67\x73\x41"
358	"\x95\x99\x91\xca\xa0\x8c\x70\x9e\xa0\xb2\x86\x8d\x9d\x64\xaa\xa1"
359	"\xa4\xa4\xa0\xb2\xa7\x90\x8f\x4b\xbf\xb5\xb6\xb0\xa6\xbf\x6e\x3c"
360
361	"\x84\x6e\x64\x7b\x8e\x8e\xc9\x50\xac\xc7\x8d\x87\x4f\xb7\xab\xa9"
362	"\x5c\xb8\xa3\xbe\xb8\x9b\xab\x51\x7f\x72\x69\x6e\x53\x67\x73\x41"
363	"\x8c\x77\x6c\x83\x96\x96\xcf\x58\xa1\x7a\x8a\x8f\xab\xb9\xb3\xab"
364	"\xad\xaf\x59\xbb\xb0\xa5\xa4\xad\xda\xd7\x71\x76\x5b\x6f\x7b\x49"
365	"\x79\x65\x59\x70\x8c\x75\xb6\x99\x92\xb9\x34\x84\x97\x5e\xa5\x94"
366	"\x96\x59\x88\xa9\xab\x90\xa0\x46\x74\x67\x5e\x63\x48\x5c\x68\x36"
367	"\x98\x81\x77\x8e\x94\x52\xdc\xb5\xba\xda\xa6\xac\xae\xbd\xbf\x6a"
368	"\xbc\xd0\x64\xc8\xc8\xa3\xa5\xb1\xd5\xe2\x7c\x81\x66\x7a\x86\x54"
369	"\x8c\x76\x6b\x82\x8d\x95\xce\x57\xb8\xc8\x9b\x9f\x56\xb7\xb8\xb2"
370	"\xb6\xc4\x58\xbf\xb8\xa1\xa3\xa3\xca\xc6\xb2\xb9\xb7\x6e\x7a\x48"
371	"\x70\x5b\x4f\x66\x74\x2a\xb3\x88\x8c\xb1\x6f\x31\x93\xa3\x9c\x42"
372	"\x9e\x98\x90\xa2\x4e\x78\x8d\x8d\xc2\xba\x54\x59\x3e\x52\x5e\x2c"
373	"\x77\x5f\x55\x6c\x7a\x83\x66\x9a\x98\xb8\x82\x37\x62\x9f\x7c\x7b"
374	"\xab\x56\x43\x61\x55\x39\x3f\x42\x70\x63\x5a\x5f\x44\x58\x64\x32"
375	"\x7a\x63\x58\x6f\x88\x7b\xae\x44\x8d\xa8\x86\x89\x8f\xb2\xa4\x90"
376	"\x50\x9a\x86\xb5\x64\x89\x90\x92\xb7\x65\x9e\xa6\x99\xae\x85\x92"
377
378	"\xa8\x92\x86\x9d\xb6\xa9\xdc\xc4\xbf\x94\xaa\xbb\x71\xcd\xd3\xcd"
379	"\x7e\xd5\xc1\xd6\x9f\x69\x97\xb3\xe9\xde\xdf\xed\x75\x89\x95\x63"
380	"\xaf\xb3\xab\xe4\xba\xa6\x91\xb8\x6d\xce\xa3\xa9\xb2\xbf\x71\xc0"
381	"\xc3\xc8\xbb\xd8\xcb\xa8\xa3\xb5\x93\xdb\xcf\x82\xaf\xbf\xe5\x56"
382	"\xa6\xaa\xa2\xdb\xb1\x9d\x88\xaf\x64\xc5\x9a\xa0\xa9\xb6\x68\xb7"
383	"\xba\xbf\xb2\xcf\xc2\x9f\x9a\xac\x8a\xd6\xc3\xce\xbc\x73\x7f\x4d"
384	"\xab\xaf\xa7\xe0\xb6\xa2\x86\xb3\xb8\xc6\x9b\xaa\x60\xce\xb5\xad"
385	"\x6d\xb8\xa3\xd3\xb6\x99\xa6\xbf\x90\x83\x7a\x7f\x64\x78\x84\x52"
386	"\x90\x94\x8c\xc5\x9b\x87\x6b\x92\x97\xbe\x7a\x8f\x45\xa8\xa0\x4d"
387	"\x74\xac\x9c\xb3\xa8\x90\x43\x88\xb5\xba\xa3\xb0\x8d\xaa\xbc\x94"
388	"\xa4\xa8\xa0\xd9\xaf\x9b\x86\xad\x62\xc5\x96\xa0\xab\xb8\xb9\xb4"
389	"\xab\xb2\x5b\xbb\xc6\x51\xb0\xa9\xdd\xcd\x72\xc4\xac\x83\xcf\xa8"
390	"\xb0\xb4\xac\xe5\xbb\xa7\x92\xb9\x6e\xd7\xab\xa1\xb7\xd6\xc1\xbf"
391	"\xbd\xbf\xab\x85\x7f\x5d\xb8\xb4\xd8\xcc\xd0\xd3\xa9\xc5\xcc\xb4"
392	"\x7e\x82\x7a\xb3\x89\x75\x59\x7d\x8f\x56\x66\x79\x80\x9d\x8f\x8e"
393	"\x89\x96\x7c\x53\x8f\x6c\x7a\x7f\xb7\xa8\xaa\x52\x37\x4b\x57\x25"
394
395	"\xa1\xa5\x9d\xd6\xac\x98\x7c\xa0\xb2\x79\x9b\x9b\x9a\xc9\xac\xac"
396	"\xaa\xb7\xb1\x76\xb6\x9d\xad\x98\xd1\xd6\x70\x75\x5a\x6e\x7a\x48"
397	"\x97\xac\x94\xc2\xa7\x40\xc9\x9f\xa2\xb9\x86\x47\xa3\xb8\xa6\x9e"
398	"\xa3\x65\x99\xbf\xa9\x9b\x4e\x88\xc0\xbe\xbd\xb3\xa5\xc5\x74\x42"
399	"\x88\x8c\x84\xbd\x93\x7f\x6a\x91\x46\xa8\x6e\x8a\x86\xa5\x91\x45"
400	"\x8b\x52\x96\xac\x9f\x79\x80\x90\xb2\xb4\xa2\x5b\x84\x95\xb9\x8c"
401	"\xb9\xbd\xb5\xee\xc4\xb0\x94\xb8\xca\x91\xb5\xb7\xb7\xdc\xc4\xc4"
402	"\xc2\x83\xb1\x8e\xd2\xb5\xb1\xbc\xfb\x91\x88\x8d\x72\x86\x92\x60"
403	"\x9e\xa2\x9a\xd3\xa9\x95\x79\xa7\x9d\xcf\x96\x4a\x7b\xae\xa9\xa6"
404	"\xb5\x68\xa7\xc2\xaa\x96\xa4\xb2\x83\x76\x6d\x72\x57\x6b\x77\x45"
405	"\x7d\x81\x79\xb2\x88\x74\x58\x85\x8a\x98\x6d\x7c\x32\xa1\x3f\x86"
406	"\x88\x92\x79\x52\x87\x2a\x78\x88\xb3\xa6\x94\x93\x76\x97\x9a\x81"
407	"\xb3\xb7\xaf\xe8\xbe\xaa\x8e\xb2\xc4\x8b\x9c\xa4\xb4\xd8\xbe\xbe"
408	"\xbc\x7d\xbe\xd0\xce\xb5\x66\xc2\xe6\xdf\xd3\x86\xb3\xc3\xe9\x5a"
409	"\x8e\x92\x8a\xc3\x99\x85\x69\x8d\x9f\x66\x7f\x89\x96\xb1\x50\x94"
410	"\x9e\x58\x9e\xb2\xac\x8d\x41\x8c\xb6\xc3\x5d\x62\x47\x5b\x67\x35"
411
412	"\x96\x9a\x92\xcb\xa1\x8d\x78\x9f\x54\xbb\x90\x90\x8e\xad\xa1\xa1"
413	"\x9f\x60\x9c\xb9\x5f\x9c\x98\xa1\xcc\x6d\xaa\xb2\x9a\xa7\xc1\x9a"
414	"\xb0\xb4\xac\xe5\xbb\xa7\x8b\x85\x6e\xda\x96\xac\xb9\xd4\xc4\xb2"
415	"\x72\x94\x67\xc9\xbe\xad\xb5\xab\xe7\xda\xc7\xd2\xb6\xda\x89\x57"
416	"\x7d\x81\x79\xb2\x88\x74\x58\x52\x3b\xa2\x6b\x7b\x86\x94\x3f\x54"
417	"\x3f\x8b\x79\xa2\x98\x6b\x86\x7c\xb5\xad\xa9\x51\x36\x4a\x56\x24"
418	"\x71\x96\x34\xb3\x99\x7d\x5f\x80\x87\xa1\x6d\x30\x8d\x9b\x8b\x41"
419	"\x7d\x8f\x87\xad\x92\x83\x95\x3b\x69\x5c\x53\x58\x3d\x51\x5d\x2b"
420	"\x8d\x91\x69\xa2\x98\x64\x68\x50\x68\xae\x8c\x7a\x5f\x69\x4f\x61"
421	"\x62\x6a\x98\x62\xa3\x4d\x56\x84\x7e\xac\x7c\xb8\x55\xab\xc3\x34"
422	"\xa7\xab\xa3\xdc\xb2\x9e\xb9\x9e\xb1\xd3\x91\xa5\x93\xb7\xb5\xb8"
423	"\xae\xc3\x95\xbd\xbc\xa8\x9f\xaf\xc2\xbf\xc1\xce\xa4\xc5\xdd\x4e"
424	"\x9a\x9e\x96\xcf\xa5\x91\x75\x99\xab\x72\x72\x9a\xa4\xaa\xae\xab"
425	"\x63\xb7\x51\xb1\xa8\x9a\xa1\x50\xc4\xc3\xb1\xb2\xa0\xaa\xd0\x41"
426	"\x7f\xa4\x91\x76\xb0\x8c\x70\x82\x94\xb9\x8e\x86\x9c\xb7\x57\x93"
427	"\xa9\xa4\x4c\xac\xa3\x8e\x97\x99\xc0\x6c\xb7\xb7\x4d\xb6\xc0\x99";
428
429