class EL_BINARY_ENCODED_PARSE_EVENT_SOURCE

(source code)

Client examples: BINARY_BUILDER_FACTORY

description

Binary encoded parse event source

note
	description: "Binary encoded parse event source"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2024-06-21 11:30:22 GMT (Friday 21st June 2024)"
	revision: "25"

class
	EL_BINARY_ENCODED_PARSE_EVENT_SOURCE

inherit
	EL_PARSE_EVENT_SOURCE
		redefine
			make, new_file_stream
		end

	EL_PARSE_EVENT_CONSTANTS

create
	make

feature {NONE}  -- Initialisation

	make (a_scanner: like scanner)
			--
		do
			Precursor (a_scanner)
			create name_index_array.make (Name_index_table_size)
			set_encoding (scanner.encoding)
		end

feature -- Factory

	new_file_stream (a_file_path: FILE_PATH): FILE
		do
			create {RAW_FILE} Result.make_with_name (a_file_path)
		end

feature -- Basic operations

	parse_from_stream (a_stream: IO_MEDIUM)
			--
		do
			input := a_stream
			read_parse_events
		end

feature {NONE} -- Unused

	parse_from_lines (a_lines: ITERABLE [STRING])
		require else
			not_callable: False
		do
		end

	parse_from_string (a_string: STRING)
			--
		require else
			not_callable: False
		do
		end

feature {NONE} -- Parse action handlers

	on_start_tag_code (index_or_count: INTEGER; is_index: BOOLEAN)
			--
		do
			check_for_last_start_tag

			set_name_from_stream (last_node_name, index_or_count, is_index)
			attribute_list.reset
		end

	on_end_tag_code
			--
		do
			check_for_last_start_tag
			scanner.on_end_tag
		end

	on_attribute_name_code (index_or_count: INTEGER; is_index: BOOLEAN)
			--
		do
			attribute_list.extend
			set_name_from_stream (attribute_list.last.raw_name, index_or_count, is_index)
		end

	on_attribute_text_code (count: INTEGER)
			--
		do
			set_string_from_stream (attribute_list.last, count)
		end

	on_text_code (count: INTEGER)
			--
		do
			check_for_last_start_tag

			if attached last_node as node then
				set_string_from_stream (node, count)
				last_node.set_type (Type_text)
				scanner.on_content (node)
			end
		end

	on_comment_code (count: INTEGER)
			--
		do
			check_for_last_start_tag

			if attached last_node as node then
				set_string_from_stream (node, count)
				node.set_type (Type_comment)
				scanner.on_content (node)
			end
		end

	on_processing_instruction_code (index_or_count: INTEGER; is_index: BOOLEAN)
			--
		do
			check_for_last_start_tag

			set_name_from_stream (last_node.raw_name, index_or_count, is_index)
			input.read_natural_16
			set_string_from_stream (last_node, input.last_natural_16)
			last_node.set_type (Type_processing_instruction)
			scanner.on_processing_instruction
		end

	on_start_document_code
			--
		do
			name_index_array.wipe_out
			attribute_list.reset
			scanner.on_start_document
		end

	on_end_document_code
			--
		do
			scanner.on_end_document
		end

	on_meta_data (a_encoding: NATURAL)
		do
			scanner.on_meta_data (xml_version, create {EL_ENCODING}.make (a_encoding))
		end

feature {NONE} -- Implementation

	read_parse_events
			--
		local
			parse_event_code, index_or_count: INTEGER; is_index: BOOLEAN
		do
			last_parse_event_code := 0

			from until last_parse_event_code = PE_end_document loop
				input.read_natural_16
				parse_event_code := (input.last_natural_16 & 0xF) + 1
				index_or_count := input.last_natural_16 |>> 4

				inspect parse_event_code
					when PE_new_start_tag, PE_existing_start_tag then
						is_index := parse_event_code = PE_existing_start_tag
						on_start_tag_code (index_or_count, is_index)

					when PE_end_tag then
						on_end_tag_code

					when PE_existing_attribute_name, PE_new_attribute_name then
						is_index := parse_event_code = PE_existing_attribute_name
						on_attribute_name_code (index_or_count, is_index)

					when PE_existing_processing_instruction, PE_new_processing_instruction then
						is_index := parse_event_code = PE_existing_processing_instruction
						on_processing_instruction_code (index_or_count, is_index)

					when PE_attribute_text then
						on_attribute_text_code (index_or_count)

					when PE_text then
						on_text_code (index_or_count)

					when PE_comment_text then
						on_comment_code (index_or_count)

					when PE_start_document then
						on_start_document_code

						input.read_real; xml_version := input.last_real
						input.read_natural
						on_meta_data (input.last_natural)

					when PE_end_document then
						on_end_document_code

				else
				end
				last_parse_event_code := parse_event_code
			end
		end

	check_for_last_start_tag
			--
		do
			inspect last_parse_event_code
				when PE_new_start_tag, PE_existing_start_tag, PE_attribute_text then
					last_node.set_type (Type_element)
					scanner.on_start_tag

			else
			end
		end

	set_name_from_stream (name: EL_UTF_8_STRING; index_or_count: INTEGER; is_index: BOOLEAN)
			--
		do
			name.wipe_out
			if is_index then
				name.append (name_index_array [index_or_count])
			else
				input.read_stream (index_or_count)
				name.append (input.last_string)
				name_index_array.extend (input.last_string.twin)
			end
		end

	set_string_from_stream (str: EL_UTF_8_STRING; count: INTEGER)
		--
		do
			str.wipe_out
			input.read_stream (count)
			str.append (input.last_string)
		end

feature {NONE} -- Implementation: attributes

	input: IO_MEDIUM

	name_index_array: ARRAYED_LIST [STRING]

	last_parse_event_code: INTEGER

end