From 8b1b857948f6c5fd170f53dc064eb7a11c585283 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Date: Tue, 14 Apr 2015 20:50:53 +0000
Subject: [PATCH] otrx: support for creating simple TRX files
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>

SVN-Revision: 45444
---
 package/utils/otrx/src/otrx.c | 185 ++++++++++++++++++++++++++++++++++
 1 file changed, 185 insertions(+)

diff --git a/package/utils/otrx/src/otrx.c b/package/utils/otrx/src/otrx.c
index 25e0592737..fbdad31912 100644
--- a/package/utils/otrx/src/otrx.c
+++ b/package/utils/otrx/src/otrx.c
@@ -220,6 +220,184 @@ out:
 	return err;
 }
 
+/**************************************************
+ * Create
+ **************************************************/
+
+static void otrx_create_parse_options(int argc, char **argv) {
+}
+
+static ssize_t otrx_create_append_file(FILE *trx, const char *in_path) {
+	FILE *in;
+	size_t bytes;
+	ssize_t length = 0;
+	uint8_t buf[128];
+
+	in = fopen(in_path, "r");
+	if (!in) {
+		fprintf(stderr, "Couldn't open %s\n", in_path);
+		return -EACCES;
+	}
+
+	while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
+		if (fwrite(buf, 1, bytes, trx) != bytes) {
+			fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, trx_path);
+			length = -EIO;
+			break;
+		}
+		length += bytes;
+	}
+
+	fclose(in);
+
+	return length;
+}
+
+static ssize_t otrx_create_append_zeros(FILE *trx, size_t length) {
+	uint8_t *buf;
+
+	buf = malloc(length);
+	if (!buf)
+		return -ENOMEM;
+	memset(buf, 0, length);
+
+	if (fwrite(buf, 1, length, trx) != length) {
+		fprintf(stderr, "Couldn't write %zu B to %s\n", length, trx_path);
+		return -EIO;
+	}
+
+	return length;
+}
+
+static ssize_t otrx_create_align(FILE *trx, size_t curr_offset, size_t alignment) {
+	if (curr_offset & (alignment - 1)) {
+		size_t length = alignment - (curr_offset % alignment);
+		return otrx_create_append_zeros(trx, length);
+	}
+
+	return 0;
+}
+
+static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) {
+	size_t bytes, length;
+	uint8_t *buf;
+	uint32_t crc32;
+
+	hdr->magic = cpu_to_le32(TRX_MAGIC);
+	hdr->version = 1;
+
+	fseek(trx, 0, SEEK_SET);
+	bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
+	if (bytes != sizeof(struct trx_header)) {
+		fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
+		return -EIO;
+	}
+
+	length = le32_to_cpu(hdr->length);
+
+	buf = malloc(length);
+	if (!buf) {
+		fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
+		return -ENOMEM;
+	}
+
+	fseek(trx, 0, SEEK_SET);
+	bytes = fread(buf, 1, length, trx);
+	if (bytes != length) {
+		fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
+		return -ENOMEM;
+	}
+
+	crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
+	hdr->crc32 = cpu_to_le32(crc32);
+
+	fseek(trx, 0, SEEK_SET);
+	bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
+	if (bytes != sizeof(struct trx_header)) {
+		fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int otrx_create(int argc, char **argv) {
+	FILE *trx;
+	struct trx_header hdr = {};
+	ssize_t sbytes;
+	size_t curr_idx = 0;
+	size_t curr_offset = sizeof(hdr);
+	int c;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No TRX file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	trx_path = argv[2];
+
+	optind = 3;
+	otrx_create_parse_options(argc, argv);
+
+	trx = fopen(trx_path, "w+");
+	if (!trx) {
+		fprintf(stderr, "Couldn't open %s\n", trx_path);
+		err = -EACCES;
+		goto out;
+	}
+	fseek(trx, curr_offset, SEEK_SET);
+
+	optind = 3;
+	while ((c = getopt(argc, argv, "f:b:")) != -1) {
+		switch (c) {
+		case 'f':
+			if (curr_idx >= TRX_MAX_PARTS) {
+				err = -ENOSPC;
+				fprintf(stderr, "Reached TRX partitions limit, no place for %s\n", optarg);
+				goto err_close;
+			}
+
+			sbytes = otrx_create_append_file(trx, optarg);
+			if (sbytes < 0) {
+				fprintf(stderr, "Failed to append file %s\n", optarg);
+			} else {
+				hdr.offset[curr_idx++] = curr_offset;
+				curr_offset += sbytes;
+			}
+
+			sbytes = otrx_create_align(trx, curr_offset, 4);
+			if (sbytes < 0)
+				fprintf(stderr, "Failed to append zeros\n");
+			else
+				curr_offset += sbytes;
+
+			break;
+		case 'b':
+			sbytes = strtol(optarg, NULL, 0) - curr_offset;
+			if (sbytes < 0) {
+				fprintf(stderr, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
+			} else {
+				sbytes = otrx_create_append_zeros(trx, sbytes);
+				if (sbytes < 0)
+					fprintf(stderr, "Failed to append zeros\n");
+				else
+					curr_offset += sbytes;
+			}
+			break;
+		}
+		if (err)
+			break;
+	}
+
+	hdr.length = curr_offset;
+	otrx_create_write_hdr(trx, &hdr);
+err_close:
+	fclose(trx);
+out:
+	return err;
+}
+
 /**************************************************
  * Extract
  **************************************************/
@@ -363,6 +541,11 @@ static void usage() {
 	printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
 	printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
 	printf("\n");
+	printf("Creating new TRX file:\n");
+	printf("\totrx create <file> [options] [partitions]\n");
+	printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
+	printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
+	printf("\n");
 	printf("Extracting from TRX file:\n");
 	printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
 	printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
@@ -375,6 +558,8 @@ int main(int argc, char **argv) {
 	if (argc > 1) {
 		if (!strcmp(argv[1], "check"))
 			return otrx_check(argc, argv);
+		else if (!strcmp(argv[1], "create"))
+			return otrx_create(argc, argv);
 		else if (!strcmp(argv[1], "extract"))
 			return otrx_extract(argc, argv);
 	}
-- 
2.30.2