/*------------------------------------------------------------------------------*
 * File Name:	readjnb.c														*
 * Creation:	GRD 8/7/2001													*
 * Purpose:		OriginC Source C file											*
 * Copyright (c) OriginLab Corp. 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008	*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*	
 *	GRD 2003.01.14 No new worksheet for Text+Binary								*
 *	Cheney 2006.07.10 REWRITE													*
 *  Hong 11/14/06 FIX_HARD_CODE_NOT_WORK										*
 *  Hong 11/14/06 MORE_FIX_ERROR_BOOK_NAME										*
 *  Hong 11/15/06 CLEAN_NOT_USE_LT_IN_ORIGIN8									*
 *  Hong 11/16/06 DISABLE_DATE_FORMAT											*
 *	Sim 02-04-2010 QA81-15063 MOVE_IMP_FILE_INFO_OUT_FROM_COL_USER_INFO_TREE	*
 *	Sim 02-05-2010 QA81-15063 ROLL_BACK_MOVE_COL_INFO_OUT_OF_USER_TREE			*
 *------------------------------------------------------------------------------*/
 
#include <origin.h>

#include "readjnb.h"
#include "oDcFL.h"
#include <..\Originlab\fu_utils.h> ///---Sim 02-04-2010 QA81-15063 MOVE_IMP_FILE_INFO_OUT_FROM_COL_USER_INFO_TREE

#define	__SUPPORT_JNB_V11__	///Sophy 8/30/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION

//	1,2,4,8, default is 8
#pragma pack(push,1)

// The first byte of the Worksheet Stream indicates whether it's a worksheet or just text
//	0x00	Indicates a worksheet.
//	0xFF	Indicates long text. Next two bytes determines length.
//	else	Indicates short text. The value indicates length.

// The first byte in the stream (see above) is included in this structure,
// so we need to do a 'rewind' and start again
// The Worksheet Header
 struct Header {
 	int		WksID;			// Must equal to 360704
 	int		BytesLeft;		// Bytes remaining in file
 	int		Unk1;			// Must equal to 28674
 	int		Unk2;			// Probably size of string which follows - always 16
 	char	WksIDText[16];	// 'JSDataWorksheet', 0x00
 	ushort  Unk3;			// Must equal to 8324
 	char 	Flag1;			// 0x03=Type1 | 0x05=Type2
	char 	Flag2;	 		// 0x08
 	int		TypeSize;		// Probably size of structure which follows
 							// 0x08 for Type1 files and 0x10 for Type2 files
 };

 //Type1 file
 struct Type1Met {
 	int		Unk1;			// ignore - always 0?
 	ushort	MaxCol0;		// Zero-base maximum number of columns
 	ushort	MaxRow0;		// Zero-base maximum number of rows
 };
 
 //Type2 file
 struct Type2Met {
 	int		Unk1;			// ignore - always 0?
 	int		Unk2;			// ignore - always 0?
 	int		MaxCol0;		// Zero-base maximum number of columns
 	int		MaxRow0;		// Zero-base maximum number of rows
 };
 
 ///Sophy 8/30/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
 struct Type2MetEx {
 	int		Unks[8];
 	int		MaxCol0;
 	int		MaxRow0;
 };
 ///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
 
 ///Sophy 8/31/2010 ORG-924-P2 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
 struct Type3Met {
 	int		Unks[7];
 	int		MaxCol0;
 	int		MaxRow0;
 };
 
 struct PreDRType1 {
 	int		Unk1;
	int		ThisCol;
 	int		Unk2;
 	int		Unk3;
};
 ///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION

 //DATA_RECORD data header
 struct DataRecHeader{
 	int 	Unk1;			// Must equal to 83914754
 	int 	Unk2;			// Must equal to 0
 };
 
 //The preamble, DATA_RECORD
 struct PreDR {
	int 	Unk1;			// Must equal to 201662592
	int 	ThisCol;		// indexed from zero
	int 	Unk2;			// Must equal 1253511
	int 	Unk3;			// Ignore this
	int 	Unk4;			// Must equal to 6
	int 	BlockFlag;		// Block decision
	int 	Unk5;			// Ignore this (duplicate column #?)
	int 	Unk6;			// Ignore this
	int 	Unk7;			// Ignore this (duplicate column #?)
	int 	NumRows;		// Indexed from zero
	int 	Unk8;			// Ignore this
	int 	Unk9;			// Ignore this
 };
 
 //NAME_RECORD data header
 struct NameRecHeader {
 	int 	Unk1;			// Must equal to 83914754
 	int 	Unk2;			// Must equal to 0
 	int 	Unk3;			// Must equal to 8322
 };
 
 //For next record
 struct PostRead {
 	char 	RecType; 		// Record Type
 	char 	Unk1;			// This we assume is OK
 	char 	Unk2;			// This we assume is OK
 	char 	Unk3;			// This we assume is OK
 	int 	Offset;			// Offset to next record
 };
 
 //The preamble, NAME_RECORD
 struct PreNR {
 	int 	Unk1;			// Must equal to 336003
 	int 	Unk2;			// Must equal to 16
 	int 	ThisCol;		// indexed from zero
 };
	
#pragma pack(pop)


#define BUFSIZE 		256
#define CHK1	 		255
#define	CHK2 			256
#define WKSID 			360704
#define HDRUNK1			28674
///Sophy 8/30/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
//#define HDRUNK2			8324
#define	HDRUNK3			8324
#define	HDRUNK3_V11		8334
#define	TYPE1FLAG_V11	4
#define	TYPE2FLAG_V11	8
///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
#define TYPE1FLAG		3
#define TYPE2FLAG		5
#define TYPE1SIZE 		8
#define TYPE2SIZE 		16
#define	TYPE3SIZE		12	///Sophy 8/31/2010 ORG-924-P2 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
#define RECFLAG1_1 		1
#define RECFLAG1_2 		2
#define RECFLAG2  		32
#define RECFLAG3  		5
#define RECFLAG4  		0
#define PNRDRHDRUNK1	83914754
#define PNRDRHDRUNK2	0
#define PDRUNK1			201662592
#define PDRUNK2			1253511
#define PDRUNK4			6
#define	DRHDRUNK3		8322
#define CHK3	 		16
#define LENGTHUPPER		254
#define LENGTHLOWER		24
#define PNRUNK1			336003
#define PNRUNK2			16
	

 enum{
	DATA_RECORD 	= 	1,
	NAME_RECORD,
	EOF_RECORD		=   134  
 };

 enum{
	FILETYPE1 		= 	1,
	FILETYPE2,
	FILETYPE3,	///Sophy 8/31/2010 ORG-924-P2 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
 };
 
 enum{
 	UNKNOW_TYPE_1 	=	18,
 	UNKNOW_TYPE_2	=	21,
 	DOUBLE_TYPE		=	22,
 	LONG_TEXT_TYPE	=	32,
 	UNKNOW_TYPE_3	=	255
 };

///---Sim 11-07-2006 REMOVE_TO_FILE_HEADER
/*
 // Error Message
 enum{
	FAILED_TO_READ_FILE_TO_TREE 			= 	-10,
	FAILED_TO_GET_DATA_FROM_STREAM,
	FAILED_TO_GET_SUBVEC_FROM_BYTE_VECTOR,
	FILE_TRUNCATED,	
	FAILED_TO_READ_FILE_HEADER,
	FAILED_TO_SEEK_START,
	FAILED_TO_READ_DATA,
	FAILED_TO_GET_WKS_NAME
 };
*/
///---END REMOVE_TO_FILE_HEADER


///Sophy 8/30/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
enum { //operation type
	OP_GET	=	0,
	OP_SET,			//set one bit
	OP_RESET,		//reinit all bit
	OP_REMOVE,		//remove one bit
};

enum {	//option bits
	JNB_VERSION_NEW	= 0x0001, //indicates file created by SigmaPlot v11.0+
};
bool	central_info_control(DWORD dwBits, int nOp)
{
	static	DWORD	s_dwOptions = 0;
#ifdef	_DEBUG
	DWORD dwDebug = s_dwOptions;
#endif	//_DEBUG
	switch( nOp )
	{
	case OP_GET:
		return (s_dwOptions & dwBits);
	case OP_SET:
		s_dwOptions |= dwBits;
		return true;
	case OP_REMOVE:
		s_dwOptions &= ~dwBits;
		return true;
	case OP_RESET:
		s_dwOptions = 0;
		return true;
	default:
		ASSERT(0);
		return false;
	}
	return false;
}
///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION


// The main function
int readjnb(LPCSTR lpcszFilename, Worksheet& wks, TreeNode& trInfo, int nC1)
{

	Tree 		trFile;
	TreeNode 	trRoot = trFile.AddNode("RootStorage");
	central_info_control(0, OP_RESET); ///Sophy 8/30/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
	if(cmpdoc_read_struct(lpcszFilename, &trRoot) != ODCFL_SUCCESS)
	{
		return JNB_ERR_FAILED_TO_READ_FILE_TO_TREE;
	}
		
	int nWksNum  = 	1;
	int nColsSum =	0;
	int nRet = _read_each_stream(lpcszFilename, trRoot, wks, trInfo, nC1, nWksNum, nColsSum);
	if(nRet < 0)
	{
		return nRet;
	}
	
	return nColsSum;
}


static int _read_each_stream(LPCSTR lpcszFilename, TreeNode &trStorage, Worksheet& wks, TreeNode& trInfo, int nC1, int& nWksNum, int& nColsSum)
{		
	int nRet = 0;
	foreach(TreeNode trNode in trStorage.Children)
	{
		if (trNode.tagName == ODCFLTREE_NODENAME_STREAM)
		{
			string strLabel;
			trNode.GetAttribute(STR_LABEL_ATTRIB, strLabel);
			
			if(strLabel != "JNBContents" && strLabel != "JNBSummaryInformation") // find the node stored data
			{
				continue;
			}
			
			if(strLabel == "JNBContents") //read wks data
			{
				vector<byte> vb;
				if ( cmpdoc_read_stream(&vb, &trNode) != ODCFL_SUCCESS )
				{
					return JNB_ERR_FAILED_TO_GET_DATA_FROM_STREAM;
				}
				
				Worksheet wksActive;
				if(nWksNum != 1) 	// for reading more than one wks
				{
					///Cheney 2006-12-29 ONE_JNB_PUT_INTO_ONE_BOOK
					//one JNB is a prj, could has multi wks
					//wksActive.Create();
					WorksheetPage wp;
					wks.GetParent(wp);
					/// Hong 02/12/07 ONLY_ADD_LAYER_IF_NOT_ENOUGH
					//wp.AddLayer();
					if( wp.Layers.Count()< nWksNum )
						wp.AddLayer();
					/// end ONLY_ADD_LAYER_IF_NOT_ENOUGH
					wksActive = wp.Layers(nWksNum - 1);
					///end ONE_MPJ_PUT_INTO_ONE_BOOK
				}
				else
				{
					wksActive = wks;
				}
				nWksNum++;
				
				nRet = _get_wks_from_byte_vec(lpcszFilename, vb, wksActive, trInfo, nC1);			
				if(nRet < 0)
				{
					return nRet;
				}		
				nColsSum += nRet;
				
				//read wks name
				/// Hong 11/14/06 FIX_HARD_CODE_NOT_WORK
				//trNode = trNode.NextNode.NextNode; // "JNBSummaryInforamtion"
				trNode = trStorage.FindNodeByAttribute(STR_LABEL_ATTRIB, "JNBSummaryInformation");
				/// end FIX_HARD_CODE_NOT_WORK
				if ( cmpdoc_read_stream(&vb, &trNode) != ODCFL_SUCCESS )
				{
					return JNB_ERR_FAILED_TO_GET_DATA_FROM_STREAM;
				}
				
				if(_read_wks_name(vb, wksActive, trInfo) < 0)
				{
					return JNB_ERR_FAILED_TO_GET_WKS_NAME;
				}
			}
		}
		
		else if ( trNode.tagName == ODCFLTREE_NODENAME_SUBSTORAGE )
		{
			nRet = _read_each_stream(lpcszFilename, trNode, wks, trInfo, nC1, nWksNum, nColsSum);
			if(nRet < 0)
			{
				break;
			}
		}
	}

	return nRet;
}


#define GET_SUBVECTOR_AND_MEMCPY(_vSub, _vSrc,  _iEnd, _cpyDest, _iLength ) \
			if(!_get_sub_vector(_vSub, _vSrc, _iLength, _iEnd)) return JNB_ERR_FAILED_TO_GET_SUBVEC_FROM_BYTE_VECTOR; \
			memcpy(&_cpyDest, _vSub, _iLength);
			

static int _get_wks_from_byte_vec(LPCSTR lpcszFilename, vector<byte>& vb, Worksheet& wks, TreeNode& trInfo, int nC1)
{
	int nTempValue;
	memcpy(&nTempValue, vb, sizeof(nTempValue));
	if((nTempValue & CHK1) != 0)
	{
		return JNB_ERR_FILE_TRUNCATED;
	}
	
	int  nSubVecEnd = -1;
	// This is a worksheet file, start with the header
	int nFileType;		// Type 1 or Type 2
	int nNumCols;		// Number of Columns
	int nFileSize;		// The file size
	if(_read_header(vb, nSubVecEnd, nFileType, nNumCols, nFileSize) < 0)
	{
		return JNB_ERR_FAILED_TO_READ_FILE_HEADER;
	}
	
	int nColEnd = nC1 + nNumCols;
	//for( int nLoop = wks.GetNumCols(); nLoop < nColEnd; nLoop = wks.GetNumCols() ) 
	//{
		//wks.AddCol();
	//}
	if(nColEnd > wks.GetNumCols())
		wks.SetSize(-1, nColEnd);
	
	// Locate the first record
	int	nRecordType;	// Record types allowed : Data, Name and EOF	
	int	nOffset;		// Offset to next recordaa
	if(_seek_start(vb, nSubVecEnd, nFileSize, nOffset, nRecordType) < 0)
	{
		return JNB_ERR_FAILED_TO_SEEK_START;
	}

	// Process the records
	if(_read_data(lpcszFilename, vb, nSubVecEnd, nOffset, nFileSize, nFileType, nRecordType, wks, nC1) < 0)
	{
		return JNB_ERR_FAILED_TO_READ_DATA;
	}
	
	return nNumCols;
}

///Sophy 8/30/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
static	bool	_invalidate_header(Header& wksHdr)
{
	if ( wksHdr.WksID != WKSID || wksHdr.Unk1 != HDRUNK1 )
		return false;
	///Sophy 8/31/2010 ORG-924-P2 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
#ifdef	__SUPPORT_JNB_V11__
	if ( wksHdr.TypeSize != TYPE1SIZE && wksHdr.TypeSize != TYPE2SIZE && wksHdr.TypeSize != TYPE3SIZE )
		return false;
#else
	if ( wksHdr.TypeSize != TYPE1SIZE && wksHdr.TypeSize != TYPE2SIZE )
		return false;
#endif	//__SUPPORT_JNB_V11__
	
#ifdef	__SUPPORT_JNB_V11__
	if ( (wksHdr.Flag1 != TYPE1FLAG && wksHdr.Flag1 != TYPE2FLAG) && (wksHdr.Flag1 != TYPE1FLAG_V11 && wksHdr.Flag1 != TYPE2FLAG_V11) )
		return false;
	if ( wksHdr.Unk3 != HDRUNK3 && wksHdr.Unk3 != HDRUNK3_V11 )
		return false;
	central_info_control(wksHdr.Unk3 == HDRUNK3_V11 ? JNB_VERSION_NEW : 0, OP_SET);
#else
	if ( (wksHdr.Flag1 != TYPE1FLAG && wksHdr.Flag1 != TYPE2FLAG) )
		return false;
	if ( wksHdr.Unk3 != HDRUNK3 )
		return false;
#endif	//__SUPPORT_JNB_V11__
	return true;
}
///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION

// Header contains the File Type and the Number of Columns
static int _read_header(vector<byte>& vb, int& nSubVecEnd, int& nFileType, int& nNumCols, int& nFileSize)
{	
	vector<byte> vbSub;
	Header wksHdr;
	
	GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, wksHdr, sizeof(wksHdr));
	///Sophy 8/30/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
	//if(wksHdr.WksID != WKSID || wksHdr.Unk1 != HDRUNK1 || wksHdr.Unk2 != HDRUNK3
		//|| (wksHdr.Flag1 != TYPE1FLAG && wksHdr.Flag1 != TYPE2FLAG) 
		//|| (wksHdr.TypeSize != TYPE1SIZE && wksHdr.TypeSize != TYPE2SIZE))
	//{
		//return -1;
	//}
	if ( !_invalidate_header(wksHdr) )
		return -1;
	///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
	
	nFileSize = wksHdr.BytesLeft + 8; 

	// Set the file Type and get the number of columns
	if(wksHdr.TypeSize == TYPE1SIZE)
	{
		nFileType = FILETYPE1;
		Type1Met type1met;
		GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, type1met, sizeof(type1met))
		nNumCols = type1met.MaxCol0 + 1;
	}
	else
	{
		///Sophy 8/30/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
		nFileType = FILETYPE2;
#ifndef	__SUPPORT_JNB_V11__
		Type2Met type2met;
		GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, type2met, sizeof(type2met))
		nNumCols = type2met.MaxCol0 + 1;
#else	//V11
		if ( wksHdr.TypeSize == TYPE3SIZE )
			nFileType = FILETYPE3;
		if ( central_info_control(JNB_VERSION_NEW, OP_GET) ) //indicate file created by SigmaPlot v11.0+
		{
			if ( nFileType == FILETYPE2 )
			{
				Type2MetEx type2metEx;
				GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, type2metEx, sizeof(type2metEx))
				nNumCols = type2metEx.MaxCol0 + 1;
			}
			else if ( nFileType == FILETYPE3 )
			{
				Type3Met type3met;
				GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, type3met, sizeof(type3met))
				nNumCols = type3met.MaxCol0 + 1;
			}
		}
		else
		{
			Type2Met type2met;
			GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, type2met, sizeof(type2met))
			nNumCols = type2met.MaxCol0 + 1;
		}
#endif	//__SUPPORT_JNB_V11__
		///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
	}

	// This 'short-circuits' the rest of the code if this is Type1 format
	// Return of -2 means use old SPW routine to read stream stored in TEMPfolder
	// When we have a routine that reads long double, we can eliminate this line
	if(nFileType == FILETYPE1)
	{
		///Sophy 8/31/2010 ORG-924-P2 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
		//return -2;
#ifdef	__SUPPORT_JNB_V11__
		//central_info_control(JNB_VERSION_NEW, OP_SET);
		//return 0; //try to support type1, well...
		//on viewing the content of the file, nFileType has nothing to do with 'long double'
		//use same SigmaPlot software like v11.0 to save same *.JNB with worksheet active or inactive, sometimes it is 'nFileType == FILETYPE1' while sometimes it isn't...
		//I still do NOT know with wksHdr.TypeSize actually stands for...
		return -2;
#else
		return -2;
#endif	//__SUPPORT_JNB_V11__
		///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
	}
	else
	{
		return 0;
	}
}


// Skip over unprocessed record types, establish current record type and offset to next record
static int _seek_start(vector<byte>& vb, int& nSubVecEnd, int nFileSize, int& nOffset, int& nRecordType)
{
	char chChar[4];
	int  nCharLen 	=  4;
	int  nMax  		=  nFileSize - nCharLen - 1;
	vector<byte> vbSub;
	
	for(int nLoop = 0; nLoop == 0 && nSubVecEnd < nMax; )
	{
		GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, chChar, nCharLen)
		nRecordType = chChar[0];
		if(chChar[0] == RECFLAG1_1 || chChar[0] == RECFLAG1_2)
		{
			if(chChar[1] == RECFLAG2 && chChar[2] == RECFLAG3 && chChar[3] == RECFLAG4)
				nLoop = 1;
		}
		else
		{
			///Sophy 8/30/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
			//nSubVecEnd += 1;
			int nStepOffset = 1;
#ifdef	__SUPPORT_JNB_V11__
			if ( central_info_control(JNB_VERSION_NEW, OP_GET) )
				nStepOffset = 0;
#endif	//__SUPPORT_JNB_V11__
			nSubVecEnd += nStepOffset;
			///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
		}
	}
	
	if(!nLoop)
	{
		return -1;
	}
	
	GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, nLoop,  sizeof(nLoop))  // this is the offset to the next record
	nOffset = nLoop;
	
	return 0;
}


// Read the file records
static int _read_data(LPCSTR lpcszFilename, vector<byte>& vb, int& nSubVecEnd, int nOffset, int nFileSize, int nFileType, int nRecordType, Worksheet& wks, int nC1)
{
	vector<byte> 	vbSub;
	int			 	nStatus  = 0;
	int 			nNumCols = 0;
	int				nMaxRows = 0;
	// Set up an infinite loop with no third expression
	for(int nLoop = 0; nLoop == 0; )
	{
		int nEndTemp = nSubVecEnd;
		switch(nRecordType)
		{
		case DATA_RECORD:
			// Reading Data
			DataRecHeader drHdr;
			GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, drHdr, sizeof(drHdr))	
			if(drHdr.Unk1 != PNRDRHDRUNK1 || drHdr.Unk2 != PNRDRHDRUNK2)
			{
				return -1;
			}
			switch(nFileType)
			{
			case FILETYPE1:
				// This code does not handle Type1
				break;
			case FILETYPE2:
			case FILETYPE3:	///Sophy 8/31/2010 ORG-924-P2 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
			{
				PreDR pdrHdr;
				GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, pdrHdr, sizeof(pdrHdr))	
				if(pdrHdr.Unk1 != PDRUNK1 || pdrHdr.Unk2 != PDRUNK2 || pdrHdr.Unk4 != PDRUNK4)
				{
					return -1;
				}

				pdrHdr.ThisCol += nC1;
				nStatus = _read_data_record_data(vb, nSubVecEnd, vbSub, wks, pdrHdr.ThisCol, pdrHdr.NumRows, pdrHdr.BlockFlag, pdrHdr.Unk9);
				nMaxRows = nMaxRows < pdrHdr.NumRows? pdrHdr.NumRows : nMaxRows;
				nNumCols++;
				
				///---Sim 02-04-2010 QA81-15063 MOVE_IMP_FILE_INFO_OUT_FROM_COL_USER_INFO_TREE
				//string strColumnInfo = "ColumnInfo";
				//Tree trColumnInfo;
				//trColumnInfo.AddTextNode(lpcszFilename, "ImportFile");
				//trColumnInfo.Enable = ENABLE_READ_ONLY;
				//trColumnInfo.SetAttribute(STR_ATTRIB_BRANCH, GETNBRANCH_OPEN);
				//bool bRet = set_user_info(wks.Columns(pdrHdr.ThisCol), strColumnInfo, trColumnInfo);
				fu_set_import_file_name_info(wks.Columns(pdrHdr.ThisCol), lpcszFilename, IMPORT_INFO_TO_USER_TREE);
				///---Sim 02-05-2010 QA81-15063 ROLL_BACK_MOVE_COL_INFO_OUT_OF_USER_TREE
				// roll back move column info out of user tree, as CP said
				//fu_set_import_file_name_info(wks.Columns(pdrHdr.ThisCol), lpcszFilename);
				///---END QA81-15063 ROLL_BACK_MOVE_COL_INFO_OUT_OF_USER_TREE
				///---END QA81-15063 MOVE_IMP_FILE_INFO_OUT_FROM_COL_USER_INFO_TREE
				break;
			}
			default:
				// Can't happen
			}	// End switch(nFileType) for DATA_RECORD
			break;
		
		case NAME_RECORD:
			// Reading Name
			NameRecHeader nrHdr;
			GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, nrHdr, sizeof(nrHdr))
			if(nrHdr.Unk1 != PNRDRHDRUNK1 || nrHdr.Unk2 != PNRDRHDRUNK2 || nrHdr.Unk3 != DRHDRUNK3)
			{
				return -1;
			}

			switch(nFileType)
			{
			case FILETYPE1:		// This is a FILETYPE1 NAME_RECORD
				// This code does not handle Type1
				break;
			case FILETYPE2:		// This is a FILETYPE2 NAME_RECORD
			case FILETYPE3:		///Sophy 9/2/2010 ORG-924-P2 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
				// Must read this value
				int nTempValue;
				GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, nTempValue, sizeof(nTempValue))
				if(nTempValue != CHK2)
				{
					return -1;
				}
				
				nStatus = _read_name_record_data(vb, nSubVecEnd, vbSub, wks);
				break;						
			default:
				// This can't happen

			}	// End switch(nFileType)
			break;
			
		case EOF_RECORD:
			// Reading EOF
			nLoop = 1;	///Sophy 9/1/2010 ORG-945-P3 JUNK_ERR_MSG_DUMP_IN_SCRIPT_WINDOW
			break;
			
		default:
			nStatus = -1;
			printf("%u\n", nRecordType);
		}	// End switch(nRecordType)
		
		nSubVecEnd = nEndTemp + nOffset;
		if(nSubVecEnd >= nFileSize - 1)
		{
			nLoop = 1;
		}
		else
		{
			PostRead prHdr;
			GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, prHdr, sizeof(prHdr))
			nRecordType = prHdr.RecType & CHK1;
			nOffset = prHdr.Offset;
		}
	} //end for
	
	#if _OC_VER < 0x0800
	LT_execute("wks.labels();");
	#endif //_OC_VER < 0x0800
	//wks.SetSize(-1, nNumCols);
	return nStatus;
}


static int _read_data_record_data(vector<byte>& vb, int& nSubVecEnd, vector<byte>& vbSub, Worksheet& wks, int nThisCol, int nNumRows, int nBlock, int nDateFlag)
{
	// Read the 'block' (see developer's documentation) of FILETYPE2 DATA_RECORD values
	int nNameLen = CHK3;
	unsigned char  chTag;
	if(!(nBlock & CHK3))
	{
		// Read the first block
		// skip over column name - may be long name
		GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd + nNameLen - 1, chTag, sizeof(chTag))
		if(chTag < nNameLen)
		{
			nSubVecEnd += nNameLen;
		}
		else
		{
			int nValueTemp;
			GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd + sizeof(nValueTemp), nValueTemp, sizeof(nValueTemp))
			///Sophy 9/3/2010 ORG-924-P1 SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
			//nSubVecEnd += (nNameLen + nValueTemp);
			if ( nValueTemp < 0 )
				nSubVecEnd += nNameLen;
			else
				nSubVecEnd += (nNameLen + nValueTemp);
			///end SUPPORT_SIGMAPLOT_JNB_IMPORT_HIGHER_VERSION
			
		}
	}
	else
	{
		// Read the second block
		nSubVecEnd += nNameLen * (nNumRows + 2);
	}
		
	nNumRows++;
	/// Hong 11/16/06 DISABLE_DATE_FORMAT
	// this code can't correctly tag date format, so diable it, need more research to support this
	/*
	if(nDateFlag > 0)
	{
		wks.Columns(nThisCol).SetFormat(OKCOLTYPE_DATE);
	}
	else
	{
		wks.Columns(nThisCol).SetFormat(OKCOLTYPE_TEXT_NUMERIC);
	}
	*/
	wks.Columns(nThisCol).SetFormat(OKCOLTYPE_TEXT_NUMERIC);
	/// DISABLE_DATE_FORMAT
	Dataset	ds(wks.Columns(nThisCol));
	ds.SetSize(nNumRows);
	 
	char	chBuffer[BUFSIZE];	// try this
	for(int nThisRow = 0; nThisRow < nNumRows ; nThisRow++)
	{
		// Read individual rows of Type 2 data here
		GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd + nNameLen - 1, chTag, sizeof(chTag))
		switch(chTag)
		{
		case UNKNOW_TYPE_1:	// Ignore
		case UNKNOW_TYPE_2:	// Ignore
			nSubVecEnd += nNameLen;
			break;
		case DOUBLE_TYPE:	//	This is a double
			double	dValue;
			GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, dValue, sizeof(dValue))
			ds[nThisRow] = dValue;
			nSubVecEnd += (nNameLen - sizeof(dValue));
			break;
		case LONG_TEXT_TYPE:	// This is Long text
			int	nIgnore;
			int	nLength;
			GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, nIgnore, sizeof(nIgnore))
			GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, nLength, sizeof(nLength))
			nSubVecEnd += (nNameLen - sizeof(nIgnore) - sizeof(nLength));
			if(nLength < LENGTHUPPER)
			{
				if(nLength > LENGTHLOWER)
				{
					#if _OC_VER < 0x0800
					// Must prepare Origin for this
					LT_set_var("width", nLength);
					LT_set_var("thiscol", nThisCol + 1);
					LT_execute("wks.col$(thiscol).twidth = width;");
					#endif //_OC_VER < 0x0800
				}
				_put_text_to_buffer(chBuffer, vb, nSubVecEnd, nLength);
				// write the value
				ds.SetText(nThisRow, chBuffer);
			}
			else
			{
				// it better be
			}
			break;
		case UNKNOW_TYPE_3:	// Ignore
			nSubVecEnd += nNameLen;
			break;
		default:	// Treat this as short text of length 'cTag'
			if(chTag < nNameLen)
			{
				_put_text_to_buffer(chBuffer, vb, nSubVecEnd, chTag);
				ds.SetText(nThisRow, chBuffer);
				nSubVecEnd += (nNameLen - chTag);
			}
			else
			{
				// who knows
			}
		}	// End switch(cTag)
	}//end for
	
	return 0;
}


static int _read_name_record_data(vector<byte>& vb, int& nSubVecEnd, vector<byte>& vbSub, Worksheet& wks)
{
	// Read an ASCIIZ value, then skip ahead	
	int  nEndTemp = nSubVecEnd;	// mark here
	char chBuffer[BUFSIZE];	// try this
	char chChar;
	_put_text_to_buffer(chBuffer, vb, nSubVecEnd, BUFSIZE);
	nSubVecEnd = nEndTemp + BUFSIZE;
	
	PreNR pnrHdr;
	GET_SUBVECTOR_AND_MEMCPY(vbSub, vb, nSubVecEnd, pnrHdr, sizeof(pnrHdr))
	if(pnrHdr.Unk1 != PNRUNK1 || pnrHdr.Unk2 != PNRUNK2)
	{
		return -1;
	}

	// set the label
	/// Hong 11/15/06 CLEAN_NOT_USE_LT_IN_ORIGIN8
	#if _OC_VER < 0x0800
		LT_set_var("thiscol", pnrHdr.ThisCol);
		LT_set_str("%N", chBuffer);
		LT_execute("wks.col$(thiscol+1).label$ = %N;");
	#else //_OC_VER < 0x0800
		wks.Columns(pnrHdr.ThisCol).SetLabel(chBuffer);
	#endif //_OC_VER < 0x0800
	/// end CLEAN_NOT_USE_LT_IN_ORIGIN8	
	return 0;
}


//nLength is vbSub's size
//nEnd will return position of vbSub's last element in vbSrc(0 offset)
static BOOL _get_sub_vector(vector<byte>& vbSub, vector<byte>& vbSrc, int nLength, int& nEnd)
{
	int nBegin = nEnd + 1;
	nEnd = nEnd + nLength;
	
	if(vbSrc.GetSubVector(vbSub, nBegin, nEnd) < 0)
	{
		return FALSE;
	}
	
	return TRUE;
}

	
static void _put_text_to_buffer(char* chBuffer, vector<byte>& vb, int& nSubVecEnd, int nLoopEnd)
{
	char chTemp;
	for(int nLoop = 0; nLoop < nLoopEnd; nLoop++, nSubVecEnd++)
	{
		// copy string
		char chTemp;
		chTemp = vb[nSubVecEnd + 1];
		chBuffer[nLoop] = chTemp;
		if(chTemp == 0)
		{	
			nLoop = nLoopEnd;
		}
	}
	chBuffer[nLoopEnd] = 0;
}


static int _read_wks_name(vector<byte>& vb, Worksheet& wks, TreeNode& trInfo)
{

	char chBuffer[BUFSIZE];
	memcpy(chBuffer, vb, vb.GetSize());
	string strWksName = chBuffer;
	int nPos = _find_name_position(strWksName);
	if(nPos < 0)
	{
		return -1;
	}
	
	strWksName = strWksName.Mid(0, nPos - 1);
	strWksName.TrimLeft();  // trim space
	strWksName.TrimRight(); // trim space
	///Hong 11/7/06 FIX_ERROR_BOOK_NAME
	//no meaning of first character, temporary delete it
	strWksName.Delete(0); 
	/// end FIX_ERROR_BOOK_NAME
	wks.SetName(strWksName);
	return 0;
}


static int _find_name_position(LPCSTR lpcszWksInfo)
{
	string strWksName = lpcszWksInfo;
	string strTagt = "Worksheet";   //find last "Worksheet" position, lpcszWksInfo always be
									//"********Worksheet******************", "Worksheet"'s left is wks name
	int nPosTemp;
	int nPosLast = -1;
	/// Hong 11/14/06 MORE_FIX_ERROR_BOOK_NAME
	// should just find the first "Worsheet" position, as there is case
	//"*********Worksheet**********Worksheet", the first "Worksheet"'s left is wks name
	/*
	while( (nPosTemp = strWksName.Find(strTagt)) >= 0)
	{
		int nStartPos = nPosTemp + strTagt.GetLength();
		strWksName = strWksName.Mid(nStartPos);
		nPosLast = nPosTemp;
	}
	*/
	nPosLast = strWksName.Find(strTagt);
	/// end MORE_FIX_ERROR_BOOK_NAME
	return nPosLast;
}
