--- /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;
+ }
+