diff --git a/include_prv/jls/buffer.h b/include_prv/jls/buffer.h new file mode 100644 index 0000000..eafc44f --- /dev/null +++ b/include_prv/jls/buffer.h @@ -0,0 +1,106 @@ +/* + * Copyright 2021-2023 Jetperch LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * + * @brief Buffer implementation for JLS files. + */ + +#ifndef JLS_BUFFER_H__ +#define JLS_BUFFER_H__ + +#include "jls/cmacro.h" +#include +#include + +/** + * @ingroup jls + * @defgroup jls_buf JLS buffer. + * + * @brief JLS buffer. + * + * This module provides JLS payload construction and parsing. + * + * @{ + */ + +JLS_CPP_GUARD_START + +#define JLS_BUF_DEFAULT_SIZE (1 << 20) // 1 MiB +#define JLS_BUF_STRING_SIZE (1 << 20) // 1 MiB + +/** + * @brief Efficient storage of constant strings. + */ +struct jls_buf_strings_s { + struct jls_buf_strings_s * next; ///< NULL or next string buffer + char * cur; ///< Pointer to place start of next string + char buffer[JLS_BUF_STRING_SIZE]; ///< Buffer for 0-terminated strings. +}; + +struct jls_buf_s { + uint8_t * start; + uint8_t * cur; + uint8_t * end; // current end + size_t length; // current length + size_t alloc_size; // end - start + struct jls_buf_strings_s * strings_head; + struct jls_buf_strings_s * strings_tail; +}; + +struct jls_buf_s * jls_buf_alloc(void); + +void jls_buf_free(struct jls_buf_s * self); + +int32_t jls_buf_realloc(struct jls_buf_s * self, size_t size); + +void jls_buf_reset(struct jls_buf_s * self); + +size_t jls_buf_length(struct jls_buf_s * self); + +/** + * @brief Persist a copy of the string. + * + * @param self The buffer instance. + * @param cstr_in The string to save. + * @param cstr_save The saved string, which remains valid until jls_buf_free(self). + * @return 0 or error code. + */ +int32_t jls_buf_string_save(struct jls_buf_s * self, const char * cstr_in, const char ** cstr_save); + +int32_t jls_buf_wr_zero(struct jls_buf_s * self, uint32_t count); +int32_t jls_buf_wr_str(struct jls_buf_s * self, const char * cstr); +int32_t jls_buf_wr_bin(struct jls_buf_s * self, const void * data, uint32_t data_size); +int32_t jls_buf_wr_u8(struct jls_buf_s * self, uint8_t value); +int32_t jls_buf_wr_u16(struct jls_buf_s * self, uint16_t value); +int32_t jls_buf_wr_u32(struct jls_buf_s * self, uint32_t value); +int32_t jls_buf_wr_f32(struct jls_buf_s * self, float value); +int32_t jls_buf_wr_i64(struct jls_buf_s * self, int64_t value); + + +int32_t jls_buf_rd_skip(struct jls_buf_s * self, size_t count); +int32_t jls_buf_rd_u8(struct jls_buf_s * self, uint8_t * value); +int32_t jls_buf_rd_u16(struct jls_buf_s * self, uint16_t * value); +int32_t jls_buf_rd_u32(struct jls_buf_s * self, uint32_t * value); +int32_t jls_buf_rd_str(struct jls_buf_s * self, const char ** value); + + +JLS_CPP_GUARD_END + +/** @} */ + +#endif /* JLS_BUFFER_H__ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e460526..ee70a6e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,6 +16,7 @@ include_directories(../include_prv) set(SOURCES bit_shift.c + buffer.c datatype.c crc32c.c ec.c diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..b964cdc --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,293 @@ +/* + * Copyright 2021-2023 Jetperch LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jls/buffer.h" +#include "jls/cdef.h" +#include "jls/ec.h" +#include "jls/log.h" +#include +#include + + +static inline int32_t wr_end(struct jls_buf_s * self) { + if (self->cur > self->end) { + self->end = self->cur; + } + return 0; +} + +static int32_t strings_alloc(struct jls_buf_s * self) { + struct jls_buf_strings_s * s = calloc(1, sizeof(struct jls_buf_strings_s)); + if (NULL == s) { + return JLS_ERROR_NOT_ENOUGH_MEMORY; + } + s->cur = s->buffer; + s->next = NULL; + if (NULL == self->strings_head) { + self->strings_head = s; + } else if (NULL != self->strings_tail) { + self->strings_tail->next = s; + } + self->strings_tail = s; + return 0; +} + +struct jls_buf_s * jls_buf_alloc(void) { + struct jls_buf_s * s = calloc(1, sizeof(struct jls_buf_s)); + if (NULL == s) { + JLS_LOGE("jls_buf_alloc out of memory on jls_buf_s"); + return NULL; + } + s->start = calloc(1, JLS_BUF_DEFAULT_SIZE); + if (NULL == s->start) { + JLS_LOGE("jls_buf_alloc out of memory on buffer"); + free(s); + return NULL; + } + s->cur = s->start; + s->end = s->start; + s->length = 0; + s->alloc_size = JLS_BUF_DEFAULT_SIZE; + s->strings_head = NULL; + s->strings_tail = NULL; + return s; +} + +void jls_buf_free(struct jls_buf_s * self) { + if (NULL == self) { + return; + } + while (NULL != self->strings_head) { + struct jls_buf_strings_s * next = self->strings_head->next; + self->strings_head->next = NULL; + free(self->strings_head); + self->strings_head = next; + } + if (NULL != self->start) { + free(self->start); + } + free(self); +} + +int32_t jls_buf_realloc(struct jls_buf_s * self, size_t size) { + if (size <= self->alloc_size) { + return 0; + } + + size_t alloc_size = self->alloc_size; + while (alloc_size < size) { + alloc_size *= alloc_size; + } + + uint8_t * ptr = realloc(self->start, alloc_size); + if (NULL == ptr) { + JLS_LOGE("jls_buf_realloc out of memory"); + return JLS_ERROR_NOT_ENOUGH_MEMORY; + } + self->start = ptr; + self->alloc_size = alloc_size; + return 0; +} + +void jls_buf_reset(struct jls_buf_s * self) { + self->cur = self->start; + self->end = self->start; + self->length = 0; +} + +size_t jls_buf_length(struct jls_buf_s * self) { + return self->length; +} + +int32_t jls_buf_string_save(struct jls_buf_s * self, const char * cstr_in, const char ** cstr_save) { + if (NULL == self->strings_tail) { + ROE(strings_alloc(self)); + } + size_t sz = strlen(cstr_in) + 1; + struct jls_buf_strings_s * s = self->strings_tail; + char * buf_end = s->buffer + sizeof(s->buffer) - 1; + if ((size_t) (buf_end - s->cur) < sz) { + ROE(strings_alloc(self)); + s = self->strings_tail; + } + memcpy(s->cur, cstr_in, sz); + if (NULL != cstr_save) { + *cstr_save = s->cur; + } + s->cur += sz; + return 0; +} + +int32_t jls_buf_wr_zero(struct jls_buf_s * self, uint32_t count) { + ROE(jls_buf_realloc(self, self->length + count)); + for (uint32_t i = 0; i < count; ++i) { + *self->cur++ = 0; + } + self->length += count; + return wr_end(self); +} + +int32_t jls_buf_wr_str(struct jls_buf_s * self, const char * cstr) { + // Strings end with {0, 0x1f} = {null, unit separator} + size_t count = 2; + size_t slen = 0; + if (cstr) { + slen = strlen(cstr); + count += slen; + } + ROE(jls_buf_realloc(self, self->length + count)); + if (slen) { + memcpy(self->cur, cstr, slen); + } + self->cur += slen; + *self->cur++ = 0; + *self->cur++ = 0x1f; + self->length += count; + return wr_end(self); +} + +int32_t jls_buf_wr_bin(struct jls_buf_s * self, const void * data, uint32_t data_size) { + ROE(jls_buf_realloc(self, self->length + data_size)); + memcpy(self->cur, data, data_size); + self->cur += data_size; + self->length += data_size; + return wr_end(self); +} + +int32_t jls_buf_wr_u8(struct jls_buf_s * self, uint8_t value) { + ROE(jls_buf_realloc(self, self->length + sizeof(value))); + *self->cur++ = value; + self->length += sizeof(value); + return wr_end(self); +} + +int32_t jls_buf_wr_u16(struct jls_buf_s * self, uint16_t value) { + ROE(jls_buf_realloc(self, self->length + sizeof(value))); + *self->cur++ = (uint8_t) (value & 0xff); + *self->cur++ = (uint8_t) ((value >> 8) & 0xff); + self->length += sizeof(value); + return wr_end(self); +} + +int32_t jls_buf_wr_u32(struct jls_buf_s * self, uint32_t value) { + ROE(jls_buf_realloc(self, self->length + sizeof(value))); + *self->cur++ = (uint8_t) (value & 0xff); + *self->cur++ = (uint8_t) ((value >> 8) & 0xff); + *self->cur++ = (uint8_t) ((value >> 16) & 0xff); + *self->cur++ = (uint8_t) ((value >> 24) & 0xff); + self->length += sizeof(value); + return wr_end(self); +} + +int32_t jls_buf_wr_f32(struct jls_buf_s * self, float value) { + uint8_t * p = (uint8_t *) &value; + ROE(jls_buf_realloc(self, self->length + sizeof(value))); + *self->cur++ = *p++; + *self->cur++ = *p++; + *self->cur++ = *p++; + *self->cur++ = *p++; + self->length += sizeof(value); + return wr_end(self); +} + +int32_t jls_buf_wr_i64(struct jls_buf_s * self, int64_t value) { + ROE(jls_buf_realloc(self, self->length + sizeof(value))); + *self->cur++ = (uint8_t) (value & 0xff); + *self->cur++ = (uint8_t) ((value >> 8) & 0xff); + *self->cur++ = (uint8_t) ((value >> 16) & 0xff); + *self->cur++ = (uint8_t) ((value >> 24) & 0xff); + *self->cur++ = (uint8_t) ((value >> 32) & 0xff); + *self->cur++ = (uint8_t) ((value >> 40) & 0xff); + *self->cur++ = (uint8_t) ((value >> 48) & 0xff); + *self->cur++ = (uint8_t) ((value >> 56) & 0xff); + self->length += sizeof(value); + return wr_end(self); +} + +int32_t jls_buf_rd_skip(struct jls_buf_s * self, size_t count) { + if ((self->cur + count) > self->end) { + return JLS_ERROR_EMPTY; + } + self->cur += count; + return 0; +} + +int32_t jls_buf_rd_u8(struct jls_buf_s * self, uint8_t * value) { + if ((self->cur + sizeof(*value)) > self->end) { + return JLS_ERROR_EMPTY; + } + *value = self->cur[0]; + self->cur += sizeof(*value); + return 0; +} + +int32_t jls_buf_rd_u16(struct jls_buf_s * self, uint16_t * value) { + if ((self->cur + sizeof(*value)) > self->end) { + return JLS_ERROR_EMPTY; + } + *value = ((uint16_t) self->cur[0]) + | (((uint16_t) self->cur[1]) << 8); + self->cur += sizeof(*value); + return 0; +} + +int32_t jls_buf_rd_u32(struct jls_buf_s * self, uint32_t * value) { + if ((self->cur + sizeof(*value)) > self->end) { + return JLS_ERROR_EMPTY; + } + *value = ((uint32_t) self->cur[0]) + | (((uint32_t) self->cur[1]) << 8) + | (((uint32_t) self->cur[2]) << 16) + | (((uint32_t) self->cur[3]) << 24); + self->cur += sizeof(*value); + return 0; +} + +int32_t jls_buf_rd_str(struct jls_buf_s * self, const char ** value) { + struct jls_buf_strings_s * s; + if (NULL == self->strings_tail) { + ROE(strings_alloc(self)); + } + s = self->strings_tail; + char * str = s->cur; + char * buf_end = s->buffer + sizeof(s->buffer) - 1; + char ch; + while (self->cur != self->end) { + if (s->cur >= buf_end) { + ROE(strings_alloc(self)); + // copy over partial. + while (str <= buf_end) { + *self->strings_tail->cur++ = *str++; + } + s = self->strings_tail; + str = self->strings_tail->buffer; + } + + ch = (char) *self->cur++; + *s->cur++ = ch; + // Strings end with {0, 0x1f} = {null, unit separator} + if (ch == 0) { + if (*self->cur == 0x1f) { + self->cur++; + } + *value = str; + return 0; + } + } + + *value = NULL; + return JLS_ERROR_EMPTY; +} diff --git a/src/reader.c b/src/reader.c index 78924aa..998ea20 100644 --- a/src/reader.c +++ b/src/reader.c @@ -20,8 +20,9 @@ #include "jls/datatype.h" #include "jls/ec.h" #include "jls/log.h" -#include "jls/crc32c.h" +#include "jls/cdef.h" #include "jls/rd_fsr.h" +#include "jls/buffer.h" #include "jls/statistics.h" #include "jls/bit_shift.h" #include "jls/util.h" @@ -33,69 +34,16 @@ #include #include -#define PAYLOAD_BUFFER_SIZE_DEFAULT (1 << 25) // 32 MB -#define STRING_BUFFER_SIZE_DEFAULT (1 << 23) // 8 MB -#define ANNOTATIONS_SIZE_DEFAULT (1 << 20) // 1 MB #define F64_BUF_LENGTH_MIN (1 << 16) #define SIGNAL_MASK (0x0fff) #define DECIMATE_PER_DURATION (25) -#define ROE(x) do { \ - int32_t rc__ = (x); \ - if (rc__) { \ - return rc__; \ - } \ -} while (0) - -#define RLE(x) do { \ - int32_t rc__ = (x); \ - if (rc__) { \ - JLS_LOGE("error %d: " #x, rc__); \ - return rc__; \ - } \ -} while (0) - -#if 0 -struct source_s { - struct jls_source_def_s def; -}; - -struct signal_s { - struct jls_signal_def_s def; -}; - -struct jls_rd_s { - struct source_s * sources[JLS_SOURCE_COUNT]; - struct signal_s * signals[JLS_SIGNAL_COUNT]; - struct jls_chunk_header_s hdr; // the header for the current chunk - uint8_t * chunk_buffer; // storage for the - size_t chunk_buffer_sz; - FILE * f; -}; -#endif - - struct chunk_s { struct jls_chunk_header_s hdr; int64_t offset; }; -struct payload_s { - uint8_t * start; - uint8_t * cur; - uint8_t * end; // current end - size_t length; // current length - size_t alloc_size; -}; - -struct strings_s { - struct strings_s * next; - char * start; - char * cur; - char * end; -}; - struct f64_buf_s { double * start; double * end; @@ -123,9 +71,7 @@ struct jls_rd_s { struct signal_s signals[JLS_SIGNAL_COUNT]; struct chunk_s chunk_cur; - struct payload_s payload; - struct strings_s * strings_tail; - struct strings_s * strings_head; + struct jls_buf_s * buf; struct f64_buf_s * f64_sample_buf; struct f64_buf_s * f64_stats_buf; @@ -135,34 +81,6 @@ struct jls_rd_s { struct chunk_s user_data_head; // user_data, ignore first }; -static int32_t strings_alloc(struct jls_rd_s * self) { - struct strings_s * s = malloc(STRING_BUFFER_SIZE_DEFAULT); - if (!s) { - return JLS_ERROR_NOT_ENOUGH_MEMORY; - } - char * c8 = (char *) s; - s->next = NULL; - s->start = c8 + sizeof(struct strings_s); - s->cur = s->start; - s->end = c8 + STRING_BUFFER_SIZE_DEFAULT; - if (!self->strings_head) { - self->strings_head = s; - self->strings_tail = s; - } else { - self->strings_tail->next = s; - } - return 0; -} - -static void strings_free(struct jls_rd_s * self) { - struct strings_s * s = self->strings_head; - while (s) { - struct strings_s * n = s->next; - free(s); - s = n; - } -} - static int32_t f64_buf_alloc(size_t length, struct f64_buf_s ** buf) { if (*buf) { if ((*buf)->alloc_length >= (size_t) length) { @@ -187,117 +105,16 @@ static int32_t f64_buf_alloc(size_t length, struct f64_buf_s ** buf) { return 0; } -static int32_t payload_skip(struct jls_rd_s * self, size_t count) { - if ((self->payload.cur + count) > self->payload.end) { - return JLS_ERROR_EMPTY; - } - self->payload.cur += count; - return 0; -} - -static int32_t payload_parse_u8(struct jls_rd_s * self, uint8_t * value) { - if ((self->payload.cur + 1) > self->payload.end) { - return JLS_ERROR_EMPTY; - } - *value = self->payload.cur[0]; - self->payload.cur += 1; - return 0; -} - -static int32_t payload_parse_u16(struct jls_rd_s * self, uint16_t * value) { - if ((self->payload.cur + 2) > self->payload.end) { - return JLS_ERROR_EMPTY; - } - *value = ((uint16_t) self->payload.cur[0]) - | (((uint16_t) self->payload.cur[1]) << 8); - self->payload.cur += 2; - return 0; -} - -static int32_t payload_parse_u32(struct jls_rd_s * self, uint32_t * value) { - if ((self->payload.cur + 4) > self->payload.end) { - return JLS_ERROR_EMPTY; - } - *value = ((uint32_t) self->payload.cur[0]) - | (((uint32_t) self->payload.cur[1]) << 8) - | (((uint32_t) self->payload.cur[2]) << 16) - | (((uint32_t) self->payload.cur[3]) << 24); - self->payload.cur += 4; - return 0; -} - -#if 0 - -static int32_t payload_parse_u64(struct jls_rd_s * self, uint64_t * value) { - if ((self->payload.cur + 8) > self->payload.end) { - return JLS_ERROR_EMPTY; - } - *value = ((uint64_t) self->payload.cur[0]) - | (((uint64_t) self->payload.cur[1]) << 8) - | (((uint64_t) self->payload.cur[2]) << 16) - | (((uint64_t) self->payload.cur[3]) << 24) - | (((uint64_t) self->payload.cur[4]) << 32) - | (((uint64_t) self->payload.cur[5]) << 40) - | (((uint64_t) self->payload.cur[6]) << 48) - | (((uint64_t) self->payload.cur[7]) << 56); - self->payload.cur += 8; - return 0; -} - -#endif - -static int32_t payload_parse_str(struct jls_rd_s * self, char ** value) { - struct strings_s * s = self->strings_tail; - char * str = s->cur; - char ch; - while (self->payload.cur != self->payload.end) { - if (s->cur >= s->end) { - ROE(strings_alloc(self)); - // copy over partial. - while (str <= s->end) { - *self->strings_tail->cur++ = *str++; - } - s = self->strings_tail; - str = s->start; - } - - ch = (char) *self->payload.cur++; - *s->cur++ = ch; - if (ch == 0) { - if (*self->payload.cur == 0x1f) { - self->payload.cur++; - } - *value = str; - return 0; - } - } - - *value = NULL; - return JLS_ERROR_EMPTY; -} - static int32_t rd(struct jls_rd_s * self) { while (1) { self->chunk_cur.offset = jls_raw_chunk_tell(self->raw); - int32_t rc = jls_raw_rd(self->raw, &self->chunk_cur.hdr, (uint32_t) self->payload.alloc_size, self->payload.start); + int32_t rc = jls_raw_rd(self->raw, &self->chunk_cur.hdr, (uint32_t) self->buf->alloc_size, self->buf->start); if (rc == JLS_ERROR_TOO_BIG) { - size_t sz_new = self->payload.alloc_size; - while (sz_new < self->chunk_cur.hdr.payload_length) { - sz_new *= 2; - } - uint8_t *ptr = realloc(self->payload.start, sz_new); - if (!ptr) { - return JLS_ERROR_NOT_ENOUGH_MEMORY; - } - self->payload.start = ptr; - self->payload.cur = ptr; - self->payload.end = ptr; - self->payload.length = 0; - self->payload.alloc_size = sz_new; + ROE(jls_buf_realloc(self->buf, self->chunk_cur.hdr.payload_length)); } else if (rc == 0) { - self->payload.cur = self->payload.start; - self->payload.length = self->chunk_cur.hdr.payload_length; - self->payload.end = self->payload.start + self->payload.length; + self->buf->cur = self->buf->start; + self->buf->length = self->chunk_cur.hdr.payload_length; + self->buf->end = self->buf->start + self->buf->length; return 0; } else { return rc; @@ -315,12 +132,12 @@ static int32_t scan_sources(struct jls_rd_s * self) { JLS_LOGW("source_id %d too big - skip", (int) source_id); } else { struct jls_source_def_s *src = &self->source_def[source_id]; - ROE(payload_skip(self, 64)); - ROE(payload_parse_str(self, (char **) &src->name)); - ROE(payload_parse_str(self, (char **) &src->vendor)); - ROE(payload_parse_str(self, (char **) &src->model)); - ROE(payload_parse_str(self, (char **) &src->version)); - ROE(payload_parse_str(self, (char **) &src->serial_number)); + ROE(jls_buf_rd_skip(self->buf, 64)); + ROE(jls_buf_rd_str(self->buf, (char **) &src->name)); + ROE(jls_buf_rd_str(self->buf, (char **) &src->vendor)); + ROE(jls_buf_rd_str(self->buf, (char **) &src->model)); + ROE(jls_buf_rd_str(self->buf, (char **) &src->version)); + ROE(jls_buf_rd_str(self->buf, (char **) &src->serial_number)); src->source_id = source_id; // indicate that this source is valid! JLS_LOGD1("Found source %d : %s", (int) source_id, src->name); } @@ -361,20 +178,20 @@ static int32_t handle_signal_def(struct jls_rd_s * self) { } struct jls_signal_def_s *s = &self->signal_def[signal_id]; s->signal_id = signal_id; - ROE(payload_parse_u16(self, &s->source_id)); - ROE(payload_parse_u8(self, &s->signal_type)); - ROE(payload_skip(self, 1)); - ROE(payload_parse_u32(self, &s->data_type)); - ROE(payload_parse_u32(self, &s->sample_rate)); - ROE(payload_parse_u32(self, &s->samples_per_data)); - ROE(payload_parse_u32(self, &s->sample_decimate_factor)); - ROE(payload_parse_u32(self, &s->entries_per_summary)); - ROE(payload_parse_u32(self, &s->summary_decimate_factor)); - ROE(payload_parse_u32(self, &s->annotation_decimate_factor)); - ROE(payload_parse_u32(self, &s->utc_decimate_factor)); - ROE(payload_skip(self, 92)); - ROE(payload_parse_str(self, (char **) &s->name)); - ROE(payload_parse_str(self, (char **) &s->units)); + ROE(jls_buf_rd_u16(self->buf, &s->source_id)); + ROE(jls_buf_rd_u8(self->buf, &s->signal_type)); + ROE(jls_buf_rd_skip(self->buf, 1)); + ROE(jls_buf_rd_u32(self->buf, &s->data_type)); + ROE(jls_buf_rd_u32(self->buf, &s->sample_rate)); + ROE(jls_buf_rd_u32(self->buf, &s->samples_per_data)); + ROE(jls_buf_rd_u32(self->buf, &s->sample_decimate_factor)); + ROE(jls_buf_rd_u32(self->buf, &s->entries_per_summary)); + ROE(jls_buf_rd_u32(self->buf, &s->summary_decimate_factor)); + ROE(jls_buf_rd_u32(self->buf, &s->annotation_decimate_factor)); + ROE(jls_buf_rd_u32(self->buf, &s->utc_decimate_factor)); + ROE(jls_buf_rd_skip(self->buf, 92)); + ROE(jls_buf_rd_str(self->buf, (char **) &s->name)); + ROE(jls_buf_rd_str(self->buf, (char **) &s->units)); if (0 == signal_validate(self, signal_id, s)) { // validate passed s->signal_id = signal_id; // indicate that this signal is valid JLS_LOGD1("Found signal %d : %s", (int) signal_id, s->name); @@ -455,12 +272,12 @@ static int32_t handle_track_head(struct jls_rd_s * self, int64_t pos) { self->signals[signal_id].track_head_offsets[track_type] = pos; size_t expect_sz = JLS_SUMMARY_LEVEL_COUNT * sizeof(int64_t); - if (self->payload.length != expect_sz) { + if (self->buf->length != expect_sz) { JLS_LOGW("cannot parse signal %d head, sz=%zu, expect=%zu", - (int) signal_id, self->payload.length, expect_sz); + (int) signal_id, self->buf->length, expect_sz); return JLS_ERROR_PARAMETER_INVALID; } - memcpy(self->signals[signal_id].track_head_data[track_type], self->payload.start, expect_sz); + memcpy(self->signals[signal_id].track_head_data[track_type], self->buf->start, expect_sz); return 0; } @@ -505,7 +322,7 @@ static int32_t scan_fsr_sample_id(struct jls_rd_s * self) { continue; } - struct jls_fsr_data_s * r = (struct jls_fsr_data_s *) self->payload.start; + struct jls_fsr_data_s * r = (struct jls_fsr_data_s *) self->buf->start; self->signal_def[signal_id].sample_id_offset = r->header.timestamp; } return 0; @@ -575,16 +392,11 @@ static int32_t jls_rd_open_inner(struct jls_rd_s ** instance, const char * path, self->signal_length[k] = -1; } - self->payload.start = malloc(PAYLOAD_BUFFER_SIZE_DEFAULT); - strings_alloc(self); - - if (!self->payload.start || !self->strings_head) { + self->buf = jls_buf_alloc(); + if (!self->buf) { jls_rd_close(self); return JLS_ERROR_NOT_ENOUGH_MEMORY; } - self->payload.alloc_size = PAYLOAD_BUFFER_SIZE_DEFAULT; - self->payload.cur = self->payload.start; - self->payload.end = self->payload.start; int32_t rc = jls_raw_open(&self->raw, path, mode); if (rc == 0) { @@ -616,11 +428,7 @@ int32_t jls_rd_open(struct jls_rd_s ** instance, const char * path) { void jls_rd_close(struct jls_rd_s * self) { if (self) { jls_raw_close(self->raw); - strings_free(self); - if (self->payload.start) { - free(self->payload.start); - self->payload.start = NULL; - } + jls_buf_free(self->buf); if (self->f64_stats_buf) { free(self->f64_stats_buf); self->f64_stats_buf = NULL; @@ -713,10 +521,10 @@ static int32_t ts_seek(struct jls_rd_s * self, uint16_t signal_id, uint8_t level JLS_LOGW("seek tag mismatch: %d", (int) self->chunk_cur.hdr.tag); } - struct jls_index_s * r = (struct jls_index_s *) self->payload.start; + struct jls_index_s * r = (struct jls_index_s *) self->buf->start; uint8_t * p_end = (uint8_t *) &r->entries[r->header.entry_count]; - if ((size_t) (p_end - self->payload.start) > self->payload.length) { + if ((size_t) (p_end - self->buf->start) > self->buf->length) { JLS_LOGE("invalid payload length"); return JLS_ERROR_PARAMETER_INVALID; } @@ -789,13 +597,13 @@ static int32_t fsr_seek(struct jls_rd_s * self, uint16_t signal_id, uint8_t leve JLS_LOGW("seek tag mismatch: %d", (int) self->chunk_cur.hdr.tag); } - struct jls_fsr_index_s * r = (struct jls_fsr_index_s *) self->payload.start; + struct jls_fsr_index_s * r = (struct jls_fsr_index_s *) self->buf->start; int64_t chunk_timestamp = r->header.timestamp; int64_t chunk_entries = r->header.entry_count; JLS_LOGD3("timestamp=%" PRIi64 ", entries=%" PRIi64, chunk_timestamp, chunk_entries); uint8_t * p_end = (uint8_t *) &r->offsets[r->header.entry_count]; - if ((size_t) (p_end - self->payload.start) > self->payload.length) { + if ((size_t) (p_end - self->buf->start) > self->buf->length) { JLS_LOGE("invalid payload length"); return JLS_ERROR_PARAMETER_INVALID; } @@ -846,13 +654,13 @@ int32_t jls_rd_fsr_length(struct jls_rd_s * self, uint16_t signal_id, int64_t * ROE(jls_raw_chunk_seek(self->raw, offset)); ROE(rd(self)); - r = (struct jls_fsr_index_s *) self->payload.start; + r = (struct jls_fsr_index_s *) self->buf->start; if (r->header.entry_size_bits != (sizeof(r->offsets[0]) * 8)) { JLS_LOGE("invalid FSR index entry size: %d bits", (int) r->header.entry_size_bits); return JLS_ERROR_PARAMETER_INVALID; } size_t sz = sizeof(r->header) + r->header.entry_count * sizeof(r->offsets[0]); - if (sz > self->payload.length) { + if (sz > self->buf->length) { JLS_LOGE("invalid payload length"); return JLS_ERROR_PARAMETER_INVALID; } @@ -863,7 +671,7 @@ int32_t jls_rd_fsr_length(struct jls_rd_s * self, uint16_t signal_id, int64_t * ROE(jls_raw_chunk_seek(self->raw, offset)); ROE(rd(self)); - r = (struct jls_fsr_index_s *) self->payload.start; + r = (struct jls_fsr_index_s *) self->buf->start; self->signal_length[signal_id] = r->header.timestamp + r->header.entry_count - self->signal_def[signal_id].sample_id_offset; *samples = self->signal_length[signal_id]; @@ -941,7 +749,7 @@ int32_t jls_rd_fsr(struct jls_rd_s * self, uint16_t signal_id, int64_t start_sam } else if (rv) { return rv; } - struct jls_fsr_data_s * r = (struct jls_fsr_data_s *) self->payload.start; + struct jls_fsr_data_s * r = (struct jls_fsr_data_s *) self->buf->start; int64_t chunk_sample_id = r->header.timestamp; int64_t chunk_sample_count = r->header.entry_count; if (r->header.entry_size_bits != entry_size_bits) { @@ -1061,8 +869,8 @@ static int32_t fsr_statistics(struct jls_rd_s * self, uint16_t signal_id, int64_t pos = jls_raw_chunk_tell(self->raw); ROE(rd_stats_chunk(self, signal_id, level)); - struct jls_fsr_f32_summary_s * f32_summary = (struct jls_fsr_f32_summary_s *) self->payload.start; - struct jls_fsr_f64_summary_s * f64_summary = (struct jls_fsr_f64_summary_s *) self->payload.start; + struct jls_fsr_f32_summary_s * f32_summary = (struct jls_fsr_f32_summary_s *) self->buf->start; + struct jls_fsr_f64_summary_s * f64_summary = (struct jls_fsr_f64_summary_s *) self->buf->start; int64_t chunk_sample_id = f32_summary->header.timestamp; if (f32_summary->header.entry_size_bits == JLS_SUMMARY_FSR_COUNT * sizeof(float) * 8) { is_f32 = true; // 32-bit float summaries @@ -1101,8 +909,8 @@ static int32_t fsr_statistics(struct jls_rd_s * self, uint16_t signal_id, if (self->chunk_cur.hdr.item_next) { ROE(jls_raw_chunk_seek(self->raw, self->chunk_cur.hdr.item_next)); ROE(rd_stats_chunk(self, signal_id, level)); - f32_summary = (struct jls_fsr_f32_summary_s *) self->payload.start; - f64_summary = (struct jls_fsr_f64_summary_s *) self->payload.start; + f32_summary = (struct jls_fsr_f32_summary_s *) self->buf->start; + f64_summary = (struct jls_fsr_f64_summary_s *) self->buf->start; if (f32_summary->header.entry_size_bits == JLS_SUMMARY_FSR_COUNT * sizeof(float) * 8) { is_f32 = true; // 32-bit float summaries } else if (f32_summary->header.entry_size_bits == JLS_SUMMARY_FSR_COUNT * sizeof(double) * 8) { @@ -1223,7 +1031,7 @@ int32_t jls_rd_fsr_statistics(struct jls_rd_s * self, uint16_t signal_id, ROE(fsr_seek(self, signal_id, 0, start_sample_id)); ROE(rd(self)); - struct jls_fsr_data_s * s = (struct jls_fsr_data_s *) self->payload.start; + struct jls_fsr_data_s * s = (struct jls_fsr_data_s *) self->buf->start; int64_t chunk_sample_id = s->header.timestamp; if (s->header.entry_size_bits != entry_size_bits) { JLS_LOGE("invalid data entry size: %d", (int) s->header.entry_size_bits); @@ -1256,7 +1064,7 @@ int32_t jls_rd_fsr_statistics(struct jls_rd_s * self, uint16_t signal_id, if (self->chunk_cur.hdr.chunk_meta != signal_id) { JLS_LOGW("unexpected chunk meta: %d", (int) self->chunk_cur.hdr.chunk_meta); } - s = (struct jls_fsr_data_s *) self->payload.start; + s = (struct jls_fsr_data_s *) self->buf->start; if (s->header.entry_size_bits != entry_size_bits) { JLS_LOGE("invalid data entry size: %d", (int) s->header.entry_size_bits); return JLS_ERROR_PARAMETER_INVALID; @@ -1329,7 +1137,7 @@ int32_t jls_rd_annotations(struct jls_rd_s * self, uint16_t signal_id, int64_t t if (self->chunk_cur.hdr.tag != JLS_TAG_TRACK_ANNOTATION_DATA) { return JLS_ERROR_NOT_FOUND; } - annotation = (struct jls_annotation_s *) self->payload.start; + annotation = (struct jls_annotation_s *) self->buf->start; annotation->timestamp -= sample_id_offset; if (cbk_fn(cbk_user_data, annotation)) { return 0; @@ -1363,7 +1171,7 @@ int32_t jls_rd_user_data(struct jls_rd_s * self, jls_rd_user_data_cbk_fn cbk_fn, } chunk_meta = self->chunk_cur.hdr.chunk_meta & 0x0fff; rv = cbk_fn(cbk_user_data, chunk_meta, storage_type, - self->payload.start, self->chunk_cur.hdr.payload_length); + self->buf->start, self->chunk_cur.hdr.payload_length); if (rv) { // iteration done return 0; } @@ -1406,7 +1214,7 @@ JLS_API int32_t jls_rd_utc(struct jls_rd_s * self, uint16_t signal_id, int64_t s if (self->chunk_cur.hdr.tag != JLS_TAG_TRACK_UTC_SUMMARY) { return JLS_ERROR_NOT_FOUND; } - utc = (struct jls_utc_summary_s *) self->payload.start; + utc = (struct jls_utc_summary_s *) self->buf->start; uint32_t idx = 0; for (; (idx < utc->header.entry_count) && (sample_id > utc->entries[idx].sample_id); ++idx) { // iterate diff --git a/src/writer.c b/src/writer.c index c48dafc..ed5839b 100644 --- a/src/writer.c +++ b/src/writer.c @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 Jetperch LLC + * Copyright 2021-2023 Jetperch LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,13 +17,13 @@ #include "jls/writer.h" #include "jls/raw.h" #include "jls/format.h" +#include "jls/buffer.h" #include "jls/wr_prv.h" #include "jls/wr_fsr.h" #include "jls/wr_ts.h" #include "jls/cdef.h" #include "jls/ec.h" #include "jls/log.h" -#include "jls/crc32c.h" #include "jls/util.h" #include #include @@ -31,9 +31,6 @@ #include -#define BUFFER_SIZE (1 << 20) - - struct chunk_s { struct jls_chunk_header_s hdr; int64_t offset; @@ -64,16 +61,9 @@ struct signal_info_s { struct jls_wr_fsr_s * signal_writer; }; -struct buf_s { - uint8_t * cur; - uint8_t * start; - uint8_t * end; -}; - struct jls_wr_s { struct jls_raw_s * raw; - uint8_t buffer[BUFFER_SIZE]; - struct buf_s buf; + struct jls_buf_s * buf; struct chunk_s source_info[JLS_SOURCE_COUNT]; struct chunk_s source_mra; // most recently added @@ -119,6 +109,12 @@ int32_t jls_wr_open(struct jls_wr_s ** instance, const char * path) { return JLS_ERROR_NOT_ENOUGH_MEMORY; } + self->buf = jls_buf_alloc(); + if (!self->buf) { + free(self); + return JLS_ERROR_NOT_ENOUGH_MEMORY; + } + for (uint16_t signal_id = 0; signal_id < JLS_SIGNAL_COUNT; ++signal_id) { for (uint8_t track_type = 0; track_type < 4; ++track_type) { struct track_info_s * t = &self->signal_info[signal_id].tracks[track_type]; @@ -176,6 +172,10 @@ int32_t jls_wr_close(struct jls_wr_s * self) { } wr_end(self); int32_t rc = jls_raw_close(self->raw); + if (self->buf) { + jls_buf_free(self->buf); + self->buf = NULL; + } free(self); return rc; } @@ -186,116 +186,6 @@ JLS_API int32_t jls_wr_flush(struct jls_wr_s * self) { return jls_raw_flush(self->raw); } -static void buf_reset(struct jls_wr_s * self) { - self->buf.start = self->buffer; - self->buf.cur = self->buffer; - self->buf.end = self->buffer + BUFFER_SIZE; -} - -static int32_t buf_add_zero(struct jls_wr_s * self, uint32_t count) { - struct buf_s * buf = &self->buf; - if ((buf->cur + count) > buf->end) { - JLS_LOGE("buffer to small"); - return JLS_ERROR_NOT_ENOUGH_MEMORY; - } - for (uint32_t i = 0; i < count; ++i) { - *buf->cur++ = 0; - } - return 0; -} - -static int32_t buf_add_str(struct jls_wr_s * self, const char * cstr) { - // Strings end with {0, 0x1f} = {null, unit separator} - struct buf_s * buf = &self->buf; - uint8_t * end = buf->end - 2; - while (buf->cur < end) { - if (cstr && *cstr) { - *buf->cur++ = *cstr++; - } else { - *buf->cur++ = 0; - *buf->cur++ = 0x1f; - return 0; - } - } - JLS_LOGE("buffer to small"); - return JLS_ERROR_NOT_ENOUGH_MEMORY; -} - -static int32_t buf_add_bin(struct jls_wr_s * self, const uint8_t * data, uint32_t data_size) { - struct buf_s * buf = &self->buf; - if ((buf->cur + data_size) > buf->end) { - JLS_LOGE("buffer to small"); - return JLS_ERROR_NOT_ENOUGH_MEMORY; - } - memcpy(buf->cur, data, data_size); - buf->cur += data_size; - return 0; -} - -static uint32_t buf_size(struct jls_wr_s * self) { - return (uint32_t) (self->buf.cur - self->buf.start); -} - -static int32_t buf_wr_u8(struct jls_wr_s * self, uint8_t value) { - struct buf_s * buf = &self->buf; - if ((buf->cur + 1) > buf->end) { - return JLS_ERROR_NOT_ENOUGH_MEMORY; - } - *buf->cur++ = value; - return 0; -} - -static int32_t buf_wr_u16(struct jls_wr_s * self, uint16_t value) { - struct buf_s * buf = &self->buf; - if ((buf->cur + 2) > buf->end) { - return JLS_ERROR_NOT_ENOUGH_MEMORY; - } - *buf->cur++ = (uint8_t) (value & 0xff); - *buf->cur++ = (uint8_t) ((value >> 8) & 0xff); - return 0; -} - -static int32_t buf_wr_u32(struct jls_wr_s * self, uint32_t value) { - struct buf_s * buf = &self->buf; - if ((buf->cur + 4) > buf->end) { - return JLS_ERROR_NOT_ENOUGH_MEMORY; - } - *buf->cur++ = (uint8_t) (value & 0xff); - *buf->cur++ = (uint8_t) ((value >> 8) & 0xff); - *buf->cur++ = (uint8_t) ((value >> 16) & 0xff); - *buf->cur++ = (uint8_t) ((value >> 24) & 0xff); - return 0; -} - -static int32_t buf_wr_f32(struct jls_wr_s * self, float value) { - struct buf_s * buf = &self->buf; - uint8_t * p = (uint8_t *) &value; - if ((buf->cur + 4) > buf->end) { - return JLS_ERROR_NOT_ENOUGH_MEMORY; - } - *buf->cur++ = *p++; - *buf->cur++ = *p++; - *buf->cur++ = *p++; - *buf->cur++ = *p++; - return 0; -} - -static int32_t buf_wr_i64(struct jls_wr_s * self, int64_t value) { - struct buf_s * buf = &self->buf; - if ((buf->cur + 8) > buf->end) { - return JLS_ERROR_NOT_ENOUGH_MEMORY; - } - *buf->cur++ = (uint8_t) (value & 0xff); - *buf->cur++ = (uint8_t) ((value >> 8) & 0xff); - *buf->cur++ = (uint8_t) ((value >> 16) & 0xff); - *buf->cur++ = (uint8_t) ((value >> 24) & 0xff); - *buf->cur++ = (uint8_t) ((value >> 32) & 0xff); - *buf->cur++ = (uint8_t) ((value >> 40) & 0xff); - *buf->cur++ = (uint8_t) ((value >> 48) & 0xff); - *buf->cur++ = (uint8_t) ((value >> 56) & 0xff); - return 0; -} - static int32_t update_mra(struct jls_wr_s * self, struct chunk_s * mra, struct chunk_s * update) { if (mra->offset) { int64_t current_pos = jls_raw_chunk_tell(self->raw); @@ -321,14 +211,14 @@ int32_t jls_wr_source_def(struct jls_wr_s * self, const struct jls_source_def_s } // construct payload - buf_reset(self); - buf_add_zero(self, 64); // reserve space for future use. - ROE(buf_add_str(self, source->name)); - ROE(buf_add_str(self, source->vendor)); - ROE(buf_add_str(self, source->model)); - ROE(buf_add_str(self, source->version)); - ROE(buf_add_str(self, source->serial_number)); - uint32_t payload_length = buf_size(self); + jls_buf_reset(self->buf); + jls_buf_wr_zero(self->buf, 64); // reserve space for future use. + ROE(jls_buf_wr_str(self->buf, source->name)); + ROE(jls_buf_wr_str(self->buf, source->vendor)); + ROE(jls_buf_wr_str(self->buf, source->model)); + ROE(jls_buf_wr_str(self->buf, source->version)); + ROE(jls_buf_wr_str(self->buf, source->serial_number)); + uint32_t payload_length = (uint32_t) jls_buf_length(self->buf); // construct header struct chunk_s * chunk = &self->source_info[source->source_id]; @@ -342,7 +232,7 @@ int32_t jls_wr_source_def(struct jls_wr_s * self, const struct jls_source_def_s chunk->offset = jls_raw_chunk_tell(self->raw); // write - ROE(jls_raw_wr(self->raw, &chunk->hdr, self->buffer)); + ROE(jls_raw_wr(self->raw, &chunk->hdr, self->buf->start)); self->payload_prev_length = payload_length; return update_mra(self, &self->source_mra, chunk); } @@ -449,22 +339,22 @@ int32_t jls_wr_signal_def(struct jls_wr_s * self, const struct jls_signal_def_s } // construct payload - buf_reset(self); - ROE(buf_wr_u16(self, def->source_id)); - ROE(buf_wr_u8(self, def->signal_type)); - ROE(buf_wr_u8(self, 0)); // reserved - ROE(buf_wr_u32(self, def->data_type)); - ROE(buf_wr_u32(self, def->sample_rate)); - ROE(buf_wr_u32(self, def->samples_per_data)); - ROE(buf_wr_u32(self, def->sample_decimate_factor)); - ROE(buf_wr_u32(self, def->entries_per_summary)); - ROE(buf_wr_u32(self, def->summary_decimate_factor)); - ROE(buf_wr_u32(self, def->annotation_decimate_factor)); - ROE(buf_wr_u32(self, def->utc_decimate_factor)); - ROE(buf_add_zero(self, 92)); // reserve space for future use. - ROE(buf_add_str(self, def->name)); - ROE(buf_add_str(self, def->units)); - uint32_t payload_length = buf_size(self); + jls_buf_reset(self->buf); + ROE(jls_buf_wr_u16(self->buf, def->source_id)); + ROE(jls_buf_wr_u8(self->buf, def->signal_type)); + ROE(jls_buf_wr_u8(self->buf, 0)); // reserved + ROE(jls_buf_wr_u32(self->buf, def->data_type)); + ROE(jls_buf_wr_u32(self->buf, def->sample_rate)); + ROE(jls_buf_wr_u32(self->buf, def->samples_per_data)); + ROE(jls_buf_wr_u32(self->buf, def->sample_decimate_factor)); + ROE(jls_buf_wr_u32(self->buf, def->entries_per_summary)); + ROE(jls_buf_wr_u32(self->buf, def->summary_decimate_factor)); + ROE(jls_buf_wr_u32(self->buf, def->annotation_decimate_factor)); + ROE(jls_buf_wr_u32(self->buf, def->utc_decimate_factor)); + ROE(jls_buf_wr_zero(self->buf, 92)); // reserve space for future use. + ROE(jls_buf_wr_str(self->buf, def->name)); + ROE(jls_buf_wr_str(self->buf, def->units)); + uint32_t payload_length = (uint32_t) jls_buf_length(self->buf); // construct header struct chunk_s * chunk = &info->chunk_def; @@ -478,7 +368,7 @@ int32_t jls_wr_signal_def(struct jls_wr_s * self, const struct jls_signal_def_s chunk->offset = jls_raw_chunk_tell(self->raw); // write - ROE(jls_raw_wr(self->raw, &chunk->hdr, self->buffer)); + ROE(jls_raw_wr(self->raw, &chunk->hdr, self->buf->start)); self->payload_prev_length = payload_length; ROE(update_mra(self, &self->signal_mra, chunk)); @@ -708,33 +598,33 @@ int32_t jls_wr_annotation(struct jls_wr_s * self, uint16_t signal_id, int64_t ti } // construct payload - buf_reset(self); - ROE(buf_wr_i64(self, timestamp)); - ROE(buf_wr_u32(self, 1)); // number of entries - ROE(buf_wr_u16(self, 0)); // unspecified entry length - ROE(buf_wr_u16(self, 0)); // reserved - ROE(buf_wr_u8(self, annotation_type)); - ROE(buf_wr_u8(self, storage_type)); - ROE(buf_wr_u8(self, group_id)); - ROE(buf_wr_u8(self, 0)); // reserved - ROE(buf_wr_f32(self, y)); + jls_buf_reset(self->buf); + ROE(jls_buf_wr_i64(self->buf, timestamp)); + ROE(jls_buf_wr_u32(self->buf, 1)); // number of entries + ROE(jls_buf_wr_u16(self->buf, 0)); // unspecified entry length + ROE(jls_buf_wr_u16(self->buf, 0)); // reserved + ROE(jls_buf_wr_u8(self->buf, annotation_type)); + ROE(jls_buf_wr_u8(self->buf, storage_type)); + ROE(jls_buf_wr_u8(self->buf, group_id)); + ROE(jls_buf_wr_u8(self->buf, 0)); // reserved + ROE(jls_buf_wr_f32(self->buf, y)); switch (storage_type) { case JLS_STORAGE_TYPE_BINARY: - ROE(buf_wr_u32(self, data_size)); - ROE(buf_add_bin(self, data, data_size)); + ROE(jls_buf_wr_u32(self->buf, data_size)); + ROE(jls_buf_wr_bin(self->buf, data, data_size)); break; case JLS_STORAGE_TYPE_STRING: - ROE(buf_wr_u32(self, (uint32_t) (strlen((const char *) data) + 1))); - ROE(buf_add_str(self, (const char *) data)); + ROE(jls_buf_wr_u32(self->buf, (uint32_t) (strlen((const char *) data) + 1))); + ROE(jls_buf_wr_str(self->buf, (const char *) data)); break; case JLS_STORAGE_TYPE_JSON: - ROE(buf_wr_u32(self, (uint32_t) (strlen((const char *) data) + 1))); - ROE(buf_add_str(self, (const char *) data)); + ROE(jls_buf_wr_u32(self->buf, (uint32_t) (strlen((const char *) data) + 1))); + ROE(jls_buf_wr_str(self->buf, (const char *) data)); break; default: return JLS_ERROR_PARAMETER_INVALID; } - uint32_t payload_length = buf_size(self); + uint32_t payload_length = (uint32_t) jls_buf_length(self->buf); // construct header struct chunk_s chunk; @@ -749,7 +639,7 @@ int32_t jls_wr_annotation(struct jls_wr_s * self, uint16_t signal_id, int64_t ti chunk.offset = offset; // write - ROE(jls_raw_wr(self->raw, &chunk.hdr, self->buf.start)); + ROE(jls_raw_wr(self->raw, &chunk.hdr, self->buf->start)); self->payload_prev_length = payload_length; ROE(update_mra(self, &signal_info->tracks[JLS_TRACK_TYPE_ANNOTATION].data, &chunk)); ROE(update_track(self, track, 0, offset)); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3a54e90..e45dd43 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -31,6 +31,8 @@ endfunction (ADD_CMOCKA_TEST) ADD_CMOCKA_TEST(bit_shift_test) target_include_directories(bit_shift_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include_prv) +ADD_CMOCKA_TEST(buffer_test) +target_include_directories(buffer_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include_prv) ADD_CMOCKA_TEST(datatype_test) target_include_directories(datatype_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include_prv) ADD_CMOCKA_TEST(crc32c_test) diff --git a/test/buffer_test.c b/test/buffer_test.c new file mode 100644 index 0000000..e021425 --- /dev/null +++ b/test/buffer_test.c @@ -0,0 +1,123 @@ +/* + * Copyright 2023 Jetperch LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "jls/buffer.h" +#include "jls/ec.h" +#include +#include + + +static void test_empty(void **state) { + (void) state; + struct jls_buf_s * b = jls_buf_alloc(); + assert_non_null(b); + assert_int_equal(0, jls_buf_length(b)); + + uint8_t u8; + uint16_t u16; + uint32_t u32; + const char * cstr; + + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_skip(b, 1)); + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_u8(b, &u8)); + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_u16(b, &u16)); + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_u32(b, &u32)); + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_str(b, &cstr)); + + jls_buf_reset(b); + assert_int_equal(0, jls_buf_length(b)); + + jls_buf_free(b); +} + +static void test_string_save(void **state) { + (void) state; + const char * str1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const char * str2 = NULL; + struct jls_buf_s * b = jls_buf_alloc(); + assert_non_null(b); + assert_null(b->strings_tail); + assert_int_equal(0, jls_buf_string_save(b, str1, &str2)); + assert_non_null(b->strings_tail); + assert_non_null(b->strings_head); + struct jls_buf_strings_s * s = b->strings_tail; + while (s == b->strings_tail) { + assert_int_equal(0, jls_buf_string_save(b, str1, &str2)); + assert_string_equal(str1, str2); + } + jls_buf_free(b); +} + +static void test_wr_rd(void **state) { + (void) state; + const char * stra = "hello world!"; + uint8_t u8a = 42; + uint16_t u16a = 4342; + uint32_t u32a = 1353254; + float f32a = 234.25f; + int64_t i64a = -347891574383495LL; + + const char * strb = NULL; + uint8_t u8b = 0; + uint16_t u16b = 0; + uint32_t u32b = 0; + //float f32b = 0.0f; + //int64_t i64b = 0; + + struct jls_buf_s * b = jls_buf_alloc(); + assert_int_equal(0, jls_buf_wr_zero(b, 32)); + assert_int_equal(0, jls_buf_wr_str(b, stra)); + assert_int_equal(0, jls_buf_wr_bin(b, &u32a, sizeof(u32a))); + assert_int_equal(0, jls_buf_wr_u8(b, u8a)); + assert_int_equal(0, jls_buf_wr_u16(b, u16a)); + assert_int_equal(0, jls_buf_wr_u32(b, u32a)); + assert_int_equal(0, jls_buf_wr_f32(b, f32a)); + assert_int_equal(0, jls_buf_wr_i64(b, i64a)); + + assert_int_equal(0x45, b->length); + b->cur = b->start; + assert_int_equal(0, jls_buf_rd_skip(b, 32)); + assert_int_equal(0, jls_buf_rd_str(b, &strb)); assert_string_equal(strb, stra); + assert_int_equal(0, jls_buf_rd_skip(b, sizeof(u32a))); + assert_int_equal(0, jls_buf_rd_u8(b, &u8b)); assert_int_equal(u8b, u8a); + assert_int_equal(0, jls_buf_rd_u16(b, &u16b)); assert_int_equal(u16b, u16a); + assert_int_equal(0, jls_buf_rd_u32(b, &u32b)); assert_int_equal(u32b, u32a); + assert_int_equal(0, jls_buf_rd_skip(b, sizeof(float))); + assert_int_equal(0, jls_buf_rd_skip(b, sizeof(i64a))); + + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_skip(b, 1)); + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_u8(b, &u8b)); + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_u16(b, &u16b)); + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_u32(b, &u32b)); + assert_int_equal(JLS_ERROR_EMPTY, jls_buf_rd_str(b, &strb)); + + jls_buf_free(b); +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_empty), + cmocka_unit_test(test_string_save), + cmocka_unit_test(test_wr_rd), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} +