3de7bfb5af1155ff906e1e7ee6c05bcccba6269c
[h316.git] / pc-tools / ldc2 / src / tape_block.cpp
1
2
3 #include <string>
4 #include <vector>
5
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <stdio.h>
10
11 #include "tape_block.hh"
12
13 #include "silent_code.hh"
14 #include "hw_constants.hh"
15
16 #include "eot_block.hh"
17 #include "data_block.hh"
18 #include "broken_block.hh"
19 #include "data_block_0.hh"
20 #include "data_block_0_0.hh"
21 #include "data_block_0_1.hh"
22 #include "data_block_0_2.hh"
23 #include "data_block_0_3.hh"
24 #include "data_block_0_4.hh"
25 #include "data_block_0_10.hh"
26 #include "data_block_0_14.hh"
27 #include "data_block_0_24.hh"
28 #include "data_block_0_44.hh"
29 #include "data_block_0_30.hh"
30 #include "data_block_0_54.hh"
31 #include "data_block_0_60.hh"
32 #include "data_block_0_50.hh"
33 #include "data_block_0_64.hh"
34 #include "data_block_1.hh"
35 #include "data_block_2.hh"
36 #include "data_block_3.hh"
37 #include "data_block_4.hh"
38 #include "data_block_5.hh"
39 #include "data_block_6.hh"
40 #include "data_block_7.hh"
41
42 using namespace std;
43
44 /***************************************************************/
45 /*!
46 *\brief Destructor.
47 */
48 tape_block::~tape_block(){
49 free(raw_data);
50 free(word_data);
51 }
52
53 /***************************************************************/
54 /*!
55 *\brief Copy constructor.
56 */
57 tape_block::tape_block(tape_block & org){
58 operator=(org);
59 }
60
61 /***************************************************************/
62 /*!
63 *\brief Assignment operator.
64 */
65 void tape_block::operator=(tape_block &org){
66 block_type=org.block_type;
67 discarded_bytes=org.discarded_bytes;
68 raw_data=0;
69 raw_size=org.raw_size;
70 word_data=0;
71 word_size=org.word_size;
72 if (raw_size){
73 raw_data=(unsigned char *)malloc(raw_size);
74 memcpy(raw_data,org.raw_data,raw_size);
75 }
76 if (word_size){
77 word_data=(unsigned short *)malloc(word_size*sizeof(unsigned short));
78 memcpy(word_data,org.word_data,word_size*sizeof(unsigned short));
79 }
80 }
81
82 /***************************************************************/
83 /*!
84 *\brief Determine the block's type
85 *
86 * This routine returns the block's type.\\
87 *\retval TBT_DATA if it's a data block
88 *\retval TBT_EOT if it's an end of tape mark
89 *
90 *\note This function is virtual. That means that if the tape block in
91 * question is of the subtype data_block which overwrites this method,
92 * it will return the block type contained in the upper 4 bits of the
93 * first data word! Try to avoid testing for TBT_DATA. \n
94 * Blocks generated by gen_from_fd should never have TBT_DATA.
95 */
96 int tape_block::get_type(){
97 return block_type;
98 }
99
100 /***************************************************************/
101 /*!
102 *\brief Determine the block's subtype
103 *
104 * Some data block types have a subtype.
105 *\note This is a virtual method and to be used in derived classes.
106 *\return Always 0
107 */
108 int tape_block::get_subtype(){
109 return 0;
110 }
111
112 /***************************************************************/
113 /*!
114 *\brief Get a cleartext description of the block.
115 *\return ldc style descriptive line for the block
116 */
117 vector<string> tape_block:: get_description(){
118 vector<string> result;
119 result.insert(result.end(),
120 "***** "+get_typestring()+"Untyped tape block");
121 return result;
122 }
123
124 /***************************************************************/
125 /*!
126 *\brief Get size of the internal raw data buffer
127 *\return The size of the internal raw data buffer
128 */
129 int tape_block::get_raw_size(){
130 return raw_size;
131 }
132
133 /***************************************************************/
134 /*!
135 *\brief Get amount of bytes discarded before beginning
136 * of block sensed.
137 *\return Length of unusable tape before block start delimiter.
138 */
139 int tape_block::get_discarded_bytes(){
140 return discarded_bytes;
141 }
142
143 /***************************************************************/
144 /*!
145 *\brief Access internal raw data buffer
146 *
147 * The raw data buffer contains all block data except the \ \
148 * block start delimiter and block end delimiter.
149 *\return Pointer to internal raw data buffer of the block
150 */
151 unsigned char * tape_block::get_raw_data(){
152 return raw_data;
153 }
154
155 /***************************************************************/
156 /*!
157 *\brief Static factory method for tape blocks.
158 *
159 * This method creates a tape_block by using the private
160 * constructor with file descriptor support.\n
161 *
162 * The factory method tries to determine the block's type and then
163 * looks for appropriate subclasses. If there's an appropriate
164 * subclass fitting the newly-created object, an
165 * object of the subclass will be created and a pointer to this
166 * object will be returned to the caller.\n
167 * This allows for easy use of the object using it's virtual
168 * interface methods or a cast of the pointer to a sub type pointer
169 * according to the type information, and then using the subtype's
170 * methods not already present in tape_block.\n
171 * Objects of the following subclasses are automagically generated:\n
172 * - eot_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 instance of tape_block or a subclass.
197 *\param fd A file descriptor where data can be read 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 broken_block * n_broken_block=0;
218
219 //Use the private constructor which reads in the block from a file descriptor
220 try{
221 n_tape_block=new tape_block(fd,input_start,input_stop,start_stop_arg);
222 }
223
224 catch(checksum_error_exception e){
225 n_broken_block=new broken_block(*(e.get_block()));
226 delete e.get_block();
227 throw checksum_error_exception(n_broken_block);
228 }
229
230 // Retype to data_block, eot_block - if possible
231 switch(n_tape_block->get_type()){
232 case tape_block::TBT_DATA:
233 n_data_block = new data_block(*n_tape_block);
234 break;
235 case tape_block::TBT_EOT:
236 n_eot_block=new eot_block(*n_tape_block);
237 delete n_tape_block;
238 return n_eot_block;
239 default: // Unknown block, a bad thing!
240 return n_tape_block;
241 }
242 delete n_tape_block;
243
244 // Now only data blocks are left
245
246 switch(n_data_block->get_type()){
247 case 00: n_data_block_0=new data_block_0(*n_data_block); break;
248 case 01: n_data_block_x=new data_block_1(*n_data_block); break;
249 case 02: n_data_block_x=new data_block_2(*n_data_block); break;
250 case 03: n_data_block_x=new data_block_3(*n_data_block); break;
251 case 04: n_data_block_x=new data_block_4(*n_data_block); break;
252 case 05: n_data_block_x=new data_block_5(*n_data_block); break;
253 case 06: n_data_block_x=new data_block_6(*n_data_block); break;
254 case 07: n_data_block_x=new data_block_7(*n_data_block); break;
255 default:
256 return n_data_block;
257 }
258 if (n_data_block_0==0){ // So we must have found another one
259 delete n_data_block;
260 return n_data_block_x;
261 }
262
263 // Here only type 0 left
264 switch(n_data_block_0->get_subtype()){
265 case 000: n_data_block_0_x=new data_block_0_0(*n_data_block_0); break;
266 case 001: n_data_block_0_x=new data_block_0_1(*n_data_block_0); break;
267 case 002: n_data_block_0_x=new data_block_0_2(*n_data_block_0); break;
268 case 003: n_data_block_0_x=new data_block_0_3(*n_data_block_0); break;
269 case 004: n_data_block_0_x=new data_block_0_4(*n_data_block_0); break;
270 case 010: n_data_block_0_x=new data_block_0_10(*n_data_block_0); break;
271 case 014: n_data_block_0_x=new data_block_0_14(*n_data_block_0); break;
272 case 024: n_data_block_0_x=new data_block_0_24(*n_data_block_0); break;
273 case 044: n_data_block_0_x=new data_block_0_44(*n_data_block_0); break;
274 case 030: n_data_block_0_x=new data_block_0_30(*n_data_block_0); break;
275 case 054: n_data_block_0_x=new data_block_0_54(*n_data_block_0); break;
276 case 060: n_data_block_0_x=new data_block_0_60(*n_data_block_0); break;
277 case 064: n_data_block_0_x=new data_block_0_64(*n_data_block_0); break;
278 case 050: n_data_block_0_x=new data_block_0_50(*n_data_block_0); break;
279 default:
280 return n_data_block_0;
281 }
282 delete n_data_block_0;
283 return n_data_block_0_x;
284 }
285
286 /***************************************************************/
287 /*!
288 *\brief Default constructor.
289 */
290 tape_block::tape_block(){}
291
292 /***************************************************************/
293 /*!
294 *\brief get a short type description string.
295 *\return A small string to be used in description methods.
296 *
297 * The string is always 19 characters long.\n
298 * An example is "(99-99) ".
299 */
300 string tape_block::get_typestring(){
301 char buffer[13];
302 sprintf(buffer,"(%o-%o) ",get_type(),get_subtype());
303 buffer[10]=0;
304 return string(buffer);
305 }
306
307 /***************************************************************/
308 /*!
309 *\brief Automatic constructor with file descriptor support
310 *
311 * This constructor is used to initialise the block read in the
312 * block's data via a file descriptor.\n
313 * This is done in the following way:
314 * - input_start() is called.
315 * - Data is read from fd. Stops on end of file or end of block
316 * or IO error. On EOF or IO error input_stop() is NOT called.
317 * - If there was no IO error the block's checksum is calculated
318 * and checked.
319 * - The block's type field is initialised.
320 * - input_stop() is called.
321 *
322 *\param fd A file descriptor where the read is taken from
323 *\param input_stop A pointer to a function called at the end of input
324 *\param input_start A pointer to a function called at the beginning
325 * of input
326 *\param start_stop_arg A pointer passed to input_start and input_stop().
327 */
328 tape_block::tape_block (int fd,
329 void(*input_start)(void *),
330 void (*input_stop)(void *),
331 void * start_stop_arg
332 )
333 {
334 unsigned char buffer;
335 int retval;
336 int eot_needed=EOT_LENGTH;
337 int eob_needed=EOB_LENGTH;
338 int block_complete=0;
339
340 block_type= TBT_BROKEN;
341 discarded_bytes=0;
342 raw_data = 0;
343 raw_size = 0;
344 word_data = 0;
345 word_size = 0;
346 poolsize = 1024;
347
348 // Get initial portion of memory
349 raw_data=(unsigned char*)malloc(poolsize);
350
351 if (input_start) input_start (start_stop_arg);
352
353 /* Look for block start in input stream */
354 do {
355 retval=read(fd, &buffer, 1);
356 if (retval == 0){ // End of file
357 free(raw_data);
358 throw eof_legal_exception(discarded_bytes);
359 return;
360 }
361 if (retval == -1){ // Error reading from fd
362 free(raw_data);
363 throw io_error_exception();
364 return;
365 }
366 discarded_bytes++;
367
368 /* Look for end ot tape sequence */
369 switch(eot_needed){
370 case 3:
371 if (buffer==EOT_SEQ_1) eot_needed--;
372 else eot_needed=EOT_LENGTH;
373 break;
374 case 2:
375 if (buffer==EOT_SEQ_2) eot_needed--;
376 else eot_needed=EOT_LENGTH;
377 break;
378 case 1:
379 if (buffer==EOT_SEQ_3){
380 raw_data=(unsigned char*)realloc(raw_data,3);
381 raw_size=3;
382 discarded_bytes-=3;
383 raw_data[0]=EOT_SEQ_1;
384 raw_data[1]=EOT_SEQ_2;
385 raw_data[2]=EOT_SEQ_3;
386 block_type =TBT_EOT;
387 return;
388 }
389 else eot_needed=EOT_LENGTH;
390 break;
391 }
392 } while (buffer != (unsigned char) BLOCK_START_DELIMITER);
393 discarded_bytes--; // Dont want to declare the start delimiter discarded!
394 raw_size=1; // But we want to account it here!
395
396 /* Now input the block data */
397 block_complete = 0;
398 do {
399 retval = read (fd, &buffer, 1);
400
401 if (retval == 0){ // End of file
402 broken_block * b_block=new broken_block(*this);
403 free(raw_data);
404 throw eof_illegal_exception(b_block);
405 }
406 if (retval == -1){ // Error reading from fd
407 free(raw_data);
408 throw io_error_exception();
409 }
410
411 /* sort in the new byte */
412 raw_size++;
413 // Need more memory??
414 if (raw_size==poolsize){
415 poolsize+=1024;
416 raw_data=(unsigned char*)realloc(raw_data,poolsize);
417 }
418
419 raw_data[raw_size-2]=buffer;
420
421 /* Look for end ot block sequence */
422 switch(eob_needed){
423 case 2:
424 if (buffer==BLOCK_END_DELIMITER_1) eob_needed--;
425 else eob_needed=EOB_LENGTH;
426 break;
427 case 1:
428 if (buffer==BLOCK_END_DELIMITER_2){
429 block_complete=1;
430 }
431 else eob_needed=EOB_LENGTH;
432 break;
433 }
434 }while (!block_complete);
435
436 if (input_stop) input_stop (start_stop_arg);
437
438
439 /* Now we have the data in. */
440
441 if (init_words()!=0){
442 broken_block * b_block=new broken_block(*this);
443 free(raw_data);
444 free(word_data);
445 throw checksum_error_exception(b_block);
446 }
447
448 if (test_checksum()!=0){
449 broken_block * b_block=new broken_block(*this);
450 free(raw_data);
451 free(word_data);
452 throw checksum_error_exception(b_block);
453 }
454 block_type=TBT_DATA;
455 }
456
457
458 /***************************************************************/
459 /*!
460 *\brief Initialize word representation of data.
461 *\retval 0 on success.
462 *\retval 1 on error.
463 */
464 int tape_block::init_words(){
465 word_size=(raw_size-EOB_LENGTH)/3;
466 if (word_size<MINIMUM_DATA_BLOCK_WORDSIZE) return 1; // Block too short!
467 word_data=(unsigned short *)malloc(word_size*sizeof(unsigned short));
468 for (int pos=0; pos<word_size; pos++)
469 word_data[pos]=combine466(raw_data+3*pos);
470 return 0;
471 }
472
473 /***************************************************************/
474 /*!
475 *\brief Calculate and check checksum.
476 *\retval 0 on success.
477 *\retval 1 on error.
478 */
479 int tape_block::test_checksum(){
480 unsigned short sum=0;
481 for (int pos=0; pos<word_size-1;pos++)
482 sum^=word_data[pos];
483 if (sum==word_data[word_size-1]) return 0;
484 else return 1;
485 }
486
487 /***************************************************************/
488 /*!
489 *\brief Standard constructor of exception base class.
490 */
491 tape_block::exception::exception(){
492 }
493
494 /***************************************************************/
495 /*!
496 *\brief Standard desctructor.
497 */
498 tape_block::exception::~exception(){
499 }
500
501 /***************************************************************/
502 /*!
503 *\brief Get pointer to erroneous tape_block
504 *\return A pointer to a tape_block instance.
505 *\note The user has to take care to free the instance contained
506 * in objects of classes supporting this method.
507 */
508 tape_block * tape_block::exception::get_block(){
509 return m_broken_block;
510 }
511
512 /***************************************************************/
513 /*!
514 *\brief Constructor
515 */
516 tape_block::checksum_error_exception::
517 checksum_error_exception (tape_block * broken_block){
518 this->m_broken_block=broken_block;
519 }
520
521 /***************************************************************/
522 /*!
523 *\brief Constructor
524 */
525 tape_block::eof_illegal_exception::
526 eof_illegal_exception (tape_block * broken_block){
527 this->m_broken_block=broken_block;
528 }
529
530 /***************************************************************/
531 /*!
532 *\brief Constructor
533 *\param bytes_consumed Amount of bytes read while looking
534 * for a block.
535 */
536 tape_block::eof_legal_exception::
537 eof_legal_exception(int bytes_consumed){
538 this->m_broken_block=NULL;
539 this->bytes_consumed=bytes_consumed;
540 }
541
542 /***************************************************************/
543 /*!
544 *\brief Get amount of consumed data before EOF came along.
545 *\return Amound of bytes read from fd while looking for
546 * new block or EOF.
547 */
548 int tape_block::eof_legal_exception::get_consumed(){
549 return bytes_consumed;
550 }
551
552 /***************************************************************/
553 /*!
554 *\brief Constructor
555 */
556 tape_block::io_error_exception::
557 io_error_exception(){
558 this->m_broken_block=NULL;
559 }
560
561
562
563
564
565