diff src/edl.c @ 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 0c98b46eaf73
children 41b74137e201
line wrap: on
line diff
--- 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;