1 /*
2 Message
3 */
4
5 #include "message.h"
6
7 #include "config.h"
8 #include "head.h"
9 #include "mem.h"
10 #include "os.h"
11 #include "print.h"
12
13 /*
14 ** Coded Message Routine Global Variables
15 */
16
17 #if EARLY
18 /* Bind at runtime */
19 static char *table;
20 static void (*letter) (char);
21 static word(*find_mode) (char);
22 #else
23 /* Only one option, so do it at link time */
24 #define table table_2
25 #define letter (letter_v3)
26 #define find_mode (find_mode_v3)
27 #endif
28
29 static int print_mode;
30 static int single_mode;
31 static word word_bank;
32
33 /*
34 ** Character Table
35 */
36
37 #if EARLY
38 static char table_1[] = {
39 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
40 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
41 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
42 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
43 'W', 'X', 'Y', 'Z', ' ', '0', '1', '2', '3', '4', '5', '6',
44 '7', '8', '9', '.', ',', '!', '?', '_', '#', '\'', '\"',
45 '/', '\\', '<', '-', ':', '(', ')', '\0', '\0'
46 };
47 #endif
48
49 static char table_2[] = {
50 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
51 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
52 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
53 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
54 'W', 'X', 'Y', 'Z', ' ', ' ', '0', '1', '2', '3', '4', '5',
55 '6', '7', '8', '9', '.', ',', '!', '?', '_', '#', '\'',
56 '\"', '/', '\\', '-', ':', '(', ')', '\0', '\0'
57 };
58
59 #if EARLY
letter_v1(char ch)60 static void letter_v1(char ch)
61 {
62 extern void (*PrintChar) (word);
63
64 switch(ch)
65 {
66 case 0:
67 (*PrintChar) ((word) ' ');
68 single_mode = print_mode;
69 break;
70 case 1:
71 new_line();
72 single_mode = print_mode;
73 break;
74 case 2:
75 single_mode = (single_mode + 1) % 3;
76 break;
77 case 3:
78 single_mode = (single_mode + 2) % 3;
79 break;
80 case 4:
81 print_mode = (single_mode + 1) % 3;
82 single_mode = print_mode;
83 break;
84 case 5:
85 print_mode = (single_mode + 2) % 3;
86 single_mode = print_mode;
87 break;
88 case 6:
89 if(single_mode == 2)
90 {
91 single_mode = 3;
92 break;
93 }
94 /* else fall through */
95 default:
96 (*PrintChar) ((word) table[(single_mode * 26) + ch - 6]);
97 single_mode = print_mode;
98 break;
99 }
100 }
101 #endif
102
103 #if EARLY
letter_v2(char ch)104 static void letter_v2(char ch)
105 {
106 extern void (*PrintChar) (word);
107
108 switch(ch)
109 {
110 case 0:
111 (*PrintChar) ((word) ' ');
112 single_mode = print_mode;
113 break;
114 case 1:
115 single_mode |= 0x80;
116 word_bank = (ch - 1) << 6;
117 break;
118 case 2:
119 single_mode = (single_mode + 1) % 3;
120 break;
121 case 3:
122 single_mode = (single_mode + 2) % 3;
123 break;
124 case 4:
125 print_mode = (single_mode + 1) % 3;
126 single_mode = print_mode;
127 break;
128 case 5:
129 print_mode = (single_mode + 2) % 3;
130 single_mode = print_mode;
131 break;
132 case 6:
133 case 7:
134 if(single_mode == 2)
135 {
136 if(ch == 6)
137 {
138 single_mode = 3;
139 }
140 else
141 {
142 new_line();
143 single_mode = print_mode;
144 }
145 break;
146 }
147 /* else fall through */
148 default:
149 (*PrintChar) ((word) table[(single_mode * 26) + ch - 6]);
150 single_mode = print_mode;
151 break;
152 }
153 }
154 #endif
155
letter_v3(char ch)156 static void letter_v3(char ch)
157 {
158 extern void (*PrintChar) (word);
159
160 switch(ch)
161 {
162 case 0:
163 (*PrintChar) ((word) ' ');
164 single_mode = print_mode;
165 break;
166 case 1:
167 case 2:
168 case 3:
169 single_mode |= 0x80;
170 word_bank = (ch - 1) << 6;
171 break;
172 case 4:
173 case 5:
174 if(single_mode == 0)
175 {
176 single_mode = ch - 3;
177 }
178 else
179 {
180 if(single_mode != ch - 3)
181 single_mode = 0;
182 print_mode = single_mode;
183 }
184 break;
185 case 6:
186 case 7:
187 if(single_mode == 2)
188 {
189 if(ch == 6)
190 {
191 single_mode = 3;
192 }
193 else
194 {
195 new_line();
196 single_mode = print_mode;
197 }
198 break;
199 }
200 /* else fall through */
201 default:
202 (*PrintChar) ((word) table[(single_mode * 26) + ch - 6]);
203 single_mode = print_mode;
204 break;
205 }
206 }
207
208 #if EARLY
find_mode_v1(char ch)209 static word find_mode_v1(char ch)
210 {
211 if(ch == 0)
212 {
213 return 3 + 3;
214 }
215 if('a' <= ch && ch <= 'z')
216 {
217 return 0;
218 }
219 if('A' <= ch && ch <= 'Z')
220 {
221 return 1 + 1;
222 }
223 return 2 + 1;
224 }
225 #endif
226
find_mode_v3(char ch)227 static word find_mode_v3(char ch)
228 {
229 if(ch == 0)
230 {
231 return 3 + 3;
232 }
233 if('a' <= ch && ch <= 'z')
234 {
235 return 0;
236 }
237 if('A' <= ch && ch <= 'Z')
238 {
239 return 1 + 3;
240 }
241 return 2 + 3;
242 }
243
convert(char ch)244 static word convert(char ch)
245 {
246 int i = os_strpos(table, ch);
247
248 if(i >= 0)
249 {
250 word code = i + 6;
251 while(code >= 0x20)
252 code -= 0x1A;
253 return code;
254 }
255 else
256 {
257 return 0;
258 }
259 }
260
decode_char(char ch)261 static void decode_char(char ch)
262 {
263 extern void (*PrintChar) (word);
264 if(single_mode & 0x80)
265 {
266 int save_mode = print_mode;
267 long_word a = hd_common() + (word_bank + 2L * ch);
268 word page = rd_byte_addr(a);
269 word offset = rd_byte_addr(a+1) << 1;
270 print_coded(&page, &offset);
271 single_mode = print_mode = save_mode;
272 }
273 else if(single_mode & 0x40)
274 {
275 (*PrintChar) (ch + ((single_mode & 0x03) << 5));
276 single_mode = print_mode;
277 }
278 else if(single_mode < 3)
279 {
280 (*letter) (ch);
281 }
282 else if(single_mode == 3)
283 {
284 single_mode = 0x40 + ch;
285 }
286 }
287
decode(word data)288 static void decode(word data)
289 {
290 decode_char((data >> (5*2)) & 0x1F);
291 decode_char((data >> (5*1)) & 0x1F);
292 decode_char((data >> (5*0)) & 0x1F);
293 }
294
295 /*
296 ** Decode Routines
297 */
298
init_message(void)299 void init_message(void)
300 {
301 #if EARLY
302 switch(hd_version())
303 {
304 case VERSION_1:
305 table = table_1;
306 letter = letter_v1;
307 find_mode = find_mode_v1;
308 break;
309 case VERSION_2:
310 table = table_2;
311 letter = letter_v2;
312 find_mode = find_mode_v1;
313 break;
314 default:
315 table = table_2;
316 letter = letter_v3;
317 find_mode = find_mode_v3;
318 break;
319 }
320 #endif
321 }
322
print_coded(word * page,word * offset)323 void print_coded(word *page, word *offset)
324 {
325 word data;
326 word p = *page;
327 word o = *offset;
328
329 /*
330 Print mode
331 0 : Lower Case Letter
332 1 : Upper Case Letter
333 2 : Number or Symbol
334 3 : ASCII Letter - first byte
335 0x40 : ASCII Letter - second byte
336 0x80 : Common Word
337 */
338
339 print_mode = 0;
340 single_mode = 0;
341
342 do
343 {
344 data = rd_word_seg(p, o);
345 o += 2;
346 if(o >= BLOCK_SIZE)
347 {
348 o -= BLOCK_SIZE;
349 p += 1;
350 }
351 decode(data);
352 } while((data & 0x8000) == 0);
353 *page = p;
354 *offset = o;
355 }
356
357 /*
358 ** Encode Routines
359 */
360
encode(byte * the_word,word coded[])361 void encode(byte *the_word, word coded[])
362 {
363 int plus = hd_plus();
364 int cpw = plus ? PLUS_CHARS_PER_WORD : STD_CHARS_PER_WORD;
365 int esz = plus ? PLUS_ENCODED_SIZE : STD_ENCODED_SIZE;
366 word data[max(STD_CHARS_PER_WORD, PLUS_CHARS_PER_WORD)];
367 int count = 0;
368 while(count < cpw)
369 {
370 byte ch = *the_word++;
371 if(ch == 0)
372 {
373 /* Finished, so fill with blanks */
374 while(count < cpw)
375 data[count++] = 5;
376 }
377 else
378 {
379 /* Get Character Print-Mode */
380 word mode = (*find_mode) ((char) ch);
381 if(mode != 0) data[count++] = mode;
382 /* Get offset of character in Table[] */
383 if(count < cpw)
384 {
385 word offset = convert((char) ch);
386 if(offset == 0)
387 {
388 /* Character not in Table[], so use ASCII */
389 data[count++] = 6;
390 if(count < cpw) data[count++] = ch >> 5;
391 if(count < cpw) data[count++] = ch & 0x1F;
392 }
393 else
394 {
395 data[count++] = offset;
396 }
397 }
398 }
399 }
400 /* Encrypt */
401 for(count = 0; count < esz; count++)
402 coded[count] = (data[count * 3 + 0] << 10)
403 | (data[count * 3 + 1] << 5)
404 | (data[count * 3 + 2] << 0);
405 coded[esz - 1] |= 0x8000;
406 }
407