//-------------------------------------------------------------------------
// Desc:	View database blocks.
// Tabs:	3
//
//		Copyright (c) 1992-2006 Novell, Inc. All Rights Reserved.
//
//		This program is free software; you can redistribute it and/or
//		modify it under the terms of version 2 of the GNU General Public
//		License as published by the Free Software Foundation.
//
//		This program is distributed in the hope that it will be useful,
//		but WITHOUT ANY WARRANTY; without even the implied warranty of
//		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//		GNU General Public License for more details.
//
//		You should have received a copy of the GNU General Public License
//		along with this program; if not, contact Novell, Inc.
//
//		To contact Novell about this file by physical or electronic mail,
//		you may find current contact information at www.novell.com
//
// $Id: viewblk.cpp 12345 2006-01-25 14:06:06 -0700 (Wed, 25 Jan 2006) dsanders $
//-------------------------------------------------------------------------

#include "view.h"

FSTATIC void InitStatusBits(
	FLMBYTE * StatusBytes);

FSTATIC void OrStatusBits(
	FLMBYTE * DestStatusBytes,
	FLMBYTE * SrcStatusBytes);

FSTATIC void SetStatusBit(
	FLMBYTE *			StatusBytes,
	eCorruptionType	eCorruptionCode);

FSTATIC FLMBOOL TestStatusBit(
	FLMBYTE *			StatusBytes,
	eCorruptionType	eCorruptionCode);

FSTATIC FLMINT OutputElmRecord(
	FLMUINT       Col,
	FLMUINT  *    RowRV,
	eColorType	  bc,
	eColorType	  fc,
	FLMUINT       LabelWidth,
	STATE_INFO *  StateInfo,
	FLMBYTE *     StatusBytes,
	FLMUINT       StatusOnlyFlag);

FSTATIC FLMINT OutBlkHdrExpNum(
	FLMUINT			Col,
	FLMUINT  *		RowRV,
	eColorType		bc,
	eColorType		fc,
	eColorType		mbc,
	eColorType		mfc,
	eColorType		sbc,
	eColorType		sfc,
	FLMUINT     	LabelWidth,
	FLMINT      	iLabelIndex,
	FLMUINT			FileNumber,
	FLMUINT     	FileOffset,
	FLMBYTE *   	ValuePtr,
	FLMUINT     	ValueType,
	FLMUINT     	ModType,
	FLMUINT     	ExpNum,
	FLMUINT     	IgnoreExpNum,
	FLMUINT     	Option);

FSTATIC void FormatBlkType(
	FLMBYTE *    TempBuf,
	FLMUINT      BlkType);

FSTATIC FLMINT OutputStatus(
	FLMUINT     Col,
	FLMUINT  *	RowRV,
	eColorType  bc,
	eColorType  fc,
	FLMUINT     LabelWidth,
	FLMINT      iLabelIndex,
	FLMBYTE *   StatusFlags);

FSTATIC FLMINT OutputHexValue(
	FLMUINT     Col,
	FLMUINT  *  RowRV,
	eColorType  bc,
	eColorType  fc,
	FLMINT		LabelIndex,
	FLMUINT		FileNumber,
	FLMUINT     FileOffset,
	FLMBYTE *   ValPtr,
	FLMUINT     ValLen,
	FLMUINT     CopyVal,
	FLMUINT		uiModFlag);

FSTATIC FLMINT OutputLeafElements(
	FLMUINT     Col,
	FLMUINT  *	RowRV,
	FLMBYTE *   BlkPtr,
	BLK_EXP_p   BlkExp,
	FLMBYTE *   BlkStatusRV,
	FLMUINT		StatusOnlyFlag,
	FLMBOOL		bEncrypted);

FSTATIC FLMINT OutputNonLeafElements(
	FLMUINT     Col,
	FLMUINT  *	RowRV,
	FLMBYTE *   BlkPtr,
	BLK_EXP_p   BlkExp,
	FLMBYTE *   BlkStatusRV,
	FLMUINT     StatusOnlyFlag,
	FLMBOOL		bEncrypted);

FSTATIC void SetSearchTopBottom(
	void
	);

extern FLMUINT	gv_uiTopLine;
extern FLMUINT	gv_uiBottomLine;

/********************************************************************
Desc: ?
*********************************************************************/
FSTATIC void InitStatusBits(
	FLMBYTE * StatusBytes
	)
{
	FLMUINT  i;

	if (StatusBytes != NULL)
	{
		for( i = 0; i < NUM_STATUS_BYTES; i++)
			StatusBytes [i] = 0;
	}
}

/********************************************************************
Desc: ?
*********************************************************************/
FSTATIC void OrStatusBits(
	FLMBYTE * DestStatusBytes,
	FLMBYTE * SrcStatusBytes
	)
{
	FLMUINT  i;

	if ((DestStatusBytes != NULL) && (SrcStatusBytes != NULL))
	{
		for( i = 0; i < NUM_STATUS_BYTES; i++)
			DestStatusBytes [i] |= SrcStatusBytes [i];
	}
}

/********************************************************************
Desc: ?
*********************************************************************/
FSTATIC void SetStatusBit(
	FLMBYTE *			StatusBytes,
	eCorruptionType	eCorruptionCode
	)
{
	FLMUINT   ByteOffset = ((FLMUINT)eCorruptionCode - 1) / 8;
	FLMBYTE   BitToSet = (FLMBYTE)0x80 >> (FLMBYTE)(((FLMUINT)eCorruptionCode - 1) % 8);

	if (StatusBytes != NULL)
		StatusBytes [ByteOffset] |= BitToSet;
}

/********************************************************************
Desc: ?
*********************************************************************/
FSTATIC FLMBOOL TestStatusBit(
	FLMBYTE *			StatusBytes,
	eCorruptionType	eCorruptionCode
	)
{
	if (eCorruptionCode == FLM_NO_CORRUPTION)
	{
		return( FALSE);
	}
	else
	{
		FLMUINT   ByteOffset = ((FLMUINT)eCorruptionCode - 1) / 8;
		FLMBYTE   BitToTest = (FLMBYTE)0x80 >> (FLMBYTE)(((FLMUINT)eCorruptionCode - 1) % 8);

		if (StatusBytes == NULL)
		{
			return( FALSE);
		}
		else
		{
			return( (StatusBytes [ByteOffset] & BitToTest) ? TRUE : FALSE);
		}
	}
}

/***************************************************************************
Name: OutputStatus
Desc: This routine outputs all of the status bits which were set for
		a block.  Each error discovered in a block will be displayed on
		a separate line.
*****************************************************************************/
FSTATIC FLMINT OutputStatus(
	FLMUINT     Col,
	FLMUINT  *	RowRV,
	eColorType	bc,
	eColorType	fc,
	FLMUINT     LabelWidth,
	FLMINT      iLabelIndex,
	FLMBYTE *   StatusFlags)
{
	FLMUINT	Row = *RowRV;
	FLMUINT	HadError = FALSE;
	FLMUINT	uiLoop;

	/* Output each error on a separate line */

	if (StatusFlags)
	{
		for( uiLoop = (FLMUINT)FLM_NO_CORRUPTION + 1; uiLoop < (FLMUINT)FLM_LAST_CORRUPT_ERROR; uiLoop++)
		{
			if (TestStatusBit( StatusFlags, (eCorruptionType)uiLoop))
			{
				HadError = TRUE;
				if (!ViewAddMenuItem( iLabelIndex, LabelWidth,
							VAL_IS_ERR_INDEX, (FLMUINT)uiLoop, 0,
							0, VIEW_INVALID_FILE_OFFSET, 0, MOD_DISABLED,
							Col, Row++, 0,
							FLM_RED, FLM_LIGHTGRAY,
							FLM_RED, FLM_LIGHTGRAY))
					return( 0);

				/* Set iLabelIndex to -1 so that it will not be displayed after */
				/* the first one. */

				iLabelIndex = -1;
			}
		}
	}

	/* If there were no errors in the block, just output an OK status */

	if (!HadError)
	{
		if (!ViewAddMenuItem( iLabelIndex, LabelWidth,
					VAL_IS_LABEL_INDEX, (FLMUINT)LBL_OK, 0,
					0, VIEW_INVALID_FILE_OFFSET, 0, MOD_DISABLED,
					Col, Row++, 0, bc, fc, bc, fc))
			return( 0);
	}
	*RowRV = Row;
	return( 1);
}

/********************************************************************
Desc: ?
*********************************************************************/
FSTATIC FLMINT OutputElmRecord(
	FLMUINT			Col,
	FLMUINT  *		RowRV,
	eColorType		bc,
	eColorType		fc,
	FLMUINT        LabelWidth,
	STATE_INFO *   StateInfo,
	FLMBYTE *      StatusBytes,
	FLMUINT        StatusOnlyFlag)
{
	eCorruptionType	eCorruptionCode;
	FLMUINT				SaveElmRecOffset;
	FLMBYTE				FOPStatusBytes [NUM_STATUS_BYTES];
	FLMUINT				FOPType;
	FLMUINT				FieldType;
	FLMUINT				Row = *RowRV;
	FLMUINT				FileOffset;
	FLMUINT				FileNumber;
	FLMUINT				FldOverhead;
	FLMBYTE *			FieldPtr;
	FLMUINT				FldFlags;

	for( ;;)
	{
		InitStatusBits( FOPStatusBytes);
		SaveElmRecOffset = StateInfo->uiElmRecOffset;
		FieldPtr = &StateInfo->pElmRec [SaveElmRecOffset];
		FileOffset = StateInfo->uiBlkAddress +
								 (StateInfo->pElmRec - StateInfo->pBlk) +
								 SaveElmRecOffset;
		FileNumber = FSGetFileNumber( StateInfo->uiBlkAddress);

		if ((eCorruptionCode = flmVerifyElmFOP( StateInfo)) != FLM_NO_CORRUPTION)
		{
			SetStatusBit( FOPStatusBytes, eCorruptionCode);
			SetStatusBit( StatusBytes, eCorruptionCode);
		}

		/* Output the field overhead */

		if (!StatusOnlyFlag)
		{
			Row++;

			/* First output the FOP type */

			switch( StateInfo->uiFOPType)
			{
				case FLM_FOP_CONT_DATA:
					FOPType = LBL_FOP_CONT;
					FldOverhead = 0;
					break;
				case FLM_FOP_STANDARD:
					FOPType = LBL_FOP_STD;
					FldOverhead = 2;
					break;
				case FLM_FOP_OPEN:
					FOPType = LBL_FOP_OPEN;
					FldFlags = FOP_GET_FLD_FLAGS( FieldPtr);
					FldOverhead = ((FOP_2BYTE_FLDNUM( FldFlags)) ? 3 : 2) +
									  ((FOP_2BYTE_FLDLEN( FldFlags)) ? 2 : 1);
					break;
				case FLM_FOP_TAGGED:
					FOPType = LBL_FOP_TAGGED;
					FldFlags = FOP_GET_FLD_FLAGS( FieldPtr);
					FldOverhead = ((FOP_2BYTE_FLDNUM( FldFlags)) ? 4 : 3) +
									  ((FOP_2BYTE_FLDLEN( FldFlags)) ? 2 : 1);
					break;
				case FLM_FOP_NO_VALUE:
					FOPType = LBL_FOP_NO_VALUE;
					FldFlags = FOP_GET_FLD_FLAGS( FieldPtr);
					FldOverhead = ((FOP_2BYTE_FLDNUM( FldFlags)) ? 3 : 2);
					break;
				case FLM_FOP_JUMP_LEVEL:
					FOPType = LBL_FOP_SET_LEVEL;
					FldOverhead = 1;
					break;
				case FLM_FOP_REC_INFO:
					FOPType = LBL_FOP_REC_INFO;
					FldFlags = FOP_GET_FLD_FLAGS( FieldPtr);
					FldOverhead = ((FOP_2BYTE_FLDLEN( FldFlags)) ? 3 : 2);
					break;
				case FLM_FOP_ENCRYPTED:
					FOPType = LBL_FOP_ENCRYPTED;
					FldFlags = 0;
					FldOverhead = 2;
					break;
				case FLM_FOP_BAD:
				default:
					FOPType = LBL_FOP_BAD;
					FldOverhead = 0;
					break;
			}
			if (!ViewAddMenuItem( LBL_FOP_TYPE, LabelWidth,
						VAL_IS_LABEL_INDEX, (FLMUINT)FOPType, 0,
						FileNumber, FileOffset, FldOverhead,
						(FLMBYTE)(MOD_BINARY | (FLMBYTE)(!FldOverhead
																 ? (FLMBYTE)MOD_DISABLED
																 : (FLMBYTE)0)),
						Col, Row++, 0, FLM_BLUE, FLM_LIGHTGRAY,
						FLM_BLUE, FLM_LIGHTGRAY))
				return( 0);

			/* Output the offset of the field within the element record */

			if (!ViewAddMenuItem( LBL_FIELD_OFFSET, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL,
						(FLMUINT)SaveElmRecOffset, 0,
						FileNumber, FileOffset, 0, MOD_DISABLED,
						Col, Row++, 0, bc, fc, bc, fc))
				return( 0);

			/* Output the field number, field type, and field level if applicable */

			if ((StateInfo->uiFOPType != FLM_FOP_CONT_DATA) &&
					(StateInfo->uiFOPType != FLM_FOP_JUMP_LEVEL) &&
					(StateInfo->uiFOPType != FLM_FOP_BAD) &&
					(StateInfo->uiFOPType != FLM_FOP_NEXT_DRN) &&
					(StateInfo->uiFOPType != FLM_FOP_REC_INFO) &&
					(eCorruptionCode != FLM_BAD_ELM_FLD_OVERHEAD))
			{
				if (!ViewAddMenuItem( LBL_FIELD_NUMBER, LabelWidth,
							VAL_IS_NUMBER | DISP_DECIMAL,
							(FLMUINT)StateInfo->uiFieldNum, 0,
							FileNumber, FileOffset, 0, MOD_DISABLED,
							Col, Row++, 0, bc, fc, bc, fc))
					return( 0);

				/* Output the field type */

				switch( StateInfo->uiFieldType)
				{
					case FLM_TEXT_TYPE:
						FieldType = LBL_TYPE_TEXT;
						break;
					case FLM_NUMBER_TYPE:
						FieldType = LBL_TYPE_NUMBER;
						break;
					case FLM_BINARY_TYPE:
						FieldType = LBL_TYPE_BINARY;
						break;
					case FLM_CONTEXT_TYPE:
						FieldType = LBL_TYPE_CONTEXT;
						break;
					default:
						FieldType = LBL_TYPE_UNKNOWN;
						break;
				}
				if (!ViewAddMenuItem( LBL_FIELD_TYPE, LabelWidth,
							VAL_IS_LABEL_INDEX, (FLMUINT)FieldType, 0,
							FileNumber, FileOffset, 0, MOD_DISABLED,
							Col, Row++, 0, bc, fc, bc, fc))
						return( 0);

				/* Output the field level */

				if (!ViewAddMenuItem( LBL_FIELD_LEVEL, LabelWidth,
							VAL_IS_NUMBER | DISP_DECIMAL,
							(FLMUINT)StateInfo->uiFieldLevel, 0,
							FileNumber, FileOffset, 0, MOD_DISABLED,
							Col, Row++, 0, bc, fc, bc, fc))
					return( 0);

				if (StateInfo->uiEncId)
				{
					if (!ViewAddMenuItem( LBL_ENC_ID, LabelWidth,
								VAL_IS_NUMBER | DISP_DECIMAL,
								(FLMUINT)StateInfo->uiEncId, 0,
								FileNumber, FileOffset, 0, MOD_DISABLED,
								Col, Row++, 0, bc, fc, bc, fc))
						return( 0);
				}
			}

			/* Output the jump level for the jump FOP */

			if (StateInfo->uiFOPType == FLM_FOP_JUMP_LEVEL)
			{
				if (!ViewAddMenuItem( LBL_JUMP_LEVEL, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL,
						(FLMUINT)StateInfo->uiJumpLevel, 0,
						FileNumber, FileOffset, 0x07, MOD_BITS | MOD_DECIMAL,
						Col, Row++, 0, bc, fc, bc, fc))
					return( 0);
			}

			/* Output the field data length */

			if (eCorruptionCode != FLM_BAD_ELM_FLD_OVERHEAD)
			{
				if (!ViewAddMenuItem( LBL_FIELD_LENGTH, LabelWidth,
							VAL_IS_NUMBER | DISP_DECIMAL,
							StateInfo->uiFOPDataLen, 0,
							FileNumber, FileOffset, 0, MOD_DISABLED,
							Col, Row++, 0, bc, fc, bc, fc))
					return( 0);
			}
		}

		/* Verify the field if it is entirely contained right here */

		if ((eCorruptionCode == FLM_NO_CORRUPTION) &&
			(StateInfo->uiFOPDataLen == (StateInfo->uiEncId
										? StateInfo->uiEncFieldLen
										: StateInfo->uiFieldLen) &&
				(StateInfo->uiFOPDataLen > 0) &&
				(StateInfo->uiFOPType != FLM_FOP_CONT_DATA)))
		{
			if (StateInfo->uiFOPType == FLM_FOP_REC_INFO)
			{
				eCorruptionCode = FLM_NO_CORRUPTION;
			}
			else
			{
				eCorruptionCode = flmVerifyField( StateInfo, StateInfo->pFOPData,
													 StateInfo->uiFOPDataLen,
													 StateInfo->uiFieldType);
			}
			if (eCorruptionCode != FLM_NO_CORRUPTION)
			{
				SetStatusBit( FOPStatusBytes, eCorruptionCode);
				SetStatusBit( StatusBytes, eCorruptionCode);
			}
		}

		/* Output the field status */

		if ((!StatusOnlyFlag) && (eCorruptionCode != FLM_NO_CORRUPTION))
		{
			if (!OutputStatus( Col, &Row, bc, fc, LabelWidth,
												 LBL_FIELD_STATUS, FOPStatusBytes))
				return( 0);
		}

		/* Output the data.  If we had a bad overhead error, output */
		/* the rest of the data in the element. */

		if ((eCorruptionCode == FLM_BAD_ELM_FLD_OVERHEAD) ||
			 ((eCorruptionCode != FLM_NO_CORRUPTION) &&
			  (StateInfo->uiElmRecOffset == SaveElmRecOffset)))
		{
			*RowRV = Row;
			if (StatusOnlyFlag)
				return( 1);
			return( OutputHexValue( Col, RowRV, bc, fc,
							(FLMUINT)((SaveElmRecOffset == 0)
									 ? (FLMUINT)LBL_RECORD
									 : (FLMUINT)LBL_FIELD_DATA),
							FileNumber, FileOffset,
							&StateInfo->pElmRec [SaveElmRecOffset],
							(FLMUINT)(StateInfo->uiElmRecLen - SaveElmRecOffset),
							FALSE, MOD_BINARY));
		}
		else if ((!StatusOnlyFlag) && (StateInfo->uiFOPDataLen))
		{
			if (!OutputHexValue( Col, &Row, bc, fc, LBL_FIELD_DATA,
						FSGetFileNumber( StateInfo->uiBlkAddress),
						FSGetFileOffset( StateInfo->uiBlkAddress) +
						(FLMUINT)(StateInfo->pFOPData - StateInfo->pBlk),
						StateInfo->pFOPData,
						StateInfo->uiFOPDataLen, FALSE, MOD_BINARY))
				return( 0);
		}

		/* See if we have reached the end of the element - or quit */
		/* if the element record offset is not changing */

		if (StateInfo->uiElmRecOffset >= StateInfo->uiElmRecLen)
		{
			*RowRV = Row;
			return( 1);
		}
	}
}


/***************************************************************************
Desc: This routine reads into memory a database block.  It will also
		allocate memory to hold the block if necessary.  The block will
		also be decrypted if necessary.
*****************************************************************************/
FLMINT ViewBlkRead(
	FLMUINT			BlkAddress,
	FLMBYTE **		BlkPtrRV,
	FLMUINT			ReadLen,
	FLMUINT16 *		pui16CalcChkSum,
	FLMUINT16 *		pui16BlkChkSum,
	FLMUINT *		puiBytesReadRV,
	FLMBOOL			bShowPartialReadError,
	FLMBOOL *		pbIsEncBlock,
	FLMBOOL			bDecryptBlock,
	FLMBOOL *		pbEncrypted
	)
{
	RCODE       rc;
	FLMBYTE *   BlkPtr;
	char			szErrMsg [80];

	/* First allocate memory to read the block into */
	/* if not already allocated */

	if (!(*BlkPtrRV))
	{
		if (RC_BAD( rc = f_alloc( ReadLen, BlkPtrRV)))
		{
			ViewShowRCError( "allocating memory to read block", rc);
			return( 0);
		}
	}
	BlkPtr = *BlkPtrRV;

	/* Read the block into memory - if block address is zero, don't */
	/* read the first byte of the file. */

	if (BlkAddress == 0)
	{
		BlkAddress++;
		*BlkPtr++ = 0xFF;
		ReadLen--;
	}
	
	if (RC_BAD( rc = gv_pSFileHdl->readBlock( BlkAddress, ReadLen,
												BlkPtr, puiBytesReadRV)))
	{
		if (rc == FERR_IO_END_OF_FILE)
		{
			rc = FERR_OK;
			f_memset( &BlkPtr [*puiBytesReadRV], 0xEE, ReadLen - *puiBytesReadRV);
			if (bShowPartialReadError)
			{
				if (!(*puiBytesReadRV))
				{
					ViewShowRCError( "reading block", FERR_IO_END_OF_FILE);
					return( 0);
				}
				else if (*puiBytesReadRV < ReadLen)
				{
					f_sprintf( szErrMsg,
						"Only %u bytes of data were read (requested %u)",
							(unsigned)*puiBytesReadRV, (unsigned)ReadLen);
					ViewShowError( szErrMsg);
				}
			}
		}
		else
		{
			ViewShowRCError( "reading block", rc);
			return( 0);
		}
	}

	if (pui16BlkChkSum)
	{
		*pui16BlkChkSum = (FLMUINT16)(((FLMUINT)BlkPtr [BH_CHECKSUM_HIGH] << 8) + 
												 BlkPtr [BH_CHECKSUM_LOW]);
	}

	/* Decrypt the block if necessary */

	if (pui16CalcChkSum != NULL)
	{
		if (FB2UW( &BlkPtr [BH_BLK_END]) >
				gv_ViewHdrInfo.FileHdr.uiBlockSize)
		{
			*pui16CalcChkSum = 0;
		}
		else
		{
			FLMBYTE		ucChecksumHigh = BlkPtr [BH_CHECKSUM_HIGH];
			FLMBYTE		ucChecksumLow  = BlkPtr [BH_CHECKSUM_LOW];

			BlkCheckSum( BlkPtr, CHECKSUM_SET, BlkAddress,
											gv_ViewHdrInfo.FileHdr.uiBlockSize);

			*pui16CalcChkSum = (FLMUINT16)(((FLMUINT)BlkPtr [BH_CHECKSUM_HIGH] << 8) + 
												 BlkPtr [BH_CHECKSUM_LOW]);

			BlkPtr [BH_CHECKSUM_HIGH] = ucChecksumHigh;
			BlkPtr [BH_CHECKSUM_LOW] = ucChecksumLow;

			// 3x Format demands we write over the checksum value.

			BlkPtr [BH_CHECKSUM_LOW] = (FLMBYTE) BlkAddress;
		}
	}
	
	if (pbEncrypted || pbIsEncBlock || bDecryptBlock)
	{
		FLMUINT	uiBlkType = BH_GET_TYPE( BlkPtr);
		FLMUINT	uiLfNum = FB2UW( &BlkPtr [BH_LOG_FILE_NUM]);
		FLMUINT	uiBufLen = getEncryptSize( BlkPtr);
		FLMUINT	uiEncLen = uiBufLen - BH_OVHD;
		LFILE *	pLFile;
		IXD *		pIxd;
		FDB *		pDb;
		FFILE *	pFile;

		if (pbEncrypted)
		{
			*pbEncrypted = FALSE;
		}
		if (pbIsEncBlock)
		{
			*pbIsEncBlock = FALSE;
		}
		
		if (uiEncLen && uiLfNum &&
			 uiBlkType != BHT_FREE &&
			 uiBlkType != BHT_LFH_BLK &&
		 	 uiBlkType != BHT_PCODE_BLK)
		{
			ViewGetDictInfo();
			if (gv_bViewHaveDictInfo)
			{
				pDb = (FDB *)gv_hViewDb;
				pFile = pDb->pFile;
				if (RC_OK( fdictGetIndex( pDb->pDict, pFile->bInLimitedMode,
								uiLfNum, &pLFile, &pIxd, TRUE)) &&
					 pIxd && pIxd->uiEncId)
				{
					if (pbEncrypted)
					{
						*pbEncrypted = TRUE;
					}
					if (pbIsEncBlock)
					{
						*pbIsEncBlock = TRUE;
					}
#ifdef FLM_USE_NICI
					if (!pFile->bInLimitedMode && bDecryptBlock)
					{
						F_CCS *	pCcs = (F_CCS *)pFile->pDictList->pIttTbl[ pIxd->uiEncId].pvItem; 

						flmAssert( pCcs);
						if (RC_OK( pCcs->decryptFromStore( &BlkPtr [BH_OVHD],
												uiEncLen, &BlkPtr [BH_OVHD], &uiEncLen)))
						{
							if (pbEncrypted)
							{
								*pbEncrypted = FALSE;
							}
						}
					}
#endif
				}
			}
		}
	}

	return( 1);
}

/***************************************************************************
Name: ViewGetLFH
Desc: This routine searches through the LFH blocks searching for the
		LFH of a particular logical file.
*****************************************************************************/
FLMINT ViewGetLFH(
	FLMUINT     lfNum,
	FLMBYTE *   lfhRV,
	FLMUINT  *	FileOffset
	)
{
	FLMUINT     BlkAddress;
	FLMUINT     BlkCount = 0;
	FLMBYTE *   BlkPtr = NULL;
	FLMUINT     EndOfBlock;
	FLMUINT     Pos;
	FLMUINT		uiBytesRead;
	FLMUINT     GotLFH = 0;

	/* Read the LFH blocks and get the information needed */
	/* If we read too many, the file is probably corrupt. */

	*FileOffset = 0;
	BlkAddress = gv_ViewHdrInfo.FileHdr.uiFirstLFHBlkAddr;
	while( BlkAddress != BT_END)
	{
		if ((!ViewBlkRead( BlkAddress, &BlkPtr,
											gv_ViewHdrInfo.FileHdr.uiBlockSize,
											NULL, NULL, &uiBytesRead, FALSE,
											NULL, FALSE, NULL)) ||
			 (!uiBytesRead))
			break;

		/* Count the blocks read to prevent too many from being read. */
		/* We don't want to get into an infinite loop if the database */
		/* is corrupted. */

		BlkCount++;

		/* Search through the block for the particular LFH which matches */
		/* the one we are looking for. */

		if (uiBytesRead <= BH_OVHD)
			EndOfBlock = BH_OVHD;
		else
		{
			EndOfBlock = FB2UW( &BlkPtr [BH_BLK_END]);
			if (EndOfBlock > gv_ViewHdrInfo.FileHdr.uiBlockSize)
				EndOfBlock = gv_ViewHdrInfo.FileHdr.uiBlockSize;
			if (EndOfBlock > uiBytesRead)
				EndOfBlock = uiBytesRead;
		}
		Pos = BH_OVHD;
		while( Pos < EndOfBlock)
		{
			FLMUINT		uiLfType;
			FLMUINT		uiLfNum;

			/* See if we got the one we wanted */

			uiLfType = BlkPtr [Pos + LFH_TYPE_OFFSET];
			uiLfNum = FB2UW( &BlkPtr [Pos + LFH_LF_NUMBER_OFFSET]);

			if ((uiLfType != LF_INVALID) && (lfNum == uiLfNum))
			{
				f_memcpy( lfhRV, &BlkPtr [Pos], LFH_SIZE);
				GotLFH = 1;
				*FileOffset = BlkAddress + Pos;
				break;
			}

			Pos += LFH_SIZE;
		}

		/* If we didn't end right on end of block, return */

		if ((Pos != EndOfBlock) || (GotLFH))
			break;

		/* If we have traversed too many blocks, things are probably corrupt */

		if (BlkCount > 100)
			break;
		if (BH_NEXT_BLK + 4 <= uiBytesRead)
			BlkAddress = FB2UD( &BlkPtr [BH_NEXT_BLK]);
		else
			BlkAddress = BT_END;
	}

	/* Be sure to free the block handle -- if one was allocated */

	f_free( &BlkPtr);
	return( GotLFH);
}

/***************************************************************************
Name: ViewGetLFName
Desc: This routine attempts to find an LFH for a particular logical
		file.  It then extracts the name from the LFH.
*****************************************************************************/
FLMINT ViewGetLFName(
	FLMBYTE *      lfName,
	FLMUINT        lfNum,
	FLMBYTE *      LFH,
	FLMUINT  *		FileOffset)
{
	FLMBYTE   TempBuf [40];

	if ((lfNum == 0) || (!ViewGetLFH( lfNum, LFH, FileOffset)))
	{
		*FileOffset = 0;
		f_sprintf( (char *)TempBuf, "lfNum=%u", (unsigned)lfNum);
		f_strcpy( (char *)lfName, (const char *)TempBuf);
		return( 0);
	}
	else
	{
		TempBuf [0] = 0;
		f_sprintf( (char *)(&TempBuf [f_strlen( (const char *)TempBuf)]), ", lfNum=%u", (unsigned)lfNum);
		f_strcpy( (char *)lfName, (const char *)TempBuf);
		return( 1);
	}
}

/***************************************************************************
Name: OutBlkHdrExpNum
Desc: This routine outputs one of the number fields in the block
		header.  It checks the number against an expected value, and if
		the number does not match the expected value also outputs the
		value which was expected.  This routine is used to output values
		in the block header where we are expected certain values.
*****************************************************************************/
FSTATIC FLMINT OutBlkHdrExpNum(
	FLMUINT		Col,
	FLMUINT  *	RowRV,
	eColorType	bc,
	eColorType	fc,
	eColorType	mbc,
	eColorType	mfc,
	eColorType	sbc,
	eColorType	sfc,
	FLMUINT     LabelWidth,
	FLMINT      iLabelIndex,
	FLMUINT		FileNumber,
	FLMUINT     FileOffset,
	FLMBYTE *   ValuePtr,
	FLMUINT     ValueType,
	FLMUINT     ModType,
	FLMUINT     ExpNum,
	FLMUINT     IgnoreExpNum,
	FLMUINT     Option)
{
	FLMUINT     Row = *RowRV;
	FLMUINT		Num = 0;

	if (!Option)
	{
		mbc = sbc = bc;
		mfc = sfc = fc;
	}
	switch( ModType & 0x0F)
	{
		case MOD_FLMUINT:
			Num = FB2UD( ValuePtr);
			break;
		case MOD_FLMUINT16:
			Num = FB2UW( ValuePtr);
			break;
		case MOD_FLMBYTE:
			Num = *ValuePtr;
			break;
		case MOD_BH_ADDR:
			Num = FB2UD( ValuePtr );/* & 0xFFFFFF00;*/  /* Could use GET_BH_ADDR() */
																/* But pass in offset */
			break;   
	}
	if (!ViewAddMenuItem( iLabelIndex, LabelWidth,
				ValueType, Num, 0,
				FileNumber, FileOffset, 0, ModType,
				Col, Row++, Option, mbc, mfc, sbc, sfc))
		return( 0);

	if ((ExpNum != IgnoreExpNum) && (Num != ExpNum))
	{
		if (!ViewAddMenuItem( LBL_EXPECTED, 0,
					ValueType, ExpNum, 0,
					0, VIEW_INVALID_FILE_OFFSET, 0, MOD_DISABLED,
					Col + LabelWidth + 1, Row++, 0,
					FLM_RED, FLM_LIGHTGRAY,
					FLM_RED, FLM_LIGHTGRAY))
			return( 0);
	}
	*RowRV = Row;
	return( 1);
}

/***************************************************************************
Name:    FormatBlkType
Desc:    This routine formats a block's type into ASCII.
*****************************************************************************/
FSTATIC void FormatBlkType(
	FLMBYTE *   TempBuf,
	FLMUINT		BlkType
	)
{
	FLMBYTE   TempBuf1 [30];

	switch( BlkType)
	{
		case BHT_FREE:
			f_strcpy( (char *)TempBuf, "Free");
			break;
		case BHT_LEAF:
			f_strcpy( (char *)TempBuf, "Leaf");
			break;
		case BHT_NON_LEAF:
			f_strcpy( (char *)TempBuf, "Non-Leaf 3x");
			break;
		case BHT_NON_LEAF_DATA:
			f_strcpy( (char *)TempBuf, "Non-Leaf Data");
			break;
		case BHT_NON_LEAF_COUNTS:
			f_strcpy( (char *)TempBuf, "Non-Leaf /w Counts");
			break;
		case BHT_LFH_BLK:
			f_strcpy( (char *)TempBuf, "LFH");
			break;
		case BHT_PCODE_BLK:
			f_strcpy( (char *)TempBuf, "PCODE");
			break;
		default:
			f_sprintf( (char *)TempBuf1, "Unknown Type: %u", (unsigned)BlkType);
			f_strcpy( (char *)TempBuf, (const char *)TempBuf1);
			break;
	}
}

/***************************************************************************
Name:    ViewOutBlkHdr
Desc:    This routine outputs a block's header.
*****************************************************************************/
FLMINT ViewOutBlkHdr(
	FLMUINT     Col,
	FLMUINT  *	RowRV,
	FLMBYTE *   BlkPtr,
	BLK_EXP_p   BlkExp,
	FLMBYTE *   BlkStatus,
	FLMUINT16   ui16CalcChkSum,
	FLMUINT16	ui16BlkChkSum
	)
{
	FLMUINT     LabelWidth = 35;
	FLMUINT     Row = *RowRV;
	FLMBYTE		TempBuf [80];
	FLMUINT		BlkAddress;
	FLMUINT		EndOfBlock;
	FLMUINT		BytesUsed;
	FLMUINT		PercentFull;
	FLMUINT     Option;
	eColorType	bc = FLM_BLACK;
	eColorType	fc = FLM_LIGHTGRAY;
	eColorType	mbc = FLM_BLACK;
	eColorType	mfc = FLM_WHITE;
	eColorType	sbc = FLM_BLUE;
	eColorType	sfc = FLM_WHITE;
	FLMBYTE		lfLFH [LFH_SIZE];
	FLMBYTE		lfName [80];
	FLMUINT		lfNum;
	FLMUINT		lfType;
	FLMUINT		TempFileOffset;
	FLMBYTE		bySaveChar;

	/* Output the block Header address */

	if (!OutBlkHdrExpNum( Col, &Row, FLM_RED, FLM_LIGHTGRAY,
			FLM_RED, FLM_WHITE, sbc, sfc,
			LabelWidth, LBL_BLOCK_ADDRESS_BLOCK_HEADER,
			FSGetFileNumber( BlkExp->BlkAddr), 
			FSGetFileOffset( BlkExp->BlkAddr), &BlkPtr [BH_ADDR],
			VAL_IS_NUMBER | DISP_HEX_DECIMAL,
			MOD_BH_ADDR | MOD_HEX,
			BlkExp->BlkAddr, 0, 0))
		return( 0);

	/* Adjust column so rest of header is indented */

	Col += 2;
	LabelWidth -= 2;

	/* Output the previous block address */

	if (FB2UD( &BlkPtr [BH_PREV_BLK]) == BT_END)
		Option = 0;
	else
		Option = PREV_BLOCK_OPTION;
	if (!OutBlkHdrExpNum( Col, &Row, bc, fc, mbc, mfc, sbc, sfc,
				LabelWidth, LBL_PREVIOUS_BLOCK_ADDRESS,
				FSGetFileNumber( BlkExp->BlkAddr), 
				FSGetFileOffset( BlkExp->BlkAddr) + BH_PREV_BLK,
				&BlkPtr [BH_PREV_BLK],
				VAL_IS_NUMBER | DISP_HEX_DECIMAL,
				MOD_FLMUINT | MOD_HEX,
				BlkExp->PrevAddr, 0, Option))
		return( 0);

	/* Output the next block address */

	if (FB2UD( &BlkPtr [BH_NEXT_BLK]) == BT_END)
		Option = 0;
	else
		Option = NEXT_BLOCK_OPTION;
	if (!OutBlkHdrExpNum( Col, &Row, bc, fc, mbc, mfc, sbc, sfc,
				LabelWidth, LBL_NEXT_BLOCK_ADDRESS,
				FSGetFileNumber( BlkExp->BlkAddr), 
				FSGetFileOffset( BlkExp->BlkAddr) + BH_NEXT_BLK,
				&BlkPtr [BH_NEXT_BLK],
				VAL_IS_NUMBER | DISP_HEX_DECIMAL,
				MOD_FLMUINT | MOD_HEX,
				BlkExp->NextAddr, 0, Option))
		return( 0);

	/* Output the logical file this block belongs to - if any */

	lfNum = FB2UW( &BlkPtr [BH_LOG_FILE_NUM]);
	if (!ViewGetLFName( lfName, lfNum, lfLFH, &TempFileOffset))
	{
		lfType = LF_INVALID;
		Option = 0;
	}
	else
	{
		lfType = lfLFH [LFH_TYPE_OFFSET];
		Option = LOGICAL_FILE_OPTION | lfNum;
	}
	if ((BlkExp->LfNum != 0) && (lfNum != BlkExp->LfNum))
		f_sprintf( (char *)TempBuf, "%s (Expected %u)", lfName, (unsigned)BlkExp->LfNum);
	else
		f_strcpy( (char *)TempBuf, (const char *)lfName);
	if (!ViewAddMenuItem( LBL_BLOCK_LOGICAL_FILE_NAME, LabelWidth,
				VAL_IS_TEXT_PTR,
				(FLMUINT)((FLMBYTE *)(&TempBuf [0])), 0,
				FSGetFileNumber( BlkExp->BlkAddr),
				FSGetFileOffset( BlkExp->BlkAddr) + BH_LOG_FILE_NUM, 0,
				MOD_FLMUINT | MOD_DECIMAL,
				Col, Row++, Option,
				!Option ? bc : mbc,
				!Option ? fc : mfc,
				!Option ? bc : sbc,
				!Option ? fc : sfc))
		return( 0);

	/* Output the logical file type */

	if (lfType != LF_INVALID)
	{
		FormatLFType( TempBuf, lfType);
		if (!ViewAddMenuItem( LBL_BLOCK_LOGICAL_FILE_TYPE, LabelWidth,
					VAL_IS_TEXT_PTR,
					(FLMUINT)((FLMBYTE *)(&TempBuf [0])), 0,
					0, VIEW_INVALID_FILE_OFFSET, 0, MOD_DISABLED,
					Col, Row++, 0, bc, fc, bc, fc))
			return( 0);
	}

	/* Output the block type */

	FormatBlkType( TempBuf, BH_GET_TYPE( BlkPtr));
	if (BH_IS_ROOT_BLK( BlkPtr))
		f_strcpy( (char *)&TempBuf [f_strlen( (const char *)TempBuf)], " (Root)");
	if (BH_GET_TYPE( BlkPtr) != (FLMBYTE) BlkExp->Type)
	{
		f_strcpy( (char *)&TempBuf [f_strlen( (const char *)TempBuf)], ", Expecting ");
		FormatBlkType( &TempBuf [f_strlen( (const char *)TempBuf)], BlkExp->Type);
	}
	if (!ViewAddMenuItem( LBL_BLOCK_TYPE, LabelWidth,
			VAL_IS_TEXT_PTR,
			(FLMUINT)((FLMBYTE *)(&TempBuf [0])), 0,
			FSGetFileNumber( BlkExp->BlkAddr),
			FSGetFileOffset( BlkExp->BlkAddr) + BH_TYPE, 0,
			MOD_FLMBYTE | MOD_HEX,
			Col, Row++, 0, bc, fc, bc, fc))
		return( 0);

	/* Output the level in the B-TREE */

	if (!OutBlkHdrExpNum( Col, &Row, bc, fc, mbc, mfc, sbc, sfc,
			LabelWidth, LBL_B_TREE_LEVEL,
			FSGetFileNumber( BlkExp->BlkAddr), 
			FSGetFileOffset( BlkExp->BlkAddr) + BH_LEVEL,
			&BlkPtr [BH_LEVEL],
			VAL_IS_NUMBER | DISP_DECIMAL,
			MOD_FLMBYTE | MOD_DECIMAL,
			(FLMUINT)BlkExp->Level, (FLMUINT)0xFF, 0))
		return( 0);

	/* Output the end of the block */

	EndOfBlock = FB2UW( &BlkPtr [BH_BLK_END]);
	if (!ViewAddMenuItem( LBL_BLOCK_END, LabelWidth,
				VAL_IS_NUMBER | DISP_DECIMAL,
				(FLMUINT)EndOfBlock, 0,
				FSGetFileNumber( BlkExp->BlkAddr),
				FSGetFileOffset( BlkExp->BlkAddr) + BH_BLK_END, 0,
				MOD_FLMUINT | MOD_DECIMAL,
				Col, Row++, 0, bc, fc, bc, fc))
		return( 0);

	/* Output the percent full */

	BytesUsed = EndOfBlock - BH_OVHD;
	if ((!BytesUsed) || (EndOfBlock < BH_OVHD))
		PercentFull = 0;
	else if (EndOfBlock > gv_ViewHdrInfo.FileHdr.uiBlockSize)
		PercentFull = 100;
	else
		PercentFull = ((FLMUINT)(BytesUsed) * (FLMUINT)(100)) /
				 (FLMUINT)(gv_ViewHdrInfo.FileHdr.uiBlockSize - BH_OVHD);
	if (!ViewAddMenuItem( LBL_PERCENT_FULL, LabelWidth,
			VAL_IS_NUMBER | DISP_DECIMAL,
			(FLMUINT)PercentFull, 0,
			0, VIEW_INVALID_FILE_OFFSET, 0, MOD_DISABLED,
			Col, Row++, 0, bc, fc, bc, fc))
		return( 0);

	/* Output the block transaction ID */

	if (!ViewAddMenuItem( LBL_BLOCK_TRANS_ID, LabelWidth,
				VAL_IS_NUMBER | DISP_DECIMAL,
				FB2UD( &BlkPtr [BH_TRANS_ID]), 0,
				FSGetFileNumber( BlkExp->BlkAddr),
				FSGetFileOffset( BlkExp->BlkAddr) + BH_TRANS_ID, 0,
				MOD_FLMUINT | MOD_DECIMAL,
				Col, Row++, 0, bc, fc, bc, fc))
		return( 0);

	/* Output the encryption flag */

	if (!ViewAddMenuItem( LBL_BLOCK_ENCRYPTED, LabelWidth,
			VAL_IS_LABEL_INDEX,
			(BlkPtr [BH_ENCRYPTED])
			? (FLMUINT)LBL_YES
			: (FLMUINT)LBL_NO, 0,
			FSGetFileNumber( BlkExp->BlkAddr),
			FSGetFileOffset( BlkExp->BlkAddr) + BH_ENCRYPTED, 0, 
			MOD_DISABLED | MOD_FLMBYTE,
			Col, Row++, 0, bc, fc, bc, fc))
		return( 0);

	/* Output the old block image address */

	BlkAddress = FB2UD( &BlkPtr [BH_PREV_BLK_ADDR]);
	if ((BlkAddress == BT_END) || (BlkAddress == 0) ||
			(FB2UD( &BlkPtr [BH_TRANS_ID]) <=
				gv_ViewHdrInfo.LogHdr.uiCurrTransID))
		Option = 0;
	else
		Option = PREV_BLOCK_IMAGE_OPTION;
	if (!ViewAddMenuItem( LBL_OLD_BLOCK_IMAGE_ADDRESS, LabelWidth,
				VAL_IS_NUMBER | DISP_HEX_DECIMAL,
				BlkAddress, 0,
				FSGetFileNumber( BlkExp->BlkAddr),
				FSGetFileOffset( BlkExp->BlkAddr) + BH_PREV_BLK_ADDR, 0,
				MOD_FLMUINT | MOD_HEX,
				Col, Row++, Option,
				!Option ? bc : mbc,
				!Option ? fc : mfc,
				!Option ? bc : sbc,
				!Option ? fc : sfc))
		return( 0);

	/* Output the old block image transaction ID */

	if (!ViewAddMenuItem( LBL_OLD_BLOCK_IMAGE_TRANS_ID, LabelWidth,
				VAL_IS_NUMBER | DISP_DECIMAL,
				FB2UD( &BlkPtr [BH_PREV_TRANS_ID]), 0,
				FSGetFileNumber( BlkExp->BlkAddr),
				FSGetFileOffset( BlkExp->BlkAddr) + BH_PREV_TRANS_ID, 0,
				MOD_FLMUINT | MOD_DECIMAL,
				Col, Row++, 0, bc, fc, bc, fc))
		return( 0);

	/* Output the low byte of the block checksum */

	bySaveChar = (FLMBYTE)(ui16BlkChkSum & 0x00FF);
	if (!OutBlkHdrExpNum( Col, &Row, bc, fc, mbc, mfc, sbc, sfc,
			LabelWidth, LBL_BLOCK_CHECKSUM_LOW,
			FSGetFileNumber( BlkExp->BlkAddr), 
			FSGetFileOffset( BlkExp->BlkAddr) + BH_CHECKSUM_LOW,
			&bySaveChar,
			VAL_IS_NUMBER | DISP_DECIMAL,
			MOD_FLMBYTE | MOD_DECIMAL,
			(FLMUINT)((ui16BlkChkSum)
						 ? (FLMUINT)(ui16CalcChkSum & 0x00FF)
						 : (FLMUINT)0), 0, 0))
	{
		BlkPtr [BH_CHECKSUM_LOW] = bySaveChar;
		return( 0);
	}

	/* Output the high byte of the block checksum */

	bySaveChar = (FLMBYTE)(ui16BlkChkSum >> 8);
	if (!OutBlkHdrExpNum( Col, &Row, bc, fc, mbc, mfc, sbc, sfc,
			LabelWidth, LBL_BLOCK_CHECKSUM_HIGH,
			FSGetFileNumber( BlkExp->BlkAddr), 
			FSGetFileOffset( BlkExp->BlkAddr) + BH_CHECKSUM_HIGH,
			&bySaveChar,
			VAL_IS_NUMBER | DISP_DECIMAL,
			MOD_FLMBYTE | MOD_DECIMAL,
			(FLMUINT)((ui16BlkChkSum)
						 ? (FLMUINT)(ui16CalcChkSum >> 8)
						 : (FLMUINT)0), 0, 0))
		return( 0);

	/* Output the flags which indicate the state of the block */

	if (!OutputStatus( Col, &Row, bc, fc, LabelWidth, LBL_BLOCK_STATUS,
										 BlkStatus))
		return( 0);

	*RowRV = Row + 1;
	return( 1);
}

/***************************************************************************
Name: ViewAvailBlk
Desc: This routine displays a block in the AVAIL list.
*****************************************************************************/
FLMINT ViewAvailBlk(
	FLMUINT		ReadAddress,
	FLMUINT		BlkAddress,
	FLMBYTE **	BlkPtrRV,
	BLK_EXP_p	BlkExp
	)
{
	FLMINT				iRc = 0;
	FLMUINT				Row;
	FLMUINT				Col;
	FLMBYTE *			BlkPtr;
	FLMBYTE				BlkStatus [NUM_STATUS_BYTES];
	STATE_INFO			StateInfo;
	FLMBOOL				bStateInitialized = FALSE;
	BLOCK_INFO			BlockInfo;
	eCorruptionType	eCorruptionCode;
	FLMUINT16			ui16CalcChkSum;
	FLMUINT16			ui16BlkChkSum;
	FLMUINT				uiBytesRead;

	/* Read the block into memory */

	if (!ViewBlkRead( ReadAddress, BlkPtrRV,
										gv_ViewHdrInfo.FileHdr.uiBlockSize,
										&ui16CalcChkSum, &ui16BlkChkSum, &uiBytesRead, TRUE,
										NULL, FALSE, NULL))
	{
		goto Exit;
	}
	BlkPtr = *BlkPtrRV;

	if (!ViewMenuInit( "AVAIL Block"))
	{
		goto Exit;
	}

	/* Output the block header first */

	Row = 0;
	Col = 5;
	BlkExp->Type = BHT_FREE;
	BlkExp->LfNum = 0;
	BlkExp->BlkAddr = BlkAddress;
	BlkExp->Level = 0xFF;

	/* Setup the STATE variable for processing through the block */

	InitStatusBits( BlkStatus);
	flmInitReadState( &StateInfo, &bStateInitialized,
							gv_ViewHdrInfo.FileHdr.uiVersionNum,
							(gv_bViewDbInitialized)
							? (FDB *)gv_hViewDb
							: (FDB *)NULL, NULL, 0, BHT_FREE, NULL);
	StateInfo.uiBlkAddress = BlkAddress;
	StateInfo.pBlk = BlkPtr;

	if ((eCorruptionCode = flmVerifyBlockHeader( &StateInfo, &BlockInfo,
											 gv_ViewHdrInfo.FileHdr.uiBlockSize,
											 BlkExp->NextAddr,
											 0, (FLMBOOL)(StateInfo.pDb != NULL
															  ? TRUE
															  : FALSE), TRUE)) != FLM_NO_CORRUPTION)
		SetStatusBit( BlkStatus, eCorruptionCode);

	if (!ViewOutBlkHdr( Col, &Row, BlkPtr, BlkExp, BlkStatus,
								ui16CalcChkSum, ui16BlkChkSum))
	{
		goto Exit;
	}
	iRc = 1;
Exit:
	if (bStateInitialized && StateInfo.pRecord)
	{
		StateInfo.pRecord->Release();
		StateInfo.pRecord = NULL;
	}
	return( iRc);
}

/***************************************************************************
Name: OutputHexValue
Desc: This routine outputs a stream of FLMBYTEs in hex format.  This
		routine is used to output key values and records within an
		element.
*****************************************************************************/
FSTATIC FLMINT OutputHexValue(
	FLMUINT     Col,
	FLMUINT  *	RowRV,
	eColorType	bc,
	eColorType	fc,
	FLMINT      iLabelIndex,
	FLMUINT		FileNumber,
	FLMUINT     FileOffset,
	FLMBYTE *   ValPtr,
	FLMUINT     ValLen,
	FLMUINT     CopyVal,
	FLMUINT		uiModFlag)
{
	FLMUINT     Row = *RowRV;
	FLMUINT     BytesPerLine = MAX_HORIZ_SIZE( Col + 3);
	FLMUINT		BytesProcessed = 0;
	FLMUINT		NumBytes;
	
	if (!ValLen)
	{
		return( 1);
	}

	if (!ViewAddMenuItem( iLabelIndex, 0,
								VAL_IS_EMPTY, 0, 0,
								FileNumber, FileOffset, 0, MOD_DISABLED,
								Col, Row++, 0, bc, fc, bc, fc))
		return( 0);
	Col += 2;
	while( BytesProcessed < ValLen)
	{
		if ((NumBytes = ValLen - BytesProcessed) > BytesPerLine)
			NumBytes = BytesPerLine;

		/* Output the line */

		if (!ViewAddMenuItem( -1, 0,
					(FLMBYTE)((CopyVal)
								? (FLMBYTE)VAL_IS_BINARY
								: (FLMBYTE)VAL_IS_BINARY_PTR),
					(FLMUINT)ValPtr, NumBytes,
					FileNumber, FileOffset, NumBytes, uiModFlag,
					Col, Row++, 0, bc, fc, bc, fc))
			return( 0);
		FileOffset += (FLMUINT)NumBytes;
		BytesProcessed += NumBytes;
		ValPtr += NumBytes;
	}
	*RowRV = Row;
	return( 1);
}

/***************************************************************************
Name:    OutputLeafElements
Desc:    This routine outputs the elements in a LEAF block.
*****************************************************************************/
FSTATIC FLMINT OutputLeafElements(
	FLMUINT     Col,
	FLMUINT  *  RowRV,
	FLMBYTE *   BlkPtr,
	BLK_EXP_p   BlkExp,
	FLMBYTE *   BlkStatusRV,
	FLMUINT     StatusOnlyFlag,
	FLMBOOL		bEncrypted
	)
{
	FLMINT				iRc = 0;
	FLMUINT				LabelWidth = 30;
	eColorType			bc = FLM_BLACK;
	eColorType			fc = FLM_LIGHTGRAY;
	FLMUINT				Row = *RowRV;
	FLMUINT				ElementCount = 0;
	eCorruptionType	eCorruptionCode;
	FLMUINT				LfType = LF_INVALID;
	FLMBYTE				ElmStatus [NUM_STATUS_BYTES];
	STATE_INFO			StateInfo;
	FLMBOOL				bStateInitialized = FALSE;
	BLOCK_INFO			BlockInfo;
	FLMBYTE				KeyBuffer [MAX_KEY_SIZ];
	LFILE *				pLFile = NULL;
	LF_HDR				LogicalFile;
	LF_STATS				LfStats;
	LF_HDR *				pLogicalFile = NULL;

	if (BlkExp->LfNum == 0)
		BlkExp->LfNum = FB2UW( &BlkPtr [BH_LOG_FILE_NUM]);

	/* Setup the STATE variable for processing through the block */

	ViewGetDictInfo();
	if (gv_bViewHaveDictInfo)
	{
		if ((RC_OK( fdictGetIndex(
				((FDB *)gv_hViewDb)->pDict,
				((FDB *)gv_hViewDb)->pFile->bInLimitedMode,
				BlkExp->LfNum, &pLFile, NULL))) ||
			 (RC_OK( fdictGetContainer(
			 	((FDB *)gv_hViewDb)->pDict,
				BlkExp->LfNum, &pLFile))))
		{
			f_memset( &LogicalFile, 0, sizeof( LF_HDR));
			f_memset( &LfStats, 0, sizeof( LF_STATS));
			pLogicalFile = &LogicalFile;
			pLogicalFile->pLfStats = &LfStats;
			LogicalFile.pLFile = pLFile;
			if (pLFile->uiLfType == LF_INDEX)
			{
				if (RC_BAD( fdictGetIndex(
					((FDB *)gv_hViewDb)->pDict,
					((FDB *)gv_hViewDb)->pFile->bInLimitedMode,
					 pLFile->uiLfNum, &LogicalFile.pLFile,
					 &LogicalFile.pIxd)))
				{
					pLogicalFile = NULL;
				}
				LogicalFile.pIfd = LogicalFile.pIxd->pFirstIfd;
			}
		}
	}
	LfType = (pLogicalFile) ? pLogicalFile->pLFile->uiLfType : LF_INVALID;

	flmInitReadState( &StateInfo, &bStateInitialized,
							gv_ViewHdrInfo.FileHdr.uiVersionNum,
							(gv_bViewDbInitialized)
							? (FDB *)gv_hViewDb
							: (FDB *)NULL, pLogicalFile, 0,
							BHT_LEAF, KeyBuffer);
	StateInfo.uiBlkAddress = BlkExp->BlkAddr;
	StateInfo.pBlk = BlkPtr;

	if ((eCorruptionCode = flmVerifyBlockHeader( &StateInfo, &BlockInfo,
								gv_ViewHdrInfo.FileHdr.uiBlockSize,
														BlkExp->NextAddr,
														BlkExp->PrevAddr,
														(FLMBOOL)(StateInfo.pDb != NULL
																	 ? TRUE
																	 : FALSE), TRUE)) != FLM_NO_CORRUPTION)
		SetStatusBit( BlkStatusRV, eCorruptionCode);

	if (bEncrypted)
	{
		if (!StatusOnlyFlag)
		{
			FLMUINT	uiEncSize = getEncryptSize( StateInfo.pBlk) - BH_OVHD;
			
			if (uiEncSize)
			{
			
				// Output the rest of the block as HEX - cannot be parsed through
				// when it is encrypted
		
				OutputHexValue( Col, &Row, bc, fc, LBL_ENC_DATA,
						FSGetFileNumber(StateInfo.uiBlkAddress),
						FSGetFileOffset(StateInfo.uiBlkAddress) + BH_OVHD,
						&StateInfo.pBlk [BH_OVHD], uiEncSize, FALSE, MOD_BINARY_ENC);
			}
		}
		iRc = 1;
		goto Exit;
	}
	
	/* Read through the elements in the block */

	while( StateInfo.uiElmOffset < StateInfo.uiEndOfBlock)
	{
		ElementCount++;
		InitStatusBits( ElmStatus);

		if ((eCorruptionCode = flmVerifyElement( &StateInfo, FLM_CHK_FIELDS)) != FLM_NO_CORRUPTION)
			SetStatusBit( ElmStatus, eCorruptionCode);
		else if (LfType == LF_INDEX)
		{
			if (StateInfo.uiCurKeyLen)
			{
				if( RC_BAD( flmVerifyIXRefs( &StateInfo, NULL, 0,
					&eCorruptionCode)) || eCorruptionCode != FLM_NO_CORRUPTION)
				{
					SetStatusBit( ElmStatus, eCorruptionCode);
				}
			}
		}

		/* Output the element */

		if (!StatusOnlyFlag)
		{
			Row++;

			/* Output the element number */

			if (!ViewAddMenuItem( LBL_ELEMENT_NUMBER, LabelWidth,
					VAL_IS_NUMBER | DISP_DECIMAL,
					(FLMUINT)ElementCount, 0,
					FSGetFileNumber( StateInfo.uiBlkAddress),
					FSGetFileOffset( StateInfo.uiBlkAddress) + StateInfo.uiElmOffset,
					0, MOD_DISABLED,
					Col, Row++, 0,
					FLM_GREEN, FLM_WHITE,
					FLM_GREEN, FLM_WHITE))
				goto Exit;

			/* Remember this item if we are searching */

			if ((gv_bViewSearching) &&
					(flmCompareKeys( StateInfo.pCurKey, StateInfo.uiCurKeyLen,
													gv_ucViewSearchKey,
													gv_uiViewSearchKeyLen) >= 0) &&
					(gv_pViewSearchItem == NULL))
			{
				gv_pViewSearchItem = gv_pViewMenuLastItem;
			}

			/* Output the element offset within the block */

			if (!ViewAddMenuItem( LBL_ELEMENT_OFFSET, LabelWidth,
									VAL_IS_NUMBER | DISP_DECIMAL,
									(FLMUINT)StateInfo.uiElmOffset, 0,
									FSGetFileNumber( StateInfo.uiBlkAddress),
									FSGetFileOffset( StateInfo.uiBlkAddress) +
										StateInfo.uiElmOffset,
									0, MOD_DISABLED,
									Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			/* Output the element length */

			if (!ViewAddMenuItem( LBL_ELEMENT_LENGTH, LabelWidth,
									VAL_IS_NUMBER | DISP_DECIMAL,
									(FLMUINT)StateInfo.uiElmLen, 0,
									FSGetFileNumber( StateInfo.uiBlkAddress),
									FSGetFileOffset( StateInfo.uiBlkAddress) + 
										StateInfo.uiElmOffset,
									0, MOD_DISABLED,
									Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			/* Display the first element flag */

			if (!ViewAddMenuItem( LBL_FIRST_ELEMENT_FLAG, LabelWidth,
					VAL_IS_LABEL_INDEX,
					(BBE_IS_FIRST( StateInfo.pElm))
					? (FLMUINT)LBL_YES
					: (FLMUINT)LBL_NO, 0,
					FSGetFileNumber( StateInfo.uiBlkAddress),
					FSGetFileOffset( StateInfo.uiBlkAddress) + StateInfo.uiElmOffset, 
					0x80, MOD_BITS | MOD_DECIMAL,
					Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			/* Display the last element flag */

			if (!ViewAddMenuItem( LBL_LAST_ELEMENT_FLAG, LabelWidth,
						VAL_IS_LABEL_INDEX,
						(BBE_IS_LAST( StateInfo.pElm))
						? (FLMUINT)LBL_YES
						: (FLMUINT)LBL_NO, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
								StateInfo.uiElmOffset, 0x40,
						MOD_BITS | MOD_DECIMAL,
						Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			if (eCorruptionCode != FLM_NO_CORRUPTION)
			{
				if ((LfType != LF_INDEX) &&
					 (LfType != LF_INVALID) &&
					 (StateInfo.uiCurKeyLen) &&
					 (StateInfo.uiElmDrn != DRN_LAST_MARKER))
				{
					FLMUINT        r = 0;
					STATE_INFO  DummyState;
					FLMBYTE      TempKeyBuffer [MAX_KEY_SIZ];

					f_memcpy( &DummyState, &StateInfo, sizeof( STATE_INFO));
					f_memcpy( TempKeyBuffer, KeyBuffer, MAX_KEY_SIZ);
					DummyState.pCurKey = &TempKeyBuffer [0];
					if (!OutputElmRecord( Col, &r, bc, fc, LabelWidth,
											&DummyState, ElmStatus, TRUE))
						goto Exit;
				}
				if (!OutputStatus( Col, &Row, bc, fc, LabelWidth,
													 LBL_ELEMENT_STATUS, ElmStatus))
					goto Exit;
			}

			/* Display the Previous Key Count */

			if (!ViewAddMenuItem( LBL_PREVIOUS_KEY_CONT_LEN, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL,
						(FLMUINT)StateInfo.uiElmPKCLen, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + StateInfo.uiElmOffset, 
						0x0F, MOD_BITS | MOD_DECIMAL,
						Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			/* Output the previous key portion, if any */

			if (!OutputHexValue( Col, &Row, bc, fc,
					LBL_PREV_ELEMENT_KEY,
					0, VIEW_INVALID_FILE_OFFSET,
					StateInfo.pCurKey, StateInfo.uiElmPKCLen,
					TRUE, MOD_BINARY))
				goto Exit;

			/* Display the key length */

			if (!ViewAddMenuItem( LBL_KEY_LENGTH, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL,
						(FLMUINT)StateInfo.uiElmKeyLen, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
							StateInfo.uiElmOffset, 0,
						MOD_KEY_LEN | MOD_DECIMAL,
						Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			/* Output the current key portion, if any */

			if (!OutputHexValue( Col, &Row, bc, fc, LBL_ELEMENT_KEY,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) +
							StateInfo.uiElmOffset + BBE_KEY,
						StateInfo.pElmKey, StateInfo.uiElmKeyLen,
						FALSE, MOD_BINARY))
				goto Exit;
			if ((LfType != LF_INDEX) && (LfType != LF_INVALID))
			{
				if (StateInfo.uiElmDrn != DRN_LAST_MARKER)
				{
					if (!ViewAddMenuItem( LBL_ELEMENT_DRN, LabelWidth,
							VAL_IS_NUMBER | DISP_DECIMAL_HEX,
							StateInfo.uiElmDrn, 0,
							FSGetFileNumber( StateInfo.uiBlkAddress),
							FSGetFileOffset( StateInfo.uiBlkAddress) + 
								StateInfo.uiElmOffset + BBE_KEY,
							StateInfo.uiElmKeyLen,
							MOD_DISABLED | MOD_BINARY,
							Col, Row++, 0, bc, fc, bc, fc))
					goto Exit;
				}

				/* Display the Next DRN marker if there is one */

				if (StateInfo.uiElmDrn == DRN_LAST_MARKER)
				{
					if (!ViewAddMenuItem( LBL_NEXT_DRN_MARKER, LabelWidth,
							VAL_IS_NUMBER | DISP_DECIMAL_HEX,
							StateInfo.uiLastElmDrn, 0,
							FSGetFileNumber( StateInfo.uiBlkAddress),
							FSGetFileOffset( StateInfo.uiBlkAddress) + 
								StateInfo.uiElmOffset + BBE_KEY+4,
							StateInfo.uiElmKeyLen,
							MOD_DISABLED | MOD_BINARY,
							Col, Row++, 0, bc, fc, bc, fc))
					goto Exit;
				}
			}

			/* Display the record length */

			if (!ViewAddMenuItem( LBL_RECORD_LENGTH, LabelWidth,
					VAL_IS_NUMBER | DISP_DECIMAL,
					(FLMUINT)StateInfo.uiElmRecLen, 0,
					FSGetFileNumber( StateInfo.uiBlkAddress),
					FSGetFileOffset( StateInfo.uiBlkAddress) + 
						StateInfo.uiElmOffset + BBE_RL,
					0,
					MOD_FLMBYTE | MOD_DECIMAL,
					Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			if ((LfType == LF_INDEX) || (LfType == LF_INVALID))
			{

				/* Output the record portion */

				if (!OutputHexValue( Col, &Row, bc, fc, LBL_RECORD,
						FSGetFileNumber(StateInfo.uiBlkAddress),
						FSGetFileOffset(StateInfo.uiBlkAddress) +
							(FLMUINT)(StateInfo.pElmRec - StateInfo.pBlk),
						StateInfo.pElmRec, StateInfo.uiElmRecLen,
						FALSE, MOD_BINARY))
					goto Exit;
			}
		}
		if ((LfType != LF_INDEX) && 
			 (LfType != LF_INVALID) &&
			 (StateInfo.uiCurKeyLen) &&
			 ( StateInfo.uiElmDrn != DRN_LAST_MARKER))
		{
			if (!OutputElmRecord( Col, &Row, bc, fc, LabelWidth,
										&StateInfo, ElmStatus, StatusOnlyFlag))
				goto Exit;
		}

		/* Go to the next element */

		StateInfo.uiElmOffset += StateInfo.uiElmLen;
		OrStatusBits( BlkStatusRV, ElmStatus);
	}

	/* Verify that we ended exactly on the end of the block */

	if ((!TestStatusBit( BlkStatusRV, FLM_BAD_BLK_HDR_BLK_END)) &&
			(StateInfo.uiElmOffset > StateInfo.uiEndOfBlock))
		SetStatusBit( BlkStatusRV, FLM_BAD_ELM_END);

	if (!StatusOnlyFlag)
	{
		*RowRV = Row;

		/* If we were searching and did not find a key, set it on the */
		/* last key found */

		if ((gv_bViewSearching) && (gv_pViewSearchItem == NULL))
		{
			gv_pViewSearchItem = gv_pViewMenuLastItem;
			while ((gv_pViewSearchItem != NULL) &&
					 (gv_pViewSearchItem->iLabelIndex != LBL_ELEMENT_NUMBER))
				gv_pViewSearchItem = gv_pViewSearchItem->PrevItem;
		}
	}
	iRc = 1;
Exit:
	if (bStateInitialized && StateInfo.pRecord)
	{
		StateInfo.pRecord->Release();
		StateInfo.pRecord = NULL;
	}
	return( iRc);
}

/***************************************************************************
Name:    ViewLeafBlk
Desc:    This routine outputs a LEAF block, including the block header.
*****************************************************************************/
FLMINT ViewLeafBlk(
	FLMUINT		ReadAddress,
	FLMUINT		BlkAddress,
	FLMBYTE **	BlkPtrRV,
	BLK_EXP_p	BlkExp
	)
{
	FLMUINT        Row;
	FLMUINT        Col;
	FLMBYTE *		BlkPtr;
	FLMBYTE			BlkStatus [NUM_STATUS_BYTES];
	FLMUINT16      ui16CalcChkSum;
	FLMUINT16		ui16BlkChkSum;
	FLMUINT			uiBytesRead;
	FLMBOOL			bEncrypted;

	InitStatusBits( BlkStatus);

	/* Read the block into memory */

	if (!ViewBlkRead( ReadAddress, BlkPtrRV,
										gv_ViewHdrInfo.FileHdr.uiBlockSize,
										&ui16CalcChkSum, &ui16BlkChkSum,
										&uiBytesRead, TRUE, NULL, TRUE, &bEncrypted))
		return( 0);
	BlkPtr = *BlkPtrRV;

	if (!ViewMenuInit( "LEAF Block"))
		return( 0);

	/* Output the block header first */

	Row = 0;
	Col = 5;
	BlkExp->Type = BHT_LEAF;
	BlkExp->BlkAddr = BlkAddress;
	BlkExp->Level = 0;

	OutputLeafElements( Col, &Row, BlkPtr, BlkExp, BlkStatus, TRUE,
								bEncrypted);
	if (!ViewOutBlkHdr( Col, &Row, BlkPtr, BlkExp, BlkStatus,
								ui16CalcChkSum, ui16BlkChkSum))
		return( 0);

	/* Now output the leaf data */

	if (!OutputLeafElements( Col, &Row, BlkPtr, BlkExp,
							BlkStatus, FALSE, bEncrypted))
		return( 0);
	return( 1);
}

/***************************************************************************
Name:    OutputNonLeafElements
Desc:    This routine outputs the elements of a NON-LEAF block.
*****************************************************************************/
FSTATIC FLMINT OutputNonLeafElements(
	FLMUINT        Col,
	FLMUINT  *		RowRV,
	FLMBYTE *		BlkPtr,
	BLK_EXP_p		BlkExp,
	FLMBYTE *		BlkStatusRV,
	FLMUINT        StatusOnlyFlag,
	FLMBOOL			bEncrypted
	)
{
	FLMINT				iRc = 0;
	FLMUINT				LabelWidth = 30;
	eColorType			bc = FLM_BLACK;
	eColorType			fc = FLM_LIGHTGRAY;
	eColorType			mbc = FLM_BLACK;
	eColorType			mfc = FLM_WHITE;
	eColorType			sbc = FLM_BLUE;
	eColorType			sfc = FLM_WHITE;
	FLMUINT				Row = *RowRV;
	FLMUINT				ElementCount = 0;
	FLMBYTE *			TempAddrPtr;
	FLMUINT				TempAddress;
	eCorruptionType	eCorruptionCode;
	FLMUINT				Option;
	FLMUINT				LfType;
	FLMUINT				uiBlkType = BlkExp->Type;
	FLMBYTE				ElmStatus [NUM_STATUS_BYTES];
	STATE_INFO			StateInfo;
	FLMBOOL				bStateInitialized = FALSE;
	BLOCK_INFO			BlockInfo;
	FLMBYTE				KeyBuffer [MAX_KEY_SIZ];
	LF_HDR				LogicalFile;
	LF_HDR *				pLogicalFile = NULL;
	LFILE *				pLFile = NULL;
	FLMUINT				uiFixedDrn = 0;

	if (BlkExp->LfNum == 0)
		BlkExp->LfNum = FB2UW( &BlkPtr [BH_LOG_FILE_NUM]);

	/* Setup the STATE variable for processing through the block */

	ViewGetDictInfo();
	if (gv_bViewHaveDictInfo)
	{
		if ((RC_OK( fdictGetIndex(
				((FDB *)gv_hViewDb)->pDict,
				((FDB *)gv_hViewDb)->pFile->bInLimitedMode,
				BlkExp->LfNum, &pLFile, NULL))) ||
			 (RC_OK( fdictGetContainer(
			 		((FDB *)gv_hViewDb)->pDict,
					BlkExp->LfNum, &pLFile))))
		{
			f_memset( &LogicalFile, 0, sizeof( LF_HDR));
			pLogicalFile = &LogicalFile;
			LogicalFile.pLFile = pLFile;
			if (pLFile->uiLfType == LF_INDEX)
			{
				if (RC_BAD( fdictGetIndex(
						((FDB *)gv_hViewDb)->pDict,
						((FDB *)gv_hViewDb)->pFile->bInLimitedMode,
						pLFile->uiLfNum, &LogicalFile.pLFile,
						&LogicalFile.pIxd)))
				{
					pLogicalFile = NULL;
				}
				LogicalFile.pIfd = LogicalFile.pIxd->pFirstIfd;
			}
		}
	}
	LfType = (pLogicalFile) ? pLogicalFile->pLFile->uiLfType : LF_INVALID;

	if (uiBlkType != BHT_NON_LEAF &&
		 uiBlkType != BHT_NON_LEAF_COUNTS &&
		 uiBlkType != BHT_NON_LEAF_DATA)
	{
		if (pLogicalFile)
		{
			if (LfType == LF_INDEX)
			{
				if (pLogicalFile->pIxd &&
					 (pLogicalFile->pIxd->uiFlags & IXD_POSITIONING))
				{
					uiBlkType = BHT_NON_LEAF_COUNTS;
				}
				else
				{
					uiBlkType = BHT_NON_LEAF;
				}
			}
			else
			{
				uiBlkType = BHT_NON_LEAF_DATA;
			}
		}
		else
		{
			uiBlkType = BHT_NON_LEAF;
		}
	}

	flmInitReadState( &StateInfo, &bStateInitialized,
							gv_ViewHdrInfo.FileHdr.uiVersionNum,
							(gv_bViewDbInitialized)
							? (FDB *)gv_hViewDb
							: (FDB *)NULL, pLogicalFile, BlkExp->Level,
							uiBlkType, KeyBuffer);
	StateInfo.uiBlkAddress = BlkExp->BlkAddr;
	StateInfo.pBlk = BlkPtr;

	if ((eCorruptionCode = flmVerifyBlockHeader( &StateInfo, &BlockInfo,
								gv_ViewHdrInfo.FileHdr.uiBlockSize,
														BlkExp->NextAddr,
														BlkExp->PrevAddr,
														(FLMBOOL)(StateInfo.pDb != NULL
																	 ? TRUE
																	 : FALSE), TRUE)) != FLM_NO_CORRUPTION)
		SetStatusBit( BlkStatusRV, eCorruptionCode);

	if (bEncrypted)
	{
		if (!StatusOnlyFlag)
		{
			FLMUINT	uiEncSize = getEncryptSize( StateInfo.pBlk) - BH_OVHD;
			
			if (uiEncSize)
			{
			
				// Output the rest of the block as HEX - cannot be parsed through
				// when it is encrypted
		
				OutputHexValue( Col, &Row, bc, fc, LBL_ENC_DATA,
						FSGetFileNumber(StateInfo.uiBlkAddress),
						FSGetFileOffset(StateInfo.uiBlkAddress) + BH_OVHD,
						&StateInfo.pBlk [BH_OVHD], uiEncSize, FALSE, MOD_BINARY_ENC);
			}
		}
		iRc = 1;
		goto Exit;
	}
	
	/* Output each element in the block */

	while (StateInfo.uiElmOffset < StateInfo.uiEndOfBlock)
	{
		InitStatusBits( ElmStatus);
		ElementCount++;

		if ((eCorruptionCode = flmVerifyElement( &StateInfo, FLM_CHK_FIELDS)) != FLM_NO_CORRUPTION)
			SetStatusBit( ElmStatus, eCorruptionCode);

		if (!StatusOnlyFlag)
		{
			Row++;

			/* Output the element number */

			if (!ViewAddMenuItem( LBL_ELEMENT_NUMBER, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL,
						(FLMUINT)ElementCount, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
							StateInfo.uiElmOffset,
						0, MOD_DISABLED,
						Col, Row++, 0,
						FLM_GREEN, FLM_WHITE,
						FLM_GREEN, FLM_WHITE))
				goto Exit;

			/* Output the element offset within the block */

			if (!ViewAddMenuItem( LBL_ELEMENT_OFFSET, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL,
						(FLMUINT)StateInfo.uiElmOffset, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
								StateInfo.uiElmOffset,
						0, MOD_DISABLED,
						Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			/* Output the element length */

			if (!ViewAddMenuItem( LBL_ELEMENT_LENGTH, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL,
						(FLMUINT)StateInfo.uiElmLen, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
							StateInfo.uiElmOffset,
						0, MOD_DISABLED,
						Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			/* Display the domain flag */

			if (!ViewAddMenuItem( LBL_DOMAIN_PRESENT_FLAG, LabelWidth,
						VAL_IS_LABEL_INDEX,
						(BNE_IS_DOMAIN( StateInfo.pElm))
						? (FLMUINT)LBL_YES
						: (FLMUINT)LBL_NO, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
							StateInfo.uiElmOffset,
						0x80, MOD_BITS | MOD_DECIMAL,
						Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			/* Display the domain number */

			if (uiBlkType != BHT_NON_LEAF_DATA && (BNE_IS_DOMAIN( StateInfo.pElm)))
			{
				TempAddrPtr = &StateInfo.pElmKey [StateInfo.uiElmKeyLen];
				TempAddress =  ((FLMUINT) (*TempAddrPtr++)) << 16;
				TempAddress |= (FLMUINT) ((*TempAddrPtr++) << 8);
				TempAddress |=  (FLMUINT) (*TempAddrPtr);
				TempAddress <<= 8;
			}
			else
				TempAddress = 0;
			if (!ViewAddMenuItem( LBL_DOMAIN_NUMBER, LabelWidth,
						VAL_IS_NUMBER | DISP_HEX_DECIMAL,
						(FLMUINT)TempAddress, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) +
								((FLMUINT)(StateInfo.pElmKey - StateInfo.pBlk) +
								StateInfo.uiElmKeyLen),
						0,
						(FLMBYTE)((TempAddress) 
									? (FLMBYTE)MOD_CHILD_BLK
									: (FLMBYTE)MOD_DISABLED),
						Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			/* Display the child block address */

			if (uiBlkType == BHT_NON_LEAF_DATA)
			{
				uiFixedDrn = f_bigEndianToUINT32( StateInfo.pElm);
				TempAddrPtr = &StateInfo.pElm [BNE_DATA_CHILD_BLOCK];
			}
			else
			{
				TempAddrPtr = &StateInfo.pElm [BNE_CHILD_BLOCK];
			}
			TempAddress = FB2UD( TempAddrPtr);
			if (TempAddress == BT_END)
				Option = 0;
			else
				Option = BLK_OPTION_CHILD_BLOCK | StateInfo.uiElmOffset;
			if (!ViewAddMenuItem( LBL_CHILD_BLOCK_ADDRESS, LabelWidth,
						VAL_IS_NUMBER | DISP_HEX_DECIMAL,
						(FLMUINT)TempAddress, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) +
							StateInfo.uiElmOffset +
							(FLMUINT) (TempAddrPtr - StateInfo.pElm),
						0, MOD_CHILD_BLK,
						Col, Row++, Option,
						!Option ? bc : mbc,
						!Option ? fc : mfc,
						!Option ? bc : sbc,
						!Option ? fc : sfc))
				goto Exit;

			if (uiBlkType == BHT_NON_LEAF_COUNTS)
			{
				TempAddrPtr = &StateInfo.pElm [BNE_CHILD_COUNT];
				if (!ViewAddMenuItem( LBL_CHILD_REFERENCE_COUNT, LabelWidth,
							VAL_IS_NUMBER,
							(FLMUINT) StateInfo.uiChildCount, 0,
							FSGetFileNumber( StateInfo.uiBlkAddress),
							FSGetFileOffset( StateInfo.uiBlkAddress) +
								StateInfo.uiElmOffset +
								(FLMUINT) (TempAddrPtr - StateInfo.pElm),
							0, MOD_FLMUINT | MOD_DECIMAL,
							Col, Row++, Option, bc, fc, bc, fc))
					goto Exit;
			}

			/* Remember this item if we are searching */

			if ((gv_bViewSearching) &&
					(flmCompareKeys( StateInfo.pCurKey, StateInfo.uiCurKeyLen,
											gv_ucViewSearchKey, gv_uiViewSearchKeyLen) >= 0) &&
					(gv_pViewSearchItem == NULL))
			{
				gv_pViewSearchItem = gv_pViewMenuLastItem;
			}

			if (eCorruptionCode != FLM_NO_CORRUPTION)
			{
				if (!OutputStatus( Col, &Row, bc, fc, LabelWidth, LBL_ELEMENT_STATUS,
													 ElmStatus))
					goto Exit;
			}

			/* Display the Previous Key Count */

			if (!ViewAddMenuItem( LBL_PREVIOUS_KEY_CONT_LEN, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL,
						(FLMUINT)StateInfo.uiElmPKCLen, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
							StateInfo.uiElmOffset, 0x0F,
						MOD_BITS | MOD_DECIMAL,
						Col, Row++, 0, bc, fc, bc, fc))
				goto Exit;

			if (uiBlkType != BHT_NON_LEAF_DATA)
			{
				/* Output the previous key portion, if any */

				if (!OutputHexValue( Col, &Row, bc, fc,
							LBL_PREV_ELEMENT_KEY,
							0, VIEW_INVALID_FILE_OFFSET,
							StateInfo.pCurKey, StateInfo.uiElmPKCLen,
							TRUE, MOD_BINARY))
					goto Exit;

				/* Display the key length */

				if (!ViewAddMenuItem( LBL_KEY_LENGTH, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL,
						(FLMUINT)StateInfo.uiElmKeyLen, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
							StateInfo.uiElmOffset, 0,
						MOD_KEY_LEN | MOD_DECIMAL,
						Col, Row++, 0, bc, fc, bc, fc))
					goto Exit;

				/* Output the current key portion, if any */

				if (!OutputHexValue( Col, &Row, bc, fc, LBL_ELEMENT_KEY,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
							(FLMUINT)(StateInfo.pElmKey - StateInfo.pBlk),
						StateInfo.pElmKey, StateInfo.uiElmKeyLen,
						FALSE, MOD_BINARY))
					goto Exit;
			}

			if (((LfType != LF_INDEX) && (LfType != LF_INVALID)) ||
				 (uiBlkType == BHT_NON_LEAF_DATA))
			{
				FLMUINT	uiDrn = StateInfo.uiElmDrn;

				if (uiBlkType == BHT_NON_LEAF_DATA)
				{
					uiDrn = uiFixedDrn;
				}
				if (!ViewAddMenuItem( LBL_ELEMENT_DRN, LabelWidth,
						VAL_IS_NUMBER | DISP_DECIMAL_HEX,
						uiFixedDrn, 0,
						FSGetFileNumber( StateInfo.uiBlkAddress),
						FSGetFileOffset( StateInfo.uiBlkAddress) + 
							(FLMUINT)(StateInfo.pElmKey - StateInfo.pBlk),
						StateInfo.uiElmKeyLen,
						MOD_DISABLED | MOD_BINARY,
						Col, Row++, 0, bc, fc, bc, fc))
					goto Exit;
			}
		}

		/* Go to the next element */

		StateInfo.uiElmOffset += StateInfo.uiElmLen;
		OrStatusBits( BlkStatusRV, ElmStatus);
	}

	/* Verify that we ended exactly on the end of the block */

	if ((!TestStatusBit( BlkStatusRV, FLM_BAD_BLK_HDR_BLK_END)) &&
			(StateInfo.uiElmOffset > StateInfo.uiEndOfBlock))
		SetStatusBit( BlkStatusRV, FLM_BAD_ELM_END);

	if (!StatusOnlyFlag)
	{
		*RowRV = Row;

		/* If we were searching and did not find a key, set it on the */
		/* last key found */

		if ((gv_bViewSearching) && (gv_pViewSearchItem == NULL))
		{
			gv_pViewSearchItem = gv_pViewMenuLastItem;
			while ((gv_pViewSearchItem != NULL) &&
						 (gv_pViewSearchItem->iLabelIndex != LBL_CHILD_BLOCK_ADDRESS))
				gv_pViewSearchItem = gv_pViewSearchItem->PrevItem;
		}
	}
	iRc = 1;
Exit:
	if (bStateInitialized && StateInfo.pRecord)
	{
		StateInfo.pRecord->Release();
		StateInfo.pRecord = NULL;
	}
	return( iRc);
}

/***************************************************************************
Name:    ViewNonLeafBlk
Desc:    This routine outputs a NON-LEAF block, including the block header.
*****************************************************************************/
FLMINT ViewNonLeafBlk(
	FLMUINT		ReadAddress,
	FLMUINT		BlkAddress,
	FLMBYTE **	BlkPtrRV,
	BLK_EXP_p	BlkExp
	)
{
	FLMUINT		Row;
	FLMUINT     Col;
	FLMBYTE *   BlkPtr;
	FLMBYTE     BlkStatus [NUM_STATUS_BYTES];
	FLMUINT16   ui16CalcChkSum;
	FLMUINT16	ui16BlkChkSum;
	FLMUINT		uiBytesRead;
	FLMBOOL		bEncrypted;

	InitStatusBits( BlkStatus);

	/* Read the block into memory */

	if (!ViewBlkRead( ReadAddress, BlkPtrRV,
										gv_ViewHdrInfo.FileHdr.uiBlockSize,
										&ui16CalcChkSum, &ui16BlkChkSum,
										&uiBytesRead, TRUE, NULL, TRUE, &bEncrypted))
		return( 0);
	BlkPtr = *BlkPtrRV;

	if (!ViewMenuInit( "NON-LEAF Block"))
		return( 0);

	/* Output the block header first */

	Row = 0;
	Col = 5;
	BlkExp->Type = BH_GET_TYPE( BlkPtr); 
	BlkExp->BlkAddr = BlkAddress;
	OutputNonLeafElements( Col, &Row, BlkPtr, BlkExp, BlkStatus, TRUE,
				bEncrypted);
	if (!ViewOutBlkHdr( Col, &Row, BlkPtr, BlkExp, BlkStatus,
							ui16CalcChkSum, ui16BlkChkSum))
		return( 0);

	/* Now output the non-leaf data */

	if (!OutputNonLeafElements( Col, &Row, BlkPtr, BlkExp, BlkStatus, FALSE,
				bEncrypted))
		return( 0);
	return( 1);
}

/********************************************************************
Desc: ?
*********************************************************************/
void ViewHexBlock(
	FLMUINT			ReadAddress,
	FLMBYTE **		BlkPtrRV,
	FLMBOOL        bViewDecrypted,
	FLMUINT        uiViewLen
	)
{
	FLMBYTE *	BlkPtr;
	FLMUINT     Row = 0;
	FLMUINT     Col = 9;
	FLMUINT     BytesPerLine = MAX_HORIZ_SIZE( Col);
	FLMUINT     BytesProcessed = 0;
	FLMUINT     NumBytes;
	FLMUINT     FileOffset;
	FLMUINT		FileNumber;
	char     	Title [80];
	FLMUINT16	ui16CalcChkSum;
	FLMUINT16	ui16BlkChkSum;
	FLMUINT		uiBytesRead;
	FLMBOOL		bIsEncBlock;
	FLMBOOL		bEncrypted;
	FLMUINT		uiModFlag;

	FileOffset = FSGetFileOffset( ReadAddress);
	FileNumber = FSGetFileNumber( ReadAddress);

	if (!ViewBlkRead( ReadAddress, BlkPtrRV, uiViewLen,
										&ui16CalcChkSum, &ui16BlkChkSum,
										&uiBytesRead, TRUE, &bIsEncBlock,
										bViewDecrypted, &bEncrypted))
		return;
	BlkPtr = *BlkPtrRV;

	f_sprintf( (char *)Title, "HEX DISPLAY OF BLOCK %08X (%s)", (unsigned)ReadAddress,
		(char *)(bIsEncBlock
					? (char *)(bEncrypted
								  ? (char *)"DECRYPTED"
								  : (char *)"ENCRYPTED (RAW)")
					: (char *)"RAW"));
	if (!ViewMenuInit( Title))
		return;

	uiModFlag = bEncrypted ? MOD_BINARY_ENC : MOD_BINARY;
	while (BytesProcessed < uiViewLen)
	{
		if ((NumBytes = uiViewLen - BytesProcessed) > BytesPerLine)
			NumBytes = BytesPerLine;

		/* Output the line */

		if (!ViewAddMenuItem( -1, 0,
				VAL_IS_BINARY_HEX,
				(FLMUINT)BlkPtr, NumBytes,
				FileNumber, FileOffset, NumBytes, uiModFlag,
				Col, Row++, 0,
				FLM_BLACK, FLM_LIGHTGRAY,
				FLM_BLACK, FLM_LIGHTGRAY))
			return;
		FileOffset += (FLMUINT)NumBytes;
		BytesProcessed += NumBytes;
		BlkPtr += NumBytes;
	}
}


/***************************************************************************
Name: ViewBlocks
Desc: This routine outputs a block in the database.  Depending on the
		type of block, it will call a different routine to display
		the block.  The routine then allows the user to press keys to
		navigate to other blocks in the database if desired.
*****************************************************************************/
void ViewBlocks(
	FLMUINT     ReadAddress,
	FLMUINT     BlkAddress,
	BLK_EXP_p   BlkExp
	)
{
	FLMUINT     Option;
	VIEW_INFO   SaveView;
	VIEW_INFO   DummySave;
	FLMUINT		Done = 0;
	FLMUINT     Repaint = 1;
	FLMBYTE *   BlkPtr = NULL;
	FLMUINT     BlkAddress2;
	BLK_EXP     BlkExp2;
	FLMUINT     SetExp = FALSE;
	FLMUINT		Type;
	FLMBOOL		bViewHex = FALSE;
	FLMBOOL     bViewDecrypted = FALSE;
	FLMUINT		uiBytesRead;

	/* Loop getting commands until hit the exit key */

	if (!gv_bViewHdrRead)
		ViewReadHdr();
	gv_pViewSearchItem = NULL;
	ViewReset( &SaveView);
	while ((!Done) && (!gv_bViewPoppingStack))
	{

		/* Display the type of block expected */

		if (Repaint)
		{
			if (bViewHex)
			{
				ViewHexBlock( ReadAddress, &BlkPtr, bViewDecrypted,
											gv_ViewHdrInfo.FileHdr.uiBlockSize);
			}
			else
			{
Switch_Statement:
				switch( BlkExp->Type)
				{
					case BHT_NON_LEAF_COUNTS:
					case BHT_NON_LEAF:
					case BHT_NON_LEAF_DATA:
						if (!ViewNonLeafBlk( ReadAddress, BlkAddress,
																 &BlkPtr, BlkExp))
							Done = 1;
						break;
					case BHT_LEAF:
						if (!ViewLeafBlk( ReadAddress, BlkAddress,
															&BlkPtr, BlkExp))
							Done = 1;
						break;
					case BHT_FREE:
						if (!ViewAvailBlk( ReadAddress, BlkAddress,
															 &BlkPtr, BlkExp))
							Done = 1;
						break;
					case BHT_LFH_BLK:
						if (!ViewLFHBlk( ReadAddress, BlkAddress,
														 &BlkPtr, BlkExp))
							Done = 1;
						break;
					case 0xFF:
						if (!ViewBlkRead( ReadAddress, &BlkPtr,
												gv_ViewHdrInfo.FileHdr.uiBlockSize,
												NULL, NULL, &uiBytesRead, FALSE,
												NULL, FALSE, NULL))
						{
							Done = 1;
						}
						else
						{
							BlkExp->Type = BH_GET_TYPE( BlkPtr );
							goto Switch_Statement;
						}
						break;
				}
			}
		}

		/* See what the user wants to do next. */

		if (!Done)
		{
			if ((SetExp) &&
				 ((BlkExp->Type == BHT_LEAF) || 
				  (BlkExp->Type == BHT_NON_LEAF_COUNTS) ||
				  (BlkExp->Type == BHT_NON_LEAF) ||
				  (BlkExp->Type == BHT_NON_LEAF_DATA) ))
			{
				BlkExp->LfNum = FB2UW( &BlkPtr [BH_LOG_FILE_NUM]);
				BlkExp->Level = BlkPtr [BH_LEVEL];
			}
			SetExp = FALSE;
			Repaint = 1;
			if (gv_bViewSearching)
			{
				SetSearchTopBottom();
				if ((BlkExp->Type == BHT_LEAF) || (gv_pViewSearchItem == NULL))
				{
					gv_bViewSearching = FALSE;
					ViewEnable();
					Option = ViewGetMenuOption();
				}
				else
					Option = gv_pViewSearchItem->Option;
			}
			else
			{
				ViewEnable();
				Option = ViewGetMenuOption();
			}
			switch( Option)
			{
				case ESCAPE_OPTION:
					Done = 1;
					break;
				case PREV_BLOCK_OPTION:
					ViewReset( &DummySave);
					BlkExp->NextAddr = BlkAddress;
					BlkExp->PrevAddr = 0;
					ReadAddress = BlkAddress = FB2UD( &BlkPtr [BH_PREV_BLK]);
					break;
				case NEXT_BLOCK_OPTION:
					ViewReset( &DummySave);
					BlkExp->NextAddr = 0;
					BlkExp->PrevAddr = BlkAddress;
					ReadAddress = BlkAddress = FB2UD( &BlkPtr [BH_NEXT_BLK]);
					break;
				case PREV_BLOCK_IMAGE_OPTION:
					if (BlkExp->Type == BHT_PCODE_BLK)
					{
						ViewShowError( 
							"This option not supported for PCODE blocks");
						Repaint = 0;
					}
					else
					{
						f_memcpy( &BlkExp2, BlkExp, sizeof( BLK_EXP));
						BlkExp2.NextAddr = 0;
						BlkExp2.PrevAddr = 0;
						ViewBlocks( FB2UD( &BlkPtr [BH_PREV_BLK_ADDR]),
												BlkAddress, &BlkExp2);
					}
					break;
				case GOTO_BLOCK_OPTION:
					if (GetBlockAddrType( &BlkAddress2, &Type))
					{
						ViewReset( &DummySave);
						ReadAddress = BlkAddress = BlkAddress2;
						BlkExp->Type = Type;
						BlkExp->Level = 0xFF;
						BlkExp->NextAddr = 0;
						BlkExp->PrevAddr = 0;
						BlkExp->LfNum = 0;
						SetExp = TRUE;
						if (BlkAddress < 2048)
						{
							bViewDecrypted = FALSE;
							bViewHex = TRUE;
						}
					}
					else
						Repaint = 0;
					break;
				case EDIT_OPTION:
				case EDIT_RAW_OPTION:
					if (!ViewEdit( TRUE,
									(Option == EDIT_OPTION) ? TRUE : FALSE))
						Repaint = 0;
					break;
				case HEX_OPTION:
					ViewDisable();
					bViewHex = bViewHex ? FALSE : TRUE;
					if (!bViewHex)
					{
						bViewDecrypted = FALSE;
					}
					break;
				case DECRYPT_OPTION:
					if (bViewHex)
					{
						ViewDisable();
						bViewDecrypted = bViewDecrypted ? FALSE : TRUE;
					}
					else
					{
						Repaint = 0;
					}
					break;
				case SEARCH_OPTION:
					switch( BH_GET_TYPE( BlkPtr))
					{
						case BHT_NON_LEAF_COUNTS:
						case BHT_NON_LEAF:
						case BHT_NON_LEAF_DATA:
						case BHT_LEAF:
							gv_uiViewSearchLfNum = FB2UW( &BlkPtr [BH_LOG_FILE_NUM]);
							if (ViewGetKey())
								gv_bViewPoppingStack = TRUE;
							break;
						case BHT_LFH_BLK:
							{
								VIEW_MENU_ITEM_p  vp = gv_pViewMenuCurrItem;

								/* Determine which logical file, if any we are pointing at */

								while ((vp != NULL) &&
											(vp->iLabelIndex != LBL_LOGICAL_FILE_NAME))
									vp = vp->PrevItem;
								if (vp != NULL)
								{
									while ((vp != NULL) &&
											(vp->iLabelIndex != LBL_LOGICAL_FILE_NUMBER))
										vp = vp->NextItem;
								}
								if (vp != NULL)
								{
									gv_uiViewSearchLfNum = (FLMUINT)vp->Value;
									if (ViewGetKey())
										gv_bViewPoppingStack = TRUE;
								}
								else
									ViewShowError(
										"Position cursor to a logical file before searching");
							}
							break;
						case BHT_PCODE_BLK:
							{
								VIEW_MENU_ITEM_p  vp = gv_pViewMenuCurrItem;

								/* Determine which logical file, if any we are pointing at */

								if ((vp->iLabelIndex != LBL_CONTAINER) ||
									(vp->iLabelIndex != LBL_INDEX_CONTAINER))
								{
									while ((vp != NULL) &&
											 (vp->iLabelIndex != LBL_INDEX))
										vp = vp->PrevItem;
								}
								if (vp != NULL)
								{
									gv_uiViewSearchLfNum = (FLMUINT)(vp->Option & (~(LOGICAL_FILE_OPTION)));
									if (ViewGetKey())
										gv_bViewPoppingStack = TRUE;
								}
								else
									ViewShowError( 
										"Position cursor to a logical file before searching");
							}
							break;
						default:
							ViewShowError(
								"This block does not belong to a logical file - cannot search");
							break;
					}
					break;
				default:
					if (Option & LOGICAL_FILE_OPTION)
						ViewLogicalFile( (FLMUINT)(Option & (~(LOGICAL_FILE_OPTION))));
					else if ((Option & LFH_OPTION_ROOT_BLOCK) ||
								(Option & LFH_OPTION_LAST_BLOCK))
					{
						FLMUINT   Offset = (FLMUINT)(BH_OVHD +
													(Option & 0x0FFF) * LFH_SIZE);

						FLMBYTE * LFHPtr = &BlkPtr [Offset];

						if (Option & LFH_OPTION_ROOT_BLOCK)
						{
							BlkExp2.Level = 0xFF;
							BlkExp2.Type = 0xFF;
							BlkAddress2 = FB2UD( &LFHPtr [LFH_ROOT_BLK_OFFSET]);
							BlkExp2.LfNum = FB2UW( &LFHPtr [LFH_LF_NUMBER_OFFSET]);
							BlkExp2.NextAddr = BlkExp2.PrevAddr = BT_END;
						}
						else
						{
							flmAssert( 0);
						}
						ViewBlocks( BlkAddress2, BlkAddress2, &BlkExp2);
					}
					else if (Option & BLK_OPTION_CHILD_BLOCK)
					{
						FLMBYTE * TempAddrPtr;
			
						if (BlkExp->Type == BHT_NON_LEAF_DATA)
							TempAddrPtr = &BlkPtr [(Option & 0xFFF) + BNE_DATA_CHILD_BLOCK];
						else
							TempAddrPtr = &BlkPtr [(Option & 0xFFF) + BNE_CHILD_BLOCK];
	
						BlkAddress2 = FB2UD( TempAddrPtr);
						f_memcpy( &BlkExp2, BlkExp, sizeof( BLK_EXP));
						BlkExp2.NextAddr = 0;
						BlkExp2.PrevAddr = 0;
						if (BlkExp2.Level == 0xFF)
							BlkExp2.Level = BlkPtr [BH_LEVEL] - 1;
						else
							BlkExp2.Level--;
						if (!BlkExp2.Level)
							BlkExp2.Type = BHT_LEAF;
						ViewBlocks( BlkAddress2, BlkAddress2, &BlkExp2);
					}
					else
						Repaint = 0;
					break;
			}
		}
	}
	f_free( &BlkPtr);
	ViewRestore( &SaveView);
}

/********************************************************************
Desc: ?
*********************************************************************/
FLMINT GetBlockAddrType(
	FLMUINT  *	BlkAddressRV,
	FLMUINT *	BlkTypeRV)
{
	char			TempBuf [20];
	FLMUINT     i;
	FLMUINT     c;
	FLMUINT     BadDigit;
	FLMUINT     GotAddress = FALSE;
	FLMUINT     GotType = FALSE;
	FLMUINT     GetOK = 1;
	FLMUINT		uiNumCols;
	FLMUINT		uiNumRows;

	f_conGetScreenSize( &uiNumCols, &uiNumRows);

	/* First get the block address */

	while ((!GotAddress) && (GetOK))
	{
		BadDigit = FALSE;
		f_conSetBackFore( FLM_BLACK, FLM_WHITE);
		f_conClearScreen( 0, uiNumRows - 2);
		ViewAskInput( "Enter Block Address (in hex): ", 
			TempBuf, sizeof( TempBuf));
		if ((f_stricmp( TempBuf, "\\") == 0) ||
				(!TempBuf [0]))
		{
			GetOK = 0;
			break;
		}
		i = 0;
		*BlkAddressRV = 0;
		while ((TempBuf [i]) && (i < 8))
		{
			(*BlkAddressRV) <<= 4;
			c = TempBuf [i];
			if ((c >= '0') && (c <= '9'))
				(*BlkAddressRV) += (FLMUINT)(c - '0');
			else if ((c >= 'a') && (c <= 'f'))
				(*BlkAddressRV) += (FLMUINT)(c - 'a' + 10);
			else if ((c >= 'A') && (c <= 'F'))
				(*BlkAddressRV) += (FLMUINT)(c - 'A' + 10);
			else
			{
				BadDigit = TRUE;
				break;
			}
			i++;
		}
		if (BadDigit)
			ViewShowError( 
				"Illegal digit in number - must be hex digits");
		else if (TempBuf [i])
			ViewShowError(
				"Too many characters in number");
		else
			GotAddress = TRUE;
	}

	/* Next get the block type */

	if (GetOK)
	{
		f_conSetBackFore( FLM_BLACK, FLM_WHITE);
		f_conClearScreen( 0, uiNumRows - 1);
		f_conStrOutXY( "View: 1=Leaf, 2=NLeafCnts, 3=NLeafVar, 4=NLeafFix, 5=Avail, 6=LFH: ",
			0, uiNumRows - 1);
	}
	while ((GetOK) && (!GotType))
	{
		c = f_conGetKey();
		switch( c)
		{
			case FKB_ESCAPE:
			case '0':
				GetOK = 0;
				break;
			case '1':
				GotType = TRUE;
				*BlkTypeRV = BHT_LEAF;
				break;
			case '2':
				GotType = TRUE;
				*BlkTypeRV = BHT_NON_LEAF_COUNTS;
				break;
			case '3':
				GotType = TRUE;
				*BlkTypeRV = BHT_NON_LEAF;
				break;
			case '4':
				GotType = TRUE;
				*BlkTypeRV = BHT_NON_LEAF_DATA;
				break;
			case '5':
				GotType = TRUE;
				*BlkTypeRV = BHT_FREE;
				break;
			case '6':
				GotType = TRUE;
				*BlkTypeRV = BHT_LFH_BLK;
				break;
			default:
				break;
		}
	}
	f_conClearScreen( 0, uiNumRows - 2);
	ViewEscPrompt();
	return( GetOK);
}

/********************************************************************
Desc: ?
*********************************************************************/
FSTATIC void SetSearchTopBottom(
	void
	)
{
	if (gv_pViewSearchItem == NULL)
	{
		gv_pViewMenuCurrItem = NULL;
		gv_uiViewMenuCurrItemNum = 0;
		gv_uiViewCurrFileOffset = 0;
		gv_uiViewCurrFileNumber = 0;
		gv_uiViewTopRow = 0;
	}
	else
	{
		gv_pViewMenuCurrItem = gv_pViewSearchItem;
		gv_uiViewMenuCurrItemNum = gv_pViewSearchItem->ItemNum;
		gv_uiViewCurrFileOffset = gv_pViewSearchItem->ModFileOffset;
		gv_uiViewCurrFileNumber = gv_pViewSearchItem->ModFileNumber;
		gv_uiViewTopRow = gv_pViewSearchItem->Row;
		if (gv_uiViewTopRow < LINES_PER_PAGE / 2)
			gv_uiViewTopRow = 0;
		else
			gv_uiViewTopRow -= (LINES_PER_PAGE / 2);
	}
	gv_uiViewBottomRow = gv_uiViewTopRow + LINES_PER_PAGE - 1;
	if (gv_uiViewBottomRow > gv_pViewMenuLastItem->Row)
	{
		gv_uiViewBottomRow = gv_pViewMenuLastItem->Row;
		if (gv_uiViewBottomRow < LINES_PER_PAGE)
			gv_uiViewTopRow = 0;
		else
			gv_uiViewTopRow = gv_uiViewBottomRow - LINES_PER_PAGE + 1;
	}
}
