changeset 12:0cc2555db371

*: make our string functions not stupid strncat() made everything slow! new addition internally: an EDL_header structure to make things not stupid. if we were using C++ it wouldn't really be necessary, but alas :)
author Paper <paper@paper.us.eu.org>
date Wed, 27 Mar 2024 13:38:30 -0400
parents a0bd92c4c0e8
children 41b74137e201
files README.md include/datatypes.h include/edl.h src/datatypes.c src/edl.c src/str.c
diffstat 6 files changed, 136 insertions(+), 105 deletions(-) [+]
line wrap: on
line diff
--- a/README.md	Fri Mar 22 20:51:46 2024 -0400
+++ b/README.md	Wed Mar 27 13:38:30 2024 -0400
@@ -18,9 +18,9 @@
 
 #include <edl.h>
 
-int file_get_contents(const char* file, char** contents, long* size) {
+int file_get_contents(const char* f, char** contents, long* size) {
     /* open the file */
-    FILE* file = fopen(file, "rb");
+    FILE* file = fopen(f, "rb");
     if (!file)
         return 1;
 
@@ -37,7 +37,7 @@
     /* hope and pray that `char` is 8-bit */
     fread(*contents, *size, 1, file);
 
-    data[*size] = '\0';
+    (*contents)[*size] = '\0';
 
     fclose(file);
 }
@@ -61,7 +61,7 @@
      *
      * it is also perfectly valid to use mmap() or
      * variations of it (ex MapViewOfFile()) here... */
-    EDL_parse(&edl, data, fsize + 1);
+    EDL_parse(&edl, data, size + 1);
 
     /* dump the data to a valid EDL string */
     char* edl_str = EDL_dump(&edl);
--- a/include/datatypes.h	Fri Mar 22 20:51:46 2024 -0400
+++ b/include/datatypes.h	Wed Mar 27 13:38:30 2024 -0400
@@ -3,6 +3,7 @@
 
 #include <stddef.h>
 #include "edl.h" /* EDL_media_type_t */
+#include "str.h"
 
 size_t EDL_internal_parse_int(const char* input, size_t offset, size_t length, int* int_return);
 size_t EDL_internal_parse_double(const char* input, size_t offset, size_t length, double* double_return);
@@ -10,9 +11,9 @@
 size_t EDL_internal_parse_media_type(const char* input, size_t offset, size_t length, EDL_media_type_t* media_return);
 size_t EDL_internal_parse_string(const char* input, size_t offset, size_t length, char** string_return);
 
-char* EDL_internal_integer_to_string(int value);
-char* EDL_internal_double_to_string(double value);
-char* EDL_internal_bool_to_string(bool value);
-char* EDL_internal_media_type_to_string(EDL_media_type_t value);
+int EDL_internal_append_integer_to_string(EDL_internal_string* str, int value);
+int EDL_internal_append_double_to_string(EDL_internal_string* str, double value);
+int EDL_internal_append_bool_to_string(EDL_internal_string* str, bool value);
+int EDL_internal_append_media_type_to_string(EDL_internal_string* str, EDL_media_type_t value);
 
 #endif /* __edl__internal__datatypes_h */
--- a/include/edl.h	Fri Mar 22 20:51:46 2024 -0400
+++ b/include/edl.h	Wed Mar 27 13:38:30 2024 -0400
@@ -16,7 +16,8 @@
 
 typedef enum {
 	EDL_PARSE_ERROR_SUCCESS = 0,
-	EDL_PARSE_ERROR_OUT_OF_MEMORY
+	EDL_PARSE_ERROR_OUT_OF_MEMORY,
+	EDL_PARSE_ERROR_HEADER
 } EDL_parse_error_t;
 
 typedef struct {
--- a/src/datatypes.c	Fri Mar 22 20:51:46 2024 -0400
+++ b/src/datatypes.c	Wed Mar 27 13:38:30 2024 -0400
@@ -1,5 +1,6 @@
 #include "datatypes.h"
 #include "util.h"
+#include "str.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -100,31 +101,33 @@
 	return EDL_internal_append_offset(input, offset, length);
 }
 
-char* EDL_internal_integer_to_string(int value) {
-	char out[256] = {0}; /* this ought to be enough. */
-	snprintf(out, 256, "%d", value);
-	out[255] = '\0';
-	return EDL_internal_strdup(out);
+int EDL_internal_append_integer_to_string(EDL_internal_string* str, int value) {
+	char out[32] = {0}; /* this ought to be enough. */
+	int c = snprintf(out, 32, "%d", value);
+	return EDL_internal_string_append(str, out, (c < 32) ? c : 32);
+}
+
+int EDL_internal_append_double_to_string(EDL_internal_string* str, double value) {
+	char out[128] = {0};
+	int c = snprintf(out, 128, "%.6f", value);
+	return EDL_internal_string_append(str, out, (c < 128) ? c : 128);
 }
 
-char* EDL_internal_double_to_string(double value) {
-	char out[256] = {0};
-	snprintf(out, 256, "%.6f", value);
-	out[255] = '\0';
-	return EDL_internal_strdup(out);
+int EDL_internal_append_bool_to_string(EDL_internal_string* str, bool value) {
+	if (value) {
+		EDL_internal_string_append(str, "TRUE", 4);
+	} else {
+		EDL_internal_string_append(str, "FALSE", 5);
+	}
 }
 
-char* EDL_internal_bool_to_string(bool value) {
-	return EDL_internal_strdup(value ? "TRUE" : "FALSE");
-}
-
-char* EDL_internal_media_type_to_string(EDL_media_type_t value) {
+int EDL_internal_append_media_type_to_string(EDL_internal_string* str, EDL_media_type_t value) {
 	switch (value) {
 		case MEDIATYPE_AUDIO:
-			return EDL_internal_strdup("AUDIO");
+			return EDL_internal_string_append(str, "AUDIO", 5);
 		case MEDIATYPE_VIDEO:
 		case MEDIATYPE_UNKNOWN:
 		default:
-			return EDL_internal_strdup("VIDEO");
+			return EDL_internal_string_append(str, "VIDEO", 5);
 	}
 }
--- a/src/edl.c	Fri Mar 22 20:51:46 2024 -0400
+++ b/src/edl.c	Wed Mar 27 13:38:30 2024 -0400
@@ -41,6 +41,12 @@
 #define EDL_HEADER_FIRSTCHANNEL		0x3071a4c6
 #define EDL_HEADER_CHANNELS			0xe94981a4
 
+typedef struct {
+	uint32_t* order;
+	size_t size;
+	size_t capacity;
+} EDL_header;
+
 /* use a CRC32 hash function to process the headers */
 static uint32_t EDL_internal_crcn32b(const unsigned char* message, size_t length) {
 	uint32_t crc = 0xffffffff;
@@ -61,47 +67,69 @@
 	return (a < b) ? a : b;
 }
 
-/* This parses the header of the EDL and creates an array with CRC32 hashes
- * in the order of the strings.
-*/
-static uint32_t* EDL_internal_parse_header(const char* data, size_t* length) {
-	/* */
-	const size_t newline = EDL_internal_size_t_min(strchr(data, '\n') - data, strchr(data, '\r') - data);
+static int EDL_internal_header_reallocate(EDL_header* header, size_t new_capacity) {
+	header->order = realloc(header->order, new_capacity * sizeof(*header->order));
+	if (!header->order)
+		return -1;
+
+	if (new_capacity > header->capacity)
+		memset(&header->order[header->capacity], 0, (new_capacity - header->capacity) * sizeof(*header->order));
+
+	header->capacity = new_capacity;
 
-	size_t current_hash = 0, hashes_size = 32;
-	uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t));
+	return header->capacity;
+}
+
+static int EDL_internal_parse_header_item(EDL_header* header, const char* data, size_t offset, size_t length) {
+	if (header->capacity <= header->size)
+		if (EDL_internal_header_reallocate(header, header->capacity * 2) < 0)
+			return -1;
+
+	header->order[header->size++] = EDL_internal_crcn32b((const unsigned char*)&data[offset], length);
 
-	/* overall iterates over the entire line,
-	 * column stores the length of the current column */
-	size_t overall, column;
+	return header->size;
+}
+
+/* EDL_header MUST be zero-initialized. */
+static int EDL_internal_parse_header(EDL_header* header, const char* data, size_t offset, size_t length) {
+	size_t newline = 0, overall = 0, column = 0;
+	{
+		const char* ln = memchr(&data[offset], '\n', length - offset);
+		if (!ln)
+			return -1;
 
-	for (overall = 0, column = 0; overall <= newline; overall++) {
-		if (data[overall] == ';' || data[overall] == ':') {
-			/* process the current column */
-			if (hashes_size < current_hash)
-				hashes = realloc(hashes, (hashes_size *= 2) * sizeof(uint32_t));
+		newline = ln - &data[offset];
+	}
+
+	EDL_internal_header_reallocate(header, 32);
 
-			hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[overall - column], column);
+	for (; overall <= newline; overall++) {
+		if (data[offset + overall] == ';' || data[offset + overall] == ':') {
+			if (EDL_internal_parse_header_item(header, data, overall - column, column) < 0)
+				return -1;
+
 			column = 0; /* reset */
 		} else column++;
 	}
 
-	*length = current_hash;
+	return overall;
+}
 
-	return hashes;
+static int EDL_internal_free_header(EDL_header* header) {
+	free(header->order);
 }
 
 int EDL_reallocate(EDL* edl, size_t new_capacity) {
 	edl->arr = realloc(edl->arr, new_capacity * sizeof(EDL_line));
 	if (!edl->arr)
-		return 0;
+		return -1;
 
 	if (new_capacity > edl->capacity)
 		memset(&edl->arr[edl->capacity], 0, (new_capacity - edl->capacity) * sizeof(EDL_line));
 
 	edl->capacity = new_capacity;
 
-	return 1;
+	return edl->capacity;
 }
 
 int EDL_append(EDL* edl, EDL_line line) {
@@ -114,21 +142,21 @@
 
 /* the big important function */
 EDL_parse_error_t EDL_parse(EDL* edl, const char* data, size_t length) {
-	size_t order_size = 0;
-	uint32_t* order = NULL;
 	size_t offset = 0;
+	EDL_header header = {0};
 
-	if (!EDL_reallocate(edl, 16))
+	if (EDL_reallocate(edl, 16) < 0)
 		return EDL_PARSE_ERROR_OUT_OF_MEMORY;
 
-	order = EDL_internal_parse_header(data, &order_size);
+	if (EDL_internal_parse_header(&header, data, offset, length) < 0)
+		return EDL_PARSE_ERROR_HEADER;
 
-	while ((offset = EDL_internal_strnchr(&data[offset], '\n', length - offset) - data + 1) < length) {
+	while ((offset = (const char*)memchr(&data[offset], '\n', length - offset) - data + 1) < length) {
 		size_t local_offset = offset; /* original offset stays intact */
 		bool ok = true;
 		int i;
 
-		for (i = 0; i < order_size; i++) {
+		for (i = 0; i < header.size; i++) {
 #define ADD_TO_OFFSET(x, a) \
 { \
 	size_t o = a(data, local_offset, length, &edl->arr[edl->size].x); \
@@ -136,7 +164,7 @@
 		ok = false; \
 	local_offset += o; \
 }
-			switch (order[i]) {
+			switch (header.order[i]) {
 				case EDL_HEADER_ID:
 					ADD_TO_OFFSET(id, EDL_internal_parse_int);
 					break;
@@ -238,60 +266,56 @@
 			break;
 
 		if (++edl->size >= edl->capacity)
-			EDL_reallocate(edl, edl->capacity * 2);
+			if (EDL_reallocate(edl, edl->capacity * 2) < 0)
+				return EDL_PARSE_ERROR_OUT_OF_MEMORY;
 	}
 
+	EDL_internal_free_header(&header);
+
 	/* put on the shrinkwrap */
-	EDL_reallocate(edl, edl->size);
-
-	free(order);
+	if (EDL_reallocate(edl, edl->size) < 0)
+		return EDL_PARSE_ERROR_OUT_OF_MEMORY;
 
 	return EDL_PARSE_ERROR_SUCCESS;
 }
 
-static void EDL_dump_line(EDL_internal_string* str, const EDL_line* line, const uint32_t* order, const size_t order_len) {
+static void EDL_dump_line(EDL_internal_string* str, const EDL_line* line, const EDL_header* header) {
 	size_t i;
 
-	for (i = 0; i < order_len; i++) {
-		switch (order[i]) {
-#define APPEND_ITEM(a, x) \
-{ \
-	char* tstr = x(line->a); \
-	EDL_internal_string_append(str, tstr, strlen(tstr)); \
-	free(tstr); \
-}
+	for (i = 0; i < header->size; i++) {
+		switch (header->order[i]) {
 			case EDL_HEADER_ID:
-				APPEND_ITEM(id, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->id);
 				break;
 			case EDL_HEADER_TRACK:
-				APPEND_ITEM(track, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->track);
 				break;
 			case EDL_HEADER_STARTTIME:
-				APPEND_ITEM(start_time, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->start_time);
 				break;
 			case EDL_HEADER_LENGTH:
-				APPEND_ITEM(length, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->length);
 				break;
 			case EDL_HEADER_PLAYRATE:
-				APPEND_ITEM(play_rate, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->play_rate);
 				break;
 			case EDL_HEADER_LOCKED:
-				APPEND_ITEM(locked, EDL_internal_bool_to_string);
+				EDL_internal_append_bool_to_string(str, line->locked);
 				break;
 			case EDL_HEADER_NORMALIZED:
-				APPEND_ITEM(normalized, EDL_internal_bool_to_string);
+				EDL_internal_append_bool_to_string(str, line->normalized);
 				break;
 			case EDL_HEADER_STRETCHMETHOD:
-				APPEND_ITEM(stretch_method, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->stretch_method);
 				break;
 			case EDL_HEADER_LOOPED:
-				APPEND_ITEM(looped, EDL_internal_bool_to_string);
+				EDL_internal_append_bool_to_string(str, line->looped);
 				break;
 			case EDL_HEADER_ONRULER:
-				APPEND_ITEM(on_ruler, EDL_internal_bool_to_string);
+				EDL_internal_append_bool_to_string(str, line->on_ruler);
 				break;
 			case EDL_HEADER_MEDIATYPE:
-				APPEND_ITEM(media_type, EDL_internal_media_type_to_string);
+				EDL_internal_append_media_type_to_string(str, line->media_type);
 				break;
 			case EDL_HEADER_FILENAME:
 				EDL_internal_string_append(str, "\"", 1);
@@ -299,66 +323,65 @@
 				EDL_internal_string_append(str, "\"", 1);
 				break;
 			case EDL_HEADER_STREAM:
-				APPEND_ITEM(stream, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->stream);
 				break;
 			case EDL_HEADER_STREAMSTART:
-				APPEND_ITEM(stream_start, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->stream_start);
 				break;
 			case EDL_HEADER_STREAMLENGTH:
-				APPEND_ITEM(stream_length, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->stream_length);
 				break;
 			case EDL_HEADER_FADETIMEIN:
-				APPEND_ITEM(fade_time_in, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->fade_time_in);
 				break;
 			case EDL_HEADER_FADETIMEOUT:
-				APPEND_ITEM(fade_time_out, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->fade_time_out);
 				break;
 			case EDL_HEADER_SUSTAINGAIN:
-				APPEND_ITEM(sustain_gain, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->sustain_gain);
 				break;
 			case EDL_HEADER_CURVEIN:
-				APPEND_ITEM(curve_in, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->curve_in);
 				break;
 			case EDL_HEADER_GAININ:
-				APPEND_ITEM(gain_in, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->gain_in);
 				break;
 			case EDL_HEADER_CURVEOUT:
-				APPEND_ITEM(curve_out, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->curve_out);
 				break;
 			case EDL_HEADER_GAINOUT:
-				APPEND_ITEM(gain_out, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->gain_out);
 				break;
 			case EDL_HEADER_LAYER:
-				APPEND_ITEM(layer, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->layer);
 				break;
 			case EDL_HEADER_COLOR:
-				APPEND_ITEM(color, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->color);
 				break;
 			case EDL_HEADER_CURVEINR:
-				APPEND_ITEM(curve_in_r, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->curve_in_r);
 				break;
 			case EDL_HEADER_CURVEOUTR:
-				APPEND_ITEM(curve_out_r, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->curve_out_r);
 				break;
 			case EDL_HEADER_PLAYPITCH:
-				APPEND_ITEM(play_pitch, EDL_internal_double_to_string);
+				EDL_internal_append_double_to_string(str, line->play_pitch);
 				break;
 			case EDL_HEADER_LOCKPITCH:
-				APPEND_ITEM(lock_pitch, EDL_internal_bool_to_string);
+				EDL_internal_append_bool_to_string(str, line->lock_pitch);
 				break;
 			case EDL_HEADER_FIRSTCHANNEL:
-				APPEND_ITEM(first_channel, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->first_channel);
 				break;
 			case EDL_HEADER_CHANNELS:
-				APPEND_ITEM(channels, EDL_internal_integer_to_string);
+				EDL_internal_append_integer_to_string(str, line->channels);
 				break;
 			default:
 				/* ... what */
 				break;
-#undef APPEND_ITEM
 		}
 
-		if (i < order_len - 1)
+		if (i < header->size - 1)
 			EDL_internal_string_append(str, ";\t", 2);
 		else
 			EDL_internal_string_append(str, ";", 1);
@@ -381,14 +404,16 @@
 	EDL_internal_string_append(&ret, order_str, strlen(order_str));
 
 	{
-		size_t order_len;
-		uint32_t* order = EDL_internal_parse_header(order_str, &order_len);
+		/* how? */
+		EDL_header header = {0};
+		if (EDL_internal_parse_header(&header, order_str, 0, strlen(order_str)) < 0)
+			return NULL;
 
 		size_t i;
 		for (i = 0; i < edl->size; i++)
-			EDL_dump_line(&ret, &edl->arr[i], order, order_len);
+			EDL_dump_line(&ret, &edl->arr[i], &header);
 
-		free(order);
+		EDL_internal_free_header(&header);
 	}
 
 	return ret.data;
--- a/src/str.c	Fri Mar 22 20:51:46 2024 -0400
+++ b/src/str.c	Wed Mar 27 13:38:30 2024 -0400
@@ -25,8 +25,8 @@
 	if (!str->data)
 		return 0;
 
-	//if (new_capacity > str->capacity)
-	//	memset(&str->data[str->capacity], 0, (new_capacity - str->capacity) * sizeof(char));
+	if (new_capacity > str->capacity)
+		memset(&str->data[str->capacity], 0, (new_capacity - str->capacity) * sizeof(char));
 
 	str->capacity = new_capacity;
 
@@ -38,6 +38,7 @@
         if (!EDL_internal_string_allocate(str, 1))
             return 0;
 
+    /* increase capacity if needed */
     if (str->size + length + 1 >= str->capacity) {
         size_t capacity = 1;
         while (capacity < (str->size + length + 1))
@@ -47,7 +48,7 @@
             return 0;
     }
 
-    strncat(str->data, data, length);
+    memcpy(&str->data[str->size], data, length);
     str->size += length;
 
     return length;