kernel/eka/kernel/crash_gzip.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// e32\kernel\crash_gzip.cpp
// Wrapper class for using Zlib with the crash logger to create GZip 
// compatible output
// 
//

#include "crash_gzip.h"

IMPORT_C TInt64 CrashTime();

//********** NOTE ************************************************************
//	This wrapper depends heavily on the version of Zlib being 1.2.3.
//	If a different verison of Zlib is used then the fake alloc functions
//	will need to be checked carefully for changes in the buffer sizes etc.
//****************************************************************************

/** Name of the file containing the crash log
	@internalComponent
*/
_LIT8(KCrashLogFileName, "crashlog.txt");


static deflate_state State;				/** Store of current state of deflate*/
static TInt BufFlags=0;					/** Store of 'allocated' buffers flags*/

		
/**	Fake heap alloc function to pass static buffers to deflateInit2_
	@internalComponent
*/


static voidpf NonAllocFunc(voidpf , uInt items, uInt size)
	{
	
static TInt8 Buf1[KCrashZlibBuf1Size]; 	/** Static 'heap' buffer1*/
static TInt8 Buf2[KCrashZlibBuf2Size]; 	/** Static 'heap' buffer2*/
static TInt8 Buf3[KCrashZlibBuf3Size]; 	/** Static 'heap' buffer3*/
static TInt8 Buf4[KCrashZlibBuf4Size]; 	/** Static 'heap' buffer4*/

	int bytes = items*size;
	
	if(bytes == sizeof(deflate_state) && !(BufFlags&1))
		{BufFlags |= 1;
		return (voidpf)&State;
		}
	else if (bytes == KCrashZlibBuf1Size && !(BufFlags&2))
		{BufFlags |= 2;
		return (voidpf)Buf1;
		}
	else if (bytes == KCrashZlibBuf2Size && !(BufFlags&4))
		{BufFlags |= 4;
		return (voidpf)Buf2;
		}
	else if (bytes == KCrashZlibBuf3Size && !(BufFlags&8))
		{BufFlags |= 8;
		return (voidpf)Buf3;
		}
	else if (bytes == KCrashZlibBuf4Size && !(BufFlags&0x10))
		{BufFlags |= 0x10;
		return (voidpf)Buf4;
		}
	return Z_NULL;
	}

/**	Dummy free function to be used by deflate
	@internalComponent
*/
static void   NonFreeFunc(voidpf , voidpf ){};

	
/** Initialises deflate algorithm and sets the gzip header
	@internalComponent
*/
TBool MCrashGzip::Init()
	{
	iOutBufLen = 0;
	iMaxBytes = 0;
	iBytesOut = 0;

	memclr(&State, sizeof State);
	BufFlags=0;

	// set max number of out bytes using virtual method of the base class
	iMaxBytes = GetMaxLength();

	// ensure input buffer is empty and all of output buffer is accessible
	// Set deflate to point to the output buffer for output
	iInBuf.SetLength(0);
	iOutBuf.SetLength(KCrashGzipOutBufSize);
	iDeflateStrm.next_out = &iOutBuf[0];
	iDeflateStrm.avail_out = KCrashGzipOutBufSize;
	
	// pass the pseudo 'heap' allocation functions to deflate
    iDeflateStrm.zalloc = (alloc_func)NonAllocFunc;
    iDeflateStrm.zfree = (free_func)NonFreeFunc;
    iDeflateStrm.opaque = (voidpf)0;	
	
	// Initialise deflate to create a GZip compatible output
	TInt err=deflateInit2(&iDeflateStrm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 
						(KCrashZlibWinBits+16), KCrashZlibMemLvl,
						Z_DEFAULT_STRATEGY);
	if (err != Z_OK)
		{return EFalse;
		}
		
	// Set the GZIP header information
	static	gz_header gzHeader;				
	gzHeader.text = 0;
	
	// GZIP like Unix time starts from 1970AD when SystemTime starts from 0AD hence the adjustment.
	TInt64 secsSince0AD = CrashTime();;
	TInt64 secsSince1970AD = secsSince0AD - KYear1970ADInSeconds;

	gzHeader.time = (uLong) secsSince1970AD; 
	gzHeader.xflags = 0; 
	gzHeader.os = 255;
	gzHeader.extra = Z_NULL;
	gzHeader.name = (Bytef*) KCrashLogFileName().Ptr();
	gzHeader.name_max = KCrashLogFileName().Length();
	gzHeader.comment = Z_NULL;
	gzHeader.hcrc = 0;
	err = deflateSetHeader(&iDeflateStrm, &gzHeader);
	if (err != Z_OK )
		{return EFalse;
		}
	return ETrue;
	}	

TBool MCrashGzip::Write(const TDesC8& aDes)
	{
	// Point delfate to the new data to be compressed	
	iDeflateStrm.next_in = (Bytef*)aDes.Ptr();	
	iDeflateStrm.avail_in = aDes.Length();
	
	// Keep processing input data until it has all been processed or
	// the output limit has been reached.  Output limit is set to be the
	// max no. of bytes that been stored minus the number of bytes that deflate
	// would need to guarantee that it will be able to complete the GZIP file
	// and footer successfully
	while ( iDeflateStrm.avail_in > 0 && 
			(iMaxBytes == -1 || iBytesOut < iMaxBytes-KCrashGzipFooterMax-(KCrashGzipOutBufSize-(TInt)iDeflateStrm.avail_out)))
		{
		// perform compression of the log data
		// can't really do anything if this fails so just return truncated but the GZIP
		// file will be corrupt and no footer info etc.
		if (deflate(&iDeflateStrm, Z_NO_FLUSH) != Z_OK)
			{
			return ETrue;
			}
		
		// Was the output buffer filled?
		if (iDeflateStrm.avail_out == 0)
			{// output buffer full so write the data to the flash and empty it
			Out(iOutBuf);
			iBytesOut += KCrashGzipOutBufSize;
			// Set the any new compressed data to be added to the start of the output buffer
		    iDeflateStrm.next_out = &iOutBuf[0];
			iDeflateStrm.avail_out = KCrashGzipOutBufSize;
			}
		}
		
	// if all the data couldn't be output it was truncated
	return (iDeflateStrm.avail_in > 0)? (TBool)ETrue : (TBool)EFalse;
	}
	
void MCrashGzip::FlushEnd()
	{			
	// Force deflate to flush any buffered data until all buffered data
	// has been output by deflate indicated by it returning Z_STREAM_END
	iDeflateStrm.avail_in = 0;
	TInt err = ~Z_STREAM_END;
	while (err != Z_STREAM_END)
		{			
		err = deflate(&iDeflateStrm, Z_FINISH);
		
		// Update for any flushed data and write the new output data to flash
		iOutBuf.SetLength(KCrashGzipOutBufSize - iDeflateStrm.avail_out);
		Out(iOutBuf);
		iOutBuf.SetLength(KCrashGzipOutBufSize);
		iDeflateStrm.next_out = &iOutBuf[0];
		iDeflateStrm.avail_out = KCrashGzipOutBufSize;
		}
	
	// Stop the deflate algorithm
	deflateEnd(&iDeflateStrm);
	}
	
TUint32 MCrashGzip::GetDataCompressed()
	{
	return iDeflateStrm.total_in;
	}