diff --git a/msvc/c/Makefile b/msvc/c/Makefile index afcf3e67f..bee8cd2b1 100755 --- a/msvc/c/Makefile +++ b/msvc/c/Makefile @@ -99,9 +99,9 @@ WRITER_OBJS = print.obj float_to_digits.obj float_to_string.obj \ READER_OBJS = read.obj parse_integer.obj parse_number.obj -STREAM_OBJS = stream.obj file.obj strm_os.obj \ - strm_clos.obj strm_string.obj strm_composite.obj \ - strm_common.obj strm_sequence.obj strm_eformat.obj +STREAM_OBJS = stream.obj file.obj strm_os.obj strm_clos.obj \ + strm_string.obj strm_composite.obj strm_common.obj \ + strm_sequence.obj strm_eformat.obj strm_binary.obj FFI_OBJS = ffi.obj libraries.obj backtrace.obj mmap.obj cdata.obj diff --git a/src/c/Makefile.in b/src/c/Makefile.in index 34293c90e..91a8da1a6 100644 --- a/src/c/Makefile.in +++ b/src/c/Makefile.in @@ -72,9 +72,9 @@ WRITER_OBJS = print.o printer/float_to_digits.o printer/float_to_string.o READER_OBJS = read.o reader/parse_integer.o reader/parse_number.o -STREAM_OBJS = stream.o file.o streams/strm_os.o \ - streams/strm_clos.o streams/strm_string.o streams/strm_composite.o \ - streams/strm_common.o streams/strm_sequence.o streams/strm_eformat.o +STREAM_OBJS = stream.o file.o streams/strm_os.o streams/strm_clos.o \ + streams/strm_string.o streams/strm_composite.o streams/strm_common.o \ + streams/strm_sequence.o streams/strm_eformat.o streams/strm_binary.o FFI_OBJS = ffi.o ffi/libraries.o ffi/backtrace.o ffi/mmap.o ffi/cdata.o diff --git a/src/c/stream.d b/src/c/stream.d index 653bf3b03..5fcc8dc62 100644 --- a/src/c/stream.d +++ b/src/c/stream.d @@ -40,6 +40,8 @@ ecl_alloc_stream(void) x->stream.buffer = NULL; x->stream.encoder = NULL; x->stream.decoder = NULL; + x->stream.byte_encoder = NULL; + x->stream.byte_decoder = NULL; x->stream.last_char = EOF; x->stream.byte_stack = ECL_NIL; x->stream.last_code[0] = x->stream.last_code[1] = EOF; diff --git a/src/c/streams/strm_binary.d b/src/c/streams/strm_binary.d new file mode 100644 index 000000000..036e215d0 --- /dev/null +++ b/src/c/streams/strm_binary.d @@ -0,0 +1,156 @@ +/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */ +/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */ + +/* + * strm_binary.d - Byte encoding/decoding for streams + * + * Copyright (c) 1984 Taiichi Yuasa and Masami Hagiya + * Copyright (c) 1990 Giuseppe Attardi + * Copyright (c) 2001 Juan Jose Garcia Ripoll + * Copyright (c) 2025 Daniel Kochmanski + * + * See file 'LICENSE' for the copyright details. + * + */ + +#include +#include + +/* Binary operators */ + +cl_object +ecl_binary_read_byte(cl_object strm) +{ + cl_index (*read_byte8)(cl_object, unsigned char *, cl_index); + unsigned char buf[ENCODING_BUFFER_MAX_SIZE]; + cl_object byte; + cl_index nbytes; + byte = strm->stream.last_byte; + unlikely_if (byte != OBJNULL) { + strm->stream.last_byte = OBJNULL; + return byte; + } + read_byte8 = strm->stream.ops->read_byte8; + nbytes = strm->stream.byte_size/8; + if (read_byte8(strm, buf, nbytes) < nbytes) + return OBJNULL; + return strm->stream.byte_decoder(strm, buf); +} + +void +ecl_binary_write_byte(cl_object strm, cl_object byte) +{ + cl_index (*write_byte8)(cl_object strm, unsigned char *c, cl_index n); + cl_index nbytes = strm->stream.byte_size/8; + unsigned char buf[ENCODING_BUFFER_MAX_SIZE]; + write_byte8 = strm->stream.ops->write_byte8; + strm->stream.byte_encoder(strm, buf, byte); + write_byte8(strm, buf, nbytes); +} + +/* + * 8-bit unsigned + */ + +cl_object +ecl_binary_u8_decoder(cl_object strm, unsigned char *buf) +{ + unsigned char c = buf[0]; + return ecl_make_fixnum(c); +} + +void +ecl_binary_u8_encoder(cl_object strm, unsigned char *buf, cl_object byte) +{ + unsigned char c = ecl_to_uint8_t(byte); + buf[0] = c; +} + +/* + * 8-bit signed + */ +cl_object +ecl_binary_s8_decoder(cl_object strm, unsigned char *buf) +{ + signed char c = (signed char)buf[0]; + return ecl_make_fixnum(c); +} + +void +ecl_binary_s8_encoder(cl_object strm, unsigned char *buf, cl_object byte) +{ + signed char c = ecl_to_int8_t(byte); + buf[0] = (unsigned char)c; +} + +/* + * Big Endian + */ +cl_object +ecl_binary_be_decoder(cl_object strm, unsigned char *buf) +{ + cl_index idx, ndx = strm->stream.byte_size/8; + cl_object output = OBJNULL; + cl_object offset = ecl_make_fixnum(8); + unsigned char c; + for (idx=0; idxstream.flags & ECL_STREAM_SIGNED_BYTES) + ? ecl_make_fixnum((signed char)c) + : ecl_make_fixnum((unsigned char)c); + } + } + return output; +} + +void +ecl_binary_be_encoder(cl_object strm, unsigned char *buf, cl_object byte) +{ + cl_index idx, ndx = strm->stream.byte_size/8; + cl_object offset = ecl_make_fixnum(-8); + cl_object mask = ecl_make_fixnum(0xFF); + for (idx=0; idxstream.byte_size/8; + cl_object output = OBJNULL; + cl_object offset = ecl_make_fixnum(8); + unsigned char c; + for (idx=0; idxstream.flags & ECL_STREAM_SIGNED_BYTES) + ? ecl_make_fixnum((signed char)c) + : ecl_make_fixnum((unsigned char)c); + } + } + return output; +} + +void +ecl_binary_le_encoder(cl_object strm, unsigned char *buf, cl_object byte) +{ + cl_index idx, ndx = strm->stream.byte_size/8; + cl_object offset = ecl_make_fixnum(-8); + cl_object mask = ecl_make_fixnum(0xFF); + for (idx=0; idxstream.column++; } -/* Maximum number of bytes required to encode a character. This currently - * corresponds to (4 + 4) for the UCS-4 encoding with 4 being the byte-order - * mark, 4 for the character. */ +/* Maximum number of octets required to encode a char or a byte. This currently + * corresponds to: + * - (4 + 4) for the UCS-4 with 4 being the byte-order mark, 4 for the char + * - (64/ 8) for the EXT:BYTE64 which is the biggest array integer type */ #define ENCODING_BUFFER_MAX_SIZE 8 /* file.d */ diff --git a/src/h/object.h b/src/h/object.h index 1f482100e..bf6deff81 100644 --- a/src/h/object.h +++ b/src/h/object.h @@ -669,6 +669,11 @@ typedef ecl_character (*cl_eformat_decoder)(cl_object stream, unsigned char **bu number of bytes used */ typedef int (*cl_eformat_encoder)(cl_object stream, unsigned char *buffer, ecl_character c); +/* Buffer is assumed to be big enough to store whole byte. The byte size is + stream->strm.byte_size. Decoder returns an object, encoder fills a buffer. */ +typedef cl_object (*cl_binary_decoder)(cl_object stream, unsigned char *buf); +typedef void (*cl_binary_encoder)(cl_object stream, unsigned char *buf, cl_object byte); + #define ECL_ANSI_STREAM_P(o) \ (ECL_IMMEDIATE(o) == 0 && ((o)->d.t == t_stream)) #define ECL_ANSI_STREAM_TYPE_P(o,m) \ @@ -697,6 +702,8 @@ struct ecl_stream { cl_object format; /* external format */ cl_eformat_encoder encoder; cl_eformat_decoder decoder; + cl_binary_encoder byte_encoder; + cl_binary_decoder byte_decoder; cl_object format_table; int flags; /* character table, flags, etc */ ecl_character eof_char;