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"
31 #include "eot_block.hh"
32 #include "discard_block.hh"
33 #include "silent_code.hh"
34 #include "hw_constants.hh"
38 /***************************************************************/
42 tape_block::~tape_block(){
47 /***************************************************************/
49 *\brief Copy constructor.
51 tape_block::tape_block(tape_block
& org
){
55 /***************************************************************/
57 *\brief Assignment operator.
59 void tape_block::operator=(tape_block
&org
){
60 block_type
=org
.block_type
;
61 init_state
=org
.init_state
;
62 discarded_bytes
=org
.discarded_bytes
;
64 raw_size
=org
.raw_size
;
66 word_size
=org
.word_size
;
68 raw_data
=(unsigned char *)malloc(raw_size
);
69 memcpy(raw_data
,org
.raw_data
,raw_size
);
72 word_data
=(unsigned short *)malloc(word_size
*sizeof(unsigned short));
73 memcpy(word_data
,org
.word_data
,word_size
*sizeof(unsigned short));
77 /***************************************************************/
79 *\brief Query the block's state.
81 * If the state is not TBS_OK, the block must be discarded.
82 *\return The block's initialisation state
84 tape_block::tb_state_t
tape_block::get_state(){
88 /***************************************************************/
90 *\brief Determine the block's type
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
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.
103 int tape_block::get_type(){
107 /***************************************************************/
109 *\brief Determine the block's subtype
111 * Some data block types have a subtype.
112 *\note This is a virtual method and to be used in derived classes.
115 int tape_block::get_subtype(){
119 /***************************************************************/
121 *\brief Get a cleartext description of the block.
122 *\return ldc style descriptive line for the block
124 vector
<string
> tape_block:: get_description(){
125 vector
<string
> result
;
126 result
.insert(result
.end(),
127 "***** "+get_typestring()+"Untyped tape block");
131 /***************************************************************/
133 *\brief Get size of the internal raw data buffer
134 *\return The size of the internal raw data buffer
136 int tape_block::get_raw_size(){
140 /***************************************************************/
142 *\brief Get amount of bytes discarded before beginning
144 *\return Length of unusable tape before block start delimiter.
146 int tape_block::get_discarded_bytes(){
147 return discarded_bytes
;
150 /***************************************************************/
152 *\brief Access internal raw data buffer
154 * The raw data buffer contains all block data except the \ \
155 * block start delimiter and block end delimiter.
156 *\return Pointer to internal raw data buffer of the block
158 unsigned char * tape_block::get_raw_data(){
162 /***************************************************************/
164 *\brief Static factory method with file descriptor support.
166 * This method creates a tape_block by using the private
167 * constructor with file descriptor support.\n
168 * It always returns a valid pointer, errors
169 * or exceptional conditions during creation are marked in the
171 * The factory method tries to determine the block's type and then
172 * looks for appropriate subclasses. If there's an appropriate
173 * subclass fitting the newly-created object, an
174 * object of the subclass will be created and a pointer to this
175 * object will be returned to the caller.\n
176 * This allows for easy use of the object using it's virtual
177 * interface methods or a cast of the pointer to a sub type pointer
178 * according to the type information, and then using the subtype's
179 * methods not already present in tape_block.\n
180 * Objects of the following subclasses are automagically generated:\n
206 *\return Pointer to an object of type tape_block or a subclass.
207 *\param fd A file descriptor where the read is taken from.
208 *\param input_start A pointer to a function
209 * called before reading data from fd.
210 *\param input_stop A pointer to a function
211 * called after reading data from fd.
213 *\param start_stop_arg A pointer passed to input_start
214 * and input_stop(). Can be anything.
216 tape_block
* tape_block::gen_from_fd(int fd
,
217 void(*input_start
)(void *),
218 void (*input_stop
)(void *),
219 void * start_stop_arg
)
221 tape_block
* n_tape_block
=0;
222 data_block
* n_data_block
=0;
223 data_block
* n_data_block_x
=0;
224 data_block_0
* n_data_block_0
=0;
225 data_block_0
* n_data_block_0_x
=0;
226 eot_block
* n_eot_block
=0;
227 discard_block
* n_discard_block
=0;
229 //Use the private constructor which reads in the block from a file descriptor
230 n_tape_block
=new tape_block(fd
,input_start
,input_stop
,start_stop_arg
);
232 // Retype to data_block, eot_block, discard_block - if possible
233 switch(n_tape_block
->get_type()){
234 case tape_block::TBT_DATA
:
235 n_data_block
= new data_block(*n_tape_block
);
237 case tape_block::TBT_EOT
:
238 n_eot_block
=new eot_block(*n_tape_block
);
241 case tape_block::TBT_DISCARD
:
242 n_discard_block
= new discard_block(*n_tape_block
);
244 return n_discard_block
;
245 default: // Unknown block, a bad thing!
250 // Now only data blocks are left
252 switch(n_data_block
->get_type()){
253 case 00: n_data_block_0
=new data_block_0(*n_data_block
); break;
254 case 01: n_data_block_x
=new data_block_1(*n_data_block
); break;
255 case 02: n_data_block_x
=new data_block_2(*n_data_block
); break;
256 case 03: n_data_block_x
=new data_block_3(*n_data_block
); break;
257 case 04: n_data_block_x
=new data_block_4(*n_data_block
); break;
258 case 05: n_data_block_x
=new data_block_5(*n_data_block
); break;
259 case 06: n_data_block_x
=new data_block_6(*n_data_block
); break;
260 case 07: n_data_block_x
=new data_block_7(*n_data_block
); break;
264 if (n_data_block_0
==0){ // So we must have found another one
266 return n_data_block_x
;
269 // Here only type 0 left
270 switch(n_data_block_0
->get_subtype()){
271 case 000: n_data_block_0_x
=new data_block_0_0(*n_data_block_0
); break;
272 case 001: n_data_block_0_x
=new data_block_0_1(*n_data_block_0
); break;
273 case 002: n_data_block_0_x
=new data_block_0_2(*n_data_block_0
); break;
274 case 003: n_data_block_0_x
=new data_block_0_3(*n_data_block_0
); break;
275 case 004: n_data_block_0_x
=new data_block_0_4(*n_data_block_0
); break;
276 case 010: n_data_block_0_x
=new data_block_0_10(*n_data_block_0
); break;
277 case 014: n_data_block_0_x
=new data_block_0_14(*n_data_block_0
); break;
278 case 024: n_data_block_0_x
=new data_block_0_24(*n_data_block_0
); break;
279 case 044: n_data_block_0_x
=new data_block_0_44(*n_data_block_0
); break;
280 case 030: n_data_block_0_x
=new data_block_0_30(*n_data_block_0
); break;
281 case 054: n_data_block_0_x
=new data_block_0_54(*n_data_block_0
); break;
282 case 060: n_data_block_0_x
=new data_block_0_60(*n_data_block_0
); break;
283 case 064: n_data_block_0_x
=new data_block_0_64(*n_data_block_0
); break;
284 case 050: n_data_block_0_x
=new data_block_0_50(*n_data_block_0
); break;
286 return n_data_block_0
;
288 delete n_data_block_0
;
289 return n_data_block_0_x
;
292 /***************************************************************/
294 *\brief Default constructor.
296 tape_block::tape_block(){}
298 /***************************************************************/
300 *\brief get a short type description string.
301 *\return A small string to be used in description methods.
303 * The string is always 19 characters long.\n
304 * An example is "(99-99) ".
306 string
tape_block::get_typestring(){
308 sprintf(buffer
,"(%o-%o) ",get_type(),get_subtype());
310 return string(buffer
);
313 /***************************************************************/
315 *\brief Automatic constructor with file descriptor support
317 * This constructor is used to initialise the block read in the block's
318 * data via a file descriptor.\n
319 * This is done in the following way:
320 * - input_start() is called.
321 * - Data is read from fd. Stops on end of file or end of block
322 * or IO error. On EOF or IO error input_stop() is NOT called.
323 * - If there was no IO error the block's checksum is calculated
325 * - The block's type field is initialised.
326 * - input_stop() is called.
328 *\param fd A file descriptor where the read is taken from
329 *\param input_stop A pointer to a function called at the end of input
330 *\param input_start A pointer to a function called at the beginning
332 *\param start_stop_arg A pointer passed to input_start and input_stop().
334 tape_block::tape_block (int fd
,
335 void(*input_start
)(void *),
336 void (*input_stop
)(void *),
337 void * start_stop_arg
340 unsigned char buffer
;
342 int eot_needed
=EOT_LENGTH
;
343 int eob_needed
=EOB_LENGTH
;
344 int block_complete
=0;
346 block_type
= TBT_DISCARD
;
347 init_state
= TBS_DEFAULT
;
355 // Get initial portion of memory
356 raw_data
=(unsigned char*)malloc(poolsize
);
358 if (input_start
) input_start (start_stop_arg
);
360 /* Look for block start in input stream */
362 retval
=read(fd
, &buffer
, 1);
363 if (retval
== 0){ // End of file
364 block_type
=TBT_DISCARD
;
365 init_state
=TBS_EOF_LEGAL
;
368 if (retval
== -1){ // Error reading from fd
369 block_type
=TBT_DISCARD
;
370 init_state
=TBS_IOERR
;
375 /* Look for end ot tape sequence */
378 if (buffer
==EOT_SEQ_1
) eot_needed
--;
379 else eot_needed
=EOT_LENGTH
;
382 if (buffer
==EOT_SEQ_2
) eot_needed
--;
383 else eot_needed
=EOT_LENGTH
;
386 if (buffer
==EOT_SEQ_3
){
387 raw_data
=(unsigned char*)malloc(3);
390 raw_data
[0]=EOT_SEQ_1
;
391 raw_data
[1]=EOT_SEQ_2
;
392 raw_data
[2]=EOT_SEQ_3
;
397 else eot_needed
=EOT_LENGTH
;
400 } while (buffer
!= (unsigned char) BLOCK_START_DELIMITER
);
401 discarded_bytes
--; // Dont want to declare the start delimiter discarded!
402 raw_size
=1; // But we want to account it here!
404 /* Now input the block data */
407 retval
= read (fd
, &buffer
, 1);
409 if (retval
== 0){ // End of file
410 block_type
=TBT_DISCARD
;
411 init_state
=TBS_EOF_ILLEGAL
;
414 if (retval
== -1){ // Error reading from fd
415 block_type
=TBT_DISCARD
;
416 init_state
=TBS_IOERR
;
420 /* sort in the new byte */
422 // Need more memory??
423 if (raw_size
==poolsize
){
425 raw_data
=(unsigned char*)realloc(raw_data
,poolsize
);
428 raw_data
[raw_size
-2]=buffer
;
430 /* Look for end ot block sequence */
433 if (buffer
==BLOCK_END_DELIMITER_1
) eob_needed
--;
434 else eob_needed
=EOB_LENGTH
;
437 if (buffer
==BLOCK_END_DELIMITER_2
){
438 raw_size
-=EOB_LENGTH
; // Don't want the delimiter(s) in the data!
441 else eob_needed
=EOB_LENGTH
;
444 }while (!block_complete
);
445 if (input_stop
) input_stop (start_stop_arg
);
447 /* Now we have the data in. */
449 if (init_words()!=0){
450 init_state
=TBS_CHECKSUM
;
454 if (test_checksum()!=0){
455 init_state
=TBS_CHECKSUM
;
458 raw_size
+=EOB_LENGTH
; // Now we want it...
465 /***************************************************************/
467 *\brief Initialize word representation of data.
468 *\retval 0 on success.
471 int tape_block::init_words(){
472 word_size
=raw_size
/3;
473 if (word_size
<MINIMUM_DATA_BLOCK_WORDSIZE
) return 1; // Block too short!
474 word_data
=(unsigned short *)malloc(raw_size
*sizeof(unsigned short));
475 for (int pos
=0; pos
<word_size
; pos
++)
476 word_data
[pos
]=combine466(raw_data
+3*pos
);
480 /***************************************************************/
482 *\brief Calculate and check checksum.
483 *\retval 0 on success.
486 int tape_block::test_checksum(){
487 unsigned short sum
=0;
488 for (int pos
=0; pos
<word_size
-1;pos
++)
490 if (sum
==word_data
[word_size
-1]) return 0;