1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 #define TITLE "byteshuf - Shuffle or unshuffle bytes in a file"
4 #define COPYR "Copyright (C) 2011 Neill Corlett"
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include "common.h"
22 #include "banner.h"
23
24 ////////////////////////////////////////////////////////////////////////////////
25
shuffle(int shuffling,const char * mainfile,const char ** subfiles,size_t subfiles_count,int overwrite)26 static int shuffle(
27 int shuffling,
28 const char* mainfile,
29 const char** subfiles,
30 size_t subfiles_count,
31 int overwrite
32 ) {
33 int returncode = 0;
34 size_t i;
35 int* chars = calloc(1, sizeof(int) * subfiles_count);
36 FILE* mf = NULL;
37 FILE** sf = calloc(1, sizeof(FILE*) * subfiles_count);
38 if(!sf || !chars) {
39 printf("Error: Out of memory\n");
40 goto error;
41 }
42 if(shuffling && !overwrite) {
43 //
44 // Ensure main file doesn't already exist
45 //
46 mf = fopen(mainfile, "rb");
47 if(mf) {
48 printf("Error: %s already exists (use -o to overwrite)\n",
49 mainfile
50 );
51 goto error;
52 }
53 }
54 if(!shuffling && !overwrite) {
55 //
56 // Ensure sub files don't already exist
57 //
58 for(i = 0; i < subfiles_count; i++) {
59 sf[i] = fopen(subfiles[i], "rb");
60 if(sf[i]) {
61 printf("Error: %s already exists (use -o to overwrite)\n",
62 subfiles[i]
63 );
64 goto error;
65 }
66 }
67 }
68 if(shuffling) {
69 size_t num_chars_last = subfiles_count;
70
71 //
72 // Open sub files
73 //
74 for(i = 0; i < subfiles_count; i++) {
75 sf[i] = fopen(subfiles[i], "rb");
76 if(!sf[i]) { goto error_sf_i; }
77 clearerr(sf[i]);
78 }
79 //
80 // Open main file
81 //
82 mf = fopen(mainfile, "wb");
83 if(!mf) { goto error_mf; }
84 clearerr(mf);
85
86 for(;;) {
87 size_t num_chars = 0;
88 for(i = 0; i < subfiles_count; i++) {
89 chars[i] = fgetc(sf[i]);
90 if(chars[i] == EOF) {
91 if(ferror(sf[i])) { goto error_sf_i; }
92 chars[i] = 0;
93 } else {
94 chars[i] &= 0xFF;
95 num_chars = i + 1;
96 }
97 }
98 if(!num_chars) { break; }
99 for(i = num_chars_last; i < subfiles_count; i++) {
100 if(fputc(0, mf) == EOF) { goto error_mf; }
101 }
102 for(i = 0; i < num_chars; i++) {
103 if(fputc(chars[i], mf) == EOF) { goto error_mf; }
104 }
105 num_chars_last = num_chars;
106 }
107 } else {
108 //
109 // Open main file
110 //
111 mf = fopen(mainfile, "rb");
112 if(!mf) { goto error_mf; }
113 clearerr(mf);
114 //
115 // Open sub files
116 //
117 for(i = 0; i < subfiles_count; i++) {
118 sf[i] = fopen(subfiles[i], "wb");
119 if(!sf[i]) { goto error_sf_i; }
120 clearerr(sf[i]);
121 }
122
123 for(;;) {
124 for(i = 0; i < subfiles_count; i++) {
125 int c = fgetc(mf);
126 if(c == EOF) {
127 if(ferror(mf)) { goto error_mf; }
128 break;
129 }
130 if(fputc(c & 0xFF, sf[i]) == EOF) { goto error_sf_i; }
131 }
132 if(i < subfiles_count) { break; }
133 }
134 }
135 goto done;
136
137 error_mf:
138 printfileerror(mf, mainfile);
139 goto error;
140 error_sf_i:
141 printfileerror(sf[i], subfiles[i]);
142 goto error;
143 error:
144 returncode = 1;
145 goto done;
146 done:
147 if(mf) { fclose(mf); }
148 if(sf) {
149 for(i = 0; i < subfiles_count; i++) {
150 if(sf[i]) { fclose(sf[i]); }
151 }
152 free(sf);
153 }
154 if(chars) { free(chars); }
155 return returncode;
156 }
157
158 ////////////////////////////////////////////////////////////////////////////////
159
checkboth(int a,int b,const char * ab)160 static int checkboth(int a, int b, const char* ab) {
161 if(a && b) {
162 printf("Error: Cannot specify both -%c and -%c\n", ab[0], ab[1]);
163 return 1;
164 }
165 return 0;
166 }
167
checkeither(int a,int b,const char * ab)168 static int checkeither(int a, int b, const char* ab) {
169 if((!a) && (!b)) {
170 printf("Error: Must specify either -%c or -%c\n", ab[0], ab[1]);
171 return 1;
172 }
173 return 0;
174 }
175
176 ////////////////////////////////////////////////////////////////////////////////
177
main(int argc,char ** argv)178 int main(int argc, char** argv) {
179 int returncode = 0;
180 struct {
181 int8_t shuffle;
182 int8_t unshuffle;
183 int8_t overwrite;
184 const char* mainfile;
185 const char** files;
186 size_t files_count;
187 } opt;
188 int i;
189
190 normalize_argv0(argv[0]);
191
192 memset(&opt, 0, sizeof(opt));
193
194 //
195 // Check options
196 //
197 if(argc == 1) { goto usage; }
198 for(i = 1; i < argc; i++) {
199 if(argv[i][0] == '-') {
200 // An option
201 if(argv[i][1] == '-' && argv[i][2] == 0) {
202 // No more options
203 i++;
204 break;
205 } else if(argv[i][1] == 's' && argv[i][2] == 0) {
206 if(opt.shuffle) { goto error_dup; }
207 if(i >= (argc - 1)) { goto error_missing; }
208 opt.shuffle = 1;
209 opt.mainfile = argv[++i];
210 continue;
211 } else if(argv[i][1] == 'u' && argv[i][2] == 0) {
212 if(opt.unshuffle) { goto error_dup; }
213 if(i >= (argc - 1)) { goto error_missing; }
214 opt.unshuffle = 1;
215 opt.mainfile = argv[++i];
216 continue;
217 } else if(argv[i][1] == 'o' && argv[i][2] == 0) {
218 opt.overwrite = 1;
219 continue;
220 }
221 printf("Error: Unknown option: %s\n", argv[i]);
222 goto error_usage;
223 } else {
224 // Not an option - stop here
225 break;
226 }
227 }
228
229 if(checkeither(opt.shuffle, opt.unshuffle, "su")) { goto error_usage; }
230 if(checkboth (opt.shuffle, opt.unshuffle, "su")) { goto error_usage; }
231 //
232 // At least two files must be specified
233 //
234 opt.files = (const char**)(argv + i);
235 opt.files_count = (argc - i);
236 if(opt.files_count < 2) {
237 printf("Error: Must specify at least two subfiles\n");
238 goto error_usage;
239 }
240
241 //
242 // Go
243 //
244 if(opt.shuffle) {
245 returncode = shuffle(
246 1, opt.mainfile, opt.files, opt.files_count, opt.overwrite
247 );
248 } else if(opt.unshuffle) {
249 returncode = shuffle(
250 0, opt.mainfile, opt.files, opt.files_count, opt.overwrite
251 );
252 }
253 goto done;
254
255 error_dup:
256 printf("Error: Specified %s twice\n", argv[i]);
257 goto error_usage;
258 error_missing:
259 printf("Error: Missing parameter for %s\n", argv[i]);
260 goto error_usage;
261 error_usage:
262 printf("\n");
263 goto usage;
264 usage:
265 banner();
266 printf(
267 "Usage:\n"
268 " To unshuffle: %s [-o] -u source [subfiles...]\n"
269 " To shuffle: %s [-o] -s destination [subfiles...]\n"
270 "\n"
271 "Options:\n"
272 " -o Force overwrite\n"
273 "\n"
274 "For example, \"%s -u abc def0 def1\" will split all the even bytes from\n"
275 "\"abc\" into \"def0\", and the odd bytes into \"def1\".\n",
276 argv[0], argv[0], argv[0]
277 );
278 goto error;
279
280 error:
281 returncode = 1;
282 goto done;
283
284 done:
285 return returncode;
286 }
287
288 ////////////////////////////////////////////////////////////////////////////////
289