/*------------------------------------------------------------------------------*
 *	File Name: 	oDcFL.h															*
 *	Purpose: Compond Document Extraction										*																	*
 *																				*
 *	Author:		CPY																*
 *  Creation:																	*
 *  	Copyright (c) OriginLab Corp.	2006									*
 *																				*
 *	Modification log                                                        	*
 *------------------------------------------------------------------------------*/


#ifndef _O_DCFL_H
#define _O_DCFL_H

#ifdef _MSC_VER
	#ifndef _DCFL_DLL_
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$we are NOT in oDcFL dll, but some other DLL")
	#else
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$we are in oDcFL dll")
	#endif

	#ifdef _DCFL_DLL_
		#define ODCFL_API __declspec(dllexport)
	#else
		#define ODCFL_API __declspec(dllimport)
	#endif

	#define TreeNode	OCXmlWrapperBase
	#define	string		CString
	#define	ByteArray	CScriptMocaObject

	extern "C" {
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ extern C in oDcFL.h")
#else
	#define	ByteArray	vector<byte>
	#define ODCFL_API
	#pragma dll(oDcFL)	// Associate all functions below to oDcFL.dll which must be in the Origin EXE folder
#endif	//_MSC_VER


// Various return codes for the functions:
enum {
	ODCFL_STREAM_COULD_NOT_BE_EXTRACTED = -20,
	ODCFL_INPUT_FILE_NOT_FOUND,
	ODCFL_NOT_COMPUND_FILE,
	ODCFL_UNUSED,
	ODCFL_GENERAL_FAILURE,
	ODCFL_INVALID_TREENODE,
	ODCFL_STREAM_OR_STORAGE_COULD_NOT_BE_FOUND,
	ODCFL_OUT_OF_MEMORY,
	
	ODCFL_SUCCESS = 0,
};

#define		ODCFLTREE_NODENAME_SUBSTORAGE		"storage"
#define		ODCFLTREE_NODENAME_STREAM			"stream"


/**
		Read the structure of a compound document
	Parameters:
		lpcszDoc = [input] compound document fullpath filename
		trStruct = [output] The structure of the tree corresponds to the structure of (sub)storages
					in the compund document (every storage can contain substorages and/or streams).
					Every (sub)storage node has tagname ODCFLTREE_NODENAME_SUBSTORAGE
					(except the one passed into the function, whose tagname is given by the caller and can be
					anything).
					Every stream has tagname ODCFLTREE_NODENAME_STREAM.
					The label of each node is the name of the storage or stream it represents, except
					the root storage node (the one passed to the function) whose label is the pathname (lpcszDoc).
					The value of each stream node is an integer representing the size of the stream in bytes.
	Return:
		ODCFL_SUCCESS if success, or a negative number from the ODCFL_ enumaration if failure.
	Example:
		// Run the function test_cmpdoc_read_struct_and_streams() by passing full pathname of a compound document file.
		// For example, any Word or Excel document is a compound document.
		#include <..\originlab\odcfl.h>
		static	void	dump_byte_array(vector<byte> &vby, int maxnumBytesToDump)
		{
			int		nSize = vby.GetSize();
			int		nNumInOneRow = 16;
			for (int ii = 0; ii < maxnumBytesToDump && ii < nSize; ii += nNumInOneRow)
			{
				int		nEnd = ii + nNumInOneRow - 1;
				if ( nEnd > nSize - 1 )
					nEnd = nSize - 1;

				printf("\t");
				string		strByteValues, strCharacters;
				for (int jj = ii; jj <= nEnd; jj++)
				{
					BYTE	by = vby[jj];
					string	str;
					str.Format("%02x ", vby[jj]);
					strByteValues += str;
					//str.Format("%c", vby[jj]);
					//strCharacters += str;
				}
				
				//printf("%s   %s\n", (LPCSTR)strByteValues, (LPCSTR)strCharacters);
				printf("%s\n", (LPCSTR)strByteValues);
			}
		}


		static	BOOL	cmpdoc_dump_all_streams(TreeNode &trStorage, LPCSTR lpcszPrefix, int maxnumBytesToDump)
		{
			string		str;
			if ( lpcszPrefix )
			{
				str = lpcszPrefix;
				str += '|';
			}
			
			string		strLabel;
			trStorage.GetAttribute(STR_LABEL_ATTRIB, strLabel);
			str += strLabel;
			foreach(TreeNode trNode in trStorage.Children)
			{
				string			strTagName = trNode.tagName;
				if ( strTagName == ODCFLTREE_NODENAME_STREAM )
				{
					trNode.GetAttribute(STR_LABEL_ATTRIB, strLabel);
					string		strStreamPathName = str + "| " + strLabel;
					out_str(strStreamPathName);
					
					vector<byte>	vby;
					if ( ODCFL_SUCCESS == cmpdoc_read_stream(&vby, &trNode) )
					{
						dump_byte_array(vby, maxnumBytesToDump);
					}
				}
				else if ( strTagName == ODCFLTREE_NODENAME_SUBSTORAGE )
				{
					// Recurse:
					cmpdoc_dump_all_streams(trNode, str, maxnumBytesToDump);
				}
				else
					ASSERT(FALSE);
			}
			
			return TRUE;
		}
		// use Excel as example compound document
		void	cmpdoc_read_struct_ex1()
		{
			string strPathName = GetOpenBox("*.xls");
			Tree		tree;
			TreeNode	trRoot = tree.AddNode("RootStorage");
			
			int			nn = cmpdoc_read_struct(strPathName, &trRoot);
			
			if ( ODCFL_SUCCESS != nn )
			{
				printf("Failed to read the compound document structure.\n"
						"The error code is %d\n", nn);
				return;
			}
			
			out_tree(trRoot);
			
			// Go over all the streams and get their content:
			printf("PathName = %s\n", strPathName);
			int			maxnumBytesToDump = 0x100;
			printf("Dumping at most %u bytes from every stream\n\n", maxnumBytesToDump);
			cmpdoc_dump_all_streams(trRoot, NULL, maxnumBytesToDump);
			
			
			return;
		}
	See also:
		cmpdoc_read_stream
*/
ODCFL_API int cmpdoc_read_struct(LPCSTR lpcszDoc, TreeNode *trStruct);

/**
		Read stream from a compound document
	Parameters:
		pv = [output] the byte array holding the contents of the stream.
		trStream = [input] a tree node from the tree obtained by calling cmpdoc_read_struct(). It must be a stream node.
	Return:
		ODCFL_SUCCESS if success, or a negative number from the ODCFL_ enumaration if failure.
	Example:
		See the example for cmpdoc_read_struct().
	See also:
		cmpdoc_read_struct
*/
ODCFL_API int cmpdoc_read_stream(ByteArray* pv, const TreeNode *trStream);


#ifdef _MSC_VER
	}
#endif	//_MSC_VER

#endif //_O_DCFL_H
