File: sfftobmp.cpp

package info (click to toggle)
sffview 0.2-6
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 116 kB
  • ctags: 165
  • sloc: cpp: 966; pascal: 204; makefile: 61
file content (652 lines) | stat: -rw-r--r-- 20,009 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
// sfftobmp.cpp
//
// This file is part of sffview, a program to view
// structured fax files (sff).

// Copyright (C) 2000 Peter Schaefer
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose and without fee is hereby granted, provided
// that the above copyright notice appear in all copies. This software 
// is provided "as is" without express or implied warranty.
//
// You can contact the author by email at peter.schaefer@gmx.de.
// 

#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#if wxUSE_STREAMS
#include "wx/wfstream.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

#ifdef __WXMSW__
#include <strstrea.h>
#else
#include <sstream>
#endif

#include "inc/sfftobmp.h"

/*-RCS-Info----------------------------------------------------

$Id: sfftobmp.cpp,v 1.6 1999/12/19 07:47:26 peter Exp peter $

---RCS-Info--------------------------------------------------*/

/*
 Auszug aus CCITT Draft Recommendation T.4:

         Table 1a. Terminating White Codes     Table 1b. Make Up White Codes 
         Code            Lng     Run           Code            Lng     Run   
         ---------------------------           ---------------------------   
         00110101        8       0             11011           5       64    
         000111          6       1             10010           5       128   
         0111            4       2             010111          6       192   
         1000            4       3             0110111         7       256   
         1011            4       4             00110110        8       320   
         1100            4       5             00110111        8       384   
         1110            4       6             01100100        8       448   
         1111            4       7             01100101        8       512   
         10011           5       8             01101000        8       576   
         10100           5       9             01100111        8       640   
         00111           5       10            011001100       9       704   
         01000           5       11            011001101       9       768   
         001000          6       12            011010010       9       832   
         000011          6       13            011010011       9       896   
         110100          6       14            011010100       9       960   
         110101          6       15            011010101       9       1024  
         101010          6       16            011010110       9       1088  
         101011          6       17            011010111       9       1152  
         0100111         7       18            011011000       9       1216  
         0001100         7       19            011011001       9       1280  
         0001000         7       20            011011010       9       1344  
         0010111         7       21            011011011       9       1408  
         0000011         7       22            010011000       9       1472  
         0000100         7       23            010011001       9       1536  
         0101000         7       24            010011010       9       1600  
         0101011         7       25            011000          6       1664  
         0010011         7       26            010011011       9       1728  
         0100100         7       27
         0011000         7       28
         00000010        8       29
         00000011        8       30
         00011010        8       31
         00011011        8       32
         00010010        8       33
         00010011        8       34
         00010100        8       35
         00010101        8       36
         00010110        8       37
         00010111        8       38
         00101000        8       39
         00101001        8       40
         00101010        8       41
         00101011        8       42
         00101100        8       43
         00101101        8       44
         00000100        8       45
         00000101        8       46
         00001010        8       47
         00001011        8       48
         01010010        8       49
         01010011        8       50
         01010100        8       51
         01010101        8       52
         00100100        8       53
         00100101        8       54
         01011000        8       55
         01011001        8       56
         01011010        8       57
         01011011        8       58
         01001010        8       59
         01001011        8       60
         00110010        8       61
         00110011        8       62
         00110100        8       63

         Table 2a. Terminating Black Codes    Table 2b. Make Up Black Codes 
         Code            Lng     Run          Code            Lng     Run   
         ---------------------------          ---------------------------   
         0000110111      10      0            0000001111      10      64    
         010             3       1            000011001000    12      128   
         11              2       2            000011001001    12      192   
         10              2       3            000001011011    12      256   
         011             3       4            000000110011    12      320   
         0011            4       5            000000110100    12      384   
         0010            4       6            000000110101    12      448   
         00011           5       7            0000001101100   13      512   
         000101          6       8            0000001101101   13      576   
         000100          6       9            0000001001010   13      640   
         0000100         7       10           0000001001011   13      704   
         0000101         7       11           0000001001100   13      768   
         0000111         7       12           0000001001101   13      832   
         00000100        8       13           0000001110010   13      896   
         00000111        8       14           0000001110011   13      960   
         000011000       9       15           0000001110100   13      1024  
         0000010111      10      16           0000001110101   13      1088  
         0000011000      10      17           0000001110110   13      1152  
         0000001000      10      18           0000001110111   13      1216  
         00001100111     11      19           0000001010010   13      1280  
         00001101000     11      20           0000001010011   13      1344  
         00001101100     11      21           0000001010100   13      1408  
         00000110111     11      22           0000001010101   13      1472  
         00000101000     11      23           0000001011010   13      1536  
         00000010111     11      24           0000001011011   13      1600  
         00000011000     11      25           0000001100100   13      1664  
         000011001010    12      26           0000001100101   13      1728  
         000011001011    12      27
         000011001100    12      28
         000011001101    12      29
         000001101000    12      30
         000001101001    12      31
         000001101010    12      32
         000001101011    12      33
         000011010010    12      34
         000011010011    12      35
         000011010100    12      36
         000011010101    12      37
         000011010110    12      38
         000011010111    12      39
         000001101100    12      40
         000001101101    12      41
         000011011010    12      42
         000011011011    12      43
         000001010100    12      44
         000001010101    12      45
         000001010110    12      46
         000001010111    12      47
         000001100100    12      48
         000001100101    12      49
         000001010010    12      50
         000001010011    12      51
         000000100100    12      52
         000000110111    12      53
         000000111000    12      54
         000000100111    12      55
         000000101000    12      56
         000001011000    12      57
         000001011001    12      58
         000000101011    12      59
         000000101100    12      60
         000001011010    12      61
         000001100110    12      62
         000001100111    12      63

	 Note: It is recognized that machines exist which accommodate
	 larger   paper   widths   whilst  maintaining  the  standard
	 horizontal resolution.  This option has been provided for by
	 the addition of the Make Up Code Set defined as follows:
     
         Table 3. Extended Make Up Codes (Black and White)
         Code            Lng     Run
         ---------------------------
         00000001000     11      1792
         00000001100     11      1856
         00000001101     11      1920
         000000010010    12      1984
         000000010011    12      2048
         000000010100    12      2112
         000000010101    12      2176
         000000010110    12      2240
         000000010111    12      2304
         000000011100    12      2368
         000000011101    12      2432
         000000011110    12      2496
         000000011111    12      2560
*/

//-Codetabellen----------------------------------------------------

#include "inc/codes.inc"

//-Constants-------------------------------------------------------

wxUint8 CSffFile::m_SFFID[4] = { 0x53, 0x66, 0x66, 0x66 };

//-----------------------------------------------------------------

char * CSimpleException::GetReason()
{
	char *pszError;
	
	switch (m_nError) {
		case err_invalidfile :
			pszError = "Not a valid sff file.";
			break;
		case err_corruptfile :
			pszError = "File seems corrupt. Reading abandoned.";
			break;
		case err_lastpageread :
			pszError = "Last page read.";
			break;
		case err_notsupported :
			pszError = "Operation not supported.";
			break;
		case err_openfile :
			pszError = "Error open file.";
			break;
		case err_nowhitestart :
			pszError = "Line doesn't begin with white code.";
			break;
		case err_noblackcode :
			pszError = "White code not followed by black code.";
			break;
		case err_noblackterm :
			pszError = "Black MUC not followed by black TERM.";
			break;
		case err_nowhiteterm :
			pszError = "White MUC not followed by white TERM.";
			break;
		case err_invalidversion :
			pszError = "OOps. Dont know how to handle this Fileversion.";
			break;
		case err_unknowncoding :
			pszError = "Oh my dear. Dont know how to handle this encoding.";
			break;
		default :
			pszError = "Unknown error.";
			break;
	}
	return pszError;
}

//-----------------------------------------------------------------

void CBitSource::NeedBits(int nCount)
{
		while ((m_dwByteCount > 0) && (m_wBitsAvail < nCount)) {
			m_dwAccu |= ((*m_pBuffer) << m_wBitsAvail);
			m_wBitsAvail += 8;
			--m_dwByteCount;
			++m_pBuffer;
		}
}

void CBitSource::ClrBits(int nCount) 
{
		m_wBitsAvail -= nCount;
		m_dwAccu = (m_dwAccu >> nCount);
}

wxUint16 CBitSource::GetBits(int nCount) 
{
		return (m_dwAccu & ((1<<(nCount))-1));	// untere x Bits ausmaskieren
};

CBitSource::CBitSource(void *pBuffer, wxUint32 nByteCount) : 
		m_pBuffer((wxUint8 *)pBuffer), 
		m_wBitsAvail(0),
		m_dwAccu(0),
		m_dwByteCount(nByteCount) 
{ 
		/* sonst nix */ 
};

//-----------------------------------------------------------------

void CBitSink::SetBits(int nCount) 
{
		while ( (m_dwByteCount > 0) && (nCount > 0)) {
			++m_wBitsAvail;
			if (m_wBitsAvail > 7) {
				m_wBitsAvail = 0;
				++m_pBuffer; --m_dwByteCount;
			}
#ifdef __WXMSW__
      *m_pBuffer &= ~(0x80 >> m_wBitsAvail);
#else
      *m_pBuffer |= (0x01 << m_wBitsAvail);
#endif
			--nCount;
		}
};
	
void CBitSink::ClearBits(int nCount) 
{
		while ( (m_dwByteCount > 0) && (nCount > 0)) {
			++m_wBitsAvail;
			if (m_wBitsAvail > 7) {
				m_wBitsAvail = 0;
				++m_pBuffer; --m_dwByteCount;
			} 
			--nCount;
		}
};
	
CBitSink::CBitSink(void *pBuffer, wxUint32 nByteCount) :
		m_pBuffer((wxUint8 *)pBuffer), 
		m_wBitsAvail(0),
		m_dwByteCount(nByteCount) 
{ 
};

//-----------------------------------------------------------------

int CHuffDecoder::FindToken(LPTABENTRY pTable)
{
	wxUint16 bits;
	while (pTable->code) {
		bits = GetBits(pTable->bits);
		if (bits == pTable->code) {
			ClrBits(pTable->bits);
			return pTable->run;
		}
		pTable++;
	}
	return -1;
}

int CHuffDecoder::DecodeLine(CBitSink& aBitSink)
{
	int	iRunlength;
	
	m_dwRunlength = 0;
	TDecoderState state = NEED_WHITE;
	
	for (;;) {
		switch (state) {
			case NEED_WHITE :
				// we expect white_term or white_markup
				NeedBits(9);
				iRunlength = FindToken(aTermWhite);
				if ( iRunlength >= 0 ) {
					if ( iRunlength > 0 ) { 
						m_dwRunlength += iRunlength;
						aBitSink.ClearBits(iRunlength);
					}
					state = NEED_BLACK;
				}	else {
					iRunlength = FindToken(aMarkUpWhite);
					if (iRunlength >= 0) {
						if ( iRunlength > 0 ) { 
							m_dwRunlength += iRunlength;
							aBitSink.ClearBits(iRunlength);
						}
						state = NEED_WHITETERM;
 					}	else 
						throw CSimpleException(CSimpleException::err_nowhitestart);
				}
				break;
			case NEED_BLACK :
				// we expect black_term or black_markup
				NeedBits(13);
				if ((iRunlength = FindToken(aTermBlack)) >= 0) {
					if ( iRunlength > 0 ) { 
						m_dwRunlength += iRunlength;
						aBitSink.SetBits(iRunlength);
					}
					state = NEED_WHITE;
				} else if ((iRunlength = FindToken(aMarkUpBlack)) >= 0) {
					if ( iRunlength > 0 ) { 
						m_dwRunlength += iRunlength;
						aBitSink.SetBits(iRunlength);
					}
					state = NEED_BLACKTERM;
				} else 
					throw CSimpleException(CSimpleException::err_noblackcode);
				break;
			case NEED_WHITETERM :
				// expect White_Term only
				NeedBits(8);
				if ((iRunlength = FindToken(aTermWhite)) >= 0) {
					if ( iRunlength > 0 ) { 
						aBitSink.ClearBits(iRunlength);
						m_dwRunlength += iRunlength;
					}
					state = NEED_BLACK;
				} else 
					throw CSimpleException(CSimpleException::err_nowhiteterm);
				break;
			case NEED_BLACKTERM :
				// expect Black_Term only
				NeedBits(12);
				if ((iRunlength = FindToken(aTermBlack)) >= 0) {
					if ( iRunlength > 0 ) { 
						m_dwRunlength += iRunlength;
						aBitSink.SetBits(iRunlength);
					}
					state = NEED_WHITE;
				} else 
					throw CSimpleException(CSimpleException::err_noblackterm);
				break;
		}
		if (m_dwByteCount <= 0)
			break;
	}			
	return m_dwRunlength;
}

//-----------------------------------------------------------------

CSffFile::CSffFile(const wxString& strFileName) :
	m_stream(strFileName),
	m_nPageCount(0)
{
	::memset(m_acPages,0,sizeof(m_acPages));
	ScanFile();
}

CSffFile::~CSffFile()
{
	for (int i = 0; i <= m_nPageCount; ++i) {
		if (m_acPages[i])
			delete m_acPages[i];
	}
}

bool CSffFile::DecodeRecord(TSFFRecord& rec, wxUint8 *pBuf, wxUint32 cbBuf)
{
	bool  rc;
		
	if (rec.type != NORMAL) 
		return FALSE;

#ifdef __WXMSW__
	::memset(pBuf, 0xFF, cbBuf);	// Puffer auf Weiss setzen
#else
	::memset(pBuf, 0x0, cbBuf);	// Puffer auf Weiss setzen
#endif
	
	CHuffDecoder source(rec.pData, rec.cb);
	CBitSink sink(pBuf, cbBuf);

	try {
		rec.runlength = source.DecodeLine(sink);
		rc = TRUE;
	}
	catch(CSimpleException)
	{
		rc = FALSE;
	}
	return rc;
}

bool CSffFile::GetRecord(TSFFRecord& rec)
{
	wxUint8 b1, b2;
	wxUint16 w;
	bool result;

	b1 = m_stream.GetC();  // Recordtyp einlesen
	if (b1 == 0) {
		// variable Anzahl Bytes folgt
		b1 = m_stream.GetC();	// LSB
		b2 = m_stream.GetC();	// MSB
		w = ((b2 << 8) | b1);
		rec.type  = NORMAL;
		rec.cb    = w;
		rec.pData = (wxUint8 *)malloc(w);
		m_stream.Read(rec.pData, w);
		result = TRUE;
	} else if (b1 < 217) {
		// normale Anzahl wxUint8s folgt
		rec.type  = NORMAL;
		rec.cb    = b1;
		rec.pData = (wxUint8 *)malloc(b1);
		m_stream.Read(rec.pData, b1);
		result = TRUE;
	} else if (b1 < 254) {
		// Whiteskip
		rec.type  = WHITESKIP;
		rec.cb    = (b1 - 216);
		rec.pData = 0;
		result = TRUE;
	} else if (b1 < 255) {
		// 254 -> Pageheader
		result = FALSE;
	} else {
		// Fehlerhafte Zeile oder Benutzerinfo
    b1 = m_stream.GetC();	// LSB
		if (b1 == 0) {
			rec.type  = BADLINE;
			rec.cb    = 1;
			rec.pData = 0;
		} else {
			rec.type  = USERINFO;
			rec.cb    = b1;
			rec.pData = (wxUint8 *)malloc(b1);
			m_stream.Read(rec.pData, b1);
		}
		result = TRUE;
	}
	return result;
}

bool CSffFile::SeekPage(int nPage)
{
	--nPage;
	if ((nPage < 0)||(nPage >= m_nPageCount)||(nPage>=_SIZE_PAGEBUFFER))
		return FALSE;
	if (!m_acPages[nPage])
		return FALSE;	
	m_stream.SeekI(m_acPages[nPage]->filepos, wxFromStart);	
	return TRUE;
}	

void CSffFile::ScanFile()
{
	TSFFFileHeader dh;
	TSFFPageHeader ph;
	wxUint8        b1 = 0,b2 = 0;
	wxUint16       w;
	int            nLineCount = 0;
	
  if (m_stream.LastError() != wxStream_NOERROR)
    return;

	m_nPageCount = 0;

	TScannerState state = NEED_MAGIC;	
	do {
		switch (state) {
			case NEED_MAGIC :
				m_stream.Read(&dh, sizeof(dh));
				if (m_stream.LastError() != wxStream_NOERROR) 
					throw CSimpleException(CSimpleException::err_invalidfile);
				if (::memcmp(&dh.sff_id, &m_SFFID, sizeof(m_SFFID)) != 0) 
					throw CSimpleException(CSimpleException::err_invalidfile);
				if (dh.version > 1) 
					throw CSimpleException(CSimpleException::err_invalidversion);
				m_stream.SeekI(dh.first_page, wxFromStart);
				state = NEED_PAGESTART;
				break;
			case NEED_PAGESTART :			
				b1 = m_stream.GetC();	// Recordheader (0xFE fuer Seitenanfang)
				if (b1 != 0xFE) 
					throw CSimpleException(CSimpleException::err_corruptfile);	
				b1 = m_stream.GetC();	// Recordlaenge (normalerweise 0x10)
				if (b1 == 0) 
					state = LAST_PAGE;
				else
					state = NEED_PAGEHEADER;
				break;
			case NEED_PAGEHEADER :
				m_stream.Read(&ph, sizeof(TSFFPageHeader));
				if (m_stream.LastError() != wxStream_NOERROR) 
					throw CSimpleException(CSimpleException::err_corruptfile);	
				if (ph.coding > 0) 
					throw CSimpleException(CSimpleException::err_unknowncoding);
				m_stream.SeekI(b1 - sizeof(TSFFPageHeader), wxFromCurrent);	// user data ueberspringen
				m_acPages[m_nPageCount] = new TSFFPage;
				m_acPages[m_nPageCount]->filepos = m_stream.TellI();
				m_acPages[m_nPageCount]->width   = ph.linelen;
				m_acPages[m_nPageCount]->height  = ph.pagelen;
				state = NEED_RECORD;
				nLineCount = 0;
				break;
			case NEED_RECORD :
				b1 = m_stream.GetC();	// Recordtyp einlesen
				if (b1 == 0) {
					// variable Anzahl Bytes folgt
					b1 = m_stream.GetC();	// LSB
					b2 = m_stream.GetC();	// MSB
					w = ((b2 << 8) | b1);
					m_stream.SeekI(w, wxFromCurrent);	// Daten berspringen
					++nLineCount;
				} else if (b1 < 217) {
					// normale Anzahl Bytes folgt
          m_stream.SeekI((long)b1, wxFromCurrent);	// Daten berspringen
					++nLineCount;
				} else if (b1 < 254) {
					// Whiteskip
					nLineCount+=(b1 - 216);
				} else if (b1 < 255) {
					// 254 -> Pageheader
					m_acPages[m_nPageCount]->height = nLineCount;
          nLineCount = 0;
					++m_nPageCount;
					b1 = m_stream.GetC();	// Recordlaenge (normalerweise 0x10)
					if (b1 == 0) {
						state = LAST_PAGE;
					} else {
						state = NEED_PAGEHEADER;
					}
				} else {
					// Fehlerhafte Zeile oder Benutzerinfo
					b1 = m_stream.GetC();	// LSB
					if (b1 == 0) {	
						++nLineCount;
					} else {
						m_stream.SeekI(b1, wxFromCurrent);	// Benutzerinfo berspringen
					}
				}
				break;
			case LAST_PAGE :
				break;
		}
	} while(state != LAST_PAGE);
	return;
}

wxUint32 CSffFile::GetPageHeight(int nPage)
{
	--nPage;
	if ((nPage < 0)||(nPage >= m_nPageCount)||(nPage>=_SIZE_PAGEBUFFER))
		return 0;
	if (!m_acPages[nPage])
		return 0;		
	return m_acPages[nPage]->height;
}

wxUint32 CSffFile::GetPageWidth(int nPage)
{
	--nPage;
	if ((nPage < 0)||(nPage >= m_nPageCount)||(nPage>=_SIZE_PAGEBUFFER))
		return 0;
	if (!m_acPages[nPage])
		return 0;		
	return m_acPages[nPage]->width;
}