note description: "Serialize/Deserialize data from a medium." legal: "See notice at end of class." status: "See notice at end of class." date: "$Date: 2017-09-25 15:53:33 +0000 (Mon, 25 Sep 2017) $" revision: "$Revision: 100789 $" class SED_MEDIUM_READER_WRITER inherit SED_BINARY_READER_WRITER redefine read_header, write_header, cleanup, write_footer, is_ready_for_reading, is_ready_for_writing, medium end PLATFORM export {NONE} all end create make, make_for_reading, make_for_writing, make_with_buffer feature {NONE} -- Initialization make (a_medium: IO_MEDIUM) -- Initialize current to read or write from a_medium. require a_medium_not_void: a_medium /= Void a_medium_support_storable: a_medium.support_storable do make_with_buffer (a_medium, Default_buffer_size) ensure medium_set: medium = a_medium buffer_size_set: buffer_size = Default_buffer_size end make_for_reading (a_medium: IO_MEDIUM) -- Initialize current to read from a_medium. require a_medium_not_void: a_medium /= Void a_medium_open_for_reading: a_medium.is_open_read a_medium_support_storable: a_medium.support_storable do make (a_medium) set_for_reading ensure medium_set: medium = a_medium buffer_size_set: buffer_size = Default_buffer_size end make_for_writing (a_medium: IO_MEDIUM) -- Initialize current to write to a_medium. require a_medium_not_void: a_medium /= Void a_medium_open_for_writing: a_medium.is_open_write a_medium_support_storable: a_medium.support_storable do make (a_medium) set_for_writing ensure medium_set: medium = a_medium buffer_size_set: buffer_size = Default_buffer_size end make_with_buffer (a_medium: IO_MEDIUM; a_buffer_size: INTEGER_32) -- Initialize current to read or write from a_medium using a buffer of size a_buffer_size. -- buffer_size will be overriden during read operation by the value of buffer_size used -- when writing. require a_medium_not_void: a_medium /= Void a_buffer_size_non_negative: a_buffer_size >= 0 a_medium_support_storable: a_medium.support_storable do medium := a_medium buffer_size := a_buffer_size create buffer.make (a_buffer_size) ensure medium_set: medium = a_medium buffer_size_set: buffer_size = a_buffer_size buffer_size_set: buffer.count = a_buffer_size end feature -- Header/Footer read_header -- Retrieve configuration of how data was stored. do read_buffer_from_medium is_little_endian_storable := read_boolean is_pointer_value_stored := read_boolean stored_pointer_bytes := read_integer_32 end write_header -- Store configuration on how data will be stored. do buffer_size := buffer.count check enough_space: buffer.count > {PLATFORM}.integer_32_bytes * 4 + {PLATFORM}.boolean_bytes * 2 end is_little_endian_storable := Is_little_endian write_chunk_header write_boolean (is_little_endian_storable) write_boolean (is_pointer_value_stored) write_integer_32 ({PLATFORM}.pointer_bytes) end write_chunk_header -- Store information about chunks do buffer_position := 0; buffer.put_integer_32_be (-1, 0) buffer_position := buffer_position + {PLATFORM}.integer_32_bytes; buffer.put_natural_32_be (Reader_writer_version_6_6, buffer_position) buffer_position := buffer_position + {PLATFORM}.natural_32_bytes buffer_position := buffer_position + {PLATFORM}.integer_32_bytes buffer_position := buffer_position + {PLATFORM}.boolean_bytes end write_footer -- Store last buffered data. do flush_buffer_to_medium (True) end feature -- Status report is_ready_for_reading: BOOLEAN -- Is Current ready for future read operations? do Result := is_for_reading and then medium.exists and then medium.is_open_read and then medium.support_storable and then medium.readable end is_ready_for_writing: BOOLEAN -- Is Current ready for future write operations? do Result := not is_for_reading and then medium.exists and then medium.is_open_write and then medium.support_storable end is_last_chunk: BOOLEAN -- Are we reading the last chunk? cleanup -- When a reading is stopped, perform the necessary cleanup to perform -- another reading or writing. do from until is_last_chunk loop read_buffer_from_medium end end feature -- Access Reader_writer_version_6_6: NATURAL_32 = 1 -- Version of format used for reading/writing. feature {NONE} -- Implementation: Access medium: IO_MEDIUM -- Medium used for read/write operations version_position: INTEGER_32 -- Position where information about version is stored do Result := size_position (False) + {PLATFORM}.integer_32_bytes end size_position (a_is_new_format: BOOLEAN): INTEGER_32 -- Position where size information for current chunk is stored. do if a_is_new_format then Result := version_position + {PLATFORM}.natural_32_bytes else Result := 0 end end new_chunk_position: INTEGER_32 -- Position where presence or not of a next chunk is stored. do Result := size_position (True) + {PLATFORM}.integer_32_bytes end chunk_header_size (a_is_new_format: BOOLEAN): INTEGER_32 -- Size of data do Result := {PLATFORM}.integer_32_bytes if a_is_new_format then Result := Result + {PLATFORM}.natural_32_bytes + {PLATFORM}.integer_32_bytes + {PLATFORM}.boolean_bytes end end feature {NONE} -- Buffer update check_buffer (n: INTEGER_32) -- If there is enough space in buffer to read n bytes, do nothing. -- Otherwise, read/write to medium to free some space. do if n + buffer_position > buffer_size then if is_for_reading then read_buffer_from_medium else flush_buffer_to_medium (False) end end end read_buffer_from_medium -- Read next chunk of data. require is_ready: is_ready_for_reading local l_version: NATURAL_32 l_is_new_format: BOOLEAN l_failure: SERIALIZATION_FAILURE do medium.read_to_managed_pointer (buffer, 0, {PLATFORM}.integer_32_bytes) if medium.bytes_read = {PLATFORM}.integer_32_bytes then buffer_size := buffer.read_integer_32_be (0) is_last_chunk := True if buffer_size = -1 then l_is_new_format := True; medium.read_to_managed_pointer (buffer, version_position, {PLATFORM}.integer_32_bytes) l_version := buffer.read_natural_32_be (version_position) if l_version = Reader_writer_version_6_6 then medium.read_to_managed_pointer (buffer, size_position (True), {PLATFORM}.integer_32_bytes) buffer_size := buffer.read_integer_32_be (size_position (True)); medium.read_to_managed_pointer (buffer, new_chunk_position, {PLATFORM}.boolean_bytes) is_last_chunk := buffer.read_boolean (new_chunk_position) end else l_is_new_format := False end buffer_position := chunk_header_size (l_is_new_format) if buffer_size > buffer.count then buffer.resize (buffer_size) end if buffer_size > {PLATFORM}.integer_32_bytes then medium.read_to_managed_pointer (buffer, buffer_position, buffer_size - buffer_position) if medium.bytes_read /= buffer_size - buffer_position then buffer_position := 0 buffer_size := buffer.count create l_failure; l_failure.set_description ("Read less than expected number of bytes in buffer."); l_failure.raise end else buffer_position := 0 buffer_size := buffer.count create l_failure; l_failure.set_description ("Read less than 4 bytes in buffer's header."); l_failure.raise end else buffer_position := 0 buffer_size := buffer.count create l_failure; l_failure.set_description ("Cannot read buffer size from header."); l_failure.raise end end flush_buffer_to_medium (last_chunk: BOOLEAN) -- Write next chunk of data to medium. require is_ready: is_ready_for_writing do buffer.put_integer_32_be (buffer_position, size_position (True)); buffer.put_boolean (last_chunk, new_chunk_position); medium.put_managed_pointer (buffer, 0, buffer_position) write_chunk_header end invariant medium_not_void: medium /= Void note library: "EiffelBase: Library of reusable components for Eiffel." copyright: "Copyright (c) 1984-2017, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software 5949 Hollister Ave., Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end -- class SED_MEDIUM_READER_WRITER
Generated by ISE EiffelStudio