*** empty log message ***
[h316.git] / pc-tools / ldc2 / src / tape_block.cpp
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <string.h>
4 #include <stdio.h>
5
6 #include "tape_block.hh"
7 #include "data_block.hh"
8 #include "data_block_0.hh"
9 #include "data_block_0_0.hh"
10 #include "data_block_0_1.hh"
11 #include "data_block_0_2.hh"
12 #include "data_block_0_3.hh"
13 #include "data_block_0_4.hh"
14 #include "data_block_0_10.hh"
15 #include "data_block_0_14.hh"
16 #include "data_block_0_24.hh"
17 #include "data_block_0_44.hh"
18 #include "data_block_0_30.hh"
19 #include "data_block_0_54.hh"
20 #include "data_block_0_60.hh"
21 #include "data_block_0_50.hh"
22 #include "data_block_0_64.hh"
23 #include "data_block_1.hh"
24 #include "data_block_2.hh"
25 #include "data_block_3.hh"
26 #include "data_block_4.hh"
27 #include "data_block_5.hh"
28 #include "data_block_6.hh"
29 #include "data_block_7.hh"
30
31 #include "eot_block.hh"
32 #include "discard_block.hh"
33 #include "silent_code.hh"
34 #include "hw_constants.hh"
35
36 using namespace std;
37
38 /***************************************************************/
39 /*!
40 *\brief Destructor.
41 */
42 tape_block::~tape_block(){
43 free(raw_data);
44 free(word_data);
45 }
46
47 /***************************************************************/
48 /*!
49 *\brief Copy constructor.
50 */
51 tape_block::tape_block(tape_block & org){
52 operator=(org);
53 }
54
55 /***************************************************************/
56 /*!
57 *\brief Assignment operator.
58 */
59 void tape_block::operator=(tape_block &org){
60 block_type=org.block_type;
61 init_state=org.init_state;
62 data_read=org.data_read;
63 raw_data=0;
64 raw_size=org.raw_size;
65 word_data=0;
66 word_size=org.word_size;
67 if (raw_size){
68 raw_data=(unsigned char *)malloc(raw_size);
69 memcpy(raw_data,org.raw_data,raw_size);
70 }
71 if (word_size){
72 word_data=(unsigned short *)malloc(word_size*sizeof(unsigned short));
73 memcpy(word_data,org.word_data,word_size*sizeof(unsigned short));
74 }
75 }
76
77 /***************************************************************/
78 /*!
79 *\brief Query the block's state.
80 *
81 * If the state is not TBS_OK, the block must be discarded.
82 *\return The block's initialisation state
83 */
84 tape_block::tb_state_t tape_block::get_state(){
85 return init_state;
86 }
87
88 /***************************************************************/
89 /*!
90 *\brief Determine the block's type
91 *
92 * This routine returns the block's type.\\
93 *\retval TBT_DATA if it's a data block
94 *\retval TBT_EOT if it's an end of tape mark
95 *\retval TBR_DISCARD if the block is unusable
96 *
97 *\note This function is virtual. That means that if the tape block in
98 * question is of the subtype data_block which overwrites this method,
99 * it will return the block type contained in the upper 4 bits of the
100 * first data word! Try to avoid testing for TBT_DATA. \n
101 * Blocks generated by gen_from_fd should never have TBT_DATA.
102 */
103 int tape_block::get_type(){
104 return block_type;
105 }
106
107 /***************************************************************/
108 /*!
109 *\brief Determine the block's subtype
110 *
111 * Some data block types have a subtype.
112 *\note This is a virtual method and to be used in derived classes.
113 *\return Always 0
114 */
115 int tape_block::get_subtype(){
116 return 0;
117 }
118
119 /***************************************************************/
120 /*!
121 *\brief Get a cleartext description of the block.
122 *\return ldc style descriptive line for the block
123 */
124 vector<string> tape_block:: get_description(){
125 vector<string> result;
126 result.insert(result.end(),
127 "***** "+get_typestring()+"Untyped tape block");
128 return result;
129 }
130
131 /***************************************************************/
132 /*!
133 *\brief Get size of the internal raw data buffer
134 *\return The size of the internal raw data buffer
135 */
136 int tape_block::get_raw_size(){
137 return raw_size;
138 }
139
140 /***************************************************************/
141 /*!
142 *\brief Access internal raw data buffer
143 *
144 * The raw data buffer contains all block data except the \ \
145 * block start delimiter and block end delimiter.
146 *\return Pointer to internal raw data buffer of the block
147 */
148 unsigned char * tape_block::get_raw_data(){
149 return raw_data;
150 }
151
152 /***************************************************************/
153 /*!
154 *\brief Static factory method with file descriptor support.
155 *
156 * This method creates a tape_block by using the private
157 * constructor with file descriptor support.\n
158 * It always returns a valid pointer, errors
159 * or exceptional conditions during creation are marked in the
160 * object's state.\n
161 * The factory method tries to determine the block's type and then
162 * looks for appropriate subclasses. If there's an appropriate
163 * subclass fitting the newly-created object, an
164 * object of the subclass will be created and a pointer to this
165 * object will be returned to the caller.\n
166 * This allows for easy use of the object using it's virtual
167 * interface methods or a cast of the pointer to a sub type pointer
168 * according to the type information, and then using the subtype's
169 * methods not already present in tape_block.\n
170 * Objects of the following subclasses are automagically generated:\n
171 * - eot_block
172 * - discard_block
173 * - data_block
174 * - data_block_0
175 * - data_block_0_0
176 * - data_block_0_1
177 * - data_block_0_2
178 * - data_block_0_3
179 * - data_block_0_4
180 * - data_block_0_10
181 * - data_block_0_14
182 * - data_block_0_24
183 * - data_block_0_30
184 * - data_block_0_50
185 * - data_block_0_54
186 * - data_block_0_60
187 * - data_block_0_64
188 * - data_block_1
189 * - data_block_2
190 * - data_block_3
191 * - data_block_4
192 * - data_block_5
193 * - data_block_6
194 * - data_block_7
195 *
196 *\return Pointer to an object of type tape_block or a subclass.
197 *\param fd A file descriptor where the read is taken from.
198 *\param input_start A pointer to a function
199 * called before reading data from fd.
200 *\param input_stop A pointer to a function
201 * called after reading data from fd.
202 *
203 *\param start_stop_arg A pointer passed to input_start
204 * and input_stop(). Can be anything.
205 */
206 tape_block * tape_block::gen_from_fd(int fd,
207 void(*input_start)(void *),
208 void (*input_stop)(void *),
209 void * start_stop_arg)
210 {
211 tape_block * n_tape_block=0;
212 data_block * n_data_block=0;
213 data_block * n_data_block_x=0;
214 data_block_0 * n_data_block_0=0;
215 data_block_0 * n_data_block_0_x=0;
216 eot_block * n_eot_block=0;
217 discard_block * n_discard_block=0;
218
219 //Use the private constructor which reads in the block from a file descriptor
220 n_tape_block=new tape_block(fd,input_start,input_stop,start_stop_arg);
221
222 // Retype to data_block, eot_block, discard_block - if possible
223 switch(n_tape_block->get_type()){
224 case tape_block::TBT_DATA:
225 n_data_block = new data_block(*n_tape_block);
226 break;
227 case tape_block::TBT_EOT:
228 n_eot_block=new eot_block(*n_tape_block);
229 delete n_tape_block;
230 return n_eot_block;
231 case tape_block::TBT_DISCARD:
232 n_discard_block = new discard_block(*n_tape_block);
233 delete n_tape_block;
234 return n_discard_block;
235 default: // Unknown block, a bad thing!
236 return n_tape_block;
237 }
238 delete n_tape_block;
239
240 // Now only data blocks are left
241
242 switch(n_data_block->get_type()){
243 case 00: n_data_block_0=new data_block_0(*n_data_block); break;
244 case 01: n_data_block_x=new data_block_1(*n_data_block); break;
245 case 02: n_data_block_x=new data_block_2(*n_data_block); break;
246 case 03: n_data_block_x=new data_block_3(*n_data_block); break;
247 case 04: n_data_block_x=new data_block_4(*n_data_block); break;
248 case 05: n_data_block_x=new data_block_5(*n_data_block); break;
249 case 06: n_data_block_x=new data_block_6(*n_data_block); break;
250 case 07: n_data_block_x=new data_block_7(*n_data_block); break;
251 default:
252 return n_data_block;
253 }
254 if (n_data_block_0==0){ // So we must have found another one
255 delete n_data_block;
256 return n_data_block_x;
257 }
258
259 // Here only type 0 left
260 switch(n_data_block_0->get_subtype()){
261 case 000: n_data_block_0_x=new data_block_0_0(*n_data_block_0); break;
262 case 001: n_data_block_0_x=new data_block_0_1(*n_data_block_0); break;
263 case 002: n_data_block_0_x=new data_block_0_2(*n_data_block_0); break;
264 case 003: n_data_block_0_x=new data_block_0_3(*n_data_block_0); break;
265 case 004: n_data_block_0_x=new data_block_0_4(*n_data_block_0); break;
266 case 010: n_data_block_0_x=new data_block_0_10(*n_data_block_0); break;
267 case 014: n_data_block_0_x=new data_block_0_14(*n_data_block_0); break;
268 case 024: n_data_block_0_x=new data_block_0_24(*n_data_block_0); break;
269 case 044: n_data_block_0_x=new data_block_0_44(*n_data_block_0); break;
270 case 030: n_data_block_0_x=new data_block_0_30(*n_data_block_0); break;
271 case 054: n_data_block_0_x=new data_block_0_54(*n_data_block_0); break;
272 case 060: n_data_block_0_x=new data_block_0_60(*n_data_block_0); break;
273 case 064: n_data_block_0_x=new data_block_0_64(*n_data_block_0); break;
274 case 050: n_data_block_0_x=new data_block_0_50(*n_data_block_0); break;
275 default:
276 return n_data_block_0;
277 }
278 delete n_data_block_0;
279 return n_data_block_0_x;
280 }
281
282 /***************************************************************/
283 /*!
284 *\brief Default constructor.
285 */
286 tape_block::tape_block(){}
287
288 /***************************************************************/
289 /*!
290 *\brief get a short type description string.
291 *\return A small string to be used in description methods.
292 *
293 * The string is always 19 characters long.\n
294 * An example is "(99-99) ".
295 */
296 string tape_block::get_typestring(){
297 char buffer[13];
298 sprintf(buffer,"(%o-%o) ",get_type(),get_subtype());
299 buffer[10]=0;
300 return string(buffer);
301 }
302
303 /***************************************************************/
304 /*!
305 *\brief Automatic constructor with file descriptor support
306 *
307 * This constructor is used to initialise the block read in the block's
308 * data via a file descriptor.\n
309 * This is done in the following way:
310 * - input_start() is called.
311 * - Data is read from fd. Stops on end of file or end of block
312 * or IO error. On EOF or IO error input_stop() is NOT called.
313 * - If there was no IO error the block's checksum is calculated
314 * and checked.
315 * - The block's type field is initialised.
316 * - input_stop() is called.
317 *
318 *\param fd A file descriptor where the read is taken from
319 *\param input_stop A pointer to a function called at the end of input
320 *\param input_start A pointer to a function called at the beginning
321 * of input
322 *\param start_stop_arg A pointer passed to input_start and input_stop().
323 */
324 tape_block::tape_block (int fd,
325 void(*input_start)(void *),
326 void (*input_stop)(void *),
327 void * start_stop_arg
328 )
329 {
330 unsigned char buffer;
331 int retval;
332 int eot_needed=EOT_LENGTH;
333 int eob_needed=EOB_LENGTH;
334 int block_complete=0;
335
336 block_type= TBT_DISCARD;
337 init_state= TBS_DEFAULT;
338 data_read = 0;
339 raw_data = 0;
340 raw_size = 0;
341 word_data = 0;
342 word_size = 0;
343
344 if (input_start) input_start (start_stop_arg);
345
346 /* Look for block start in input stream */
347 do {
348 retval=read(fd, &buffer, 1);
349 if (retval == 0){ // End of file
350 block_type=TBT_DISCARD;
351 init_state=TBS_EOF_LEGAL;
352 return;
353 }
354 if (retval == -1){ // Error reading from fd
355 block_type=TBT_DISCARD;
356 init_state=TBS_IOERR;
357 return;
358 }
359 data_read++;
360
361 /* Look for end ot tape sequence */
362 switch(eot_needed){
363 case 3:
364 if (buffer==EOT_SEQ_1) eot_needed--;
365 else eot_needed=EOT_LENGTH;
366 break;
367 case 2:
368 if (buffer==EOT_SEQ_2) eot_needed--;
369 else eot_needed=EOT_LENGTH;
370 break;
371 case 1:
372 if (buffer==EOT_SEQ_3){
373 raw_data=(unsigned char*)malloc(3);
374 raw_size=3;
375 raw_data[0]=EOT_SEQ_1;
376 raw_data[1]=EOT_SEQ_2;
377 raw_data[2]=EOT_SEQ_3;
378 block_type =TBT_EOT;
379 init_state =TBS_OK;
380 return;
381 }
382 else eot_needed=EOT_LENGTH;
383 break;
384 }
385 } while (buffer != (unsigned char) BLOCK_START_DELIMITER);
386
387
388 /* Now input the block data */
389 block_complete = 0;
390 do {
391 retval = read (fd, &buffer, 1);
392
393 if (retval == 0){ // End of file
394 block_type=TBT_DISCARD;
395 init_state=TBS_EOF_ILLEGAL;
396 return;
397 }
398 if (retval == -1){ // Error reading from fd
399 block_type=TBT_DISCARD;
400 init_state=TBS_IOERR;
401 return;
402 }
403 data_read++; // We have consumed a byte
404
405 /* sort in the new byte */
406 raw_size++;
407 raw_data=(unsigned char*)realloc(raw_data,raw_size);
408 raw_data[raw_size-1]=buffer;
409
410 /* Look for end ot block sequence */
411 switch(eob_needed){
412 case 2:
413 if (buffer==BLOCK_END_DELIMITER_1) eob_needed--;
414 else eob_needed=EOB_LENGTH;
415 break;
416 case 1:
417 if (buffer==BLOCK_END_DELIMITER_2){
418 raw_size-=EOB_LENGTH; // Don't want the delimiter(s) in the data!
419 raw_data=(unsigned char*)realloc(raw_data,raw_size);
420 block_complete=1;
421 }
422 else eob_needed=EOB_LENGTH;
423 break;
424 }
425 }while (!block_complete);
426 if (input_stop) input_stop (start_stop_arg);
427
428 /* Now we have the data in. */
429
430 if (init_words()!=0){
431 init_state=TBS_CHECKSUM;
432 return;
433 }
434
435 if (test_checksum()!=0){
436 init_state=TBS_CHECKSUM;
437 return;
438 }
439
440 block_type=TBT_DATA;
441 init_state=TBS_OK;
442 }
443
444
445 /***************************************************************/
446 /*!
447 *\brief Initialize word representation of data.
448 *\retval 0 on success.
449 *\retval 1 on error.
450 */
451 int tape_block::init_words(){
452 word_size=raw_size/3;
453 if (word_size<MINIMUM_DATA_BLOCK_WORDSIZE) return 1; // Block too short!
454 word_data=(unsigned short *)malloc(raw_size*sizeof(unsigned short));
455 for (int pos=0; pos<word_size; pos++)
456 word_data[pos]=combine466(raw_data+3*pos);
457 return 0;
458 }
459
460 /***************************************************************/
461 /*!
462 *\brief Calculate and check checksum.
463 *\retval 0 on success.
464 *\retval 1 on error.
465 */
466 int tape_block::test_checksum(){
467 unsigned short sum=0;
468 for (int pos=0; pos<word_size-1;pos++)
469 sum^=word_data[pos];
470 if (sum==word_data[word_size-1]) return 0;
471 else return 1;
472 }
473