/ webserv / practice / config / JsonParser.cpp
JsonParser.cpp
  1  #include "JsonParser.hpp"
  2  
  3  static void	_errorExit(std::string const& msg);
  4  
  5  /* *************************************************************************** *
  6   * Constructor & Destructor                                                    *
  7   * ****************************************************************************/
  8  
  9  JsonParser::JsonParser(void) {}
 10  
 11  JsonParser::~JsonParser(void) {}
 12  
 13  /* *************************************************************************** *
 14   * Public Member Functions                                                     *
 15   * ****************************************************************************/
 16  
 17  JsonData const&	JsonParser::getJson(void) const
 18  {
 19  	return this->_json;
 20  }
 21  
 22  JsonData	JsonParser::parseJson(std::string const& filepath)
 23  {
 24  	std::string				text;
 25  	std::string::iterator	start;
 26  
 27  	readFile(filepath, text);
 28  	start = text.begin();
 29  	this->_json = parseObject(text, start);
 30  	return this->_json;
 31  }
 32  
 33  /* *************************************************************************** *
 34   * Private Member Functions                                                    *
 35   * ****************************************************************************/
 36  
 37  void	JsonParser::readFile
 38  (std::string const& filepath, std::string& output)
 39  {
 40  	std::ifstream	file(filepath.c_str());
 41  	std::string		line;
 42  
 43  	if (!file.is_open())
 44  	{
 45  		_errorExit("Error: cannot open file " + filepath);
 46  	}
 47  
 48  	while (std::getline(file, line, '\0'))
 49  	{
 50  		output.append(line);
 51  	}
 52  }
 53  
 54  std::pair<std::string, JsonData>	JsonParser::retriveKeyValuePair
 55  (std::string const& text, std::string::iterator& it)
 56  {
 57  	std::string	key;
 58  	JsonData	data;
 59  
 60  	if (it == text.end())
 61  	{
 62  		_errorExit("Error: Incomplete object");
 63  	}
 64  
 65  	while (std::isspace(*it))
 66  		it++;
 67  
 68  	if (*it == '\"')
 69  	{
 70  		key = parseStringKey(text, it);
 71  	}
 72  	else if (*it == '}')
 73  	{
 74  		return std::make_pair(key, data);
 75  	}
 76  	else
 77  	{
 78  		_errorExit("Error: Invalid object key");
 79  	}
 80  
 81  	while (std::isspace(*it))
 82  		it++;
 83  
 84  	if (*it == '{')
 85  	{
 86  		data = parseObject(text, it);
 87  	}
 88  	else if (*it == '\"')
 89  	{
 90  		data._type = TYPE_STRING;
 91  		data._str = parseStringValue(text, it);
 92  	}
 93  	else if (*it == '[')
 94  	{
 95  		data._type = TYPE_ARRAY;
 96  		data._arr = parseArray(text, it);
 97  	}
 98  	else if (std::isalnum(*it))
 99  	{
100  		data._str = parsePrimitive(it, data._type);
101  	}
102  	else
103  	{
104  		_errorExit("Error: Invalid object value");
105  	}
106  
107  	if (checkKeyValueEnd(text, it) == false)
108  	{
109  		_errorExit("Error: Malformed object format");
110  	}
111  
112  	it++;
113  	while (*it == ',' || std::isspace(*it))
114  		it++;
115  
116  	return std::make_pair(key, data);
117  }
118  
119  std::vector<JsonData>	JsonParser::parseArray
120  (std::string const& text, std::string::iterator& it)
121  {
122  	std::vector<JsonData>	arr;
123  	std::string::iterator	nxt;
124  
125  	it++;
126  	while (it != text.end())
127  	{
128  		JsonData	data;
129  
130  		while (std::isspace(*it))
131  			it++;
132  		if (*it == '{')
133  		{
134  			data = parseObject(text, it);
135  		}
136  		else if (*it == '\"')
137  		{
138  			data._type = TYPE_STRING;
139  			data._str = parseStringValue(text, it);
140  		}
141  		else if (*it == '[')
142  		{
143  			data._type = TYPE_ARRAY;
144  			data._arr = parseArray(text, it);
145  		}
146  		else if (*it == ']')
147  		{
148  			break;
149  		}
150  		else if (std::isalnum(*it))
151  		{
152  			data._str = parsePrimitive(it, data._type);
153  		}
154  		else
155  		{
156  			_errorExit("Error: Invalid array element");
157  		}
158  
159  		if (checkElementEnd(text, it) == false)
160  		{
161  			_errorExit("Error: Malformed array format");
162  		}
163  
164  		it++;
165  		while (*it == ',' || std::isspace(*it))
166  			it++;
167  
168  		arr.push_back(data);
169  	}
170  
171  	return arr;
172  }
173  
174  JsonData	JsonParser::parseObject
175  (std::string const& text, std::string::iterator& it)
176  {
177  	JsonData										jsonData;
178  	std::vector<std::pair< std::string, JsonData> >	jsonObject;
179  
180  	while (std::isspace(*it))
181  		++it;
182  
183  	if (*it != '{')
184  	{
185  		_errorExit("Error: Object must start with open curly bracket");
186  	}
187  	it++;
188  
189  	do {
190  		std::pair<std::string, JsonData> keyValuePair
191  			= retriveKeyValuePair(text, it);
192  
193  		jsonObject.push_back(keyValuePair);
194  
195  		while (std::isspace(*it))
196  			it++;
197  
198  	} while (*it != '}');
199  
200  	jsonData._type = TYPE_OBJECT;
201  	jsonData._obj = jsonObject;
202  
203  	return jsonData;
204  }
205  
206  bool	JsonParser::checkElementEnd
207  (std::string const& text, std::string::iterator& it)
208  {
209  	std::string::iterator	cur;
210  	bool					comma = false;
211  
212  	if (it == text.end())
213  	{
214  		_errorExit("Error: Incomplete array");
215  	}
216  
217  	cur = it + 1;
218  	while (*cur == ',' || std::isspace(*cur))
219  	{
220  		if (*cur == ',')
221  		{
222  			if (comma == false)
223  			{
224  				comma = true;
225  			}
226  			else
227  			{
228  				_errorExit("Error: Duplicate comma");
229  			}
230  		}
231  		cur++;
232  	}
233  
234  	if (*cur == '\"')
235  	{
236  		if (comma == true)
237  		{
238  			return true;
239  		}
240  		else
241  		{
242  			_errorExit("Error: Missing comma before element");
243  		}
244  	}
245  	else if (*cur == '{')
246  	{
247  		if (comma == true)
248  		{
249  			return true;
250  		}
251  		else
252  		{
253  			_errorExit("Error: Missing comma before element");
254  		}
255  	}
256  	else if (*cur == '[')
257  	{
258  		if (comma == true)
259  		{
260  			return true;
261  		}
262  		else
263  		{
264  			_errorExit("Error: Missing comma before element");
265  		}
266  	}
267  	else if (std::isalnum(*cur))
268  	{
269  		if (comma == true)
270  		{
271  			return true;
272  		}
273  		else
274  		{
275  			_errorExit("Error: Missing comma before element");
276  		}
277  	}
278  	else if (*cur == ']')
279  	{
280  		if (comma == false)
281  		{
282  			return true;
283  		}
284  		else
285  		{
286  			_errorExit("Error: Found comma before end of array");
287  		}
288  	}
289  
290  	return false;
291  }
292  
293  bool	JsonParser::checkKeyValueEnd
294  (std::string const& text, std::string::iterator& it)
295  {
296  	std::string::iterator	cur;
297  	bool					comma = false;
298  
299  	if (it == text.end())
300  	{
301  		_errorExit("Error: Incomplete object");
302  	}
303  
304  	cur = it + 1;
305  	while (*cur == ',' || std::isspace(*cur))
306  	{
307  		if (*cur == ',')
308  		{
309  			if (comma == false)
310  			{
311  				comma = true;
312  			}
313  			else
314  			{
315  				_errorExit("Error: Duplicate comma");
316  			}
317  		}
318  		cur++;
319  	}
320  
321  	if (*cur == '\"')
322  	{
323  		if (comma == true)
324  		{
325  			return true;
326  		}
327  		else
328  		{
329  			_errorExit("Error: Missing comma before key");
330  		}
331  	}
332  	else if (*cur == '}')
333  	{
334  		if (comma == false)
335  		{
336  			return true;
337  		}
338  		else
339  		{
340  			_errorExit("Error: Found comma before end of object");
341  		}
342  	}
343  
344  	return false;
345  }
346  
347  std::string	JsonParser::parsePrimitive
348  (std::string::iterator& it, jsonType& type)
349  {
350  	std::string	value;
351  
352  	while (*it != ',' && *it != '}' && *it != ']' && !std::isspace(*it))
353  	{
354  		if (*it == '\"')
355  		{
356  			_errorExit("Error: Malformed primitive format");
357  		}
358  		value += *it;
359  		it++;
360  	}
361  	it--;
362  
363  	type = getPrimitiveType(value);
364  	if (type == TYPE_ERROR)
365  	{
366  		_errorExit("Error: Invalid primitive");
367  	}
368  
369  	return value;
370  }
371  
372  std::string	JsonParser::parseStringKey
373  (std::string const& text, std::string::iterator& it)
374  {
375  	std::string	key;
376  
377  	key = getStringData(text, it);
378  
379  	it++;
380  	while (std::isspace(*it))
381  		it++;
382  
383  	if (*it != ':')
384  	{
385  		_errorExit("Error: Missing colon after key");
386  	}
387  	it++;
388  
389  	return key;
390  }
391  
392  std::string	JsonParser::parseStringValue
393  (std::string const& text, std::string::iterator& it)
394  {
395  	return getStringData(text, it);
396  }
397  
398  std::string	JsonParser::getStringData
399  (std::string const& text, std::string::iterator& it)
400  {
401  	std::string	str;
402  	bool		insideQuote = false;
403  	bool		escape = false;
404  	char		ch;
405  
406  	while (it != text.end())
407  	{
408  		ch = *it;
409  		if (insideQuote)
410  		{
411  			if (ch == '\n')
412  			{
413  				_errorExit("Error: Malformed String Data type");
414  			}
415  			if (escape)
416  			{
417  				str += ch;
418  				escape = false;
419  			}
420  			else if (ch == '\\')
421  			{
422  				escape = true;
423  			}
424  			else if (ch == '\"')
425  			{
426  				insideQuote = false;
427  				break;
428  			}
429  			else
430  			{
431  				str += ch;
432  			}
433  		}
434  		else if (ch == '\"')
435  		{
436  			insideQuote = true;
437  		}
438  		else if (ch == '\\')
439  		{
440  			escape = true;
441  		}
442  		else
443  		{
444  			_errorExit("Error: Malformed String Data type");
445  		}
446  		it++;
447  	}
448  
449  	if ((it == text.end()) || insideQuote)
450  	{
451  		_errorExit("Error: Malformed String Data type");
452  	}
453  
454  	return str;
455  }
456  
457  jsonType	JsonParser::getPrimitiveType(std::string const& str)
458  {
459  	char*	endptr;
460  
461  	static_cast<void>(strtol(str.c_str(), &endptr, 10));
462  	if (*endptr == '\0')
463  		return TYPE_INTEGER;
464  	static_cast<void>(strtod(str.c_str(), &endptr));
465  	if (*endptr == '\0')
466  		return TYPE_FLOAT;
467  	if (str == "true" || str == "false")
468  		return TYPE_BOOLEAN;
469  	if (str == "null")
470  		return TYPE_NULL;
471  	return TYPE_ERROR;
472  }
473  
474  /* *************************************************************************** *
475   * Helper Functions                                                            *
476   * ****************************************************************************/
477  
478  static void	_errorExit(std::string const& msg)
479  {
480  	std::cerr << msg << std::endl;
481  	std::exit(1);
482  }