diff -r 17af172ffa5f -r 630d2f34d719 fax/faxclientandserver/faxio/FAXIO.CPP --- a/fax/faxclientandserver/faxio/FAXIO.CPP Thu Aug 19 11:03:36 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,763 +0,0 @@ -// 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 -#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<> 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>(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=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>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> 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<>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<=0) - *scan++=color; - else - bits+=32; - out=color-(color<=0;--code) - { - *scan++=color; - *scan++=color; - } - out = color-(color<