1 /******************************************************************************
5 * $Date: 2007/12/23 15:25:11 $
8 * $Log: tape_block.cpp,v $
9 * Revision 2.2 2007/12/23 15:25:11 hachti
10 * *** empty log message ***
12 * Revision 2.1 2007-03-26 03:20:31 hachti
13 * *** empty log message ***
15 * Revision 2.0 2007-03-26 01:00:40 hachti
16 * *** empty log message ***
19 ******************************************************************************/
29 #include "tape_block.hh"
31 #include "silent_code.hh"
32 #include "hw_constants.hh"
34 #include "eot_block.hh"
35 #include "data_block.hh"
36 #include "broken_block.hh"
37 #include "data_block_0.hh"
38 #include "data_block_0_0.hh"
39 #include "data_block_0_1.hh"
40 #include "data_block_0_2.hh"
41 #include "data_block_0_3.hh"
42 #include "data_block_0_4.hh"
43 #include "data_block_0_10.hh"
44 #include "data_block_0_14.hh"
45 #include "data_block_0_24.hh"
46 #include "data_block_0_44.hh"
47 #include "data_block_0_30.hh"
48 #include "data_block_0_54.hh"
49 #include "data_block_0_60.hh"
50 #include "data_block_0_50.hh"
51 #include "data_block_0_64.hh"
52 #include "data_block_1.hh"
53 #include "data_block_2.hh"
54 #include "data_block_3.hh"
55 #include "data_block_4.hh"
56 #include "data_block_5.hh"
57 #include "data_block_6.hh"
58 #include "data_block_7.hh"
62 /***************************************************************/
66 tape_block::~tape_block(){
71 /***************************************************************/
73 *\brief Copy constructor.
75 tape_block::tape_block(tape_block
& org
){
79 /***************************************************************/
81 *\brief Assignment operator.
83 void tape_block::operator=(tape_block
&org
){
84 block_type
=org
.block_type
;
85 discarded_bytes
=org
.discarded_bytes
;
87 raw_size
=org
.raw_size
;
89 word_size
=org
.word_size
;
91 raw_data
=(unsigned char *)malloc(raw_size
);
92 memcpy(raw_data
,org
.raw_data
,raw_size
);
95 word_data
=(unsigned short *)malloc(word_size
*sizeof(unsigned short));
96 memcpy(word_data
,org
.word_data
,word_size
*sizeof(unsigned short));
100 /***************************************************************/
102 *\brief Determine the block's type
104 * This routine returns the block's type.\\
105 *\retval TBT_DATA if it's a data block
106 *\retval TBT_EOT if it's an end of tape mark
108 *\note This function is virtual. That means that if the tape block in
109 * question is of the subtype data_block which overwrites this method,
110 * it will return the block type contained in the upper 4 bits of the
111 * first data word! Try to avoid testing for TBT_DATA. \n
112 * Blocks generated by gen_from_fd should never have TBT_DATA.
114 int tape_block::get_type(){
118 /***************************************************************/
120 *\brief Determine the block's subtype
122 * Some data block types have a subtype.
123 *\note This is a virtual method and to be used in derived classes.
126 int tape_block::get_subtype(){
130 /***************************************************************/
132 *\brief Get a cleartext description of the block.
133 *\return ldc style descriptive line for the block
135 vector
<string
> tape_block:: get_description(){
136 vector
<string
> result
;
137 result
.insert(result
.end(),
138 "***** "+get_typestring()+"Untyped tape block");
142 /***************************************************************/
144 *\brief Get size of the internal raw data buffer
145 *\return The size of the internal raw data buffer
147 int tape_block::get_raw_size(){
151 /***************************************************************/
153 *\brief Get amount of bytes discarded before beginning
155 *\return Length of unusable tape before block start delimiter.
157 int tape_block::get_discarded_bytes(){
158 return discarded_bytes
;
161 /***************************************************************/
163 *\brief Access internal raw data buffer
165 * The raw data buffer contains all block data except the
166 * block start and end delimiters.
167 *\return Pointer to internal raw data buffer of the block
169 unsigned char * tape_block::get_raw_data(){
173 /***************************************************************/
175 *\brief Dump contents of the block to a file descriptor.
177 *\param fd A writable file descriptor.
178 *\return Always zero.
179 *\throw io_error_exception A write error occured.
181 int tape_block::dump_to_fd(int fd
){
182 int to_write
=raw_size
;
183 unsigned char * dump_ptr
=raw_data
;
186 written
=write(fd
,dump_ptr
,to_write
);
187 if (written
< 0) throw io_error_exception();
194 /***************************************************************/
196 *\brief Determine if the block marks the end of an object
197 *\retval true The block marks the end of an object.
198 *\retval false The block does not mark the end of an object.
199 *\note This is only a virtual method returning always false.
200 * Classes which can be the legal last block of an object
201 * will overwrite this method so that it returns true.
203 bool tape_block::is_endblock(){
207 /***************************************************************/
209 *\brief Get exported symbols.
210 *\return A vector containing any symbols exported in this block.
211 *\note This is only a virtual method returning always an empty
212 * vector. Classes describing appropriate data blocks
213 * will override this method.
215 vector
<string
> tape_block::get_exported_symbols(){
216 vector
<string
> result
;
220 /***************************************************************/
222 *\brief Get called symbols.
223 *\return A vector containing any symbols called in this block.
224 *\note This is only a virtual method returning always an empty
225 * vector. Classes describing appropriate data blocks
226 * will override this method.
228 vector
<string
> tape_block::get_called_symbols(){
229 vector
<string
> result
;
233 /***************************************************************/
235 *\brief Dump block contents
236 *\return A vector containing Information about the block's
239 vector
<string
> tape_block::dump_contents(){
240 vector
<string
> result
;
241 result
.insert(result
.end(),"No known contents.");
245 /***************************************************************/
247 *\brief Determine if the block has a known type.
248 *\return true if type and subtype are known.
249 *\return false if the block type is not one of the valid end
250 * nodes of the type tree.
252 bool tape_block::has_known_type(){
253 return m_has_known_type
;
256 /***************************************************************/
258 *\brief Static factory method for tape blocks.
260 * This method creates a tape_block by using the private
261 * constructor with file descriptor support.\n
263 * The factory method tries to determine the block's type and then
264 * looks for appropriate subclasses. If there's an appropriate
265 * subclass fitting the newly-created object, an
266 * object of the subclass will be created and a pointer to this
267 * object will be returned to the caller.\n
268 * This allows for easy use of the object using it's virtual
269 * interface methods or a cast of the pointer to a sub type pointer
270 * according to the type information, and then using the subtype's
271 * methods not already present in tape_block.\n
272 * Objects of the following subclasses are automagically generated:\n
297 *\return Pointer to an instance of tape_block or a subclass.
298 *\param fd A file descriptor where data can be read from.
299 *\param input_start A pointer to a function
300 * called before reading data from fd.
301 *\param input_stop A pointer to a function
302 * called after reading data from fd.
304 *\param start_stop_arg A pointer passed to input_start
305 * and input_stop(). Can be anything.
307 tape_block
* tape_block::gen_from_fd(int fd
,
308 void(*input_start
)(void *),
309 void (*input_stop
)(void *),
310 void * start_stop_arg
)
312 tape_block
* n_tape_block
=0;
313 data_block
* n_data_block
=0;
314 data_block
* n_data_block_x
=0;
315 data_block_0
* n_data_block_0
=0;
316 data_block_0
* n_data_block_0_x
=0;
317 eot_block
* n_eot_block
=0;
318 broken_block
* n_broken_block
=0;
320 //Use the private constructor which reads in the block from a file descriptor
322 n_tape_block
=new tape_block(fd
,input_start
,input_stop
,start_stop_arg
);
325 catch(checksum_error_exception e
){
326 n_broken_block
=new broken_block(*(e
.get_block()));
327 delete e
.get_block();
328 throw checksum_error_exception(n_broken_block
);
331 // Retype to data_block, eot_block - if possible
332 switch(n_tape_block
->get_type()){
333 case tape_block::TBT_DATA
:
334 n_data_block
= new data_block(*n_tape_block
);
336 case tape_block::TBT_EOT
:
337 n_eot_block
=new eot_block(*n_tape_block
);
339 n_eot_block
->m_has_known_type
=true;
341 default: // Unknown block, a bad thing!
346 // Now only data blocks are left
348 switch(n_data_block
->get_type()){
349 case 00: n_data_block_0
=new data_block_0(*n_data_block
); break;
350 case 01: n_data_block_x
=new data_block_1(*n_data_block
); break;
351 case 02: n_data_block_x
=new data_block_2(*n_data_block
); break;
352 case 03: n_data_block_x
=new data_block_3(*n_data_block
); break;
353 case 04: n_data_block_x
=new data_block_4(*n_data_block
); break;
354 case 05: n_data_block_x
=new data_block_5(*n_data_block
); break;
355 case 06: n_data_block_x
=new data_block_6(*n_data_block
); break;
356 case 07: n_data_block_x
=new data_block_7(*n_data_block
); break;
360 if (n_data_block_0
==0){ // So we must have found another one
362 n_data_block_x
->m_has_known_type
=true;
363 return n_data_block_x
;
366 // Here only type 0 left
367 switch(n_data_block_0
->get_subtype()){
368 case 000: n_data_block_0_x
=new data_block_0_0(*n_data_block_0
); break;
369 case 001: n_data_block_0_x
=new data_block_0_1(*n_data_block_0
); break;
370 case 002: n_data_block_0_x
=new data_block_0_2(*n_data_block_0
); break;
371 case 003: n_data_block_0_x
=new data_block_0_3(*n_data_block_0
); break;
372 case 004: n_data_block_0_x
=new data_block_0_4(*n_data_block_0
); break;
373 case 010: n_data_block_0_x
=new data_block_0_10(*n_data_block_0
); break;
374 case 014: n_data_block_0_x
=new data_block_0_14(*n_data_block_0
); break;
375 case 024: n_data_block_0_x
=new data_block_0_24(*n_data_block_0
); break;
376 case 044: n_data_block_0_x
=new data_block_0_44(*n_data_block_0
); break;
377 case 030: n_data_block_0_x
=new data_block_0_30(*n_data_block_0
); break;
378 case 054: n_data_block_0_x
=new data_block_0_54(*n_data_block_0
); break;
379 case 060: n_data_block_0_x
=new data_block_0_60(*n_data_block_0
); break;
380 case 064: n_data_block_0_x
=new data_block_0_64(*n_data_block_0
); break;
381 case 050: n_data_block_0_x
=new data_block_0_50(*n_data_block_0
); break;
383 return n_data_block_0
;
385 delete n_data_block_0
;
386 n_data_block_0_x
->m_has_known_type
=true;
387 return n_data_block_0_x
;
390 /***************************************************************/
392 *\brief Default constructor.
394 tape_block::tape_block(){}
396 /***************************************************************/
398 *\brief get a short type description string.
399 *\return A small string to be used in description methods.
401 * The string is always 19 characters long.\n
402 * An example is "(99-99) ".
404 string
tape_block::get_typestring(){
406 sprintf(buffer
,"(%o-%o) ",get_type(),get_subtype());
408 return string(buffer
);
411 /***************************************************************/
413 *\brief Automatic constructor with file descriptor support
415 * This constructor is used to initialise the block read in the
416 * block's data via a file descriptor.\n
417 * This is done in the following way:
418 * - input_start() is called.
419 * - Data is read from fd. Stops on end of file or end of block
420 * or IO error. On EOF or IO error input_stop() is NOT called.
421 * - If there was no IO error the block's checksum is calculated
423 * - The block's type field is initialised.
424 * - input_stop() is called.
426 *\param fd A file descriptor where the read is taken from
427 *\param input_stop A pointer to a function called at the end of input
428 *\param input_start A pointer to a function called at the beginning
430 *\param start_stop_arg A pointer passed to input_start and input_stop().
432 tape_block::tape_block (int fd
,
433 void(*input_start
)(void *),
434 void (*input_stop
)(void *),
435 void * start_stop_arg
438 unsigned char buffer
;
440 int eot_needed
=EOT_LENGTH
;
441 int eob_needed
=EOB_LENGTH
;
442 int block_complete
=0;
444 block_type
= TBT_BROKEN
;
452 // Get initial portion of memory
453 raw_data
=(unsigned char*)malloc(poolsize
);
455 if (input_start
) input_start (start_stop_arg
);
457 /* Look for block start in input stream */
459 retval
=read(fd
, &buffer
, 1);
460 if (retval
== 0){ // End of file
462 throw eof_legal_exception(discarded_bytes
);
465 if (retval
== -1){ // Error reading from fd
467 throw io_error_exception();
472 /* Look for end ot tape sequence */
475 if (buffer
==EOT_SEQ_1
) eot_needed
--;
476 else eot_needed
=EOT_LENGTH
;
479 if (buffer
==EOT_SEQ_2
) eot_needed
--;
480 else eot_needed
=EOT_LENGTH
;
483 if (buffer
==EOT_SEQ_3
){
484 raw_data
=(unsigned char*)realloc(raw_data
,3);
487 raw_data
[0]=EOT_SEQ_1
;
488 raw_data
[1]=EOT_SEQ_2
;
489 raw_data
[2]=EOT_SEQ_3
;
493 else eot_needed
=EOT_LENGTH
;
496 } while (buffer
!= (unsigned char) BLOCK_START_DELIMITER
);
497 discarded_bytes
--; // Don't want to declare the start delimiter discarded!
498 raw_size
=1; // But we want to account it here!
500 /* Now input the block data */
503 raw_data
[0]=buffer
; // Put the start delimiter in!
506 retval
= read (fd
, &buffer
, 1);
508 if (retval
== 0){ // End of file
509 broken_block
* b_block
=new broken_block(*this);
511 throw eof_illegal_exception(b_block
);
513 if (retval
== -1){ // Error reading from fd
515 throw io_error_exception();
518 /* sort in the new byte */
520 // Need more memory??
521 if (raw_size
>poolsize
){
523 raw_data
=(unsigned char*)realloc(raw_data
,poolsize
);
526 raw_data
[raw_size
-1]=buffer
;
528 /* Look for end ot block sequence */
531 if (buffer
==BLOCK_END_DELIMITER_1
) eob_needed
--;
532 else eob_needed
=EOB_LENGTH
;
535 if (buffer
==BLOCK_END_DELIMITER_2
){
538 else eob_needed
=EOB_LENGTH
;
541 }while (!block_complete
);
543 if (input_stop
) input_stop (start_stop_arg
);
546 /* Now we have the data in. */
548 if (init_words()!=0){
549 broken_block
* b_block
=new broken_block(*this);
552 throw checksum_error_exception(b_block
);
555 if (test_checksum()!=0){
556 broken_block
* b_block
=new broken_block(*this);
559 throw checksum_error_exception(b_block
);
565 /***************************************************************/
567 *\brief Initialize word representation of data.
568 *\retval 0 on success.
571 int tape_block::init_words(){
572 word_size
=(raw_size
-EOB_LENGTH
-1)/3;
573 if (word_size
<MINIMUM_DATA_BLOCK_WORDSIZE
) return 1; // Block too short!
574 word_data
=(unsigned short *)malloc(word_size
*sizeof(unsigned short));
575 for (int pos
=0; pos
<word_size
; pos
++)
576 word_data
[pos
]=combine466(raw_data
+1+3*pos
);
580 /***************************************************************/
582 *\brief Calculate and check checksum.
583 *\retval 0 on success.
586 int tape_block::test_checksum(){
587 unsigned short sum
=0;
588 for (int pos
=0; pos
<word_size
-1;pos
++)
590 if (sum
==word_data
[word_size
-1]) return 0;
594 /***************************************************************/
596 *\brief Standard constructor of exception base class.
598 tape_block::exception::exception(){
601 /***************************************************************/
603 *\brief Standard desctructor.
605 tape_block::exception::~exception(){
608 /***************************************************************/
610 *\brief Get pointer to erroneous tape_block
611 *\return A pointer to a tape_block instance.
612 *\note The user has to take care to free the instance contained
613 * in objects of classes supporting this method.
615 tape_block
* tape_block::exception::get_block(){
616 return m_broken_block
;
619 /***************************************************************/
623 tape_block::checksum_error_exception::
624 checksum_error_exception (tape_block
* broken_block
){
625 this->m_broken_block
=broken_block
;
628 /***************************************************************/
632 tape_block::eof_illegal_exception::
633 eof_illegal_exception (tape_block
* broken_block
){
634 this->m_broken_block
=broken_block
;
637 /***************************************************************/
640 *\param bytes_consumed Amount of bytes read while looking
643 tape_block::eof_legal_exception::
644 eof_legal_exception(int bytes_consumed
){
645 this->m_broken_block
=NULL
;
646 this->bytes_consumed
=bytes_consumed
;
649 /***************************************************************/
651 *\brief Get amount of consumed data before EOF came along.
652 *\return Amount of bytes read from fd while looking for
655 int tape_block::eof_legal_exception::get_consumed(){
656 return bytes_consumed
;
659 /***************************************************************/
663 tape_block::io_error_exception::
664 io_error_exception(){
665 this->m_broken_block
=NULL
;