*** empty log message ***
[h316.git] / pc-tools / ldc2 / src / tape_block.cpp
CommitLineData
7880ae2d 1
2
3#include <string>
4#include <vector>
5
97b26985 6#include <stdlib.h>
7#include <unistd.h>
8#include <string.h>
09cb0f4f 9#include <stdio.h>
6c06db96 10
97b26985 11#include "tape_block.hh"
7880ae2d 12
13#include "silent_code.hh"
14#include "hw_constants.hh"
15
16#include "eot_block.hh"
97b26985 17#include "data_block.hh"
7880ae2d 18#include "broken_block.hh"
0ec6e042 19#include "data_block_0.hh"
09cb0f4f 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"
fd9632c0 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"
97b26985 41
6c06db96 42using namespace std;
43
44/***************************************************************/
45/*!
46 *\brief Destructor.
47 */
48tape_block::~tape_block(){
49 free(raw_data);
50 free(word_data);
51}
52
53/***************************************************************/
54/*!
55 *\brief Copy constructor.
56 */
57tape_block::tape_block(tape_block & org){
58 operator=(org);
59}
60
61/***************************************************************/
62/*!
63 *\brief Assignment operator.
64 */
65void tape_block::operator=(tape_block &org){
66 block_type=org.block_type;
fed2c751 67 discarded_bytes=org.discarded_bytes;
6c06db96 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
6c06db96 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
6c06db96 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 */
96int 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 */
108int 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 */
117vector<string> tape_block:: get_description(){
6c06db96 118 vector<string> result;
09cb0f4f 119 result.insert(result.end(),
120 "***** "+get_typestring()+"Untyped tape block");
6c06db96 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 */
129int tape_block::get_raw_size(){
130 return raw_size;
131}
132
fed2c751 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 */
139int tape_block::get_discarded_bytes(){
140 return discarded_bytes;
141}
142
6c06db96 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 */
151unsigned char * tape_block::get_raw_data(){
152 return raw_data;
153}
154
155/***************************************************************/
156/*!
7880ae2d 157 *\brief Static factory method for tape blocks.
6c06db96 158 *
159 * This method creates a tape_block by using the private
09cb0f4f 160 * constructor with file descriptor support.\n
7880ae2d 161 *
6c06db96 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
09cb0f4f 170 * methods not already present in tape_block.\n
171 * Objects of the following subclasses are automagically generated:\n
6c06db96 172 * - eot_block
173 * - data_block
09cb0f4f 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
fd9632c0 187 * - data_block_0_64
09cb0f4f 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
6c06db96 195 *
7880ae2d 196 *\return Pointer to an instance of tape_block or a subclass.
197 *\param fd A file descriptor where data can be read from.
6c06db96 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 */
0ec6e042 206tape_block * tape_block::gen_from_fd(int fd,
207 void(*input_start)(void *),
208 void (*input_stop)(void *),
209 void * start_stop_arg)
97b26985 210{
fd9632c0 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;
7880ae2d 217 broken_block * n_broken_block=0;
218
50c86ded 219 //Use the private constructor which reads in the block from a file descriptor
7880ae2d 220 try{
fd9632c0 221 n_tape_block=new tape_block(fd,input_start,input_stop,start_stop_arg);
7880ae2d 222 }
fd9632c0 223
7880ae2d 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
fd9632c0 231 switch(n_tape_block->get_type()){
232 case tape_block::TBT_DATA:
233 n_data_block = new data_block(*n_tape_block);
0ec6e042 234 break;
09cb0f4f 235 case tape_block::TBT_EOT:
fd9632c0 236 n_eot_block=new eot_block(*n_tape_block);
237 delete n_tape_block;
238 return n_eot_block;
50c86ded 239 default: // Unknown block, a bad thing!
240 return n_tape_block;
0ec6e042 241 }
fd9632c0 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;
0ec6e042 255 default:
fd9632c0 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;
0ec6e042 261 }
0ec6e042 262
fd9632c0 263 // Here only type 0 left
fd9632c0 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;
0ec6e042 279 default:
fd9632c0 280 return n_data_block_0;
0ec6e042 281 }
fd9632c0 282 delete n_data_block_0;
283 return n_data_block_0_x;
97b26985 284}
285
6c06db96 286/***************************************************************/
0ec6e042 287/*!
288 *\brief Default constructor.
289 */
290tape_block::tape_block(){}
291
09cb0f4f 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 */
300string 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}
0ec6e042 306
6c06db96 307/***************************************************************/
0ec6e042 308/*!
309 *\brief Automatic constructor with file descriptor support
310 *
7880ae2d 311 * This constructor is used to initialise the block read in the
312 * block's data via a file descriptor.\n
0ec6e042 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 */
97b26985 328tape_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
7880ae2d 340 block_type= TBT_BROKEN;
fed2c751 341 discarded_bytes=0;
97b26985 342 raw_data = 0;
343 raw_size = 0;
344 word_data = 0;
345 word_size = 0;
fed2c751 346 poolsize = 1024;
347
348 // Get initial portion of memory
349 raw_data=(unsigned char*)malloc(poolsize);
350
97b26985 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
7880ae2d 357 free(raw_data);
358 throw eof_legal_exception(discarded_bytes);
97b26985 359 return;
360 }
361 if (retval == -1){ // Error reading from fd
7880ae2d 362 free(raw_data);
363 throw io_error_exception();
97b26985 364 return;
365 }
fed2c751 366 discarded_bytes++;
97b26985 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){
7880ae2d 380 raw_data=(unsigned char*)realloc(raw_data,3);
97b26985 381 raw_size=3;
fed2c751 382 discarded_bytes-=3;
97b26985 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;
97b26985 387 return;
388 }
389 else eot_needed=EOT_LENGTH;
390 break;
391 }
392 } while (buffer != (unsigned char) BLOCK_START_DELIMITER);
fed2c751 393 discarded_bytes--; // Dont want to declare the start delimiter discarded!
394 raw_size=1; // But we want to account it here!
97b26985 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
7880ae2d 402 broken_block * b_block=new broken_block(*this);
403 free(raw_data);
404 throw eof_illegal_exception(b_block);
97b26985 405 }
406 if (retval == -1){ // Error reading from fd
7880ae2d 407 free(raw_data);
408 throw io_error_exception();
97b26985 409 }
97b26985 410
411 /* sort in the new byte */
412 raw_size++;
fed2c751 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;
97b26985 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){
97b26985 429 block_complete=1;
430 }
431 else eob_needed=EOB_LENGTH;
432 break;
433 }
434 }while (!block_complete);
7880ae2d 435
97b26985 436 if (input_stop) input_stop (start_stop_arg);
437
7880ae2d 438
97b26985 439 /* Now we have the data in. */
440
441 if (init_words()!=0){
7880ae2d 442 broken_block * b_block=new broken_block(*this);
443 free(raw_data);
444 free(word_data);
445 throw checksum_error_exception(b_block);
97b26985 446 }
7880ae2d 447
97b26985 448 if (test_checksum()!=0){
7880ae2d 449 broken_block * b_block=new broken_block(*this);
450 free(raw_data);
451 free(word_data);
452 throw checksum_error_exception(b_block);
97b26985 453 }
97b26985 454 block_type=TBT_DATA;
97b26985 455}
456
97b26985 457
6c06db96 458/***************************************************************/
0ec6e042 459/*!
6c06db96 460 *\brief Initialize word representation of data.
461 *\retval 0 on success.
462 *\retval 1 on error.
0ec6e042 463 */
97b26985 464int tape_block::init_words(){
7880ae2d 465 word_size=(raw_size-EOB_LENGTH)/3;
97b26985 466 if (word_size<MINIMUM_DATA_BLOCK_WORDSIZE) return 1; // Block too short!
7880ae2d 467 word_data=(unsigned short *)malloc(word_size*sizeof(unsigned short));
97b26985 468 for (int pos=0; pos<word_size; pos++)
469 word_data[pos]=combine466(raw_data+3*pos);
470 return 0;
471}
472
6c06db96 473/***************************************************************/
0ec6e042 474/*!
6c06db96 475 *\brief Calculate and check checksum.
476 *\retval 0 on success.
477 *\retval 1 on error.
0ec6e042 478 */
97b26985 479int tape_block::test_checksum(){
480 unsigned short sum=0;
481 for (int pos=0; pos<word_size-1;pos++)
0ec6e042 482 sum^=word_data[pos];
97b26985 483 if (sum==word_data[word_size-1]) return 0;
484 else return 1;
485}
6c06db96 486
7880ae2d 487/***************************************************************/
488/*!
489 *\brief Standard constructor of exception base class.
490 */
491tape_block::exception::exception(){
492}
493
494/***************************************************************/
495/*!
496 *\brief Standard desctructor.
497 */
498tape_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 */
508tape_block * tape_block::exception::get_block(){
509 return m_broken_block;
510}
511
512/***************************************************************/
513/*!
514 *\brief Constructor
515 */
516tape_block::checksum_error_exception::
517checksum_error_exception (tape_block * broken_block){
518 this->m_broken_block=broken_block;
519}
520
521/***************************************************************/
522/*!
523 *\brief Constructor
524 */
525tape_block::eof_illegal_exception::
526eof_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 */
536tape_block::eof_legal_exception::
537eof_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 */
548int tape_block::eof_legal_exception::get_consumed(){
549 return bytes_consumed;
550}
551
552/***************************************************************/
553/*!
554 *\brief Constructor
555 */
556tape_block::io_error_exception::
557io_error_exception(){
558 this->m_broken_block=NULL;
559}
560
561
562
563
564
565