| /* |
| * Copyright (c) 2024 Kelly Helmut Lord |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <errno.h> |
| #include <stdint.h> |
| #include <zephyr/data/cobs.h> |
| |
| int cobs_encode(struct net_buf *src, struct net_buf *dst, uint32_t flags) |
| { |
| uint8_t delimiter = COBS_FLAG_CUSTOM_DELIMITER(flags); |
| |
| /* Calculate required space for worst case */ |
| size_t max_encoded_size = cobs_max_encoded_len(src->len, flags); |
| |
| /* Check if destination has enough space */ |
| if (net_buf_tailroom(dst) < max_encoded_size) { |
| return -ENOMEM; |
| } |
| |
| uint8_t *code_ptr = net_buf_add(dst, 1); |
| uint8_t code = 1; |
| |
| /* Process all input bytes */ |
| uint8_t data = 0; |
| |
| while (src->len > 0) { |
| data = net_buf_pull_u8(src); |
| if (data == delimiter) { |
| /* Delimiter found - write current code and start new block */ |
| *code_ptr = code; |
| code_ptr = net_buf_add(dst, 1); |
| code = 1; |
| } else { |
| /* Add non-zero byte to output */ |
| net_buf_add_u8(dst, data); |
| code++; |
| |
| /* If we've reached maximum block size, start a new block */ |
| if (code == 0xFF && (src->len - 1 >= 0)) { |
| *code_ptr = code; |
| code_ptr = net_buf_add(dst, 1); |
| code = 1; |
| } |
| } |
| } |
| |
| *code_ptr = code; |
| |
| if (flags & COBS_FLAG_TRAILING_DELIMITER) { |
| /* Add final delimiter */ |
| net_buf_add_u8(dst, delimiter); |
| } |
| |
| return 0; |
| } |
| |
| int cobs_decode(struct net_buf *src, struct net_buf *dst, uint32_t flags) |
| { |
| uint8_t delimiter = COBS_FLAG_CUSTOM_DELIMITER(flags); |
| |
| if (flags & COBS_FLAG_TRAILING_DELIMITER) { |
| uint8_t end_delim = net_buf_remove_u8(src); |
| |
| if (end_delim != delimiter) { |
| return -EINVAL; |
| } |
| } |
| |
| while (src->len > 0) { |
| /* Pull the COBS offset byte */ |
| uint8_t offset = net_buf_pull_u8(src); |
| |
| if (offset == delimiter && !(flags & COBS_FLAG_TRAILING_DELIMITER)) { |
| return -EINVAL; |
| } |
| |
| /* Verify we have enough data */ |
| if (src->len < (offset - 1)) { |
| return -EINVAL; |
| } |
| |
| /* Copy offset-1 bytes */ |
| for (uint8_t i = 0; i < offset - 1; i++) { |
| uint8_t byte = net_buf_pull_u8(src); |
| |
| if (byte == delimiter) { |
| return -EINVAL; |
| } |
| net_buf_add_u8(dst, byte); |
| } |
| |
| /* If this wasn't a maximum offset and we have more data, |
| * there was a delimiter here in the original data |
| */ |
| if (offset != 0xFF && src->len > 0) { |
| net_buf_add_u8(dst, delimiter); |
| } |
| } |
| |
| return 0; |
| } |