ptgen: add Chromium OS kernel partition support
[project/firmware-utils.git] / src / xorimage.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * xorimage.c - partially based on OpenWrt's addpattern.c
4 */
5
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdbool.h>
11 #include <stdint.h>
12 #include <unistd.h>
13 #include <sys/stat.h>
14
15 static char default_pattern[] = "12345678";
16 static int is_hex_pattern;
17
18
19 int xor_data(void *data, size_t len, const void *pattern, int p_len, int p_off)
20 {
21 const uint8_t *key = pattern;
22 uint8_t *d = data;
23
24 while (len--) {
25 *d ^= key[p_off];
26 d++;
27 p_off = (p_off + 1) % p_len;
28 }
29 return p_off;
30 }
31
32
33 void usage(void) __attribute__ (( __noreturn__ ));
34
35 void usage(void)
36 {
37 fprintf(stderr, "Usage: xorimage [-i infile] [-o outfile] [-p <pattern>] [-x]\n");
38 exit(EXIT_FAILURE);
39 }
40
41
42 int main(int argc, char **argv)
43 {
44 char buf[1024]; /* keep this at 1k or adjust garbage calc below */
45 FILE *in = stdin;
46 FILE *out = stdout;
47 char *ifn = NULL;
48 char *ofn = NULL;
49 const char *pattern = default_pattern;
50 char hex_pattern[128];
51 unsigned int hex_buf;
52 int c;
53 size_t n;
54 int p_len, p_off = 0;
55
56 while ((c = getopt(argc, argv, "i:o:p:xh")) != -1) {
57 switch (c) {
58 case 'i':
59 ifn = optarg;
60 break;
61 case 'o':
62 ofn = optarg;
63 break;
64 case 'p':
65 pattern = optarg;
66 break;
67 case 'x':
68 is_hex_pattern = true;
69 break;
70 case 'h':
71 default:
72 usage();
73 }
74 }
75
76 if (optind != argc || optind == 1) {
77 fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
78 usage();
79 }
80
81 if (ifn && !(in = fopen(ifn, "r"))) {
82 fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
83 usage();
84 }
85
86 if (ofn && !(out = fopen(ofn, "w"))) {
87 fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
88 usage();
89 }
90
91 p_len = strlen(pattern);
92
93 if (p_len == 0) {
94 fprintf(stderr, "pattern cannot be empty\n");
95 usage();
96 }
97
98 if (is_hex_pattern) {
99 int i;
100
101 if ((p_len / 2) > sizeof(hex_pattern)) {
102 fprintf(stderr, "provided hex pattern is too long\n");
103 usage();
104 }
105
106 if (p_len % 2 != 0) {
107 fprintf(stderr, "the number of characters (hex) is incorrect\n");
108 usage();
109 }
110
111 for (i = 0; i < (p_len / 2); i++) {
112 if (sscanf(pattern + (i * 2), "%2x", &hex_buf) < 0) {
113 fprintf(stderr, "invalid hex digit around %d\n", i * 2);
114 usage();
115 }
116 hex_pattern[i] = (char)hex_buf;
117 }
118 }
119
120 while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
121 if (n < sizeof(buf)) {
122 if (ferror(in)) {
123 FREAD_ERROR:
124 fprintf(stderr, "fread error\n");
125 return EXIT_FAILURE;
126 }
127 }
128
129 if (is_hex_pattern) {
130 p_off = xor_data(buf, n, hex_pattern, (p_len / 2),
131 p_off);
132 } else {
133 p_off = xor_data(buf, n, pattern, p_len, p_off);
134 }
135
136 if (!fwrite(buf, n, 1, out)) {
137 FWRITE_ERROR:
138 fprintf(stderr, "fwrite error\n");
139 return EXIT_FAILURE;
140 }
141 }
142
143 if (ferror(in)) {
144 goto FREAD_ERROR;
145 }
146
147 if (fflush(out)) {
148 goto FWRITE_ERROR;
149 }
150
151 fclose(in);
152 fclose(out);
153
154 return EXIT_SUCCESS;
155 }