libzypp 17.37.10

json.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9
10#include "json.h"
11#include <zypp-core/AutoDispose.h>
12
13 namespace zypp::json {
14
15 constexpr std::string_view TOK_NAMES[Parser::Token::TOK_COUNT] = {
16 "TOK_STRING",
17 "TOK_NUMBER_FLOAT",
18 "TOK_NUMBER_UINT",
19 "TOK_NUMBER_INT",
20 "TOK_BOOL_TRUE",
21 "TOK_BOOL_FALSE",
22 "TOK_NULL",
23 "TOK_LSQUARE_BRACKET",
24 "TOK_RSQUARE_BRACKET",
25 "TOK_LCURLY_BRACKET",
26 "TOK_RCURLY_BRACKET",
27 "TOK_COMMA",
28 "TOK_COLON",
29 "TOK_END"
30 };
31
32 static bool isWhiteSpace ( const char ch ) {
33 static constexpr char whitespaces[] { ' ', '\n', '\r', '\t', 0 };
34 return ( std::find (whitespaces, whitespaces+4, ch ) != whitespaces+4 );
35 }
36
37 zyppng::expected<Value> Parser::parse( const InputStream &input_r )
38 {
39 using namespace zyppng::operators;
40 _stream = input_r;
41 zypp_defer{
42 _stream.reset();
43 };
44
45 auto document = nextToken()
46 | and_then( [&](Parser::Token t) {
47 switch ( t._type ) {
48 case Token::TOK_LSQUARE_BRACKET:
49 return parseArray() | and_then([&]( Array a ){ return zyppng::make_expected_success( Value(std::move(a))); } );
50 case Token::TOK_LCURLY_BRACKET:
51 return parseObject() | and_then([&]( Object a ){ return zyppng::make_expected_success( Value(std::move(a))); } );
52 case Token::TOK_STRING:
53 return zyppng::make_expected_success<Value>( String(t._token) );
54 case Token::TOK_BOOL_FALSE:
55 return zyppng::make_expected_success<Value>( Bool(false) );
56 case Token::TOK_BOOL_TRUE:
57 return zyppng::make_expected_success<Value>( Bool(true) );
58 case Token::TOK_NUMBER_FLOAT:
59 return Number::fromString( t._token ) | and_then( []( Number n ){ return zyppng::make_expected_success( Value(std::move(n)) ); } );
60 case Token::TOK_NUMBER_UINT:
61 return UInt::fromString( t._token ) | and_then( []( UInt n ){ return zyppng::make_expected_success( Value(std::move(n)) ); } );
62 case Token::TOK_NUMBER_INT:
63 return Int::fromString( t._token ) | and_then( []( Int n ){ return zyppng::make_expected_success( Value(std::move(n)) ); } );
64 case Token::TOK_NULL:
65 return zyppng::make_expected_success( Value() );
66 case Token::TOK_END:
67 return zyppng::make_expected_success( Value() );
68 default:
69 return makeParseError<Value>( str::Str() << "Unexpected token " << TOK_NAMES[t._type] << ", json document must consist of a valid JSON value, object or array.", ZYPP_EX_CODELOCATION );
70 }
71 });
72
73 if ( !document )
74 return document;
75
76 // expect end of document
77 auto endToken = nextToken();
78 if ( !endToken )
79 return zyppng::expected<Value>::error( endToken.error() );
80 if ( endToken->_type != Token::TOK_END ) {
81 return makeParseError<Value>( str::Str() << "Unexpected token " << TOK_NAMES[endToken->_type] << ", EOF was expected.", ZYPP_EX_CODELOCATION );
82 }
83 // all good
84 return document;
85 }
86
87 zyppng::expected<Object> Parser::parseObject()
88 {
89 using namespace zyppng::operators;
90
91 _nestingDepth++;
92 zypp_defer{ _nestingDepth--; };
93 if ( _nestingDepth > 1000 ) {
94 return makeParseError<Object>( str::Str() << "Nesting level is too deep ( > 1000 ).", ZYPP_EX_CODELOCATION );
95 }
96
97 enum State {
98 Obj_Start,
99 Obj_Expect_Comma_Or_End,
100 Obj_Expect_Pair
101 } state = Obj_Start;
102
103 Object o;
104
105 const auto &parsePair = [&]( String &&key ) {
106 return nextToken()
107 | and_then([&]( Token maybeColon ) {
108 if ( maybeColon._type == Token::TOK_COLON )
109 return parseValue();
110 else
111 return makeParseError<Value>( str::Str() << "Unexpected token " << TOK_NAMES[maybeColon._type] << ", colon was expected in key, value pair.", ZYPP_EX_CODELOCATION );
112 })
113 | and_then([&]( Value val ){
114 o.add ( key, std::move(val) );
115 return zyppng::expected<void>::success ();
116 });
117 };
118
119 while ( true ) {
120
121 auto t = nextToken();
122 if ( !t )
123 return zyppng::expected<Object>::error( t.error( ) );
124
125 switch ( state ) {
126 case Obj_Start: {
127 // we can have either the start of a key-value pair or a closing }
128 switch ( t->_type ) {
129 case Token::TOK_STRING: {
130 auto res = parsePair( String( std::move(t->_token) ) );
131 if ( !res )
132 return zyppng::expected<Object>::error( res.error( ) );
133
134 state = Obj_Expect_Comma_Or_End;
135 break;
136 }
137 case Token::TOK_RCURLY_BRACKET: {
138 return zyppng::make_expected_success(std::move(o));
139 break;
140 }
141 default:
142 return makeParseError<Object>( str::Str() << "Unexpected token " << TOK_NAMES[t->_type] << " while parsing a Object.", ZYPP_EX_CODELOCATION );
143 break;
144 }
145 break;
146 }
147 case Obj_Expect_Comma_Or_End: {
148 switch ( t->_type ) {
149 case Token::TOK_COMMA: {
150 state = Obj_Expect_Pair;
151 break;
152 }
153 case Token::TOK_RCURLY_BRACKET: {
154 return zyppng::make_expected_success(std::move(o));
155 break;
156 }
157 default:
158 return makeParseError<Object>( str::Str() << "Unexpected token " << TOK_NAMES[t->_type] << " while parsing a Object.", ZYPP_EX_CODELOCATION );
159 break;
160 }
161 break;
162 }
163 case Obj_Expect_Pair: {
164 // we can have either the start of a key-value pair or a closing }
165 switch ( t->_type ) {
166 case Token::TOK_STRING: {
167 auto res = parsePair( String( std::move(t->_token) ) );
168 if ( !res )
169 return zyppng::expected<Object>::error( res.error( ) );
170
171 state = Obj_Expect_Comma_Or_End;
172 break;
173 }
174 default:
175 return makeParseError<Object>( str::Str() << "Unexpected token " << TOK_NAMES[t->_type] << " while parsing a Object.", ZYPP_EX_CODELOCATION );
176 break;
177 }
178 break;
179 }
180 }
181 }
182 }
183
184 zyppng::expected<Array> Parser::parseArray()
185 {
186 using namespace zyppng::operators;
187
188 _nestingDepth++;
189 zypp_defer{ _nestingDepth--; };
190 if ( _nestingDepth > 1000 ) {
191 return makeParseError<Array>( str::Str() << "Nesting level is too deep ( > 1000 ).", ZYPP_EX_CODELOCATION );
192 }
193
194 enum State {
195 Arr_Init, // can be value or array end token
196 Arr_Value, // next token must be a value
197 Arr_Expect_Comma_Or_End, // next token must be TOK_COMMA or TOK_RSQUARE_BRACKET
198 } state = Arr_Init;
199
200 Array a;
201 while ( true ) {
202 switch ( state ) {
203 case Arr_Init: {
204 auto tok = nextToken();
205 if ( !tok )
206 return zyppng::expected<Array>::error( tok.error( ) );
207
208 if ( tok->_type == Token::TOK_RSQUARE_BRACKET )
209 return zyppng::make_expected_success( std::move(a) );
210
211 auto maybeVal = finishParseValue( std::move(*tok) );
212 if ( !maybeVal )
213 return zyppng::expected<Array>::error( maybeVal.error( ) );
214
215 a.add( std::move(*maybeVal) );
216 state = Arr_Expect_Comma_Or_End;
217 break;
218 }
219 case Arr_Value: {
220 auto maybeVal = parseValue();
221 if ( !maybeVal )
222 return zyppng::expected<Array>::error( maybeVal.error( ) );
223
224 a.add( std::move(*maybeVal) );
225 state = Arr_Expect_Comma_Or_End;
226 break;
227 }
228 case Arr_Expect_Comma_Or_End: {
229 auto tok = nextToken();
230 if ( !tok )
231 return zyppng::expected<Array>::error( tok.error( ) );
232
233 switch(tok->_type) {
234 case Token::TOK_RSQUARE_BRACKET:
235 return zyppng::make_expected_success( std::move(a) );
236 case Token::TOK_COMMA:
237 state = Arr_Value;
238 break;
239 default:
240 return makeParseError<Array>( str::Str() << "Unexpected token " << TOK_NAMES[tok->_type] << " while parsing a JSON value.", ZYPP_EX_CODELOCATION );
241 break;
242 }
243 break;
244 }
245 }
246 }
247 }
248
252 zyppng::expected<Value> Parser::parseValue()
253 {
254 using namespace zyppng::operators;
255 return nextToken()
256 | and_then([&]( Token &&tok ) {
257 return finishParseValue ( std::move(tok) );
258 });
259 }
260
265 zyppng::expected<Value> Parser::finishParseValue( Token begin )
266 {
267 using namespace zyppng::operators;
268 switch( begin._type ) {
269 case Token::TOK_STRING:
270 return zyppng::make_expected_success( Value( String( std::move(begin._token) )));
271 case Token::TOK_NUMBER_FLOAT:
272 return Number::fromString( begin._token ) | and_then( []( Number n ){ return zyppng::make_expected_success( Value(std::move(n)) ); } );
273 case Token::TOK_NUMBER_UINT:
274 return UInt::fromString( begin._token ) | and_then( []( UInt n ){ return zyppng::make_expected_success( Value(std::move(n)) ); } );
275 case Token::TOK_NUMBER_INT:
276 return Int::fromString( begin._token ) | and_then( []( Int n ){ return zyppng::make_expected_success( Value(std::move(n)) ); } );
277 case Token::TOK_BOOL_TRUE:
278 return zyppng::make_expected_success( Value( Bool( true ) ));
279 case Token::TOK_BOOL_FALSE:
280 return zyppng::make_expected_success( Value( Bool( false ) ));
281 case Token::TOK_NULL:
282 return zyppng::make_expected_success( Value() );
283 case Token::TOK_LSQUARE_BRACKET:
284 return parseArray() | and_then( []( Array a ){ return zyppng::make_expected_success( Value(std::move(a)) ); } );
285 case Token::TOK_LCURLY_BRACKET:
286 return parseObject() | and_then( []( Object o ){ return zyppng::make_expected_success( Value(std::move(o)) ); } );
287 default:
288 return makeParseError<Value>( str::Str() << "Unexpected token " << TOK_NAMES[begin._type] << " while parsing a JSON value.", ZYPP_EX_CODELOCATION );
289 break;
290 }
291 }
292
293 zyppng::expected<Parser::Token> Parser::parseNullToken()
294 {
295 using namespace zyppng::operators;
296 return consumeString ( "null" )
297 | and_then ( [&](){
298 return zyppng::make_expected_success( Token{ ._type = Token::TOK_NULL } );
299 });
300 }
301
302 zyppng::expected<Parser::Token> Parser::parseBoolToken()
303 {
304 using namespace zyppng::operators;
305 char next = peekChar();
306 if ( next == 't' ) {
307 return consumeString ( "true" )
308 | and_then ( [&](){
309 return zyppng::make_expected_success( Token{ ._type = Token::TOK_BOOL_TRUE } );
310 });
311 } else if ( next == 'f' ) {
312 return consumeString ( "false" )
313 | and_then ( [&](){
314 return zyppng::make_expected_success( Token{ ._type = Token::TOK_BOOL_FALSE } );
315 });
316 } else if ( next == eofChar() ) {
317 return makeParseError( str::Str() << "Unexpected EOF while parsing a boolean", ZYPP_EX_CODELOCATION );
318 } else {
319 return makeParseError( str::Str() << "Unexpected char " << next << " while parsing a boolean", ZYPP_EX_CODELOCATION );
320 }
321 }
322
323 zyppng::expected<Parser::Token> Parser::parseNumberToken()
324 {
325 enum State {
326 Begin, // accepts sign, 0-9
327 ExpectFraction_or_End, // received 0 in init state, now needs a fraction a exponent or an end
328 ExpectDigit, // requires a digit to be next
329 Digit, // expects digit 0-9 or e E to move into exponent parsing, any other char ends number parsing
330 Exponent_Begin, // we saw a e or E and now expect a sign or digit
331 Exponent_ExpectDigit, // state entered after a sign, where we require a digit
332 Exponent // digits until we see something else
333 } state = Begin;
334
335 Token t;
336 bool isSigned = false;
337 bool acceptSign = true;
338 bool done = false;
339 bool isFloating = false;
340 bool hasFraction = false;
341
342 while ( !done ) {
343 char c = peekChar();
344
345 switch ( state ) {
346 case Begin: {
347 if ( c == '-' && acceptSign ) {
348 acceptSign = false;
349 isSigned = true;
350 t._token.push_back(c);
351 consumeChar();
352 } else if ( c >= '1' && c <= '9' ) {
353 t._token.push_back (c);
354 consumeChar();
355 state = Digit;
356 } else if ( c == '0' ) {
357 t._token.push_back (c);
358 consumeChar();
359 state = ExpectFraction_or_End;
360 } else if ( c == eofChar() ) {
361 return makeParseError( str::Str() << "Unexpected EOF while parsing a number.", ZYPP_EX_CODELOCATION );
362 } else {
363 return makeParseError( str::Str() << "Unexpected char " << c << " while parsing a number.", ZYPP_EX_CODELOCATION );
364 }
365 break;
366 }
367 case ExpectFraction_or_End: {
368 if ( c == '.' ) {
369 t._token.push_back(c);
370 consumeChar();
371 isFloating = true;
372 hasFraction = true;
373 state = ExpectDigit;
374 } else if ( c == 'e' || c == 'E' ) {
375 t._token.push_back (c);
376 consumeChar();
377 state = Exponent_Begin;
378 isFloating = true;
379 } else {
380 // any other char marks the end of the number
381 done = true;
382 }
383 break;
384 }
385 case ExpectDigit: {
386 if ( c >= '0' && c <= '9' ) {
387 t._token.push_back (c);
388 consumeChar();
389 state = Digit;
390 } else {
391 // any other char is a error
392 return makeParseError( str::Str() << "Unexpected char " << c << " while parsing a number, digit was expected.", ZYPP_EX_CODELOCATION );
393 }
394 break;
395 }
396 case Digit: {
397 if ( c >= '0' && c <= '9' ) {
398 t._token.push_back (c);
399 consumeChar();
400 } else if ( c == 'e' || c == 'E' ) {
401 t._token.push_back (c);
402 consumeChar();
403 state = Exponent_Begin;
404 isFloating = true;
405 } else if ( c == '.' && !hasFraction ) {
406 t._token.push_back(c);
407 consumeChar();
408 isFloating = true;
409 hasFraction = true;
410 state = ExpectDigit;
411 } else {
412 // any other char marks the end of the number
413 done = true;
414 }
415 break;
416 }
417 case Exponent_Begin: {
418 if ( c == '+' || c == '-' ) {
419 t._token.push_back (c);
420 consumeChar();
421 state = Exponent_ExpectDigit;
422 } else if ( c >= '0' && c <= '9') {
423 t._token.push_back (c);
424 consumeChar();
425 state = Exponent;
426 } else if ( c == eofChar() ) {
427 return makeParseError( str::Str() << "Unexpected EOF while parsing a number.", ZYPP_EX_CODELOCATION );
428 } else {
429 return makeParseError( str::Str() << "Unexpected char " << c << " while parsing a number, sign or digit was expected.", ZYPP_EX_CODELOCATION );
430 }
431 break;
432 }
433 case Exponent_ExpectDigit:
434 case Exponent: {
435 if ( c >= '0' && c <= '9' ) {
436
437 if ( state != Exponent )
438 state = Exponent;
439
440 t._token.push_back (c);
441 consumeChar();
442
443 } else if ( state == Exponent_ExpectDigit ) {
444 return makeParseError( str::Str() << "Unexpected char " << c << " while parsing a number with exponent, digit was expected.", ZYPP_EX_CODELOCATION );
445 } else {
446 // any other char marks the end of the number
447 done = true;
448 }
449 break;
450 }
451 }
452 }
453
454 if ( isFloating ) {
455 t._type = Token::TOK_NUMBER_FLOAT;
456 } else {
457 if ( isSigned ) {
458 t._type = Token::TOK_NUMBER_INT;
459 } else {
460 t._type = Token::TOK_NUMBER_UINT;
461 }
462 }
463 return zyppng::make_expected_success( std::move(t) );
464 }
465
466 std::istream::char_type Parser::popChar()
467 {
468 if ( !_stream )
469 return std::istream::traits_type::eof();
470
471 auto &input = _stream->stream();
472 if ( input.eof () )
473 return std::istream::traits_type::eof();
474
475 return input.get();
476 }
477
478 std::istream::char_type Parser::peekChar()
479 {
480 if ( !_stream )
481 return std::istream::traits_type::eof();
482
483 auto &input = _stream->stream();
484 if ( input.eof () )
485 return std::istream::traits_type::eof();
486
487 return input.peek();
488 }
489
490 void Parser::consumeChar()
491 {
492 if ( _stream )
493 _stream->stream().ignore();
494 }
495
496 zyppng::expected<void> Parser::consumeString( const std::string &str )
497 {
498 for ( uint i = 0; i < str.size(); i++ ) {
499 char c = popChar();
500 if ( c == eofChar () )
501 return makeParseError<void>( str::Str() << "Unexpected EOF while parsing: " << str, ZYPP_EX_CODELOCATION );
502 if ( c != str.at(i) )
503 return makeParseError<void>( str::Str() << "Unexpected char " << c << " ,character " << str.at(i) << " was expected while parsing: " << str, ZYPP_EX_CODELOCATION );
504 }
505 return zyppng::expected<void>::success();
506 }
507
508 zyppng::expected<Parser::Token> Parser::nextToken()
509 {
510 try {
511 char nextChar = peekChar();
512
513 while ( nextChar != eofChar()
514 && isWhiteSpace (nextChar) ) {
515 consumeChar ();
516 nextChar = peekChar();
517 }
518
519 if ( nextChar == eofChar() ) {
520 return zyppng::make_expected_success( Token {
521 ._type = Token::TOK_END
522 } );
523 }
524
525 switch ( nextChar ) {
526 case '"': {
527 return parseStringToken ();
528 }
529 case '-':
530 case '0':
531 case '1':
532 case '2':
533 case '3':
534 case '4':
535 case '5':
536 case '6':
537 case '7':
538 case '8':
539 case '9': {
540 return parseNumberToken();
541 }
542 case 't':
543 case 'f': {
544 return parseBoolToken();
545 }
546 case 'n': {
547 return parseNullToken();
548 }
549 case '{': {
550 consumeChar ();
551 return zyppng::make_expected_success( Token {
552 ._type = Token::TOK_LCURLY_BRACKET
553 } );
554 }
555 case '}': {
556 consumeChar ();
557 return zyppng::make_expected_success( Token {
558 ._type = Token::TOK_RCURLY_BRACKET
559 } );
560 }
561 case '[': {
562 consumeChar ();
563 return zyppng::make_expected_success( Token {
564 ._type = Token::TOK_LSQUARE_BRACKET
565 } );
566 }
567 case ']': {
568 consumeChar ();
569 return zyppng::make_expected_success( Token {
570 ._type = Token::TOK_RSQUARE_BRACKET
571 } );
572 }
573 case ':': {
574 consumeChar ();
575 return zyppng::make_expected_success( Token {
576 ._type = Token::TOK_COLON
577 } );
578 }
579 case ',': {
580 consumeChar ();
581 return zyppng::make_expected_success( Token {
582 ._type = Token::TOK_COMMA
583 } );
584 }
585 default:
586 return makeParseError( ( str::Str() << "Unexpected token: " << nextChar << " in json stream."), ZYPP_EX_CODELOCATION );
587 break;
588 }
589 } catch (...) {
590 return zyppng::expected<Token>::error( ZYPP_FWD_CURRENT_EXCPT() );
591 }
592 }
593
594 zyppng::expected<Parser::Token> Parser::parseStringToken()
595 {
596 using namespace zyppng::operators;
597 auto c = popChar ();
598
599 // shouldn't happen because we peeked before that there is a "
600 if ( c != '"' ) {
601 return makeParseError( ( str::Str() << "Unexpected token: " << c << ", a JSON String must start with \"."), ZYPP_EX_CODELOCATION );
602 }
603
604 Token t {
605 ._type = Token::TOK_STRING
606 };
607
608 while( true ) {
609 c = popChar();
610 // escaped
611 if ( c == eofChar () ) {
612 return makeParseError( ( str::Str() << "Unexpected EOF token in the middle of a string."), ZYPP_EX_CODELOCATION );
613
614 } else if ( c == '\\' ) {
615
616 c = this->popChar();
617 if ( c == eofChar() ) {
618 return makeParseError( "Unexpected EOF in escaped string character.", ZYPP_EX_CODELOCATION );
619 }
620
621 switch ( c ) {
622 case '"' :
623 case '\\':
624 case '/' :
625 {
626 t._token.push_back(c);
627 break;
628 }
629 case 'b' : {
630 t._token.push_back( '\b' );
631 break;
632 }
633 case 'f' : {
634 t._token.push_back( '\f' );
635 break;
636 }
637 case 'n' : {
638 t._token.push_back( '\n' );
639 break;
640 }
641 case 'r' : {
642 t._token.push_back( '\r' );
643 break;
644 }
645 case 't' : {
646 t._token.push_back( '\t' );
647 break;
648 }
649 case 'u' : {
650 const auto &pop4HexBytes = [&]( ) {
651 std::vector<char> data( 4, '\0' );
652 for (int i = 0; i < 4; i++) {
653 data[i] = this->popChar();
654 if ( data[i] == eofChar() ) {
655 return makeParseError<std::vector<char>>( "Unexpected EOF in \\u escaped string character.", ZYPP_EX_CODELOCATION );
656 }
657
658 if ( (data[i] >= '0' && data[i] <= '9' )
659 || (data[i] >= 'A' && data[i] <= 'F' )
660 || (data[i] >= 'a' && data[i] <= 'f' )
661 ) {
662 // accept char
663 continue;
664 }
665 return makeParseError<std::vector<char>>( str::Str() << "Unexpected token " << str::hexstring(c) << " in \\u escaped string character.", ZYPP_EX_CODELOCATION );
666 }
667 return zyppng::expected<std::vector<char>>::success( std::move(data) );
668 };
669
670 // check data and convert it to a codepoint, if data contains the
671 // start of a surrogate pair, read the second value and return the resulting codepoint
672 const auto &convertToCodepoint = [&]( std::vector<char> data ){
673 // check if the codepoint is int the UTF-16 surrogate pair range,
674 // if yes we need to fetch another 4 bits
675
676 const auto data1View = std::string_view(data.data(), data.size());
677 auto cp = str::hexCharToValue<uint32_t>( data1View );
678
679 if ( !cp ) {
680 return makeParseError<uint32_t>( str::Str() << "Invalid \\u escaped character: " << data1View , ZYPP_EX_CODELOCATION );
681 }
682
683 // UTF16 surrogate pair?
684 if ( (*cp) >= 0xd800 && (*cp) <= 0xdbff ) {
685 return consumeString ("\\u" ) // require another \u
686 | and_then( [&](){ return pop4HexBytes( ); })
687 | and_then( [&]( std::vector<char> data2 ){
688 // convert to codepoint
689 const auto data2View = std::string_view(data2.data(), data2.size());
690 const auto lowCp = str::hexCharToValue<uint32_t>( data2View );
691
692 if ( !lowCp ) {
693 return makeParseError<uint32_t>( str::Str() << "Invalid \\u escaped character: " << data2View , ZYPP_EX_CODELOCATION );
694 }
695
696 if ( *lowCp < 0xDC00 || *lowCp > 0xDFFF) {
697 return makeParseError<uint32_t>( str::Str() << "Invalid UTF16 surrogate pair: (" << data1View << "," << data2View <<")" , ZYPP_EX_CODELOCATION );
698 }
699
700 constexpr uint16_t low10BitMask = 0x3FF; // low 10 bits
701 uint32_t codepoint = (( (*cp) & low10BitMask ) << 10 ) | ( (*lowCp) & low10BitMask );
702 codepoint += 0x10000;
703 return zyppng::expected<uint32_t>::success( codepoint );
704 });
705
706 } else {
707 return zyppng::expected<uint32_t>::success( *cp );
708 }
709 };
710
711 const auto &codepointToUtf8String = [&]( uint32_t cp ) {
712 if ( cp == 0 ) {
713 // json does allow a null character to be part of the string
714 t._token += '\0';
715 return zyppng::expected<void>::success();
716 }
717 const auto &conv = str::codepointToUtf8String( cp );
718 if ( conv.size () == 0 ) {
719 return makeParseError<void>( str::Str() << "Invalid codepoint in string " << cp, ZYPP_EX_CODELOCATION );
720 }
721 if ( !str::validateUtf8(conv) ) {
722 return makeParseError<void>( str::Str() << "Invalid codepoint in string " << cp << " ,this is not a valid UTF-8 character.", ZYPP_EX_CODELOCATION );
723 }
724 t._token += conv;
725 return zyppng::expected<void>::success();
726 };
727
728 auto res = pop4HexBytes()
729 | and_then( convertToCodepoint )
730 | and_then( codepointToUtf8String );
731
732 if ( !res )
733 return zyppng::expected<Parser::Token>::error(res.error());
734
735 break;
736 }
737 default:
738 return makeParseError( str::Str() << "Unexpected token " << str::hexstring(c) << " in \\ escaped string character.", ZYPP_EX_CODELOCATION );
739 }
740 } else if( c == '"' ) {
741 break;
742 } else if( c >= 0 && c <= 0x1f ) {
743 return makeParseError( str::Str() << "Unescaped control character " << str::hexstring(c) << " in string is not allowed.", ZYPP_EX_CODELOCATION );
744 } else {
745 t._token.push_back(c);
746 }
747 }
748
749 return zyppng::make_expected_success(t);
750 }
751
752 Parser::Token Parser::Token::eof()
753 {
754 return Token {
755 ._type = Token::TOK_END
756 };
757 }
758
759
760}
761
762
zypp::InputStream
Helper to create and pass std::istream.
Definition inputstream.h:57
zypp::json::Array
Definition JsonValue.h:32
zypp::json::Bool
Definition JsonBool.h:20
zypp::json::Int
Definition JsonNumber.h:66
zypp::json::Int::fromString
static zyppng::expected< Int > fromString(const std::string &str)
Definition JsonNumber.h:86
zypp::json::Number
Definition JsonNumber.h:19
zypp::json::Number::fromString
static zyppng::expected< Number > fromString(const std::string &str)
Definition JsonNumber.h:32
zypp::json::Object
Definition JsonValue.h:99
zypp::json::Object::add
void add(String key_r, Value val_r)
Add key/value pair.
Definition JsonValue.cc:48
zypp::json::Parser::parseNullToken
zyppng::expected< Token > parseNullToken()
Definition json.cc:293
zypp::json::Parser::parseBoolToken
zyppng::expected< Token > parseBoolToken()
Definition json.cc:302
zypp::json::Parser::_nestingDepth
int _nestingDepth
Definition json.h:102
zypp::json::Parser::finishParseValue
zyppng::expected< Value > finishParseValue(Token begin)
Definition json.cc:265
zypp::json::Parser::parseObject
zyppng::expected< Object > parseObject()
Definition json.cc:87
zypp::json::Parser::parseNumberToken
zyppng::expected< Token > parseNumberToken()
Definition json.cc:323
zypp::json::Parser::consumeString
zyppng::expected< void > consumeString(const std::string &str)
Definition json.cc:496
zypp::json::Parser::parseValue
zyppng::expected< Value > parseValue()
Definition json.cc:252
zypp::json::Parser::parse
zyppng::expected< Value > parse(const InputStream &input_r)
Parse the stream.
Definition json.cc:37
zypp::json::Parser::nextToken
zyppng::expected< Token > nextToken()
Definition json.cc:508
zypp::json::Parser::parseArray
zyppng::expected< Array > parseArray()
Definition json.cc:184
zypp::json::Parser::eofChar
static std::istream::char_type eofChar()
Definition json.h:91
zypp::json::Parser::consumeChar
void consumeChar()
Definition json.cc:490
zypp::json::Parser::parseStringToken
zyppng::expected< Token > parseStringToken()
Definition json.cc:594
zypp::json::Parser::popChar
std::istream::char_type popChar()
Definition json.cc:466
zypp::json::Parser::peekChar
std::istream::char_type peekChar()
Definition json.cc:478
zypp::json::Parser::_stream
std::optional< InputStream > _stream
Definition json.h:101
zypp::json::Parser::makeParseError
zyppng::expected< T > makeParseError(const std::string &message, exception_detail::CodeLocation &&loc)
Definition json.h:96
zypp::json::String
Definition JsonString.h:113
zypp::json::UInt
Definition JsonNumber.h:111
zypp::json::UInt::fromString
static zyppng::expected< UInt > fromString(const std::string &str)
Definition JsonNumber.h:123
zypp::json::Value
Definition JsonValue.h:173
zyppng::expected
Definition expected.h:27
zyppng::expected::success
static expected success(ConsParams &&...params)
Definition expected.h:115
zyppng::expected::error
E & error()
Definition expected.h:225
json.h
a
unsigned short a
Definition mediablocklist.cc:0
str
String related utilities and Regular expression matching.
zypp::json
Definition TargetImpl.cc:150
zypp::json::isWhiteSpace
static bool isWhiteSpace(const char ch)
Definition json.cc:32
zypp::json::TOK_NAMES
constexpr std::string_view TOK_NAMES[Parser::Token::TOK_COUNT]
Definition json.cc:15
zypp::str::codepointToUtf8String
std::string codepointToUtf8String(uint32_t unichar)
Definition String.cc:525
zypp::str::validateUtf8
bool validateUtf8(std::string_view str)
Definition String.cc:520
zypp::str::hexstring
std::string hexstring(char n, int w=4)
Definition String.h:325
zyppng::operators
Definition asyncresult.h:279
zyppng::operators::and_then
auto and_then(Fun &&function)
Definition expected.h:623
zyppng::make_expected_success
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition expected.h:397
zypp::json::Parser::Token
Definition json.h:43
zypp::json::Parser::Token::eof
static Token eof()
Definition json.cc:752
zypp::json::Parser::Token::_token
std::string _token
Definition json.h:64
zypp::json::Parser::Token::TOK_NUMBER_FLOAT
@ TOK_NUMBER_FLOAT
Definition json.h:47
zypp::json::Parser::Token::TOK_NULL
@ TOK_NULL
Definition json.h:52
zypp::json::Parser::Token::TOK_LSQUARE_BRACKET
@ TOK_LSQUARE_BRACKET
Definition json.h:53
zypp::json::Parser::Token::TOK_COUNT
@ TOK_COUNT
Definition json.h:60
zypp::json::Parser::Token::TOK_END
@ TOK_END
Definition json.h:59
zypp::json::Parser::Token::TOK_STRING
@ TOK_STRING
Definition json.h:46
zypp::json::Parser::Token::TOK_RSQUARE_BRACKET
@ TOK_RSQUARE_BRACKET
Definition json.h:54
zypp::json::Parser::Token::TOK_BOOL_FALSE
@ TOK_BOOL_FALSE
Definition json.h:51
zypp::json::Parser::Token::TOK_COMMA
@ TOK_COMMA
Definition json.h:57
zypp::json::Parser::Token::TOK_NUMBER_INT
@ TOK_NUMBER_INT
Definition json.h:49
zypp::json::Parser::Token::TOK_RCURLY_BRACKET
@ TOK_RCURLY_BRACKET
Definition json.h:56
zypp::json::Parser::Token::TOK_COLON
@ TOK_COLON
Definition json.h:58
zypp::json::Parser::Token::TOK_NUMBER_UINT
@ TOK_NUMBER_UINT
Definition json.h:48
zypp::json::Parser::Token::TOK_BOOL_TRUE
@ TOK_BOOL_TRUE
Definition json.h:50
zypp::json::Parser::Token::TOK_LCURLY_BRACKET
@ TOK_LCURLY_BRACKET
Definition json.h:55
zypp::json::Parser::Token::_type
Type _type
Definition json.h:63
zypp::str::Str
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:213
AutoDispose.h
zypp_defer
#define zypp_defer
Definition AutoDispose.h:293
ZYPP_EX_CODELOCATION
#define ZYPP_EX_CODELOCATION
Create CodeLocation object storing the current location.
Definition Exception.h:69
ZYPP_FWD_CURRENT_EXCPT
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition Exception.h:471