Files
mars-tinyldap/mstorage_add_bin.c
2024-02-02 14:38:25 +00:00

81 lines
1.9 KiB
C

#include <libowfat/uint32.h>
#include <sys/types.h>
#include <string.h>
#include "mstorage.h"
/* this is tinyldap specific. If the data contains at least one 0-byte,
* it is stored in a tinyldap specific encoding:
* char 0;
* uint32 len;
* char data[len] */
ssize_t mstorage_add_bin(mstorage_t* p,const char* s,size_t n) {
ssize_t x;
if (n >> 31) // limit length to 32-bit SSIZE_MAX
return -1; // #range
#if 1
// unsigned int i;
// static char zero;
// char intbuf[4];
if (n==0 || memchr(s,0,n)) {
// n+5 can't overflow because we limited to SSIZE_MAX on a size_t
x=mstorage_reserve(p,n+5);
if (x!=-1) {
char* t=p->root+x;
*t=0;
uint32_pack(t+1,n);
memcpy(t+5,s,n);
}
return x;
} else {
// regular string; make sure there's a 0-terminator
// n-1 doesn't underflow because for n==0 we took the other branch
size_t needzero=(s[n-1] != 0);
x=mstorage_reserve(p,n+needzero);
if (x!=-1) {
char* t=p->root+x;
memcpy(t,s,n);
if (needzero)
t[n]=0;
}
return x;
}
#else
if (n==0 || (n==1 && s[0]==0)) goto encodebinary;
for (i=0; i<n-1; ++i)
if (!s[i]) {
encodebinary:
x=mstorage_add(p,&zero,1);
uint32_pack(intbuf,n);
mstorage_add(p,intbuf,4);
mstorage_add(p,s,n);
return x;
}
x=mstorage_add(p,s,n);
if (s[n-1])
mstorage_add(p,&zero,1);
return x;
#endif
}
#ifdef UNITTEST
#undef UNITTEST
#include <assert.h>
#include "mstorage_add.c"
#include "mstorage_init.c"
#include "mstorage_unmap.c"
int main() {
mstorage_t m;
mstorage_init(&m);
assert(mstorage_add_bin(&m,"foo",(size_t)-1) == -1); // #range
assert(mstorage_add_bin(&m,"foo",3) == 0);
// make sure 0 byte is added
assert(mstorage_add_bin(&m,"bar",3) == 4);
// trigger binary header
m.used=0;
assert(mstorage_add_bin(&m,"f\x00o",3) == 0);
assert(m.used == 8); // 0, len, f\0o
mstorage_unmap(&m);
return 0;
}
#endif