1/*
2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6#include <errno.h>
7#include <fcntl.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/stat.h>
12#include <unistd.h>
13
14
15void
16write_string(int fd, const char* data)
17{
18	int len = strlen(data);
19	if (len == 0)
20		return;
21
22	ssize_t written = write(fd, data, len);
23	if (written < 0) {
24		fprintf(stderr, "Error: Failed to write to output file: %s\n",
25			strerror(errno));
26		exit(1);
27	}
28}
29
30
31int
32main(int argc, const char* const* argv)
33{
34	if (argc != 5) {
35		fprintf(stderr,
36			"Usage: %s <data var name> <size var name> <input> <output>\n",
37			argv[0]);
38		exit(1);
39	}
40	const char* dataVarName = argv[1];
41	const char* sizeVarName = argv[2];
42	const char* inFileName = argv[3];
43	const char* outFileName = argv[4];
44
45	// open files
46	int inFD = open(inFileName, O_RDONLY);
47	if (inFD < 0) {
48		fprintf(stderr, "Error: Failed to open input file \"%s\": %s\n",
49			inFileName, strerror(errno));
50		exit(1);
51	}
52
53	int outFD = open(outFileName, O_WRONLY | O_CREAT | O_TRUNC,
54		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
55	if (outFD < 0) {
56		fprintf(stderr, "Error: Failed to open output file \"%s\": %s\n",
57			outFileName, strerror(errno));
58		exit(1);
59	}
60
61	const int kCharsPerLine = 15;
62	const int kBufferSize = 16 * 1024;
63	unsigned char buffer[kBufferSize];
64	char lineBuffer[128];
65
66	sprintf(lineBuffer, "#include <stddef.h>\n");
67	write_string(outFD, lineBuffer);
68	sprintf(lineBuffer, "const unsigned char %s[] = {\n", dataVarName);
69	write_string(outFD, lineBuffer);
70
71	off_t offset = 0;
72	char* lineBufferEnd = lineBuffer;
73	*lineBufferEnd = '\0';
74	while (true) {
75		// read a buffer
76		ssize_t bytesRead = read(inFD, buffer, kBufferSize);
77		if (bytesRead < 0) {
78			fprintf(stderr, "Error: Failed to read from input file: %s\n",
79				strerror(errno));
80			exit(1);
81		}
82		if (bytesRead == 0)
83			break;
84
85		// write lines
86		for (int i = 0; i < bytesRead; i++, offset++) {
87			if (offset % kCharsPerLine == 0) {
88				if (offset > 0) {
89					// line is full -- flush it
90					strcpy(lineBufferEnd, ",\n");
91					write_string(outFD, lineBuffer);
92					lineBufferEnd = lineBuffer;
93					*lineBufferEnd = '\0';
94				}
95
96				sprintf(lineBufferEnd, "\t%u", (unsigned)buffer[i]);
97			} else
98				sprintf(lineBufferEnd, ", %u", (unsigned)buffer[i]);
99
100			lineBufferEnd += strlen(lineBufferEnd);
101		}
102	}
103
104	// flush the line buffer
105	if (lineBufferEnd != lineBuffer) {
106		strcpy(lineBufferEnd, ",\n");
107		write_string(outFD, lineBuffer);
108	}
109
110	// close the braces and write the size variable
111	sprintf(lineBuffer, "};\nconst size_t %s = sizeof(%s);\n", sizeVarName,
112		dataVarName);
113	write_string(outFD, lineBuffer);
114
115	close(inFD);
116	close(outFD);
117
118	return 0;
119}
120