fax/faxclientandserver/faxio/FAXIO.CPP
changeset 20 244d7c5f118e
parent 19 1f776524b15c
child 23 6b1d113cdff3
equal deleted inserted replaced
19:1f776524b15c 20:244d7c5f118e
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <s32mem.h>
       
    17 #include "CFAXIO.H"
       
    18 
       
    19 #include "FAXSTPAN.H"
       
    20 #include "FAXUHUFF.H"
       
    21 #include "FAXHUFF.H"
       
    22 
       
    23 // COPIED function from pdrutil
       
    24 
       
    25 GLDEF_C void Panic (TFaxStorePanic aPanic)
       
    26 // Panic the process with ETEXT as the category.
       
    27  //
       
    28 
       
    29 {
       
    30 	User::Panic (_L ("FaxStore"), aPanic);
       
    31 }
       
    32 
       
    33 // END OF COPIED
       
    34 
       
    35 //#define KFaxFileName _L("c:\\temp.fax")
       
    36 
       
    37 /********************************************************************/
       
    38 
       
    39 #define RLE_MAKEUP(aTable,aRun) TUint8((aTable)+KRleMakeup+((aRun)>>6<<1))
       
    40 #define RLE_RUN(aTable,aRun) TUint8((aTable)+((aRun)<<1))
       
    41 
       
    42 #define WRITE_RLE(ptr,table,run) {if (run>63) {*ptr++=RLE_MAKEUP(table,run);run&=0x3f;} *ptr++=RLE_RUN(table,run);}
       
    43 #define READ_RLE(ptr,pos) {TInt x=*ptr++;if (x>=KRleMakeup) {pos+=(x&KRleMakeupMask)<<5;x=*ptr++;}pos+=x>>1;}
       
    44 
       
    45 LOCAL_C TUint8* RleEncoding(const TUint32 * aScan, TUint8* aRleEncoding)
       
    46 //
       
    47 // RLE encode a 1728 pixel scanline into the buffer, and return the end-of-rle data
       
    48 // The edge detection algorithm is almost optimal for ARM
       
    49 //
       
    50 	{
       
    51 	// the edge detection looks at multiple pixels at a time
       
    52 	// tests show that for ARM, testing 8 is only 1-2% faster than testing 6
       
    53 	// testing only 6 makes for a smaller lookup table
       
    54 
       
    55 	// The FirstBit table is (5 - bitpos) of the least significant
       
    56 	// bit that is set in the array index value
       
    57 
       
    58 	const TInt KTestBitCount=6;
       
    59 	const TInt KTestBitMask=(1u<<KTestBitCount)-1;
       
    60 	const TInt KRunBias=KTestBitCount-2;
       
    61 	static const TUint8 KFirstBit[64]=
       
    62 		{
       
    63 		0,5,4,5,3,5,4,5,2,5,4,5,3,5,4,5,1,5,4,5,3,5,4,5,2,5,4,5,3,5,4,5,
       
    64 		0,5,4,5,3,5,4,5,2,5,4,5,3,5,4,5,1,5,4,5,3,5,4,5,2,5,4,5,3,5,4,5
       
    65 		};
       
    66 
       
    67 	const TUint32 *end = aScan + (KFaxPixelsPerScanLine >> 5);
       
    68 	TUint32 color = ~0u;			// white at start
       
    69 	TInt table=KRleWhite;
       
    70 	TInt run = KRunBias;			// initialise run length
       
    71 	const TUint8* lookup=KFirstBit;	// force the table to be in a register
       
    72 
       
    73 	nextword:
       
    74 	while (aScan < end)
       
    75 		{
       
    76 		run += 32;
       
    77 		TUint32 pixels = *aScan++ ^ color;
       
    78 		if (pixels)      // do no work if there is no edge
       
    79 			{
       
    80 			TInt bit = 31 + KTestBitCount;
       
    81 			for (;;)
       
    82 				{
       
    83 				TUint pix;
       
    84 				do
       
    85 					{
       
    86 					if ((bit-=KTestBitCount) < 0)
       
    87 						goto nextword;	// finished processing the word
       
    88 					// now examine the next 6 pixels
       
    89 					// break out if we have found an edge
       
    90 					pix=(pixels>>(31-bit))&KTestBitMask;
       
    91 					} while (pix==0);
       
    92 				// there is an edge, use the table to discover which pixel
       
    93 				bit+=lookup[pix];
       
    94 				// store the run-length
       
    95 				run-=bit;
       
    96 				WRITE_RLE(aRleEncoding,table,run);
       
    97 				// flip color and look for the next edge
       
    98 				color = ~color;
       
    99 				table=KRleWhite-table;
       
   100 				pixels=~pixels;
       
   101 				run = bit;
       
   102 				}
       
   103 			}
       
   104 		}
       
   105 	// store the final run
       
   106 	run-=KRunBias;
       
   107 	WRITE_RLE(aRleEncoding,table,run);
       
   108 	return aRleEncoding;
       
   109 	}
       
   110 
       
   111 LOCAL_C TUint8* RleEncoding (const TUint32 *aScanline,TInt aLength,TUint8* aRleEncoding)
       
   112 //
       
   113 // Justify the scanline into a full size buffer before encoding
       
   114 //
       
   115 	{
       
   116 	__ASSERT_DEBUG(aLength < (KFaxPixelsPerScanLine >> 3),User::Invariant());
       
   117 //
       
   118 	TUint32 justified[KFaxPixelsPerScanLine/32];
       
   119 //
       
   120 	TInt margin = ((KFaxPixelsPerScanLine >> 3) - aLength) / 2;
       
   121 	Mem::Fill (justified, sizeof(justified), 0xff);       // white fill
       
   122 	Mem::Copy ((TUint8*)justified + margin, aScanline, aLength);
       
   123 	return RleEncoding(justified,aRleEncoding);
       
   124 	}
       
   125 
       
   126 LOCAL_C TUint8* RleEncoding (const TDesC8& aScanLine, TUint8* aRleEncoding)
       
   127 //
       
   128 // Build the RLE encoding for aScanline, handling wrong-sized scanlines
       
   129 //
       
   130 	{
       
   131 	TInt len = aScanLine.Length ();
       
   132 	const TUint32 *scan = (const TUint32 *) aScanLine.Ptr ();
       
   133 	__ASSERT_DEBUG ((TUint (scan) & 3) == 0, Panic (EFaxEncodeScanlineAlignment));
       
   134 	if (len >= (KFaxPixelsPerScanLine >> 3))
       
   135 		return RleEncoding(scan + ((len - (KFaxPixelsPerScanLine >> 3)) >> 3),aRleEncoding);  // margin in words
       
   136 	else
       
   137 		return RleEncoding(scan,len,aRleEncoding);
       
   138 	}
       
   139 
       
   140 LOCAL_C void EncodeHuffman(TDes8 & anEncodedScanLine,TInt aTagCode,const TUint8* aRleEncoding,const TUint8* aRleEnd)
       
   141 //
       
   142 // Starting with the tag code, encode all codes in the rle data using the single huffman table
       
   143 //
       
   144 	{
       
   145 	TUint8 *t4 = (TUint8 *) anEncodedScanLine.Ptr ();
       
   146 	TUint8 *const e4 = t4;
       
   147 	// start with tag code
       
   148 	TCodeDef huff=KCodes[aTagCode];
       
   149 	TUint code=HUFFBITS(huff);
       
   150 	TInt bits=HUFFLEN(huff)-16;
       
   151 	while (aRleEncoding<aRleEnd)
       
   152 		{
       
   153 		__ASSERT_DEBUG (bits < 0, User::Invariant ());
       
   154 		TUint8 c=*aRleEncoding++;
       
   155 		TCodeDef huff=KCodes[c];
       
   156 		code|=HUFFBITS(huff)>>(bits+16);
       
   157 		bits+=HUFFLEN(huff);
       
   158 		if (bits<0)
       
   159 			continue;
       
   160 		*t4++=TUint8(code>>24);
       
   161 		*t4++=TUint8(code>>16);
       
   162 		code<<=16;
       
   163 		bits-=16;
       
   164 		}
       
   165 	if (bits>-16)
       
   166 		{	// flush out the remaining bits
       
   167 		*t4++=TUint8(code>>24);
       
   168 		if (bits>-8)
       
   169 			*t4++=TUint8(code>>16);
       
   170 		}
       
   171 	anEncodedScanLine.SetLength (t4 - e4);
       
   172 	}
       
   173 
       
   174 /********************************************************************/
       
   175 
       
   176 inline CFaxT4::CFaxT4 ()
       
   177 	{PageInitialize(EFaxNormal,EModifiedHuffman);}
       
   178 
       
   179 EXPORT_C CFaxT4 *CFaxT4::NewLC ()
       
   180 /** Constructs a CFaxT4 object, which provides utility functions to encode and 
       
   181 decode fax scan lines. 
       
   182 
       
   183 As is usual in Symbian OS, the only difference between this function and NewL() 
       
   184 is that this variant pushes the object to the cleanup stack.
       
   185 
       
   186 The new object is constructed with the default compression and resolution: 
       
   187 EModifiedHuffman and EFaxNormal respectively.
       
   188 
       
   189 @leave KErrNoMemory There is insufficient memory to perform the operation.
       
   190 @return A pointer to the newly created object. 
       
   191 @capability None
       
   192 */
       
   193 	{
       
   194 	CFaxT4 *self = NewL ();
       
   195 	CleanupStack::PushL (self);
       
   196 	return self;
       
   197 	}
       
   198 
       
   199 EXPORT_C CFaxT4 *CFaxT4::NewL ()
       
   200 /** Constructs a CFaxT4 object, which provides utility functions to encode and 
       
   201 decode fax scan lines. 
       
   202 
       
   203 The function is exactly the same as NewLC() except that the new object is 
       
   204 popped from the cleanup stack.
       
   205 
       
   206 The new object is constructed with the default compression and resolution: 
       
   207 EModifiedHuffman and EFaxNormal respectively.
       
   208 
       
   209 @leave KErrNoMemory There is insufficient memory to perform the operation. 
       
   210 @return A pointer to the newly created object. 
       
   211 @capability None
       
   212 */
       
   213 	{
       
   214 	return new (ELeave) CFaxT4;
       
   215 	}
       
   216 
       
   217 EXPORT_C void CFaxT4::PageInitialize (TFaxResolution aResolution, TFaxCompression aCompression, TInt aFlag2)
       
   218 /**
       
   219 Initialize fax page, set page parameters.
       
   220 
       
   221 @param   aResolution     defines fax resolution
       
   222 @param   aCompression    defines fax compression
       
   223 @param   aFlag2          reserved flag.
       
   224 @capability None
       
   225 */
       
   226 	{
       
   227 	__ASSERT_ALWAYS (((aCompression == EModifiedHuffman) || (aCompression == EModifiedRead)), Panic (EFaxUnsupportedCompression));
       
   228 	iCompression = aCompression;
       
   229 	iResolution = aResolution;
       
   230 	iReservedFlag2 = aFlag2;
       
   231 	iK = iResolution == EFaxFine ? 4 : 2;
       
   232 	iLineCount = 1;
       
   233 	// an all-white reference line
       
   234 	iRef[0]=RLE_MAKEUP(KRleWhite,KFaxBytesPerScanLine);
       
   235 	iRef[1]=RLE_RUN(KRleWhite,0);
       
   236 	iEndRef=iRef+2;
       
   237 	}
       
   238 
       
   239 EXPORT_C void CFaxT4::EncodeScanLine (const TDesC8 & aScanLine, TDes8 & anEncodedScanLine)
       
   240 /** Encodes a scan line using either one dimensional Modified Huffman (MH) or two 
       
   241 dimensional Modified Read (MR) encoding. 
       
   242 
       
   243 The type of encoding used depends on the compression type specified when the 
       
   244 object was initialised - using PageInitialize(). If the object was not initialised, 
       
   245 then the default compression is MH.
       
   246 
       
   247 @param aScanLine The raw scan line to be encoded. 
       
   248 @param anEncodedScanLine On return, contains the encoded scan line. 
       
   249 @capability None
       
   250 */
       
   251 	{
       
   252 	if (iCompression == EModifiedRead)
       
   253 		EncodeScanLine2D (aScanLine, anEncodedScanLine);
       
   254 	else
       
   255 		EncodeScanLine1D(aScanLine,anEncodedScanLine);
       
   256 	}
       
   257 
       
   258 EXPORT_C void CFaxT4::EncodeScanLine1D (const TDesC8 & aScanLine, TDes8 & anEncodedScanLine)
       
   259 /** Encodes a scan line using Modified Huffman compression.
       
   260 
       
   261 @param aScanLine The scan line to be encoded. 
       
   262 @param anEncodedScanLine On return, contains the MH encoded scan line. 
       
   263 @capability None
       
   264 */
       
   265 	{
       
   266 	iEndRef=RleEncoding(aScanLine,iRef);
       
   267 	EncodeHuffman(anEncodedScanLine,iCompression == EModifiedHuffman ? KRleStd1D : KRleTag1D,iRef,iEndRef);
       
   268 	}
       
   269 
       
   270 EXPORT_C void CFaxT4::EncodeScanLine2D (const TDesC8 & aScanLine, TDes8 & anEncodedScanLine)
       
   271 /** Encodes a scan line using Modified Read compression.
       
   272 
       
   273 @param aScanLine The scan line to be encoded. 
       
   274 @param anEncodedScanLine On return, contains the MR encoded scan line. 
       
   275 @capability None
       
   276 */
       
   277 	{
       
   278 	// initialize our own scan line
       
   279 	TInt lc=iLineCount-1;
       
   280 	if (lc==0)
       
   281 		{	// 1D reference line
       
   282 		iLineCount=iK;
       
   283 		EncodeScanLine1D(aScanLine,anEncodedScanLine);
       
   284 		}
       
   285 	else
       
   286 		{	// 2D line
       
   287 		iLineCount=lc;
       
   288 		DoEncodeScanLine2D(aScanLine,anEncodedScanLine);
       
   289 		}
       
   290 	}
       
   291 
       
   292 void CFaxT4::DoEncodeScanLine2D (const TDesC8 & aScanLine, TDes8 & aEncodedScanLine)
       
   293 	{
       
   294 	TUint8 rlebuf[KFaxPixelsPerScanLine*3/2 + 16]; // for output + reference line
       
   295 
       
   296 	// the buffer is big enough that the 2d coding output into the buffer will not
       
   297 	// catch the reference coding before it is used
       
   298 
       
   299 	// copy the reference line into the end of the stack buffer
       
   300 
       
   301 	TInt len=iEndRef-iRef;
       
   302 	TUint8* ref=rlebuf+sizeof(rlebuf)-len;
       
   303 	Mem::Copy(ref,iRef,len);
       
   304 
       
   305 	// Do the standard RLE encoding of the current line
       
   306 	iEndRef=RleEncoding(aScanLine,iRef);
       
   307 	const TUint8* cur=iRef;
       
   308 
       
   309 	TUint8* rle=rlebuf;
       
   310 	TInt a0=-1;			// previous edge on current line
       
   311 	TInt a1=0;			// current edge on current line
       
   312 	TInt b0;			// previous edge on reference line
       
   313 	TInt b1=0;			// current edge on reference line
       
   314 	TInt b2=0;			// look-ahead edge on reference line
       
   315 	TInt color=KRleWhite;	// color at a0 (initially white)
       
   316 
       
   317 	// the reference color is not tracked. Instead the number of reference edges
       
   318 	// traversed is monitored (modulo 2) to ensure that edge b1 is of the same
       
   319 	// color to a1 at "gotB2"
       
   320 
       
   321 	READ_RLE(cur,a1);		// find the first edge
       
   322 
       
   323 	for (;;)
       
   324 		{
       
   325 		do
       
   326 			{	// find the new current and next edges on reference line
       
   327 			b0=b1;
       
   328 			b1=b2;
       
   329 			if (b1==KFaxPixelsPerScanLine)
       
   330 				break;			// end of line
       
   331 			READ_RLE(ref,b2);
       
   332 refMove1:	//	find just the look-ahead edge on the reference line
       
   333 			b0=b1;
       
   334 			b1=b2;
       
   335 			if (b1==KFaxPixelsPerScanLine)
       
   336 				break;
       
   337 			READ_RLE(ref,b2);
       
   338 			} while(b1<=a0);		// ensure that we have the right reference edge
       
   339 
       
   340 gotB2:	if (b2 < a1)
       
   341 			{	// pass mode detected
       
   342 			*rle++=KRlePassMode;
       
   343 			a0=b2;	// move along by 2 edges
       
   344 			continue;
       
   345 			}
       
   346 
       
   347 		if (TUint(b1-a1+3)<=6u)
       
   348 			{	// vertical mode
       
   349 			*rle++=TUint8(KRleVertMode0 + (b1 - a1));
       
   350 			if (a1==KFaxPixelsPerScanLine)
       
   351 				break;		// complete
       
   352 			if (b0>a1)
       
   353 				{
       
   354 				// special case of vertical mode edge "cross-over"
       
   355 				// the next edge may match an earlier reference edge than this!
       
   356 				// rewind the reference line by 2 edges
       
   357 				// we know that [b0,b1] is small, and so only uses 1 byte in the rle
       
   358 				// we check for [b1,b2] requiring a makeup byte as well
       
   359 				ref-=2;
       
   360 				if (b2-b1>=64)
       
   361 					--ref;
       
   362 				b2=b0;
       
   363 				b1=0;	// no longer know b0, but this cannot happen again without traversing 2 edges
       
   364 				}
       
   365 			a0 = a1;	// traverse a single edge
       
   366 			READ_RLE(cur,a1);
       
   367 			color=KRleWhite-color;
       
   368 			goto refMove1;
       
   369 			}
       
   370 
       
   371 		// we must be in horizontal mode - write out the RLE codes for remainder
       
   372 		// and copy RLE codes for next edge from current coding
       
   373 
       
   374 		*rle++=KRleHorzMode;
       
   375 		a0=Max(0,a0);			// deal with start-effects (a0==-1)
       
   376 		TInt run=a1-a0;
       
   377 		WRITE_RLE(rle,color,run);
       
   378 		// copy the next run
       
   379 		if (a1==KFaxPixelsPerScanLine)
       
   380 			{	// complete, need a zero-length, other-color, run to finish
       
   381 			*rle++=RLE_RUN(KRleWhite-color,0);
       
   382 			break;
       
   383 			}
       
   384 		// copy the next RLE code directly from the current line
       
   385 		TInt x=*cur++;
       
   386 		__ASSERT_DEBUG((x&KRleWhite)==KRleWhite-color,User::Invariant());
       
   387 		if (x>=KRleMakeup)
       
   388 			{
       
   389 			*rle++=TUint8(x);
       
   390 			a1+=(x&KRleMakeupMask)<<5;
       
   391 			x=*cur++;
       
   392 			}
       
   393 		*rle++=TUint8(x);
       
   394 		a1+=x>>1;
       
   395 		if (a1==KFaxPixelsPerScanLine)
       
   396 			break;	// complete
       
   397 		a0=a1;
       
   398 		READ_RLE(cur,a1);	// traverse another edge
       
   399 		if (b1>a0)
       
   400 			goto gotB2;
       
   401 		}
       
   402 	EncodeHuffman(aEncodedScanLine,KRleTag2D,rlebuf,rle);
       
   403 	}
       
   404 
       
   405 EXPORT_C TInt CFaxT4::DecodeScanLine (TDes8 & aScanLine, const TDesC8 & anEncodedScanLine)
       
   406 /** Decodes a scan line. 
       
   407 
       
   408 The decoding method depends on the compression type specified when the object 
       
   409 was initialised - using PageInitialize(). If the object was not initialised, 
       
   410 then the scan line is decoded as Modified Huffman.
       
   411 
       
   412 The fax client can determine the type of compression used in a fax from its 
       
   413 header, and can hence use PageInitialize() to set the correct decoding method. 
       
   414 KErrUnderflow is returned if the wrong type of compression is specified.
       
   415 
       
   416 @param aScanLine On return, contains the decoded scan line. 
       
   417 @param anEncodedScanLine The encoded scan line to be decoded. 
       
   418 @return KErrNone if successful, otherwise another of the system-wide error 
       
   419 codes. 
       
   420 @capability None
       
   421 */
       
   422 	{
       
   423 	if (iCompression == EModifiedHuffman)
       
   424 		return (DecodeScanLine1D (aScanLine, anEncodedScanLine));
       
   425 	else
       
   426 		return (DecodeScanLine2D (aScanLine, anEncodedScanLine));
       
   427 	}
       
   428 
       
   429 void CFaxT4::DecodeHuffman(const TDesC8 & aEncodedScanLine)
       
   430 	{
       
   431 	// If all goes wrong then the reference line is unchanged and will be
       
   432 	// used for the current line
       
   433 
       
   434 	const TUint8* t4=aEncodedScanLine.Ptr();
       
   435 	const TUint8* endt4=t4+aEncodedScanLine.Length();
       
   436 	TUint bits=0;
       
   437 
       
   438 	// store the basic RLE data locally, and copy to the member data if the decode
       
   439 	// is successful
       
   440 
       
   441 	TUint8 rlebuf[KFaxPixelsPerScanLine+4];
       
   442 	TUint8* rle=rlebuf;
       
   443 
       
   444 	// Keep track of where we have got to on the reference (previous) line
       
   445 	const TUint8* ref=iRef;
       
   446 	TInt b1=0;		// pixel position on the reference line
       
   447 	TInt a0=0;		// previous position on the current line
       
   448 	TInt a1=0;		// current position on the current line
       
   449 
       
   450 	// start decoding using the tag-tree, which finds the first 1-bit
       
   451 	// and then determines the encoding (1D or 2D) based on the next bit
       
   452 	const TNode* tree=KTagTree;
       
   453 
       
   454 	// "color" stores the current line color (in bit 0), the reference line
       
   455 	// color (in bit 1), and the number of white/black codes to expect (x4)
       
   456 	// if color<0, then we are in 2d-tree mode
       
   457 	// initially unused until the encoding type is known
       
   458 
       
   459 	TInt color=0;
       
   460 	TInt code;
       
   461 
       
   462 	for (;;)
       
   463 		{
       
   464 		// the structure of the following code maxmises the speed of the
       
   465 		// huffman decoder. Don't change it.
       
   466 		code = 0;		// start at the root of the tree
       
   467 nextBit2d:
       
   468 		if (((bits <<= 1) & 0x80000000)==0)
       
   469 			goto nextByte2d;		// run out of bits in the current byte
       
   470 decode2d:
       
   471 		code = CODE (tree, code, bits & 0x80);
       
   472 		if (ISBRANCH (code))
       
   473 			goto nextBit2d;			// a branch code
       
   474 
       
   475 		// We have the huffman code
       
   476 
       
   477 		if (code<KOurEol)
       
   478 			{	// the code was a white/black length code
       
   479 			__ASSERT_DEBUG(color>=0,User::Invariant());
       
   480 			TInt v=CODEVALUE(code);
       
   481 			a1+=v;
       
   482 			if (a1>KFaxPixelsPerScanLine)
       
   483 				return;		// overflow
       
   484 			if (v < 64)
       
   485 				{	// a run code (as opposed to make-up code). Emit the RLE
       
   486 				a0=a1-a0;
       
   487 				WRITE_RLE(rle,(color&1),a0);
       
   488 				a0=a1;
       
   489 				color^=KRleWhite;	// switch color
       
   490 				color-=4;			// one less white/black code
       
   491 				tree=color>=0 ? color&KRleWhite ? KWhiteTree : KBlackTree : KTwoTree;
       
   492 				}
       
   493 			continue;
       
   494 			}
       
   495 		if (code<KPassMode)
       
   496 			{
       
   497 			if (code == KHorzMode)
       
   498 				{	// expect two white/black codes to follow
       
   499 				color+=8;
       
   500 				tree = color&KRleWhite ? KWhiteTree : KBlackTree;
       
   501 				continue;
       
   502 				}
       
   503 			if (code==KTag1D)
       
   504 				{	// 1d decoding: set color to maximum positive value
       
   505 					// as all codes are standard white/black code.
       
   506 				color=KMaxTInt;		// current and reference color both 1 (white)
       
   507 				tree=KWhiteTree;
       
   508 				continue;
       
   509 				}
       
   510 			if (code==KTag2D)
       
   511 				{	// 2d decoding: set color negative to indicate 2d-tree
       
   512 				color=-1;			// current and reference color both 1 (white)
       
   513 				tree=KTwoTree;
       
   514 				continue;
       
   515 				}
       
   516 			if (code==KOurEol)
       
   517 				goto eol2d;
       
   518 			__ASSERT_DEBUG(code == KBadRun,User::Invariant());
       
   519 			return;			// bad run, give up
       
   520 			}
       
   521 
       
   522 		// The remaining 2D possibilities all require that we know the various 2D determinants
       
   523 		// so we proceed as follows :
       
   524 
       
   525 		// b0 tracks the previous "edge" in the reference line
       
   526 		TInt b0=0;
       
   527 		// find the next "edge" on the reference line after a1
       
   528 		// if we've just started decoding (rle==rlebuf), b1 boundary at 0 is correct
       
   529 		if (rle!=rlebuf)
       
   530 			{
       
   531 			while (b1<=a1)
       
   532 				{
       
   533 				color^=KRleWhite<<1;
       
   534 				b0=b1;
       
   535 				if (b1!=KFaxPixelsPerScanLine)
       
   536 					READ_RLE(ref,b1);
       
   537 				}
       
   538 			}
       
   539 		// the b1 "edge" must match the colors of a1, so move one more edge if
       
   540 		// the a0 color (color&1) is the same as the b1 color (color&2)
       
   541 		if (((color^(color>>1))&1)==0)
       
   542 			{
       
   543 			b0=b1;
       
   544 			if (b1!=KFaxPixelsPerScanLine)
       
   545 				READ_RLE(ref,b1);
       
   546 			color^=KRleWhite<<1;
       
   547 			}
       
   548 
       
   549 		// If the code is below PASSMODE then it is one of the vertical code words
       
   550 		// which are pretty easy to decipher as we have all the data. Vertical mode
       
   551 		// flips the colour and then continues
       
   552 
       
   553 		if (code==KPassMode)
       
   554 			{
       
   555 			// we need to identify the next reference "edge"
       
   556 			if (b1==KFaxPixelsPerScanLine)
       
   557 				return;		// overflow
       
   558 			READ_RLE(ref,b1);
       
   559 			if (b1==KFaxPixelsPerScanLine)
       
   560 				return;		// overflow
       
   561 			color^=KRleWhite<<1;
       
   562 			a1=b1;
       
   563 			continue;
       
   564 			}
       
   565 
       
   566 		__ASSERT_DEBUG(code>=KVtMode3n && code<=KVtMode3p,User::Invariant());
       
   567 		// vertical mode
       
   568 		a1=b1+(code-(KVtMode0));
       
   569 		if (a1>KFaxPixelsPerScanLine)
       
   570 			return;		// overflow
       
   571 		if (b0>a1)
       
   572 			{
       
   573 			// special case of vertical mode cross-over
       
   574 			// rewind the reference line to the previous "edge"
       
   575 			b1=b0;
       
   576 			--ref;
       
   577 			color^=KRleWhite<<1;
       
   578 			}
       
   579 		a0=a1-a0;
       
   580 		WRITE_RLE(rle,(color&1),a0);
       
   581 		a0=a1;
       
   582 		color^=KRleWhite;
       
   583 		}
       
   584 nextByte2d:
       
   585 	if (t4 < endt4)
       
   586 		{
       
   587 		bits = 0xff000000u | *t4++;
       
   588 		goto decode2d;
       
   589 		}
       
   590 eol2d:
       
   591 	if (a0==KFaxPixelsPerScanLine)
       
   592 		iEndRef=Mem::Copy(iRef,rlebuf,rle-rlebuf);
       
   593 	}
       
   594 
       
   595 EXPORT_C TInt CFaxT4::DecodeScanLine2D (TDes8 & aScanLine, const TDesC8 & aEncodedScanLine)
       
   596 /** Decodes a Modified Read encoded scan line.
       
   597 	
       
   598 @param aScanLine On return, contains the decoded scan line. 
       
   599 @param anEncodedScanLine The 2D encoded scan line to be decoded. 
       
   600 @return KErrNone if successful, KErrUnderflow if the scan line is encoded as 
       
   601 MR, otherwise another of the system-wide error codes. 
       
   602 @capability None
       
   603 */
       
   604 	{
       
   605 	DecodeHuffman(aEncodedScanLine);
       
   606 //
       
   607 //	decode the RLE into the scanline
       
   608 //
       
   609 	aScanLine.SetLength (KFaxPixelsPerScanLine / 8);
       
   610 	TUint32 *scan = (TUint32 *) aScanLine.Ptr ();
       
   611 	__ASSERT_DEBUG ((TUint (scan) & 3) == 0, Panic (EFaxDecodeScanlineAlignment));
       
   612 
       
   613 	const TUint8* rle=iRef;
       
   614 	const TUint8* const end=iEndRef;
       
   615 
       
   616 	TUint color = ~0u;		// start white
       
   617 	TUint out = 0;			// output pixels in accumulation
       
   618 	TInt bits = 0;          // this is the number of used bits in out
       
   619 
       
   620 	while (rle<end)
       
   621 		{
       
   622 		TInt run=*rle++;
       
   623 		__ASSERT_DEBUG(TUint((run&1))==(color&1),User::Invariant());	// rle-data correct
       
   624 		if (run<KRleMakeup)
       
   625 			{	// run length code (x2)
       
   626 			out += color << bits;		// complete the current 32-bits
       
   627 			bits += run >> 1;			// add the run length
       
   628 			if (bits < 32)				// hasn't completed the word
       
   629 				out -= color << bits;	// remove the trailing bits
       
   630 			else
       
   631 				{
       
   632 				*scan++ = out;			// write the 32-bits
       
   633 				bits -= 64;
       
   634 				if (bits >= 0)
       
   635 					*scan++ = color;	// + another 32 bits
       
   636 				else
       
   637 					bits += 32;			// no extra
       
   638 				out = color - (color<<bits);	// bits remaining
       
   639 				}
       
   640 			color = ~color;				// swap color
       
   641 			}
       
   642 		else
       
   643 			{
       
   644 			// make-up code. (run-KRleMakeup)>>1 is the multiple of 64 bits
       
   645 			out += color << bits;		// complete the current 32-bits
       
   646 			*scan++ = out;				// output
       
   647 			*scan++ = color;			// +32 bits of color
       
   648 			for (run -= KRleMakeup+4;run >= 0;run -= 2)
       
   649 				{	// extra multiples of 64 bits
       
   650 				*scan++ = color;
       
   651 				*scan++ = color;
       
   652 				}
       
   653 			out = color - (color<<bits);	// remainder bits
       
   654 			}
       
   655 		}
       
   656 	return KErrNone;
       
   657 	}
       
   658 
       
   659 EXPORT_C TInt CFaxT4::DecodeScanLine1D (TDes8 & aScanLine, const TDesC8 & anEncodedScanLine)
       
   660 //
       
   661 // This could be done through DecodeScanLine2D, but this is an optimized version for 1D
       
   662 // The intermediate rle encoding is skipped
       
   663 //
       
   664 /** Decodes a Modified Huffman encoded scan line.
       
   665 
       
   666 @param aScanLine On return, contains the decoded scan line. 
       
   667 @param anEncodedScanLine The MH encoded scan line to be decoded. 
       
   668 @return KErrNone if successful, KErrUnderflow if the scan line is encoded as 
       
   669 MR, otherwise another of the system-wide error codes. 
       
   670 @capability None
       
   671 */
       
   672 	{
       
   673 	const TUint8 *t4 = anEncodedScanLine.Ptr ();
       
   674 	const TUint8 *const endt4 = t4 + anEncodedScanLine.Length ();
       
   675 	//
       
   676 	aScanLine.SetLength (KFaxPixelsPerScanLine / 8);
       
   677 	TUint32 *scan = (TUint32 *) aScanLine.Ptr ();
       
   678 	__ASSERT_DEBUG ((TUint (scan) & 3) == 0, Panic (EFaxDecodeScanlineAlignment));
       
   679 	TUint out = 0;
       
   680 	TInt bits = 0;               // this is the number ofused bits
       
   681 	//
       
   682 	TInt dotsleft = KFaxPixelsPerScanLine;
       
   683 	const TNode *tree = KSynchTree;
       
   684 	TUint octet=0;
       
   685 	TUint color = 0xffffffffu;
       
   686 
       
   687 nextCode1d:
       
   688 	TInt code = 0;
       
   689 nextBit1d:
       
   690 	if (((octet <<= 1) & 0x80000000)==0)
       
   691 		goto nextByte1d;
       
   692 decode1d:
       
   693 	code = CODE (tree, code, octet & 0x80);
       
   694 	if (ISBRANCH (code))
       
   695 		goto nextBit1d;
       
   696 
       
   697 	// end of huffman code
       
   698 
       
   699 	if (code<KEndCode+0x40)
       
   700 		{
       
   701 		code-=KEndCode;
       
   702 		if ((dotsleft -= code) < 0)
       
   703 			return KErrOverflow;
       
   704 		out += color<<bits;
       
   705 		bits+=code;
       
   706 		if (bits<32)
       
   707 			out -= color<<bits;	// output word not full
       
   708 		else
       
   709 			{	// out is full
       
   710 			*scan++=out;
       
   711 			bits-=64;
       
   712 			if (bits>=0)
       
   713 				*scan++=color;
       
   714 			else
       
   715 				bits+=32;
       
   716 			out=color-(color<<bits);
       
   717 			}
       
   718 		color = ~color;
       
   719 		if (color)
       
   720 			tree=KWhiteTree;
       
   721 		else
       
   722 			tree=KBlackTree;
       
   723 		goto nextCode1d;
       
   724 		}
       
   725 	else if (code<=KEndCode+KMaxRun)
       
   726 		{	// makeup (multiple of 64)
       
   727 		code-=KEndCode+0x40;
       
   728 		if ((dotsleft -= code<<6) < 0)
       
   729 			return KErrOverflow;
       
   730 		out += color << bits;
       
   731 		*scan++=out;
       
   732 		*scan++=color;
       
   733 		for (code-=2;code>=0;--code)
       
   734 			{
       
   735 			*scan++=color;
       
   736 			*scan++=color;
       
   737 			}
       
   738 		out = color-(color<<bits);
       
   739 		goto nextCode1d;
       
   740 		}
       
   741 	else if (code == KOurEol)
       
   742 		goto eol1d;
       
   743 	else if (code == KStd1D)
       
   744 		{
       
   745 		tree=KWhiteTree;
       
   746 		goto nextCode1d;
       
   747 		}
       
   748 	else
       
   749 		{
       
   750 		__ASSERT_DEBUG (code == KBadRun, User::Invariant ());
       
   751 		return KErrCorrupt;
       
   752 		}
       
   753 nextByte1d:
       
   754 	if (t4 < endt4)
       
   755 		{
       
   756 		octet = 0xff000000u | *t4++;
       
   757 		goto decode1d;
       
   758 		}
       
   759 eol1d:
       
   760 	__ASSERT_DEBUG (dotsleft || (TUint8 *) scan - aScanLine.Ptr () == KFaxPixelsPerScanLine / 8, User::Invariant ());
       
   761 	return dotsleft ? KErrUnderflow : KErrNone;
       
   762 	}
       
   763