*** empty log message ***
[h316.git] / pc-tools / ldc2 / src / tape_block.cpp
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <string.h>
4
5 #include <string>
6 #include <vector>
7
8 #include "tape_block.hh"
9 #include "data_block.hh"
10 #include "data_block_0.hh"
11
12 #include "silent_code.hh"
13 #include "hw_constants.hh"
14
15 using namespace std;
16
17 /***************************************************************/
18 /*!
19 *\brief Destructor.
20 */
21 tape_block::~tape_block(){
22 free(raw_data);
23 free(word_data);
24 }
25
26 /***************************************************************/
27 /*!
28 *\brief Copy constructor.
29 */
30 tape_block::tape_block(tape_block & org){
31 operator=(org);
32 }
33
34 /***************************************************************/
35 /*!
36 *\brief Assignment operator.
37 */
38 void tape_block::operator=(tape_block &org){
39 block_type=org.block_type;
40 init_state=org.init_state;
41 data_read=org.data_read;
42 raw_data=0;
43 raw_size=org.raw_size;
44 word_data=0;
45 word_size=org.word_size;
46 if (raw_size){
47 raw_data=(unsigned char *)malloc(raw_size);
48 memcpy(raw_data,org.raw_data,raw_size);
49 }
50 if (word_size){
51 word_data=(unsigned short *)malloc(word_size*sizeof(unsigned short));
52 memcpy(word_data,org.word_data,word_size*sizeof(unsigned short));
53 }
54 }
55
56 /***************************************************************/
57 /*!
58 *\brief Query the block's state.
59 *
60 * If the state is not TBS_OK, the block must be discarded.
61 *\return The block's initialisation state
62 */
63 tape_block::tb_state_t tape_block::get_state(){
64 return init_state;
65 }
66
67 /***************************************************************/
68 /*!
69 *\brief Determine the block's type
70 *
71 * This routine returns the block's type.\\
72 *\retval TBT_DATA if it's a data block
73 *\retval TBT_EOT if it's an end of tape mark
74 *\retval TBR_DISCARD if the block is unusable
75 *
76 *\note This function is virtual. That means that if the tape block in
77 * question is of the subtype data_block which overwrites this method,
78 * it will return the block type contained in the upper 4 bits of the
79 * first data word! Try to avoid testing for TBT_DATA. \n
80 * Blocks generated by gen_from_fd should never have TBT_DATA.
81 */
82 int tape_block::get_type(){
83 return block_type;
84 }
85
86 /***************************************************************/
87 /*!
88 *\brief Determine the block's subtype
89 *
90 * Some data block types have a subtype.
91 *\note This is a virtual method and to be used in derived classes.
92 *\return Always 0
93 */
94 int tape_block::get_subtype(){
95 return 0;
96 }
97
98 /***************************************************************/
99 /*!
100 *\brief Get a cleartext description of the block.
101 *\return ldc style descriptive line for the block
102 */
103 vector<string> tape_block:: get_description(){
104 char buffer[100];
105 sprintf(buffer," (%0o-%02o) Untyped tape block",
106 get_type(),get_subtype());
107 vector<string> result;
108 result.insert(result.end(),buffer);
109 return result;
110 }
111
112 /***************************************************************/
113 /*!
114 *\brief Get size of the internal raw data buffer
115 *\return The size of the internal raw data buffer
116 */
117 int tape_block::get_raw_size(){
118 return raw_size;
119 }
120
121 /***************************************************************/
122 /*!
123 *\brief Access internal raw data buffer
124 *
125 * The raw data buffer contains all block data except the \ \
126 * block start delimiter and block end delimiter.
127 *\return Pointer to internal raw data buffer of the block
128 */
129 unsigned char * tape_block::get_raw_data(){
130 return raw_data;
131 }
132
133 /***************************************************************/
134 /*!
135 *\brief Static factory method with file descriptor support.
136 *
137 * This method creates a tape_block by using the private
138 * constructor with file descriptor support.\t
139 * It always returns a valid pointer, errors
140 * or exceptional conditions during creation are marked in the
141 * object's state.\n
142 * The factory method tries to determine the block's type and then
143 * looks for appropriate subclasses. If there's an appropriate
144 * subclass fitting the newly-created object, an
145 * object of the subclass will be created and a pointer to this
146 * object will be returned to the caller.\n
147 * This allows for easy use of the object using it's virtual
148 * interface methods or a cast of the pointer to a sub type pointer
149 * according to the type information, and then using the subtype's
150 * methods not already present in tape_block.\t
151 * Objects of the following subclasses are automagically generated:\t
152 * - eot_block
153 * - data_block
154 * -data_block_0
155 * -data_block_0_0
156 * -data_block_0_1
157 * -data_block_0_2
158 * -data_block_0_3
159 * -data_block_0_4
160 * -data_block_0_10
161 * -data_block_0_14
162 * -data_block_0_24
163 * -data_block_0_30
164 * -data_block_0_50
165 * -data_block_0_54
166 * -data_block_0_60
167 * -data_block_1
168 * -data_block_2
169 * -data_block_3
170 * -data_block_4
171 * -data_block_5
172 * -data_block_6
173 * -data_block_7
174 *
175 *\return Pointer to an object of type tape_block or a subclass.
176 *\param fd A file descriptor where the read is taken from.
177 *\param input_start A pointer to a function
178 * called before reading data from fd.
179 *\param input_stop A pointer to a function
180 * called after reading data from fd.
181 *
182 *\param start_stop_arg A pointer passed to input_start
183 * and input_stop(). Can be anything.
184 */
185 tape_block * tape_block::gen_from_fd(int fd,
186 void(*input_start)(void *),
187 void (*input_stop)(void *),
188 void * start_stop_arg)
189 {
190 tape_block * res_block;
191 res_block=new tape_block(fd,input_start,input_stop,start_stop_arg);
192 data_block * d_block;
193 data_block_0 * d0_block;
194
195 // Retype to data_block if possible
196 switch(res_block->get_type()){
197 case tape_block::TBT_DATA: // Make pointer a data block
198 d_block=new data_block(*res_block);
199 delete res_block;
200 res_block=d_block;
201 break;
202 default: // All other cases
203 return res_block;
204 }
205
206 // Retype again, if it's a data_block now
207
208 switch(res_block->get_type()){
209 case 00:
210 d0_block=new data_block_0(*d_block);
211 d_block=d0_block;
212 break;
213 // case 01: d_block=new data_block_1(*d_block); break;
214 // case 02: d_block=new data_block_2(*d_block); break;
215 // case 03: d_block=new data_block_3(*d_block); break;
216 // case 04: d_block=new data_block_4(*d_block); break;
217 // case 05: d_block=new data_block_5(*d_block); break;
218 // case 06: d_block=new data_block_6(*d_block); break;
219 // case 07: d_block=new data_block_7(*d_block); break;
220 default:
221 return res_block;
222 }
223 delete res_block;
224 res_block=d_block;
225
226 if (res_block->get_type()==0) switch(d0_block->get_subtype()){
227 // case 000: d0_block=new data_block_0_00(d0_block); break;
228 // case 001: d0_block=new data_block_0_01(d0_block); break;
229 // case 002: d0_block=new data_block_0_02(d0_block); break;
230 // case 003: d0_block=new data_block_0_03(d0_block); break;
231 // case 004: d0_block=new data_block_0_04(d0_block); break;
232 // case 010: d0_block=new data_block_0_10(d0_block); break;
233 // case 014: d0_block=new data_block_0_14(d0_block); break;
234 // case 024: d0_block=new data_block_0_24(d0_block); break;
235 // case 030: d0_block=new data_block_0_30(d0_block); break;
236 // case 054: d0_block=new data_block_0_54(d0_block); break;
237 // case 060: d0_block=new data_block_0_60(d0_block); break;
238 // case 060: d0_block=new data_block_0_50(d0_block); break;
239 default:
240 return res_block;
241 }
242 delete res_block;
243 res_block=d0_block;
244
245 return res_block;
246 }
247
248 /***************************************************************/
249 /*!
250 *\brief Default constructor.
251 */
252 tape_block::tape_block(){}
253
254
255 /***************************************************************/
256 /*!
257 *\brief Automatic constructor with file descriptor support
258 *
259 * This constructor is used to initialise the block read in the block's
260 * data via a file descriptor.\n
261 * This is done in the following way:
262 * - input_start() is called.
263 * - Data is read from fd. Stops on end of file or end of block
264 * or IO error. On EOF or IO error input_stop() is NOT called.
265 * - If there was no IO error the block's checksum is calculated
266 * and checked.
267 * - The block's type field is initialised.
268 * - input_stop() is called.
269 *
270 *\param fd A file descriptor where the read is taken from
271 *\param input_stop A pointer to a function called at the end of input
272 *\param input_start A pointer to a function called at the beginning
273 * of input
274 *\param start_stop_arg A pointer passed to input_start and input_stop().
275 */
276 tape_block::tape_block (int fd,
277 void(*input_start)(void *),
278 void (*input_stop)(void *),
279 void * start_stop_arg
280 )
281 {
282 unsigned char buffer;
283 int retval;
284 int eot_needed=EOT_LENGTH;
285 int eob_needed=EOB_LENGTH;
286 int block_complete=0;
287
288 block_type= TBT_DISCARD;
289 init_state= TBS_DEFAULT;
290 data_read = 0;
291 raw_data = 0;
292 raw_size = 0;
293 word_data = 0;
294 word_size = 0;
295
296 if (input_start) input_start (start_stop_arg);
297
298 /* Look for block start in input stream */
299 do {
300 retval=read(fd, &buffer, 1);
301 if (retval == 0){ // End of file
302 block_type=TBT_DISCARD;
303 init_state=TBS_EOF_LEGAL;
304 return;
305 }
306 if (retval == -1){ // Error reading from fd
307 block_type=TBT_DISCARD;
308 init_state=TBS_IOERR;
309 return;
310 }
311 data_read++;
312
313 /* Look for end ot tape sequence */
314 switch(eot_needed){
315 case 3:
316 if (buffer==EOT_SEQ_1) eot_needed--;
317 else eot_needed=EOT_LENGTH;
318 break;
319 case 2:
320 if (buffer==EOT_SEQ_2) eot_needed--;
321 else eot_needed=EOT_LENGTH;
322 break;
323 case 1:
324 if (buffer==EOT_SEQ_3){
325 raw_data=(unsigned char*)malloc(3);
326 raw_size=3;
327 raw_data[0]=EOT_SEQ_1;
328 raw_data[1]=EOT_SEQ_2;
329 raw_data[2]=EOT_SEQ_3;
330 block_type =TBT_EOT;
331 init_state =TBS_OK;
332 return;
333 }
334 else eot_needed=EOT_LENGTH;
335 break;
336 }
337 } while (buffer != (unsigned char) BLOCK_START_DELIMITER);
338
339
340 /* Now input the block data */
341 block_complete = 0;
342 do {
343 retval = read (fd, &buffer, 1);
344
345 if (retval == 0){ // End of file
346 block_type=TBT_DISCARD;
347 init_state=TBS_EOF_ILLEGAL;
348 return;
349 }
350 if (retval == -1){ // Error reading from fd
351 block_type=TBT_DISCARD;
352 init_state=TBS_IOERR;
353 return;
354 }
355 data_read++; // We have consumed a byte
356
357 /* sort in the new byte */
358 raw_size++;
359 raw_data=(unsigned char*)realloc(raw_data,raw_size);
360 raw_data[raw_size-1]=buffer;
361
362 /* Look for end ot block sequence */
363 switch(eob_needed){
364 case 2:
365 if (buffer==BLOCK_END_DELIMITER_1) eob_needed--;
366 else eob_needed=EOB_LENGTH;
367 break;
368 case 1:
369 if (buffer==BLOCK_END_DELIMITER_2){
370 raw_size-=EOB_LENGTH; // Don't want the delimiter(s) in the data!
371 raw_data=(unsigned char*)realloc(raw_data,raw_size);
372 block_complete=1;
373 }
374 else eob_needed=EOB_LENGTH;
375 break;
376 }
377 }while (!block_complete);
378 if (input_stop) input_stop (start_stop_arg);
379
380 /* Now we have the data in. */
381
382 if (init_words()!=0){
383 init_state=TBS_CHECKSUM;
384 return;
385 }
386
387 if (test_checksum()!=0){
388 init_state=TBS_CHECKSUM;
389 return;
390 }
391
392 block_type=TBT_DATA;
393 init_state=TBS_OK;
394 }
395
396
397 /***************************************************************/
398 /*!
399 *\brief Initialize word representation of data.
400 *\retval 0 on success.
401 *\retval 1 on error.
402 */
403 int tape_block::init_words(){
404 word_size=raw_size/3;
405 if (word_size<MINIMUM_DATA_BLOCK_WORDSIZE) return 1; // Block too short!
406 word_data=(unsigned short *)malloc(raw_size*sizeof(unsigned short));
407 for (int pos=0; pos<word_size; pos++)
408 word_data[pos]=combine466(raw_data+3*pos);
409 return 0;
410 }
411
412 /***************************************************************/
413 /*!
414 *\brief Calculate and check checksum.
415 *\retval 0 on success.
416 *\retval 1 on error.
417 */
418 int tape_block::test_checksum(){
419 unsigned short sum=0;
420 for (int pos=0; pos<word_size-1;pos++)
421 sum^=word_data[pos];
422 if (sum==word_data[word_size-1]) return 0;
423 else return 1;
424 }
425