2 * Tool for testing PCX run-length encoding.
3 * Copyright © 2012 Nick Bowler
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <engine/pcx.h>
30 #define PROGNAME "pcxrle"
31 static const char *progname = PROGNAME;
32 static const char sopts[] = "VH";
33 static const struct option lopts[] = {
34 { "version", 0, NULL, 'V' },
35 { "help", 0, NULL, 'H' },
39 static void print_usage(FILE *f)
41 fprintf(f, "Usage: %s [options] bytes [bytes ...]\n", progname);
44 static void print_version(void)
46 printf("%s (%s) %s\n", PROGNAME, PACKAGE_NAME, PACKAGE_VERSION);
47 puts("Copyright (C) 2012 Nick Bowler.");
48 puts("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.");
49 puts("This is free software: you are free to change and redistribute it.");
50 puts("There is NO WARRANTY, to the extent permitted by law.");
53 static void rle_error(const unsigned char *raw, size_t n, const char *str)
55 fprintf(stderr, "%s: %s\n", progname, str);
56 fprintf(stderr, "%s: raw input was:\n", progname);
58 fprintf(stderr, "%*s", 4, "");
59 for (size_t i = 0; i < n; i++)
60 printf("%.2hhx", raw[i]);
64 static int compare_rle(const unsigned char *rle_buf, size_t rle_len,
65 const unsigned char *raw_buf, size_t raw_len)
67 unsigned char tmp[raw_len];
70 for (size_t i = 0; i < rle_len; i++) {
73 if ((rle_buf[i] & 0xc0) == 0xc0) {
74 count = rle_buf[i] & 0x3f;
76 rle_error(raw_buf, raw_len, "invalid RLE encoding");
81 if (offset + count > raw_len) {
82 rle_error(raw_buf, raw_len, "RLE expansion exceeds raw size");
86 memset(tmp+offset, rle_buf[i], count);
90 if (offset < raw_len) {
91 rle_error(raw_buf, raw_len, "RLE expansion falls short of raw size");
95 if (memcmp(raw_buf, tmp, raw_len) != 0) {
96 rle_error(raw_buf, raw_len, "RLE expansion does not match raw data");
103 static int encode_rle(FILE *tmp, const char *hex)
105 unsigned char buf[256], rle_buf[sizeof buf*2];
106 struct pcx_head head;
111 n = test_decode_hex(hex, buf, sizeof buf);
113 fprintf(stderr, "%s: invalid hex sequence: %s\n",
117 fprintf(stderr, "%s: empty argument\n", progname);
119 } else if (n > sizeof buf) {
120 fprintf(stderr, "%s: hex sequence too long: %s\n",
126 head.width = head.height = n;
127 rc = pcx_write_scanline(&head, buf, tmp);
129 fprintf(stderr, "%s: failed to encode data: %s\n",
130 progname, strerror(errno));
136 fprintf(stderr, "%s: failed to get file offset: %s\n",
137 progname, strerror(errno));
142 if (fread(rle_buf, offset, 1, tmp) != 1) {
143 fprintf(stderr, "%s: failed to read RLE data: %s\n",
144 progname, strerror(errno));
148 ret = compare_rle(rle_buf, offset, buf, n);
149 for (long i = 0; i < offset; i++)
150 printf("%.2hhx", rle_buf[i]);
155 int main(int argc, char **argv)
157 int opt, ret = EXIT_SUCCESS;
163 while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
184 fprintf(stderr, "%s: failed to create temporary file: %s\n",
185 progname, strerror(errno));
189 for (int i = optind; i < argc; i++) {
190 if (encode_rle(tmp, argv[i]) != 0) {