#line 1 "src/internal_modules/roc_address/endpoint_uri_parse.rl"
/*
* Copyright (c) 2019 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "roc_address/endpoint_uri.h"
#include "roc_address/protocol_map.h"
#include "roc_core/log.h"
#include "roc_core/panic.h"

namespace roc {
	namespace address {
		

#line 18 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"
static const signed char _parse_endpoint_uri_actions[] = {
			0, 1, 0, 1, 1, 1, 2, 1,
			3, 1, 4, 1, 6, 2, 2, 0,
			2, 2, 6, 2, 3, 0, 2, 3,
			6, 2, 4, 6, 2, 5, 6, 3,
			0, 5, 6, 3, 2, 5, 6, 3,
			3, 5, 6, 3, 4, 5, 6, 4,
			2, 0, 5, 6, 0
		};
		
		static const signed char _parse_endpoint_uri_key_offsets[] = {
			0, 0, 6, 7, 8, 13, 15, 19,
			23, 30, 36, 38, 40, 42, 46, 53,
			60, 62, 66, 71, 0
		};
		
		static const char _parse_endpoint_uri_trans_keys[] = {
			43, 58, 48, 57, 97, 122, 47, 47,
			47, 58, 64, 91, 93, 48, 57, 47,
			64, 91, 93, 47, 64, 91, 93, 43,
			47, 63, 48, 57, 97, 122, 47, 58,
			63, 64, 91, 93, 35, 63, 35, 63,
			35, 63, 47, 63, 48, 57, 35, 47,
			58, 63, 64, 91, 93, 35, 47, 58,
			63, 64, 91, 93, 35, 63, 35, 63,
			48, 57, 35, 47, 63, 48, 57, 47,
			58, 63, 0
		};
		
		static const signed char _parse_endpoint_uri_single_lengths[] = {
			0, 2, 1, 1, 5, 0, 4, 4,
			3, 6, 2, 2, 2, 2, 7, 7,
			2, 2, 3, 3, 0
		};
		
		static const signed char _parse_endpoint_uri_range_lengths[] = {
			0, 2, 0, 0, 0, 1, 0, 0,
			2, 0, 0, 0, 0, 1, 0, 0,
			0, 1, 1, 0, 0
		};
		
		static const signed char _parse_endpoint_uri_index_offsets[] = {
			0, 0, 5, 7, 9, 15, 17, 22,
			27, 33, 40, 43, 46, 49, 53, 61,
			69, 72, 76, 81, 0
		};
		
		static const signed char _parse_endpoint_uri_cond_targs[] = {
			1, 2, 1, 1, 0, 3, 0, 4,
			0, 0, 0, 0, 6, 0, 9, 13,
			0, 0, 0, 0, 0, 7, 0, 0,
			0, 19, 7, 1, 10, 11, 1, 1,
			0, 10, 5, 14, 0, 0, 0, 9,
			0, 11, 10, 0, 0, 12, 0, 0,
			12, 10, 11, 13, 0, 9, 16, 17,
			14, 12, 12, 12, 15, 9, 16, 17,
			14, 12, 12, 12, 15, 0, 11, 16,
			0, 0, 18, 12, 0, 16, 11, 18,
			12, 10, 5, 11, 0, 0, 1, 2,
			3, 4, 5, 6, 7, 8, 9, 10,
			11, 12, 13, 14, 15, 16, 17, 18,
			19, 0
		};
		
		static const signed char _parse_endpoint_uri_cond_actions[] = {
			0, 3, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 1, 0, 1, 1,
			0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 1, 1, 0, 1, 1,
			0, 13, 5, 5, 0, 0, 0, 0,
			0, 9, 0, 0, 0, 1, 0, 0,
			0, 19, 7, 0, 0, 0, 13, 13,
			5, 1, 1, 1, 1, 0, 13, 5,
			5, 0, 0, 0, 0, 0, 9, 0,
			0, 0, 1, 0, 0, 19, 7, 0,
			0, 13, 5, 5, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 11, 16, 25,
			31, 28, 22, 47, 35, 43, 28, 39,
			16, 0
		};
		
		static const signed char _parse_endpoint_uri_eof_trans[] = {
			86, 87, 88, 89, 90, 91, 92, 93,
			94, 95, 96, 97, 98, 99, 100, 101,
			102, 103, 104, 105, 0
		};
		
		static const int parse_endpoint_uri_start = 8;
		static const int parse_endpoint_uri_first_final = 8;
		static const int parse_endpoint_uri_error = 0;
		
		static const int parse_endpoint_uri_en_main = 8;
		
		
#line 20 "src/internal_modules/roc_address/endpoint_uri_parse.rl"

		
		namespace {
			
			bool parse_endpoint_uri_imp(const char* str, EndpointUri::Subset subset, EndpointUri& result) {
				if (!str) {
					roc_log(LogError, "parse endpoint uri: input string is null");
					return false;
				}
				
				result.clear(subset);
				
				// for ragel
				const char* p = str;
				const char *pe = str + strlen(str);
				
				const char *eof = pe;
				int cs = 0;
				
				// for actions
				Protocol proto = Proto_None;
				const char* start_p = NULL;
				
				// parse result
				bool success = false;
				

#line 138 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"
	{
					cs = (int)parse_endpoint_uri_start;
				}

#line 141 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"
	{
					int _klen;
					unsigned int _trans = 0;
					const char * _keys;
					const signed char * _acts;
					unsigned int _nacts;
					_resume: {}
					if ( p == pe && p != eof )
						goto _out;
					if ( p == eof ) {
						if ( _parse_endpoint_uri_eof_trans[cs] > 0 ) {
							_trans = (unsigned int)_parse_endpoint_uri_eof_trans[cs] - 1;
						}
					}
					else {
						_keys = ( _parse_endpoint_uri_trans_keys + (_parse_endpoint_uri_key_offsets[cs]));
						_trans = (unsigned int)_parse_endpoint_uri_index_offsets[cs];
						
						_klen = (int)_parse_endpoint_uri_single_lengths[cs];
						if ( _klen > 0 ) {
							const char *_lower = _keys;
							const char *_upper = _keys + _klen - 1;
							const char *_mid;
							while ( 1 ) {
								if ( _upper < _lower ) {
									_keys += _klen;
									_trans += (unsigned int)_klen;
									break;
								}
								
								_mid = _lower + ((_upper-_lower) >> 1);
								if ( ( (*( p))) < (*( _mid)) )
									_upper = _mid - 1;
								else if ( ( (*( p))) > (*( _mid)) )
									_lower = _mid + 1;
								else {
									_trans += (unsigned int)(_mid - _keys);
									goto _match;
								}
							}
						}
						
						_klen = (int)_parse_endpoint_uri_range_lengths[cs];
						if ( _klen > 0 ) {
							const char *_lower = _keys;
							const char *_upper = _keys + (_klen<<1) - 2;
							const char *_mid;
							while ( 1 ) {
								if ( _upper < _lower ) {
									_trans += (unsigned int)_klen;
									break;
								}
								
								_mid = _lower + (((_upper-_lower) >> 1) & ~1);
								if ( ( (*( p))) < (*( _mid)) )
									_upper = _mid - 2;
								else if ( ( (*( p))) > (*( _mid + 1)) )
									_lower = _mid + 2;
								else {
									_trans += (unsigned int)((_mid - _keys)>>1);
									break;
								}
							}
						}
						
						_match: {}
					}
					cs = (int)_parse_endpoint_uri_cond_targs[_trans];
					
					if ( _parse_endpoint_uri_cond_actions[_trans] != 0 ) {
						
						_acts = ( _parse_endpoint_uri_actions + (_parse_endpoint_uri_cond_actions[_trans]));
						_nacts = (unsigned int)(*( _acts));
						_acts += 1;
						while ( _nacts > 0 ) {
							switch ( (*( _acts)) )
							{
								case 0:  {
										{
#line 47 "src/internal_modules/roc_address/endpoint_uri_parse.rl"
										
										start_p = p;
									}
									
#line 225 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"

									break; 
								}
								case 1:  {
										{
#line 51 "src/internal_modules/roc_address/endpoint_uri_parse.rl"
										
										char scheme[16] = {};
										if (p - start_p >= sizeof(scheme)) {
											roc_log(LogError, "parse endpoint uri: invalid protocol");
											return false;
										}
										strncpy(scheme, start_p, p - start_p);
										
										const ProtocolAttrs* attrs = ProtocolMap::instance().find_by_scheme(scheme);
										if (!attrs) {
											roc_log(LogError, "parse endpoint uri: invalid protocol");
											return false;
										}
										
										if (!result.set_proto(attrs->protocol)) {
											roc_log(LogError, "parse endpoint uri: invalid protocol");
											return false;
										}
									}
									
#line 251 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"

									break; 
								}
								case 2:  {
										{
#line 71 "src/internal_modules/roc_address/endpoint_uri_parse.rl"
										
										if (subset != EndpointUri::Subset_Full) {
											roc_log(LogError,
											"parse endpoint uri: unexpected host when parsing resource");
											return false;
										}
										if (!result.set_host(start_p, p - start_p)) {
											roc_log(LogError, "parse endpoint uri: invalid host");
											return false;
										}
									}
									
#line 269 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"

									break; 
								}
								case 3:  {
										{
#line 83 "src/internal_modules/roc_address/endpoint_uri_parse.rl"
										
										if (subset != EndpointUri::Subset_Full) {
											roc_log(LogError,
											"parse endpoint uri: unexpected port when parsing resource");
											return false;
										}
										
										char* end_p = NULL;
										long port = strtol(start_p, &end_p, 10);
										
										if (port == LONG_MAX || port == LONG_MIN || end_p != p) {
											roc_log(LogError, "parse endpoint uri: invalid port");
											return false;
										}
										
										if (!result.set_port((int)port)) {
											roc_log(LogError, "parse endpoint uri: invalid port");
											return false;
										}
									}
									
#line 296 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"

									break; 
								}
								case 4:  {
										{
#line 104 "src/internal_modules/roc_address/endpoint_uri_parse.rl"
										
										if (!result.set_encoded_path(start_p, p - start_p)) {
											roc_log(LogError, "parse endpoint uri: invalid path");
											return false;
										}
									}
									
#line 309 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"

									break; 
								}
								case 5:  {
										{
#line 111 "src/internal_modules/roc_address/endpoint_uri_parse.rl"
										
										if (!result.set_encoded_query(start_p, p - start_p)) {
											roc_log(LogError, "parse endpoint uri: invalid query");
											return false;
										}
									}
									
#line 322 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"

									break; 
								}
								case 6:  {
										{
#line 131 "src/internal_modules/roc_address/endpoint_uri_parse.rl"
										success = true; }
									
#line 330 "build/src/x86_64-pc-linux-gnu/gcc-15.2.1-release/internal_modules/roc_address/endpoint_uri_parse.cpp"

									break; 
								}
							}
							_nacts -= 1;
							_acts += 1;
						}
						
					}
					
					if ( p == eof ) {
						if ( cs >= 8 )
							goto _out;
					}
					else {
						if ( cs != 0 ) {
							p += 1;
							goto _resume;
						}
					}
					_out: {}
				}
				
#line 136 "src/internal_modules/roc_address/endpoint_uri_parse.rl"

				
				if (!success) {
					if (subset == EndpointUri::Subset_Full) {
						roc_log(LogError,
						"parse endpoint uri: expected"
						" 'PROTO://HOST[:PORT][/PATH][?QUERY]',\n"
						" got '%s'",
						str);
					} else {
						roc_log(LogError,
						"parse endpoint uri: expected"
						" '[/PATH][?QUERY]',\n"
						" got '%s'",
						str);
					}
					return false;
				}
				
				if (!result.verify(subset)) {
					roc_log(LogError, "parse endpoint uri: invalud uri");
					return false;
				}
				
				return true;
			}
			
		} // namespace
		
		bool parse_endpoint_uri(const char* str, EndpointUri::Subset subset, EndpointUri& result) {
			if (!parse_endpoint_uri_imp(str, subset, result)) {
				result.invalidate(subset);
				return false;
			}
			return true;
		}
		
	} // namespace address
} // namespace roc
