fax/faxclientandserver/faxio/FAXIO.CPP
changeset 0 3553901f7fa8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fax/faxclientandserver/faxio/FAXIO.CPP	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,763 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <s32mem.h>
+#include "CFAXIO.H"
+
+#include "FAXSTPAN.H"
+#include "FAXUHUFF.H"
+#include "FAXHUFF.H"
+
+// COPIED function from pdrutil
+
+GLDEF_C void Panic (TFaxStorePanic aPanic)
+// Panic the process with ETEXT as the category.
+ //
+
+{
+	User::Panic (_L ("FaxStore"), aPanic);
+}
+
+// END OF COPIED
+
+//#define KFaxFileName _L("c:\\temp.fax")
+
+/********************************************************************/
+
+#define RLE_MAKEUP(aTable,aRun) TUint8((aTable)+KRleMakeup+((aRun)>>6<<1))
+#define RLE_RUN(aTable,aRun) TUint8((aTable)+((aRun)<<1))
+
+#define WRITE_RLE(ptr,table,run) {if (run>63) {*ptr++=RLE_MAKEUP(table,run);run&=0x3f;} *ptr++=RLE_RUN(table,run);}
+#define READ_RLE(ptr,pos) {TInt x=*ptr++;if (x>=KRleMakeup) {pos+=(x&KRleMakeupMask)<<5;x=*ptr++;}pos+=x>>1;}
+
+LOCAL_C TUint8* RleEncoding(const TUint32 * aScan, TUint8* aRleEncoding)
+//
+// RLE encode a 1728 pixel scanline into the buffer, and return the end-of-rle data
+// The edge detection algorithm is almost optimal for ARM
+//
+	{
+	// the edge detection looks at multiple pixels at a time
+	// tests show that for ARM, testing 8 is only 1-2% faster than testing 6
+	// testing only 6 makes for a smaller lookup table
+
+	// The FirstBit table is (5 - bitpos) of the least significant
+	// bit that is set in the array index value
+
+	const TInt KTestBitCount=6;
+	const TInt KTestBitMask=(1u<<KTestBitCount)-1;
+	const TInt KRunBias=KTestBitCount-2;
+	static const TUint8 KFirstBit[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,
+		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
+		};
+
+	const TUint32 *end = aScan + (KFaxPixelsPerScanLine >> 5);
+	TUint32 color = ~0u;			// white at start
+	TInt table=KRleWhite;
+	TInt run = KRunBias;			// initialise run length
+	const TUint8* lookup=KFirstBit;	// force the table to be in a register
+
+	nextword:
+	while (aScan < end)
+		{
+		run += 32;
+		TUint32 pixels = *aScan++ ^ color;
+		if (pixels)      // do no work if there is no edge
+			{
+			TInt bit = 31 + KTestBitCount;
+			for (;;)
+				{
+				TUint pix;
+				do
+					{
+					if ((bit-=KTestBitCount) < 0)
+						goto nextword;	// finished processing the word
+					// now examine the next 6 pixels
+					// break out if we have found an edge
+					pix=(pixels>>(31-bit))&KTestBitMask;
+					} while (pix==0);
+				// there is an edge, use the table to discover which pixel
+				bit+=lookup[pix];
+				// store the run-length
+				run-=bit;
+				WRITE_RLE(aRleEncoding,table,run);
+				// flip color and look for the next edge
+				color = ~color;
+				table=KRleWhite-table;
+				pixels=~pixels;
+				run = bit;
+				}
+			}
+		}
+	// store the final run
+	run-=KRunBias;
+	WRITE_RLE(aRleEncoding,table,run);
+	return aRleEncoding;
+	}
+
+LOCAL_C TUint8* RleEncoding (const TUint32 *aScanline,TInt aLength,TUint8* aRleEncoding)
+//
+// Justify the scanline into a full size buffer before encoding
+//
+	{
+	__ASSERT_DEBUG(aLength < (KFaxPixelsPerScanLine >> 3),User::Invariant());
+//
+	TUint32 justified[KFaxPixelsPerScanLine/32];
+//
+	TInt margin = ((KFaxPixelsPerScanLine >> 3) - aLength) / 2;
+	Mem::Fill (justified, sizeof(justified), 0xff);       // white fill
+	Mem::Copy ((TUint8*)justified + margin, aScanline, aLength);
+	return RleEncoding(justified,aRleEncoding);
+	}
+
+LOCAL_C TUint8* RleEncoding (const TDesC8& aScanLine, TUint8* aRleEncoding)
+//
+// Build the RLE encoding for aScanline, handling wrong-sized scanlines
+//
+	{
+	TInt len = aScanLine.Length ();
+	const TUint32 *scan = (const TUint32 *) aScanLine.Ptr ();
+	__ASSERT_DEBUG ((TUint (scan) & 3) == 0, Panic (EFaxEncodeScanlineAlignment));
+	if (len >= (KFaxPixelsPerScanLine >> 3))
+		return RleEncoding(scan + ((len - (KFaxPixelsPerScanLine >> 3)) >> 3),aRleEncoding);  // margin in words
+	else
+		return RleEncoding(scan,len,aRleEncoding);
+	}
+
+LOCAL_C void EncodeHuffman(TDes8 & anEncodedScanLine,TInt aTagCode,const TUint8* aRleEncoding,const TUint8* aRleEnd)
+//
+// Starting with the tag code, encode all codes in the rle data using the single huffman table
+//
+	{
+	TUint8 *t4 = (TUint8 *) anEncodedScanLine.Ptr ();
+	TUint8 *const e4 = t4;
+	// start with tag code
+	TCodeDef huff=KCodes[aTagCode];
+	TUint code=HUFFBITS(huff);
+	TInt bits=HUFFLEN(huff)-16;
+	while (aRleEncoding<aRleEnd)
+		{
+		__ASSERT_DEBUG (bits < 0, User::Invariant ());
+		TUint8 c=*aRleEncoding++;
+		TCodeDef huff=KCodes[c];
+		code|=HUFFBITS(huff)>>(bits+16);
+		bits+=HUFFLEN(huff);
+		if (bits<0)
+			continue;
+		*t4++=TUint8(code>>24);
+		*t4++=TUint8(code>>16);
+		code<<=16;
+		bits-=16;
+		}
+	if (bits>-16)
+		{	// flush out the remaining bits
+		*t4++=TUint8(code>>24);
+		if (bits>-8)
+			*t4++=TUint8(code>>16);
+		}
+	anEncodedScanLine.SetLength (t4 - e4);
+	}
+
+/********************************************************************/
+
+inline CFaxT4::CFaxT4 ()
+	{PageInitialize(EFaxNormal,EModifiedHuffman);}
+
+EXPORT_C CFaxT4 *CFaxT4::NewLC ()
+/** Constructs a CFaxT4 object, which provides utility functions to encode and 
+decode fax scan lines. 
+
+As is usual in Symbian OS, the only difference between this function and NewL() 
+is that this variant pushes the object to the cleanup stack.
+
+The new object is constructed with the default compression and resolution: 
+EModifiedHuffman and EFaxNormal respectively.
+
+@leave KErrNoMemory There is insufficient memory to perform the operation.
+@return A pointer to the newly created object. 
+@capability None
+*/
+	{
+	CFaxT4 *self = NewL ();
+	CleanupStack::PushL (self);
+	return self;
+	}
+
+EXPORT_C CFaxT4 *CFaxT4::NewL ()
+/** Constructs a CFaxT4 object, which provides utility functions to encode and 
+decode fax scan lines. 
+
+The function is exactly the same as NewLC() except that the new object is 
+popped from the cleanup stack.
+
+The new object is constructed with the default compression and resolution: 
+EModifiedHuffman and EFaxNormal respectively.
+
+@leave KErrNoMemory There is insufficient memory to perform the operation. 
+@return A pointer to the newly created object. 
+@capability None
+*/
+	{
+	return new (ELeave) CFaxT4;
+	}
+
+EXPORT_C void CFaxT4::PageInitialize (TFaxResolution aResolution, TFaxCompression aCompression, TInt aFlag2)
+/**
+Initialize fax page, set page parameters.
+
+@param   aResolution     defines fax resolution
+@param   aCompression    defines fax compression
+@param   aFlag2          reserved flag.
+@capability None
+*/
+	{
+	__ASSERT_ALWAYS (((aCompression == EModifiedHuffman) || (aCompression == EModifiedRead)), Panic (EFaxUnsupportedCompression));
+	iCompression = aCompression;
+	iResolution = aResolution;
+	iReservedFlag2 = aFlag2;
+	iK = iResolution == EFaxFine ? 4 : 2;
+	iLineCount = 1;
+	// an all-white reference line
+	iRef[0]=RLE_MAKEUP(KRleWhite,KFaxBytesPerScanLine);
+	iRef[1]=RLE_RUN(KRleWhite,0);
+	iEndRef=iRef+2;
+	}
+
+EXPORT_C void CFaxT4::EncodeScanLine (const TDesC8 & aScanLine, TDes8 & anEncodedScanLine)
+/** Encodes a scan line using either one dimensional Modified Huffman (MH) or two 
+dimensional Modified Read (MR) encoding. 
+
+The type of encoding used depends on the compression type specified when the 
+object was initialised - using PageInitialize(). If the object was not initialised, 
+then the default compression is MH.
+
+@param aScanLine The raw scan line to be encoded. 
+@param anEncodedScanLine On return, contains the encoded scan line. 
+@capability None
+*/
+	{
+	if (iCompression == EModifiedRead)
+		EncodeScanLine2D (aScanLine, anEncodedScanLine);
+	else
+		EncodeScanLine1D(aScanLine,anEncodedScanLine);
+	}
+
+EXPORT_C void CFaxT4::EncodeScanLine1D (const TDesC8 & aScanLine, TDes8 & anEncodedScanLine)
+/** Encodes a scan line using Modified Huffman compression.
+
+@param aScanLine The scan line to be encoded. 
+@param anEncodedScanLine On return, contains the MH encoded scan line. 
+@capability None
+*/
+	{
+	iEndRef=RleEncoding(aScanLine,iRef);
+	EncodeHuffman(anEncodedScanLine,iCompression == EModifiedHuffman ? KRleStd1D : KRleTag1D,iRef,iEndRef);
+	}
+
+EXPORT_C void CFaxT4::EncodeScanLine2D (const TDesC8 & aScanLine, TDes8 & anEncodedScanLine)
+/** Encodes a scan line using Modified Read compression.
+
+@param aScanLine The scan line to be encoded. 
+@param anEncodedScanLine On return, contains the MR encoded scan line. 
+@capability None
+*/
+	{
+	// initialize our own scan line
+	TInt lc=iLineCount-1;
+	if (lc==0)
+		{	// 1D reference line
+		iLineCount=iK;
+		EncodeScanLine1D(aScanLine,anEncodedScanLine);
+		}
+	else
+		{	// 2D line
+		iLineCount=lc;
+		DoEncodeScanLine2D(aScanLine,anEncodedScanLine);
+		}
+	}
+
+void CFaxT4::DoEncodeScanLine2D (const TDesC8 & aScanLine, TDes8 & aEncodedScanLine)
+	{
+	TUint8 rlebuf[KFaxPixelsPerScanLine*3/2 + 16]; // for output + reference line
+
+	// the buffer is big enough that the 2d coding output into the buffer will not
+	// catch the reference coding before it is used
+
+	// copy the reference line into the end of the stack buffer
+
+	TInt len=iEndRef-iRef;
+	TUint8* ref=rlebuf+sizeof(rlebuf)-len;
+	Mem::Copy(ref,iRef,len);
+
+	// Do the standard RLE encoding of the current line
+	iEndRef=RleEncoding(aScanLine,iRef);
+	const TUint8* cur=iRef;
+
+	TUint8* rle=rlebuf;
+	TInt a0=-1;			// previous edge on current line
+	TInt a1=0;			// current edge on current line
+	TInt b0;			// previous edge on reference line
+	TInt b1=0;			// current edge on reference line
+	TInt b2=0;			// look-ahead edge on reference line
+	TInt color=KRleWhite;	// color at a0 (initially white)
+
+	// the reference color is not tracked. Instead the number of reference edges
+	// traversed is monitored (modulo 2) to ensure that edge b1 is of the same
+	// color to a1 at "gotB2"
+
+	READ_RLE(cur,a1);		// find the first edge
+
+	for (;;)
+		{
+		do
+			{	// find the new current and next edges on reference line
+			b0=b1;
+			b1=b2;
+			if (b1==KFaxPixelsPerScanLine)
+				break;			// end of line
+			READ_RLE(ref,b2);
+refMove1:	//	find just the look-ahead edge on the reference line
+			b0=b1;
+			b1=b2;
+			if (b1==KFaxPixelsPerScanLine)
+				break;
+			READ_RLE(ref,b2);
+			} while(b1<=a0);		// ensure that we have the right reference edge
+
+gotB2:	if (b2 < a1)
+			{	// pass mode detected
+			*rle++=KRlePassMode;
+			a0=b2;	// move along by 2 edges
+			continue;
+			}
+
+		if (TUint(b1-a1+3)<=6u)
+			{	// vertical mode
+			*rle++=TUint8(KRleVertMode0 + (b1 - a1));
+			if (a1==KFaxPixelsPerScanLine)
+				break;		// complete
+			if (b0>a1)
+				{
+				// special case of vertical mode edge "cross-over"
+				// the next edge may match an earlier reference edge than this!
+				// rewind the reference line by 2 edges
+				// we know that [b0,b1] is small, and so only uses 1 byte in the rle
+				// we check for [b1,b2] requiring a makeup byte as well
+				ref-=2;
+				if (b2-b1>=64)
+					--ref;
+				b2=b0;
+				b1=0;	// no longer know b0, but this cannot happen again without traversing 2 edges
+				}
+			a0 = a1;	// traverse a single edge
+			READ_RLE(cur,a1);
+			color=KRleWhite-color;
+			goto refMove1;
+			}
+
+		// we must be in horizontal mode - write out the RLE codes for remainder
+		// and copy RLE codes for next edge from current coding
+
+		*rle++=KRleHorzMode;
+		a0=Max(0,a0);			// deal with start-effects (a0==-1)
+		TInt run=a1-a0;
+		WRITE_RLE(rle,color,run);
+		// copy the next run
+		if (a1==KFaxPixelsPerScanLine)
+			{	// complete, need a zero-length, other-color, run to finish
+			*rle++=RLE_RUN(KRleWhite-color,0);
+			break;
+			}
+		// copy the next RLE code directly from the current line
+		TInt x=*cur++;
+		__ASSERT_DEBUG((x&KRleWhite)==KRleWhite-color,User::Invariant());
+		if (x>=KRleMakeup)
+			{
+			*rle++=TUint8(x);
+			a1+=(x&KRleMakeupMask)<<5;
+			x=*cur++;
+			}
+		*rle++=TUint8(x);
+		a1+=x>>1;
+		if (a1==KFaxPixelsPerScanLine)
+			break;	// complete
+		a0=a1;
+		READ_RLE(cur,a1);	// traverse another edge
+		if (b1>a0)
+			goto gotB2;
+		}
+	EncodeHuffman(aEncodedScanLine,KRleTag2D,rlebuf,rle);
+	}
+
+EXPORT_C TInt CFaxT4::DecodeScanLine (TDes8 & aScanLine, const TDesC8 & anEncodedScanLine)
+/** Decodes a scan line. 
+
+The decoding method depends on the compression type specified when the object 
+was initialised - using PageInitialize(). If the object was not initialised, 
+then the scan line is decoded as Modified Huffman.
+
+The fax client can determine the type of compression used in a fax from its 
+header, and can hence use PageInitialize() to set the correct decoding method. 
+KErrUnderflow is returned if the wrong type of compression is specified.
+
+@param aScanLine On return, contains the decoded scan line. 
+@param anEncodedScanLine The encoded scan line to be decoded. 
+@return KErrNone if successful, otherwise another of the system-wide error 
+codes. 
+@capability None
+*/
+	{
+	if (iCompression == EModifiedHuffman)
+		return (DecodeScanLine1D (aScanLine, anEncodedScanLine));
+	else
+		return (DecodeScanLine2D (aScanLine, anEncodedScanLine));
+	}
+
+void CFaxT4::DecodeHuffman(const TDesC8 & aEncodedScanLine)
+	{
+	// If all goes wrong then the reference line is unchanged and will be
+	// used for the current line
+
+	const TUint8* t4=aEncodedScanLine.Ptr();
+	const TUint8* endt4=t4+aEncodedScanLine.Length();
+	TUint bits=0;
+
+	// store the basic RLE data locally, and copy to the member data if the decode
+	// is successful
+
+	TUint8 rlebuf[KFaxPixelsPerScanLine+4];
+	TUint8* rle=rlebuf;
+
+	// Keep track of where we have got to on the reference (previous) line
+	const TUint8* ref=iRef;
+	TInt b1=0;		// pixel position on the reference line
+	TInt a0=0;		// previous position on the current line
+	TInt a1=0;		// current position on the current line
+
+	// start decoding using the tag-tree, which finds the first 1-bit
+	// and then determines the encoding (1D or 2D) based on the next bit
+	const TNode* tree=KTagTree;
+
+	// "color" stores the current line color (in bit 0), the reference line
+	// color (in bit 1), and the number of white/black codes to expect (x4)
+	// if color<0, then we are in 2d-tree mode
+	// initially unused until the encoding type is known
+
+	TInt color=0;
+	TInt code;
+
+	for (;;)
+		{
+		// the structure of the following code maxmises the speed of the
+		// huffman decoder. Don't change it.
+		code = 0;		// start at the root of the tree
+nextBit2d:
+		if (((bits <<= 1) & 0x80000000)==0)
+			goto nextByte2d;		// run out of bits in the current byte
+decode2d:
+		code = CODE (tree, code, bits & 0x80);
+		if (ISBRANCH (code))
+			goto nextBit2d;			// a branch code
+
+		// We have the huffman code
+
+		if (code<KOurEol)
+			{	// the code was a white/black length code
+			__ASSERT_DEBUG(color>=0,User::Invariant());
+			TInt v=CODEVALUE(code);
+			a1+=v;
+			if (a1>KFaxPixelsPerScanLine)
+				return;		// overflow
+			if (v < 64)
+				{	// a run code (as opposed to make-up code). Emit the RLE
+				a0=a1-a0;
+				WRITE_RLE(rle,(color&1),a0);
+				a0=a1;
+				color^=KRleWhite;	// switch color
+				color-=4;			// one less white/black code
+				tree=color>=0 ? color&KRleWhite ? KWhiteTree : KBlackTree : KTwoTree;
+				}
+			continue;
+			}
+		if (code<KPassMode)
+			{
+			if (code == KHorzMode)
+				{	// expect two white/black codes to follow
+				color+=8;
+				tree = color&KRleWhite ? KWhiteTree : KBlackTree;
+				continue;
+				}
+			if (code==KTag1D)
+				{	// 1d decoding: set color to maximum positive value
+					// as all codes are standard white/black code.
+				color=KMaxTInt;		// current and reference color both 1 (white)
+				tree=KWhiteTree;
+				continue;
+				}
+			if (code==KTag2D)
+				{	// 2d decoding: set color negative to indicate 2d-tree
+				color=-1;			// current and reference color both 1 (white)
+				tree=KTwoTree;
+				continue;
+				}
+			if (code==KOurEol)
+				goto eol2d;
+			__ASSERT_DEBUG(code == KBadRun,User::Invariant());
+			return;			// bad run, give up
+			}
+
+		// The remaining 2D possibilities all require that we know the various 2D determinants
+		// so we proceed as follows :
+
+		// b0 tracks the previous "edge" in the reference line
+		TInt b0=0;
+		// find the next "edge" on the reference line after a1
+		// if we've just started decoding (rle==rlebuf), b1 boundary at 0 is correct
+		if (rle!=rlebuf)
+			{
+			while (b1<=a1)
+				{
+				color^=KRleWhite<<1;
+				b0=b1;
+				if (b1!=KFaxPixelsPerScanLine)
+					READ_RLE(ref,b1);
+				}
+			}
+		// the b1 "edge" must match the colors of a1, so move one more edge if
+		// the a0 color (color&1) is the same as the b1 color (color&2)
+		if (((color^(color>>1))&1)==0)
+			{
+			b0=b1;
+			if (b1!=KFaxPixelsPerScanLine)
+				READ_RLE(ref,b1);
+			color^=KRleWhite<<1;
+			}
+
+		// If the code is below PASSMODE then it is one of the vertical code words
+		// which are pretty easy to decipher as we have all the data. Vertical mode
+		// flips the colour and then continues
+
+		if (code==KPassMode)
+			{
+			// we need to identify the next reference "edge"
+			if (b1==KFaxPixelsPerScanLine)
+				return;		// overflow
+			READ_RLE(ref,b1);
+			if (b1==KFaxPixelsPerScanLine)
+				return;		// overflow
+			color^=KRleWhite<<1;
+			a1=b1;
+			continue;
+			}
+
+		__ASSERT_DEBUG(code>=KVtMode3n && code<=KVtMode3p,User::Invariant());
+		// vertical mode
+		a1=b1+(code-(KVtMode0));
+		if (a1>KFaxPixelsPerScanLine)
+			return;		// overflow
+		if (b0>a1)
+			{
+			// special case of vertical mode cross-over
+			// rewind the reference line to the previous "edge"
+			b1=b0;
+			--ref;
+			color^=KRleWhite<<1;
+			}
+		a0=a1-a0;
+		WRITE_RLE(rle,(color&1),a0);
+		a0=a1;
+		color^=KRleWhite;
+		}
+nextByte2d:
+	if (t4 < endt4)
+		{
+		bits = 0xff000000u | *t4++;
+		goto decode2d;
+		}
+eol2d:
+	if (a0==KFaxPixelsPerScanLine)
+		iEndRef=Mem::Copy(iRef,rlebuf,rle-rlebuf);
+	}
+
+EXPORT_C TInt CFaxT4::DecodeScanLine2D (TDes8 & aScanLine, const TDesC8 & aEncodedScanLine)
+/** Decodes a Modified Read encoded scan line.
+	
+@param aScanLine On return, contains the decoded scan line. 
+@param anEncodedScanLine The 2D encoded scan line to be decoded. 
+@return KErrNone if successful, KErrUnderflow if the scan line is encoded as 
+MR, otherwise another of the system-wide error codes. 
+@capability None
+*/
+	{
+	DecodeHuffman(aEncodedScanLine);
+//
+//	decode the RLE into the scanline
+//
+	aScanLine.SetLength (KFaxPixelsPerScanLine / 8);
+	TUint32 *scan = (TUint32 *) aScanLine.Ptr ();
+	__ASSERT_DEBUG ((TUint (scan) & 3) == 0, Panic (EFaxDecodeScanlineAlignment));
+
+	const TUint8* rle=iRef;
+	const TUint8* const end=iEndRef;
+
+	TUint color = ~0u;		// start white
+	TUint out = 0;			// output pixels in accumulation
+	TInt bits = 0;          // this is the number of used bits in out
+
+	while (rle<end)
+		{
+		TInt run=*rle++;
+		__ASSERT_DEBUG(TUint((run&1))==(color&1),User::Invariant());	// rle-data correct
+		if (run<KRleMakeup)
+			{	// run length code (x2)
+			out += color << bits;		// complete the current 32-bits
+			bits += run >> 1;			// add the run length
+			if (bits < 32)				// hasn't completed the word
+				out -= color << bits;	// remove the trailing bits
+			else
+				{
+				*scan++ = out;			// write the 32-bits
+				bits -= 64;
+				if (bits >= 0)
+					*scan++ = color;	// + another 32 bits
+				else
+					bits += 32;			// no extra
+				out = color - (color<<bits);	// bits remaining
+				}
+			color = ~color;				// swap color
+			}
+		else
+			{
+			// make-up code. (run-KRleMakeup)>>1 is the multiple of 64 bits
+			out += color << bits;		// complete the current 32-bits
+			*scan++ = out;				// output
+			*scan++ = color;			// +32 bits of color
+			for (run -= KRleMakeup+4;run >= 0;run -= 2)
+				{	// extra multiples of 64 bits
+				*scan++ = color;
+				*scan++ = color;
+				}
+			out = color - (color<<bits);	// remainder bits
+			}
+		}
+	return KErrNone;
+	}
+
+EXPORT_C TInt CFaxT4::DecodeScanLine1D (TDes8 & aScanLine, const TDesC8 & anEncodedScanLine)
+//
+// This could be done through DecodeScanLine2D, but this is an optimized version for 1D
+// The intermediate rle encoding is skipped
+//
+/** Decodes a Modified Huffman encoded scan line.
+
+@param aScanLine On return, contains the decoded scan line. 
+@param anEncodedScanLine The MH encoded scan line to be decoded. 
+@return KErrNone if successful, KErrUnderflow if the scan line is encoded as 
+MR, otherwise another of the system-wide error codes. 
+@capability None
+*/
+	{
+	const TUint8 *t4 = anEncodedScanLine.Ptr ();
+	const TUint8 *const endt4 = t4 + anEncodedScanLine.Length ();
+	//
+	aScanLine.SetLength (KFaxPixelsPerScanLine / 8);
+	TUint32 *scan = (TUint32 *) aScanLine.Ptr ();
+	__ASSERT_DEBUG ((TUint (scan) & 3) == 0, Panic (EFaxDecodeScanlineAlignment));
+	TUint out = 0;
+	TInt bits = 0;               // this is the number ofused bits
+	//
+	TInt dotsleft = KFaxPixelsPerScanLine;
+	const TNode *tree = KSynchTree;
+	TUint octet=0;
+	TUint color = 0xffffffffu;
+
+nextCode1d:
+	TInt code = 0;
+nextBit1d:
+	if (((octet <<= 1) & 0x80000000)==0)
+		goto nextByte1d;
+decode1d:
+	code = CODE (tree, code, octet & 0x80);
+	if (ISBRANCH (code))
+		goto nextBit1d;
+
+	// end of huffman code
+
+	if (code<KEndCode+0x40)
+		{
+		code-=KEndCode;
+		if ((dotsleft -= code) < 0)
+			return KErrOverflow;
+		out += color<<bits;
+		bits+=code;
+		if (bits<32)
+			out -= color<<bits;	// output word not full
+		else
+			{	// out is full
+			*scan++=out;
+			bits-=64;
+			if (bits>=0)
+				*scan++=color;
+			else
+				bits+=32;
+			out=color-(color<<bits);
+			}
+		color = ~color;
+		if (color)
+			tree=KWhiteTree;
+		else
+			tree=KBlackTree;
+		goto nextCode1d;
+		}
+	else if (code<=KEndCode+KMaxRun)
+		{	// makeup (multiple of 64)
+		code-=KEndCode+0x40;
+		if ((dotsleft -= code<<6) < 0)
+			return KErrOverflow;
+		out += color << bits;
+		*scan++=out;
+		*scan++=color;
+		for (code-=2;code>=0;--code)
+			{
+			*scan++=color;
+			*scan++=color;
+			}
+		out = color-(color<<bits);
+		goto nextCode1d;
+		}
+	else if (code == KOurEol)
+		goto eol1d;
+	else if (code == KStd1D)
+		{
+		tree=KWhiteTree;
+		goto nextCode1d;
+		}
+	else
+		{
+		__ASSERT_DEBUG (code == KBadRun, User::Invariant ());
+		return KErrCorrupt;
+		}
+nextByte1d:
+	if (t4 < endt4)
+		{
+		octet = 0xff000000u | *t4++;
+		goto decode1d;
+		}
+eol1d:
+	__ASSERT_DEBUG (dotsleft || (TUint8 *) scan - aScanLine.Ptr () == KFaxPixelsPerScanLine / 8, User::Invariant ());
+	return dotsleft ? KErrUnderflow : KErrNone;
+	}
+