Skip to content

Instantly share code, notes, and snippets.

@charlesnicholson
Created May 29, 2025 15:48
Show Gist options
  • Save charlesnicholson/4c370c9b7d7cdb6f73caae5b4d31dd85 to your computer and use it in GitHub Desktop.
Save charlesnicholson/4c370c9b7d7cdb6f73caae5b4d31dd85 to your computer and use it in GitHub Desktop.
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
/** COBS encode data to buffer
@param data Pointer to input data to encode
@param length Number of bytes to encode
@param buffer Pointer to encoded output buffer
@return Encoded buffer length in bytes
@note Does not output delimiter byte
*/
size_t cobsEncode(const void *data, size_t length, uint8_t *buffer)
{
assert(data && buffer);
const char *strng = (const char *)data; // Data as string
uint8_t *encode = buffer; // Encoded bytes pointer
uint8_t *codep = encode++; // Output code pointer
while (length)
{
size_t l = strnlen(strng, length);
l = l > 0xfe ? 0xfe : l; // Clip output
if (codep)
*codep = l + 1; codep = NULL; // Commit code
if (l)
{
memcpy(encode, strng, l), strng += l, encode += l; // Copy non-zero bytes
if ((length -= l) && l == 0xfe)
codep = encode++; // Restart block
}
else
{
++strng;
if (--length)
codep = encode++; // Prepare encoded zero
else
*encode++ = 1; // Trailing zero
}
}
return (size_t)(encode - buffer);
}
/** COBS decode data from buffer
@param buffer Pointer to encoded input bytes
@param length Number of bytes to decode
@param data Pointer to decoded output data
@return Number of bytes successfully decoded
@note Stops decoding if delimiter byte is found
*/
size_t cobsDecode(const uint8_t *buffer, size_t length, void *data)
{
assert(buffer && data);
uint8_t *decode = (uint8_t *)data; // Decoded bytes pointer
uint8_t block, code = 0xff; // Current block and code value
while (length && (block = *buffer++))
{
if (block > length)
return 0; // Malformed buffer
if (code != 0xff)
*decode++ = 0; // Decode zero
code = block;
length -= block;
if (--block)
memcpy(decode, buffer, block), buffer += block, decode += block; // Decode non-zero bytes
}
return (size_t)(decode - (uint8_t *)data);
}
unsigned char s_decoded[1024];
void wikipedia_example(unsigned index, unsigned char const *encoded,
size_t encoded_len, unsigned char const *expected,
unsigned expected_len) {
size_t const len = cobsDecode(encoded, encoded_len, s_decoded);
printf("Example %u: Expected (%u)", index, expected_len);
for (size_t i = 0; i < expected_len; ++i) {
printf(" 0x%02X", expected[i]);
}
printf(", Actual (%u)", (unsigned)len);
for (size_t i = 0; i < len; ++i) {
printf(" 0x%02X", s_decoded[i]);
}
printf("\n");
}
void wikipedia_example_1(void) {
unsigned char const encoded[] = {0x01, 0x01, 0x00};
unsigned char const expected[] = {0x00};
wikipedia_example(1, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_2(void) {
unsigned char const encoded[] = {0x01, 0x01, 0x00, 0x00};
unsigned char const expected[] = {0x00, 0x00};
wikipedia_example(2, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_3(void) {
unsigned char const encoded[] = {0x01, 0x02, 0x11, 0x01, 0x00};
unsigned char const expected[] = {0x00, 0x11, 0x00};
wikipedia_example(3, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_4(void) {
unsigned char const encoded[] = {0x03, 0x11, 0x22, 0x02, 0x33, 0x00};
unsigned char const expected[] = {0x11, 0x22, 0x00, 0x33};
wikipedia_example(4, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_5(void) {
unsigned char const encoded[] = {0x05, 0x11, 0x22, 0x33, 0x44, 0x00};
unsigned char const expected[] = {0x11, 0x22, 0x33, 0x44};
wikipedia_example(5, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_6(void) {
unsigned char const encoded[] = {0x02, 0x11, 0x01, 0x01, 0x01, 0x00};
unsigned char const expected[] = {0x11, 0x00, 0x00, 0x00};
wikipedia_example(6, encoded, sizeof(encoded), expected, sizeof(expected));
}
int main(int argc, char const *argv[]) {
(void)argc;
(void)argv;
wikipedia_example_1();
wikipedia_example_2();
wikipedia_example_3();
wikipedia_example_4();
wikipedia_example_5();
wikipedia_example_6();
return 0;
}
@charlesnicholson
Copy link
Author

Compile this to see that the alternate cobs encoder / decoder implementation does not successfully encode + decode the examples from the wikipedia page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment