*** empty log message ***
[h316.git] / pc-tools / ldc2 / src / tape_block.cpp
CommitLineData
97b26985 1#include <stdlib.h>
2#include <unistd.h>
3#include <string.h>
09cb0f4f 4#include <stdio.h>
6c06db96 5
97b26985 6#include "tape_block.hh"
7#include "data_block.hh"
0ec6e042 8#include "data_block_0.hh"
09cb0f4f 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"
fd9632c0 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"
97b26985 30
09cb0f4f 31#include "eot_block.hh"
32#include "discard_block.hh"
97b26985 33#include "silent_code.hh"
34#include "hw_constants.hh"
35
6c06db96 36using namespace std;
37
38/***************************************************************/
39/*!
40 *\brief Destructor.
41 */
42tape_block::~tape_block(){
43 free(raw_data);
44 free(word_data);
45}
46
47/***************************************************************/
48/*!
49 *\brief Copy constructor.
50 */
51tape_block::tape_block(tape_block & org){
52 operator=(org);
53}
54
55/***************************************************************/
56/*!
57 *\brief Assignment operator.
58 */
59void tape_block::operator=(tape_block &org){
60 block_type=org.block_type;
61 init_state=org.init_state;
fed2c751 62 discarded_bytes=org.discarded_bytes;
6c06db96 63 raw_data=0;
64 raw_size=org.raw_size;
65 word_data=0;
66 word_size=org.word_size;
67 if (raw_size){
68 raw_data=(unsigned char *)malloc(raw_size);
69 memcpy(raw_data,org.raw_data,raw_size);
70 }
71 if (word_size){
72 word_data=(unsigned short *)malloc(word_size*sizeof(unsigned short));
73 memcpy(word_data,org.word_data,word_size*sizeof(unsigned short));
74 }
75}
76
77/***************************************************************/
78/*!
79 *\brief Query the block's state.
80 *
81 * If the state is not TBS_OK, the block must be discarded.
82 *\return The block's initialisation state
83 */
84tape_block::tb_state_t tape_block::get_state(){
85 return init_state;
86}
0ec6e042 87
6c06db96 88/***************************************************************/
89/*!
90 *\brief Determine the block's type
91 *
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
96 *
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.
102 */
103int tape_block::get_type(){
104 return block_type;
105}
106
107/***************************************************************/
108/*!
109 *\brief Determine the block's subtype
110 *
111 * Some data block types have a subtype.
112 *\note This is a virtual method and to be used in derived classes.
113 *\return Always 0
114 */
115int tape_block::get_subtype(){
116 return 0;
117}
118
119/***************************************************************/
120/*!
121 *\brief Get a cleartext description of the block.
122 *\return ldc style descriptive line for the block
123 */
124vector<string> tape_block:: get_description(){
6c06db96 125 vector<string> result;
09cb0f4f 126 result.insert(result.end(),
127 "***** "+get_typestring()+"Untyped tape block");
6c06db96 128 return result;
129}
130
131/***************************************************************/
132/*!
133 *\brief Get size of the internal raw data buffer
134 *\return The size of the internal raw data buffer
135 */
136int tape_block::get_raw_size(){
137 return raw_size;
138}
139
fed2c751 140/***************************************************************/
141/*!
142 *\brief Get amount of bytes discarded before beginning
143 * of block sensed.
144 *\return Length of unusable tape before block start delimiter.
145 */
146int tape_block::get_discarded_bytes(){
147 return discarded_bytes;
148}
149
6c06db96 150/***************************************************************/
151/*!
152 *\brief Access internal raw data buffer
153 *
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
157 */
158unsigned char * tape_block::get_raw_data(){
159 return raw_data;
160}
161
162/***************************************************************/
163/*!
164 *\brief Static factory method with file descriptor support.
165 *
166 * This method creates a tape_block by using the private
09cb0f4f 167 * constructor with file descriptor support.\n
6c06db96 168 * It always returns a valid pointer, errors
169 * or exceptional conditions during creation are marked in the
170 * object's state.\n
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
09cb0f4f 179 * methods not already present in tape_block.\n
180 * Objects of the following subclasses are automagically generated:\n
6c06db96 181 * - eot_block
09cb0f4f 182 * - discard_block
6c06db96 183 * - data_block
09cb0f4f 184 * - data_block_0
185 * - data_block_0_0
186 * - data_block_0_1
187 * - data_block_0_2
188 * - data_block_0_3
189 * - data_block_0_4
190 * - data_block_0_10
191 * - data_block_0_14
192 * - data_block_0_24
193 * - data_block_0_30
194 * - data_block_0_50
195 * - data_block_0_54
196 * - data_block_0_60
fd9632c0 197 * - data_block_0_64
09cb0f4f 198 * - data_block_1
199 * - data_block_2
200 * - data_block_3
201 * - data_block_4
202 * - data_block_5
203 * - data_block_6
204 * - data_block_7
6c06db96 205 *
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.
212 *
213 *\param start_stop_arg A pointer passed to input_start
214 * and input_stop(). Can be anything.
215 */
0ec6e042 216tape_block * tape_block::gen_from_fd(int fd,
217 void(*input_start)(void *),
218 void (*input_stop)(void *),
219 void * start_stop_arg)
97b26985 220{
fd9632c0 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;
228
50c86ded 229 //Use the private constructor which reads in the block from a file descriptor
fd9632c0 230 n_tape_block=new tape_block(fd,input_start,input_stop,start_stop_arg);
231
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);
0ec6e042 236 break;
09cb0f4f 237 case tape_block::TBT_EOT:
fd9632c0 238 n_eot_block=new eot_block(*n_tape_block);
239 delete n_tape_block;
240 return n_eot_block;
09cb0f4f 241 case tape_block::TBT_DISCARD:
fd9632c0 242 n_discard_block = new discard_block(*n_tape_block);
243 delete n_tape_block;
244 return n_discard_block;
50c86ded 245 default: // Unknown block, a bad thing!
246 return n_tape_block;
0ec6e042 247 }
fd9632c0 248 delete n_tape_block;
249
250 // Now only data blocks are left
251
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;
0ec6e042 261 default:
fd9632c0 262 return n_data_block;
263 }
264 if (n_data_block_0==0){ // So we must have found another one
265 delete n_data_block;
266 return n_data_block_x;
0ec6e042 267 }
0ec6e042 268
fd9632c0 269 // Here only type 0 left
fd9632c0 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;
0ec6e042 285 default:
fd9632c0 286 return n_data_block_0;
0ec6e042 287 }
fd9632c0 288 delete n_data_block_0;
289 return n_data_block_0_x;
97b26985 290}
291
6c06db96 292/***************************************************************/
0ec6e042 293/*!
294 *\brief Default constructor.
295 */
296tape_block::tape_block(){}
297
09cb0f4f 298/***************************************************************/
299/*!
300 *\brief get a short type description string.
301 *\return A small string to be used in description methods.
302 *
303 * The string is always 19 characters long.\n
304 * An example is "(99-99) ".
305 */
306string tape_block::get_typestring(){
307 char buffer[13];
308 sprintf(buffer,"(%o-%o) ",get_type(),get_subtype());
309 buffer[10]=0;
310 return string(buffer);
311}
0ec6e042 312
6c06db96 313/***************************************************************/
0ec6e042 314/*!
315 *\brief Automatic constructor with file descriptor support
316 *
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
324 * and checked.
325 * - The block's type field is initialised.
326 * - input_stop() is called.
327 *
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
331 * of input
332 *\param start_stop_arg A pointer passed to input_start and input_stop().
333 */
97b26985 334tape_block::tape_block (int fd,
335 void(*input_start)(void *),
336 void (*input_stop)(void *),
337 void * start_stop_arg
338 )
339{
340 unsigned char buffer;
341 int retval;
342 int eot_needed=EOT_LENGTH;
343 int eob_needed=EOB_LENGTH;
344 int block_complete=0;
345
346 block_type= TBT_DISCARD;
347 init_state= TBS_DEFAULT;
fed2c751 348 discarded_bytes=0;
97b26985 349 raw_data = 0;
350 raw_size = 0;
351 word_data = 0;
352 word_size = 0;
fed2c751 353 poolsize = 1024;
354
355 // Get initial portion of memory
356 raw_data=(unsigned char*)malloc(poolsize);
357
97b26985 358 if (input_start) input_start (start_stop_arg);
359
360 /* Look for block start in input stream */
361 do {
362 retval=read(fd, &buffer, 1);
363 if (retval == 0){ // End of file
364 block_type=TBT_DISCARD;
365 init_state=TBS_EOF_LEGAL;
366 return;
367 }
368 if (retval == -1){ // Error reading from fd
369 block_type=TBT_DISCARD;
370 init_state=TBS_IOERR;
371 return;
372 }
fed2c751 373 discarded_bytes++;
97b26985 374
375 /* Look for end ot tape sequence */
376 switch(eot_needed){
377 case 3:
378 if (buffer==EOT_SEQ_1) eot_needed--;
379 else eot_needed=EOT_LENGTH;
380 break;
381 case 2:
382 if (buffer==EOT_SEQ_2) eot_needed--;
383 else eot_needed=EOT_LENGTH;
384 break;
385 case 1:
386 if (buffer==EOT_SEQ_3){
387 raw_data=(unsigned char*)malloc(3);
388 raw_size=3;
fed2c751 389 discarded_bytes-=3;
97b26985 390 raw_data[0]=EOT_SEQ_1;
391 raw_data[1]=EOT_SEQ_2;
392 raw_data[2]=EOT_SEQ_3;
393 block_type =TBT_EOT;
394 init_state =TBS_OK;
395 return;
396 }
397 else eot_needed=EOT_LENGTH;
398 break;
399 }
400 } while (buffer != (unsigned char) BLOCK_START_DELIMITER);
fed2c751 401 discarded_bytes--; // Dont want to declare the start delimiter discarded!
402 raw_size=1; // But we want to account it here!
97b26985 403
404 /* Now input the block data */
405 block_complete = 0;
406 do {
407 retval = read (fd, &buffer, 1);
408
409 if (retval == 0){ // End of file
410 block_type=TBT_DISCARD;
411 init_state=TBS_EOF_ILLEGAL;
412 return;
413 }
414 if (retval == -1){ // Error reading from fd
415 block_type=TBT_DISCARD;
416 init_state=TBS_IOERR;
417 return;
418 }
97b26985 419
420 /* sort in the new byte */
421 raw_size++;
fed2c751 422 // Need more memory??
423 if (raw_size==poolsize){
424 poolsize+=1024;
425 raw_data=(unsigned char*)realloc(raw_data,poolsize);
426 }
427
428 raw_data[raw_size-2]=buffer;
97b26985 429
430 /* Look for end ot block sequence */
431 switch(eob_needed){
432 case 2:
433 if (buffer==BLOCK_END_DELIMITER_1) eob_needed--;
434 else eob_needed=EOB_LENGTH;
435 break;
436 case 1:
437 if (buffer==BLOCK_END_DELIMITER_2){
438 raw_size-=EOB_LENGTH; // Don't want the delimiter(s) in the data!
97b26985 439 block_complete=1;
440 }
441 else eob_needed=EOB_LENGTH;
442 break;
443 }
444 }while (!block_complete);
445 if (input_stop) input_stop (start_stop_arg);
446
447 /* Now we have the data in. */
448
449 if (init_words()!=0){
450 init_state=TBS_CHECKSUM;
451 return;
452 }
453
454 if (test_checksum()!=0){
455 init_state=TBS_CHECKSUM;
456 return;
457 }
fed2c751 458 raw_size+=EOB_LENGTH; // Now we want it...
459
97b26985 460 block_type=TBT_DATA;
461 init_state=TBS_OK;
462}
463
97b26985 464
6c06db96 465/***************************************************************/
0ec6e042 466/*!
6c06db96 467 *\brief Initialize word representation of data.
468 *\retval 0 on success.
469 *\retval 1 on error.
0ec6e042 470 */
97b26985 471int 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);
477 return 0;
478}
479
6c06db96 480/***************************************************************/
0ec6e042 481/*!
6c06db96 482 *\brief Calculate and check checksum.
483 *\retval 0 on success.
484 *\retval 1 on error.
0ec6e042 485 */
97b26985 486int tape_block::test_checksum(){
487 unsigned short sum=0;
488 for (int pos=0; pos<word_size-1;pos++)
0ec6e042 489 sum^=word_data[pos];
97b26985 490 if (sum==word_data[word_size-1]) return 0;
491 else return 1;
492}
6c06db96 493