#include "lib.h" #include "log.h" #include #include #include ImplList(Buffer) Buffer ListBuffer_serialize(ListBuffer list) { Buffer out = {0}; for (ListBuffer lptr = list; lptr != NULL; lptr = lptr->rest) { Buffer buf = lptr->head; out = concat(out, Buffer_serialize(buf)); } return out; } ListBuffer ListBuffer_deserialize(Buffer buf) { ListBuffer out = NULL; for (size_t len = 0; len < buf.len;) { Buffer mbuf = Buffer_deserialize((Buffer) { .buf = buf.len + (Byte*)len, .len = 0, }); len += mbuf.len + sizeof(size_t); out = ListBuffer_cons(mbuf, out); } return out; } bool mkdir_p(SafeStr fpath, mode_t mode) { char* tmp = calloc(fpath.len + 1, sizeof(char)); size_t len = 0; for (size_t i = 0; i < fpath.len; ++i) { char c = fpath.str[i]; if (c == '/') { if (len != 0) { if (mkdir(tmp, mode) != 0) { if (errno != EEXIST) try(-1); } } } tmp[len++] = c; } // INFO: This needs to get done one more time in case there isn't a '/' at // the end of the fpath if (mkdir(tmp, mode) != 0) { if (errno != EEXIST) try(-1); } return true; } void Buffer_deinit(Buffer kod) { free(kod.buf); } void Buffer_write(Buffer buf, FILE* f) { exists(f); fwrite(buf.buf, sizeof(Byte), buf.len, f); } Buffer Buffer_read(FILE* f) { exists(f); fseek(f, 0, SEEK_END); size_t len = (size_t)ftell(f); fseek(f, 0, SEEK_SET); Buffer buf = { .buf = calloc(len, sizeof(Byte)), .len = len, }; exists(buf.buf); size_t count = fread(buf.buf, sizeof(Byte), len, f); if (count != len) { log(FATAL, "Error reading file\n"); exit(EXIT_FAILURE); } return buf; } Byte* copy(Byte* src, size_t nbytes) { exists(src); Byte* out = (Byte*)malloc(nbytes * sizeof(Byte)); exists(out); memcpy(out, src, nbytes); return out; } /// Allocates new memory from src and returns a buffer to that memory. The user /// must free that memory. Buffer bufcpy(Buffer src) { Byte* buf = (Byte*)malloc(src.len * sizeof(Byte)); exists(buf); memcpy(buf, src.buf, src.len); return (Buffer){ .buf = buf, .len = src.len, }; } /// Checks whether the buffer contains a valid string and that the size provided /// matches the size of that string. Buffer validate_str(Buffer str, size_t max_len) { size_t calculated_len = safe_strlen((const char*)str.buf, max_len); if (str.len != calculated_len) { log(ERROR, "%s:%d String's length (%zu) is not equal to given length (%zu).", __FILE__, __LINE__, calculated_len, str.len); printf("\nBuffer contains: "); for (size_t i = 0; i < max_len; ++i) printf("[%d] ", str.buf[i]); printf("\n"); exit(1); } if (str.len > max_len) { log(ERROR, "%s:%d String's length (%zu) is larger than the buffer that contains it (%zu)\n", str.len, calculated_len); printf("\nBuffer contains: "); for (size_t i = 0; i < max_len; ++i) printf("[%d] ", str.buf[i]); printf("\n"); exit(1); } return str; } // uses memchr to calculate strlen. size_t safe_strlen(Str str, size_t max_len) { char* last = memchr(str, '\0', max_len); return last != NULL ? (size_t)last - (size_t)str : max_len; } // Esta funcion convierte un string a un buffer. Buffer atob(const char* str) { return (Buffer){ .buf = (Byte*)str, .len = strlen(str), }; } Buffer SafeStr_serialize(SafeStr str) { return concat(size_t_serialize(str.len), to_buffer(str.str, str.len)); } SafeStr SafeStr_deserialize(Buffer buf) { size_t len = size_t_deserialize((Buffer) { .buf = buf.buf, .len = sizeof(size_t) }); Str str = calloc(len + 1, sizeof(char)); memcpy((void*)str, (void*)(buf.buf + sizeof(size_t)), len); return (SafeStr){ .str = str, .len = len, }; } Buffer size_t_serialize(size_t a) { Buffer out = { .len = sizeof(size_t), .buf = (Byte*)calloc(1, sizeof(size_t)), }; memcpy(out.buf, &a, sizeof(size_t)); return out; } size_t size_t_deserialize(Buffer buf) { size_t out = 0; if (buf.len != sizeof(size_t)) { log(FATAL, "size_t has incorrect size\n"); exit(EXIT_FAILURE); } memcpy(&out, buf.buf, sizeof(size_t)); return out; } Buffer concat(Buffer l, Buffer r) { // INFO: Notice that whenever either is null, the other is returned. if (l.buf == NULL) { return r; } else if (r.buf == NULL) { return l; } Buffer out = { .len = l.len + r.len, .buf = (Byte*)calloc(l.len + r.len, sizeof(Byte)), }; exists(out.buf); memcpy(out.buf, l.buf, l.len); memcpy(out.buf + l.len, r.buf, r.len); free(l.buf); free(r.buf); return out; } bool Str_eq(Str l, Str r) { return strcmp(l, r) == 0; } Buffer Buffer_serialize(Buffer buf) { Buffer size = size_t_serialize(buf.len); exists(size.buf); return concat(size, buf); } Buffer Buffer_deserialize(Buffer buf) { size_t size = size_t_deserialize((Buffer){ .buf = buf.buf, .len = sizeof(size_t) }); if (buf.len < size + sizeof(size_t)) { log(FATAL, "Error deserializing buffer. Incorrect size. Got: %zu. Expected greater than: %zu\n", buf.len, size + sizeof(size_t)); exit(EXIT_FAILURE); } Buffer out = { .buf = (Byte*)calloc(size, sizeof(Byte)), .len = size, }; exists(out.buf); memcpy(out.buf, buf.buf + sizeof(size_t), size); return out; } Buffer to_buffer(const void* thing, size_t nbytes) { Buffer out = { .buf = (Byte*)calloc(1, nbytes), .len = nbytes, }; exists(out.buf); memcpy(out.buf, thing, nbytes); return out; } Buffer uint8_t_serialize(uint8_t n) { return to_buffer(&n, sizeof(uint8_t)); } uint8_t uint8_t_deserialize(Buffer buf) { exists(buf.buf); if (buf.len != sizeof(uint8_t)) { log(FATAL, "Could not deserialize uint8_t. Buffer length incorrect: %zu\n", buf.len); exit(EXIT_FAILURE); } uint8_t x; memcpy(&x, buf.buf, sizeof x); return x; } Buffer uint16_t_serialize(uint16_t n) { return to_buffer(&n, sizeof(uint16_t)); } uint16_t uint16_t_deserialize(Buffer buf) { exists(buf.buf); if (buf.len != sizeof(uint16_t)) { log(FATAL, "Could not deserialize uint16_t. Buffer length incorrect: %zu\n", buf.len); exit(EXIT_FAILURE); } uint16_t x; memcpy(&x, buf.buf, sizeof x); return x; } Buffer uint32_t_serialize(uint32_t n) { return to_buffer(&n, sizeof(uint32_t)); } uint32_t uint32_t_deserialize(Buffer buf) { exists(buf.buf); if (buf.len != sizeof(uint32_t)) { log(FATAL, "Could not deserialize uint32_t. Buffer length incorrect: %zu\n", buf.len); exit(EXIT_FAILURE); } uint32_t x; memcpy(&x, buf.buf, sizeof x); return x; } SafeStr atoss(Str str) { return (SafeStr) { .str = str, .len = strlen(str), }; } size_t min(size_t l, size_t r) { return l < r ? l : r; } LazyBuffer open(Str fpath) { FILE* f = fopen(fpath, "r"); exists(f); fseek(f, 0, SEEK_END); size_t size = (size_t)ftell(f); fseek(f, 0, SEEK_SET); return (LazyBuffer){ .fptr = f, .buf = {0}, .len = 0, .position = 0, .size = size, }; } LazyBuffer next_chunk(LazyBuffer b) { exists(b.fptr); size_t read_len = min(b.size - b.position, CHUNK_SIZE); if (read_len == 0) { b.len = 0; return b; } size_t count = fread(b.buf, sizeof(Byte), read_len, b.fptr); if (count != read_len) { log(FATAL, "Error reading file. Expected to read %zu bytes, got %zu\n", read_len, count); exit(EXIT_FAILURE); } b.position += read_len; b.len = read_len; return b; }