fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/utils/aym/encode.c *
7 * Created: 2015-05-21 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2015-2016 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28
29
30static
31int aym_skip_space (FILE *fp)
32{
33 int c, com;
34
35 com = 0;
36
37 while ((c = fgetc (fp)) != EOF) {
38 if (c == '#') {
39 com = 1;
40 }
41 else if ((c == 0x0a) || (c == 0x0d)) {
42 com = 0;
43 }
44 else if ((c == ' ') || (c == '\t')) {
45 ;
46 }
47 else if (com) {
48 ;
49 }
50 else {
51 ungetc (c, fp);
52 return (0);
53 }
54 }
55
56 return (0);
57}
58
59static
60int aym_get_str (FILE *fp, char *dst, unsigned max)
61{
62 int c;
63 unsigned i;
64
65 aym_skip_space (fp);
66
67 i = 0;
68
69 while (i < max) {
70 if ((c = fgetc (fp)) == EOF) {
71 break;
72 }
73
74 if ((c >= 'A') && (c <= 'Z')) {
75 ;
76 }
77 else {
78 ungetc (c, fp);
79 break;
80 }
81
82 dst[i++] = c;
83 }
84
85 if ((i == 0) || (i >= max)) {
86 return (1);
87 }
88
89 dst[i++] = 0;
90
91 return (0);
92}
93
94static
95int aym_get_int (FILE *fp, unsigned long long *val)
96{
97 int c, ok;
98 unsigned dig;
99
100 aym_skip_space (fp);
101
102 ok = 0;
103
104 *val = 0;
105
106 while (1) {
107 if ((c = fgetc (fp)) == EOF) {
108 break;
109 }
110
111 if ((c >= '0') && (c <= '9')) {
112 dig = c - '0';
113 }
114 else {
115 ungetc (c, fp);
116 break;
117 }
118
119 *val = 10 * *val + dig;
120
121 ok = 1;
122 }
123
124 return (ok == 0);
125}
126
127static
128int aym_get_byte (FILE *fp, unsigned *val)
129{
130 int c, ok;
131 unsigned dig;
132
133 aym_skip_space (fp);
134
135 ok = 0;
136
137 *val = 0;
138
139 while (1) {
140 if ((c = fgetc (fp)) == EOF) {
141 break;
142 }
143
144 if ((c >= '0') && (c <= '9')) {
145 dig = c - '0';
146 }
147 else if ((c >= 'A') && (c <= 'F')) {
148 dig = c - 'A' + 10;
149 }
150 else if ((c >= 'a') && (c <= 'f')) {
151 dig = c - 'a' + 10;
152 }
153 else {
154 ungetc (c, fp);
155 break;
156 }
157
158 *val = 16 * *val + dig;
159
160 ok = 1;
161 }
162
163 return (ok == 0);
164}
165
166static
167void aym_write_delay (FILE *out, unsigned long long val)
168{
169 while (val >= 0xfff000000) {
170 fputc (0x3f, out);
171 fputc (0xff, out);
172 val -= 0xfff000000;
173 }
174
175 if (val & 0xfff000000) {
176 fputc (0x30 | ((val >> 32) & 0x0f), out);
177 fputc ((val >> 24) & 0xff, out);
178 }
179
180 if (val & 0x00fff000) {
181 fputc (0x20 | ((val >> 20) & 0x0f), out);
182 fputc ((val >> 12) & 0xff, out);
183 }
184
185 if (val & 0x00000fff) {
186 fputc (0x10 | ((val >> 8) & 0x0f), out);
187 fputc (val & 0xff, out);
188 }
189}
190
191static
192int aym_encode_text (FILE *inp, FILE *out)
193{
194 int c;
195 unsigned i, n, type;
196 unsigned long long val;
197 char str[256];
198
199 if (aym_get_int (inp, &val)) {
200 return (1);
201 }
202
203 type = val & 0x0f;
204
205 n = 0;
206
207 while ((n < 256) && ((c = fgetc (inp)) != EOF)) {
208 if ((c == 0x0d) || (c == 0x0a)) {
209 break;
210 }
211
212 if ((n == 0) && ((c == ' ') || (c == 't'))) {
213 continue;
214 }
215
216 str[n++] = c;
217 }
218
219 if (n > 255) {
220 return (1);
221 }
222
223 while ((n > 0) && ((str[n - 1] == ' ') || (str[n - 1] == '\t'))) {
224 n -= 1;
225 }
226
227 fputc (0x80 | type, out);
228 fputc (n, out);
229
230 for (i = 0; i < n; i++) {
231 fputc (str[i], out);
232 }
233
234 return (0);
235}
236
237static
238int aym_encode_fp (FILE *inp, FILE *out, unsigned long th)
239{
240 unsigned long long vers, delay;
241 unsigned char buf[8];
242 char str[256];
243
244 if (aym_get_str (inp, str, 256)) {
245 return (1);
246 }
247
248 if (strcmp (str, "AYM") != 0) {
249 fprintf (stderr, "%s: bad magic (%s)\n", arg0, str);
250 return (1);
251 }
252
253 if (aym_get_int (inp, &vers)) {
254 return (1);
255 }
256
257 if (vers != 0) {
258 fprintf (stderr, "%s: unknown version (%llu)\n", arg0, vers);
259 return (1);
260 }
261
262 aym_set_uint32_be (buf, 0, AYM_MAGIC);
263 aym_set_uint32_be (buf, 4, 0);
264
265 if (fwrite (buf, 1, 8, out) != 8) {
266 return (1);
267 }
268
269 delay = 0;
270
271 while (1) {
272 if (aym_get_str (inp, str, 256)) {
273 return (1);
274 }
275
276 if (strcmp (str, "DEL") == 0) {
277 unsigned long long val;
278
279 if (aym_get_int (inp, &val)) {
280 return (1);
281 }
282
283 delay += val;
284 }
285 else if (strcmp (str, "END") == 0) {
286 fputc (0xff, out);
287 fputc (0xff, out);
288 break;
289 }
290 else if (strcmp (str, "REG") == 0) {
291 unsigned v1, v2;
292
293 if ((delay > 0) && (delay >= th)) {
294 aym_write_delay (out, delay);
295 delay = 0;
296 }
297
298 if (aym_get_byte (inp, &v1)) {
299 return (1);
300 }
301
302 if (aym_get_byte (inp, &v2)) {
303 return (1);
304 }
305
306 fputc (v1 & 0x0f, out);
307 fputc (v2 & 0xff, out);
308 }
309 else if (strcmp (str, "TXT") == 0) {
310 if (aym_encode_text (inp, out)) {
311 return (1);
312 }
313 }
314 else {
315 fprintf (stderr, "%s: bad keyword (%s)\n", arg0, str);
316 return (1);
317 }
318 }
319
320 return (0);
321}
322
323int aym_encode (const char *inp, const char *out, unsigned long th)
324{
325 int r;
326 FILE *finp, *fout;
327
328 if (inp == NULL) {
329 finp = stdin;
330 }
331 else if ((finp = fopen (inp, "r")) == NULL) {
332 fprintf (stderr, "%s: can't open input file (%s)\n", arg0, inp);
333 return (1);
334 }
335
336 if (out == NULL) {
337 fout = stdout;
338 }
339 else if ((fout = fopen (out, "wb")) == NULL) {
340 fprintf (stderr, "%s: can't open output file (%s)\n", arg0, out);
341 fclose (finp);
342 return (1);
343 }
344
345 r = aym_encode_fp (finp, fout, th);
346
347 if (fout != stdout) {
348 fclose (fout);
349 }
350
351 if (finp != stdin) {
352 fclose (finp);
353 }
354
355 return (r);
356}