11 #include "tape_block.hh"
13 #include "silent_code.hh"
14 #include "hw_constants.hh"
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"
44 /***************************************************************/
48 tape_block::~tape_block(){
53 /***************************************************************/
55 *\brief Copy constructor.
57 tape_block::tape_block(tape_block
& org
){
61 /***************************************************************/
63 *\brief Assignment operator.
65 void tape_block::operator=(tape_block
&org
){
66 block_type
=org
.block_type
;
67 discarded_bytes
=org
.discarded_bytes
;
69 raw_size
=org
.raw_size
;
71 word_size
=org
.word_size
;
73 raw_data
=(unsigned char *)malloc(raw_size
);
74 memcpy(raw_data
,org
.raw_data
,raw_size
);
77 word_data
=(unsigned short *)malloc(word_size
*sizeof(unsigned short));
78 memcpy(word_data
,org
.word_data
,word_size
*sizeof(unsigned short));
82 /***************************************************************/
84 *\brief Determine the block's type
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
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.
96 int tape_block::get_type(){
100 /***************************************************************/
102 *\brief Determine the block's subtype
104 * Some data block types have a subtype.
105 *\note This is a virtual method and to be used in derived classes.
108 int tape_block::get_subtype(){
112 /***************************************************************/
114 *\brief Get a cleartext description of the block.
115 *\return ldc style descriptive line for the block
117 vector
<string
> tape_block:: get_description(){
118 vector
<string
> result
;
119 result
.insert(result
.end(),
120 "***** "+get_typestring()+"Untyped tape block");
124 /***************************************************************/
126 *\brief Get size of the internal raw data buffer
127 *\return The size of the internal raw data buffer
129 int tape_block::get_raw_size(){
133 /***************************************************************/
135 *\brief Get amount of bytes discarded before beginning
137 *\return Length of unusable tape before block start delimiter.
139 int tape_block::get_discarded_bytes(){
140 return discarded_bytes
;
143 /***************************************************************/
145 *\brief Access internal raw data buffer
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
151 unsigned char * tape_block::get_raw_data(){
155 /***************************************************************/
157 *\brief Static factory method for tape blocks.
159 * This method creates a tape_block by using the private
160 * constructor with file descriptor support.\n
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
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.
203 *\param start_stop_arg A pointer passed to input_start
204 * and input_stop(). Can be anything.
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
)
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;
219 //Use the private constructor which reads in the block from a file descriptor
221 n_tape_block
=new tape_block(fd
,input_start
,input_stop
,start_stop_arg
);
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
);
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
);
235 case tape_block::TBT_EOT
:
236 n_eot_block
=new eot_block(*n_tape_block
);
239 default: // Unknown block, a bad thing!
244 // Now only data blocks are left
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;
258 if (n_data_block_0
==0){ // So we must have found another one
260 return n_data_block_x
;
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;
280 return n_data_block_0
;
282 delete n_data_block_0
;
283 return n_data_block_0_x
;
286 /***************************************************************/
288 *\brief Default constructor.
290 tape_block::tape_block(){}
292 /***************************************************************/
294 *\brief get a short type description string.
295 *\return A small string to be used in description methods.
297 * The string is always 19 characters long.\n
298 * An example is "(99-99) ".
300 string
tape_block::get_typestring(){
302 sprintf(buffer
,"(%o-%o) ",get_type(),get_subtype());
304 return string(buffer
);
307 /***************************************************************/
309 *\brief Automatic constructor with file descriptor support
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
319 * - The block's type field is initialised.
320 * - input_stop() is called.
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
326 *\param start_stop_arg A pointer passed to input_start and input_stop().
328 tape_block::tape_block (int fd
,
329 void(*input_start
)(void *),
330 void (*input_stop
)(void *),
331 void * start_stop_arg
334 unsigned char buffer
;
336 int eot_needed
=EOT_LENGTH
;
337 int eob_needed
=EOB_LENGTH
;
338 int block_complete
=0;
340 block_type
= TBT_BROKEN
;
348 // Get initial portion of memory
349 raw_data
=(unsigned char*)malloc(poolsize
);
351 if (input_start
) input_start (start_stop_arg
);
353 /* Look for block start in input stream */
355 retval
=read(fd
, &buffer
, 1);
356 if (retval
== 0){ // End of file
358 throw eof_legal_exception(discarded_bytes
);
361 if (retval
== -1){ // Error reading from fd
363 throw io_error_exception();
368 /* Look for end ot tape sequence */
371 if (buffer
==EOT_SEQ_1
) eot_needed
--;
372 else eot_needed
=EOT_LENGTH
;
375 if (buffer
==EOT_SEQ_2
) eot_needed
--;
376 else eot_needed
=EOT_LENGTH
;
379 if (buffer
==EOT_SEQ_3
){
380 raw_data
=(unsigned char*)realloc(raw_data
,3);
383 raw_data
[0]=EOT_SEQ_1
;
384 raw_data
[1]=EOT_SEQ_2
;
385 raw_data
[2]=EOT_SEQ_3
;
389 else eot_needed
=EOT_LENGTH
;
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!
396 /* Now input the block data */
399 retval
= read (fd
, &buffer
, 1);
401 if (retval
== 0){ // End of file
402 broken_block
* b_block
=new broken_block(*this);
404 throw eof_illegal_exception(b_block
);
406 if (retval
== -1){ // Error reading from fd
408 throw io_error_exception();
411 /* sort in the new byte */
413 // Need more memory??
414 if (raw_size
==poolsize
){
416 raw_data
=(unsigned char*)realloc(raw_data
,poolsize
);
419 raw_data
[raw_size
-2]=buffer
;
421 /* Look for end ot block sequence */
424 if (buffer
==BLOCK_END_DELIMITER_1
) eob_needed
--;
425 else eob_needed
=EOB_LENGTH
;
428 if (buffer
==BLOCK_END_DELIMITER_2
){
431 else eob_needed
=EOB_LENGTH
;
434 }while (!block_complete
);
436 if (input_stop
) input_stop (start_stop_arg
);
439 /* Now we have the data in. */
441 if (init_words()!=0){
442 broken_block
* b_block
=new broken_block(*this);
445 throw checksum_error_exception(b_block
);
448 if (test_checksum()!=0){
449 broken_block
* b_block
=new broken_block(*this);
452 throw checksum_error_exception(b_block
);
458 /***************************************************************/
460 *\brief Initialize word representation of data.
461 *\retval 0 on success.
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
);
473 /***************************************************************/
475 *\brief Calculate and check checksum.
476 *\retval 0 on success.
479 int tape_block::test_checksum(){
480 unsigned short sum
=0;
481 for (int pos
=0; pos
<word_size
-1;pos
++)
483 if (sum
==word_data
[word_size
-1]) return 0;
487 /***************************************************************/
489 *\brief Standard constructor of exception base class.
491 tape_block::exception::exception(){
494 /***************************************************************/
496 *\brief Standard desctructor.
498 tape_block::exception::~exception(){
501 /***************************************************************/
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.
508 tape_block
* tape_block::exception::get_block(){
509 return m_broken_block
;
512 /***************************************************************/
516 tape_block::checksum_error_exception::
517 checksum_error_exception (tape_block
* broken_block
){
518 this->m_broken_block
=broken_block
;
521 /***************************************************************/
525 tape_block::eof_illegal_exception::
526 eof_illegal_exception (tape_block
* broken_block
){
527 this->m_broken_block
=broken_block
;
530 /***************************************************************/
533 *\param bytes_consumed Amount of bytes read while looking
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
;
542 /***************************************************************/
544 *\brief Get amount of consumed data before EOF came along.
545 *\return Amound of bytes read from fd while looking for
548 int tape_block::eof_legal_exception::get_consumed(){
549 return bytes_consumed
;
552 /***************************************************************/
556 tape_block::io_error_exception::
557 io_error_exception(){
558 this->m_broken_block
=NULL
;