#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "text_oem.h"
#include "thr_func.h"

#if defined DMC_WIN
	#include <windows.h>
	#include <process.h>
	#include <tchar.h>
	#include <time.h>
#else
	#include <unistd.h>
#endif

#define sizeofarray(a) (sizeof(a) / sizeof(*a))

/* For Multithread Application */
#define MAX_THREAD_INTERVAL	3
#define MAX_THREAD_NUM		50

typedef enum {
	FT_GET_TEXT_V4 = 0,
	FT_GET_PAGE_TEXT_V4,
	FT_GET_PROPERTY_V4,
	FT_GET_PWD_TEXT_V4,
	FT_GET_PWD_PAGE_TEXT_V4,
	FT_GET_PWD_PROPERTY_V4,
	FT_GET_TEXT_STREAM_V4,
	FT_GET_PAGE_TEXT_STREAM_V4,
	FT_GET_TEXT,
	FT_GET_PAGE_TEXT,
	FT_GET_PROPERTY,
	FT_GET_PWD_TEXT,
	FT_GET_PWD_PAGE_TEXT,
	FT_GET_PWD_PROPERTY
} FUNC_TYPE;


typedef RESULT_TYPE (CALLING *FuncPtr)(void*);

typedef struct {
	int nFileCount;
	int nFilePos;
	char sDstDir[MAX_PATH_LEN];
	char txtfile[MAX_PATH_LEN];
	char GroupName[MAX_GROUP_NAME];
	char DefLangName[MAX_LANG_NAME];
	BOOL bBigEndian;
	DWord Option;
	DWord Option1;
	int pages;
	char password[MAX_PASSWORD_LEN];
	BOOL bMultiThread;
	BOOL bOU;
	DWord size;
	Word Csv_c;
	int nThreadInterval;
	int nThreadNumber;
	FUNC_TYPE funcType;
} CMDINFO;

void WriteUsage(void)
{
	std::string app_name;

#if defined DMC_WIN
	app_name = "app_ww";
#elif defined DMC_LINUX
	app_name = "app_ll";
#elif defined DMC_SOLARIS
	app_name = "app_ss";
#elif defined DMC_AIX
	app_name = "app_xx";
#elif defined DMC_HPUX
	app_name = "app_hh";
#else
	#error "Unknown platform!"
#endif

	printf("Usage: %s appfile [-o txtfile] [-t target dir] [-g GroupName] [-e bBigEndian] [-d DefLangName] [-p Option] [-m bMultithread] [-n Pages] [-f function number] [-w password] [-s size] [-c Csv_c] [-hi thread interval] [-hn thread number]\n", app_name.c_str());
	printf("\n");
	printf("DefLangName:     en\n");
	printf("                 jp                    \t(default)\n");
	printf("                 cn\n");
	printf("                 tw\n");
	printf("                 ko\n");
	printf("GroupName:       EUC-JP\n");
	printf("                 EUC-JP-FIX\n");
	printf("                 ISO-10646-UCS-2\n");
	printf("                 ISO-10646-UCS-4\n");
	printf("                 ISO-2022-JP\n");
	printf("                 ISO-8859-1\n");
	printf("                 Shift_JIS             \t(default)\n");
	printf("                 UTF-16\n");
	printf("                 UTF-8\n");
	printf("                 WINDOWS31J\n");
	printf("                 ChineseGBK(V4 must use GBK)\n");//ChineseGBK->GBK
	printf("                 ChineseBIG5(V4 must use Big5)\n");//ChineseBIG5->Big5
	printf("                 GB18030\n");
	printf("                 KoreanKSC(V4 must use KS_C_5601-1987)\n");//KoreanKSC->KS_C_5601-1987
	printf("                 Shift_JIS-2004\n");//2006/08/02
	printf("                 ISO-2022-JP-2004\n");//2006/08/02
	printf("                 EUC-JIS-2004\n");//2006/08/02
	printf("bBigEndian:      0: little endian\n");
	printf("                 1: big endian         \t(default)\n");
	printf("Option:          DMC_GETTEXT_OPT_KEISEN\n");
	printf("                 DMC_GETTEXT_OPT_TAG\n");
	printf("                 DMC_GETTEXT_OPT_CRLF  \t(default)\n");
	printf("                 DMC_GETTEXT_OPT_CR\n");
	printf("                 DMC_GETTEXT_OPT_LF\n");
	printf("                 DMC_GETTEXT_OPT_U2028\n");
	printf("                 DMC_GETTEXT_OPT_U2029\n");
	printf("                 DMC_GETTEXT_OPT_SHEET\n");
	printf("                 DMC_GETTEXT_OPT_RUBI\n");
	printf("                 DMC_GETTEXT_OPT_PWD\n");
	printf("                 DMC_GETTEXT_OPT_OLE   \t\n");
	printf("                 DMC_GETTEXT_OPT_OLE1\n");
	printf("                 DMC_GETTEXT_OPT_OLE2  \t\n");
	printf("                 DMC_GETTEXT_OPT_OLE3  \t\n");
	printf("                 DMC_GETTEXT_OPT_OUT\n");
	printf("                 DMC_GETTEXT_OPT_LOOP\n");
	printf("                 DMC_GETTEXT_OPT_SHEET1\n");
	printf("                 DMC_GETTEXT_OPT_CELL\n");
	printf("                 DMC_GETTEXT_OPT_SIZE\n");
	printf("                 DMC_GETTEXT_OPT_CSV1\n");
	printf("                 DMC_GETTEXT_OPT_CSV2\n");
	printf("                 DMC_GETTEXT_OPT_PDFSYM\n");
	printf("                 DMC_GETTEXT_OPT_OWNERPWD1\n");
	printf("                 DMC_GETTEXT_OPT_OWNERPWD2\n");
	printf("                 DMC_GETTEXT_OPT_OWNERPWD3\n");
	printf("                 DMC_GETTEXT_OPT_OWNERPWD4\n");
	printf("                 DMC_GETTEXT_OPT1_OWNERPWD5\n");
	printf("                 DMC_GETTEXT_OPT_ENDCODE\n");
	printf("                 DMC_GETTEXT_OPT_NULL\n");
	printf("                 DMC_GETTEXT_OPT_SHFTAG\n");
	printf("                 DMC_GETTEXT_OPT_SHFHEAD\n");
	printf("                 DMC_GETTEXT_OPT1_TEMP\n");
	printf("                 DMC_GETTEXT_OPT1_INSERTF\n");
	printf("                 DMC_GETTEXT_OPT1_INSERTF1\n");
	printf("                 DMC_GETTEXT_OPT1_INSERTF2\n");
	printf("                 DMC_GETTEXT_OPT1_INSERTF3\n");
	printf("                 DMC_GETTEXT_OPT1_COMPRESS\n");
	printf("                 DMC_GETTEXT_OPT1_COMPRESS1\n");
	printf("                 DMC_GETTEXT_OPT1_COMPRESS2\n");
	printf("                 DMC_GETTEXT_OPT1_COMPRESS3\n");
	printf("                 DMC_GETTEXT_OPT1_COMPRESS4\n");
	printf("                 DMC_GETTEXT_OPT1_TRACK\n");
	printf("                 DMC_GETTEXT_OPT1_COMPRESS5\n");
	printf("                 DMC_GETTEXT_OPT1_INSERTF4\n");
	printf("                 DMC_GETTEXT_OPT1_TXCONV\n");
	printf("                 DMC_GETTEXT_OPT1_TXCONV2\n");
	printf("bMultithread:    0: single thread test \t(default)\n");
	printf("                 1: multi-thread test\n");
	printf("Pages:           0: get page count     \t(default)\n");
	printf("                 1,2,3...: page number\n");
	printf("function number: 0: test DMC_GetText_V4\t(default)\n");
	printf("                 1: test DMC_GetPageText_V4\n");
	printf("                 2: test DMC_GetProperty_V4\n");
	printf("                 3: test DMC_GetPwdText_V4\n");
	printf("                 4: test DMC_GetPwdPageText_V4\n");
	printf("                 5: test DMC_GetPwdProperty_V4\n");
	printf("                 6: test DMC_GetTextStream_V4\n");
	printf("                 7: test DMC_GetPageTextStream_V4\n");
	printf("                 8: test DMC_GetText\n");
	printf("                 9: test DMC_GetPageText\n");
	printf("                10: test DMC_GetProperty\n");
	printf("                11: test DMC_GetPwdText\n");
	printf("                12: test DMC_GetPwdPageText\n");
	printf("                13: test DMC_GetPwdProperty\n");
	printf("thread interval: the interval of main thread sleeping, the default is 3 seconds. 0 or negative number means no sleeping.\n");
	printf("thread number:   the number of thread to create.\n");
	printf("                 the default is 50 threads\n");
	printf("-g from V3->V4 have changed.Please see the usage!\n");
}

void translang(char* dst, char* src)
{
	if(strcmp(src,"cn")==0) {
		strcpy(dst,"Simplified Chinese");
		return;
	}
	if(strcmp(src,"tw")==0) {
		strcpy(dst,"Traditional Chinese");
		return;
	}
	if(strcmp(src,"jp")==0) {
		strcpy(dst,"Japanese");
		return;
	}
	if(strcmp(src,"en")==0) {
		strcpy(dst,"English");
		return;
	}
	if(strcmp(src,"ko")==0) {
		strcpy(dst,"Korean");
		return;
	}
}

BOOL ParseCmdLine(int argc, char** argv, CMDINFO* pinfo)
{
	int i,len;
	int nFilePos = 0;
	int nFileCount=0;
	char *pCmd;
	BOOL bth=DMC_FALSE;

	/* initialize defalut value */
	memset(pinfo,0,sizeof(CMDINFO));
	strcpy(pinfo->GroupName,"Shift_JIS");
	strcpy(pinfo->DefLangName,"Japanese");
	pinfo->bBigEndian= 1;
	pinfo->funcType= FT_GET_TEXT_V4;
	pinfo->pages= 0;
	pinfo->bMultiThread= 0;
	pinfo->bOU= DMC_FALSE;
	pinfo->nThreadInterval = MAX_THREAD_INTERVAL;
	pinfo->nThreadNumber = MAX_THREAD_NUM;

	/* parse command line */
	if( argc < 2 ) {
		return DMC_FALSE;
	}
	for( i=1; i<argc; i++ ) {
		switch(argv[i][0]) {
		case '-':
			len= strlen(argv[i]);
			if( len < 2 ) {
				return DMC_FALSE;
			}
			if( len == 2 && i > argc-2 ) {
				return DMC_FALSE;
			}
			if( len == 2 && argv[i+1][0] == '-' ) {
				return DMC_FALSE;
			}
			switch(argv[i][1]) {
			case 't':
			case 'T':
				if( len == 2 ) strcpy(pinfo->sDstDir,argv[i+1]);
				else {
					pCmd= &argv[i][2];
					strcpy(pinfo->sDstDir,pCmd);
				}
				break;
			case 'o':
			case 'O':
				if( len == 2 ) strcpy(pinfo->txtfile,argv[i+1]);
				else {
					pCmd= &argv[i][2];
					strcpy(pinfo->txtfile,pCmd);
				}
				pinfo->bOU= DMC_TRUE;
				break;
			case 'g':
			case 'G':
				if( len == 2 ) strcpy(pinfo->GroupName,argv[i+1]);
				else {
					pCmd= &argv[i][2];
					strcpy(pinfo->GroupName,pCmd);
				}
				break;
			case 'w':
			case 'W':
				if( len == 2 ) strcpy(pinfo->password,argv[i+1]);
				else {
					pCmd= &argv[i][2];
					strcpy(pinfo->password,pCmd);
				}
				break;
			case 'e':
			case 'E':
				if( len == 2 ) {
					if( strlen(argv[i+1]) >1 ) {
						return DMC_FALSE;
					}
					switch( argv[i+1][0] ) {
					case '0':
						pinfo->bBigEndian= DMC_FALSE;
						break;
					case '1':
						pinfo->bBigEndian= DMC_TRUE;
						break;
					default:
						return DMC_FALSE;
					}
				}
				else {
					pCmd= &argv[i][2];
					if( strlen(pCmd) >1 ) {
						return DMC_FALSE;
					}
					switch( pCmd[0] ) {
					case '0':
						pinfo->bBigEndian= DMC_FALSE;
						break;
					case '1':
						pinfo->bBigEndian= DMC_TRUE;
						break;
					default:
						return DMC_FALSE;
					}
				}
				break;
			case 'd':
			case 'D':
				if( len == 2 ) translang(pinfo->DefLangName,argv[i+1]);
				else {
					pCmd= &argv[i][2];
					translang(pinfo->DefLangName,pCmd);
				}
				break;
			case 'p':
				if( len == 2 ) {
					pCmd= argv[i+1];
				}
				else {
					pCmd= &argv[i][2];
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_KEISEN") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_KEISEN;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_TAG") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_TAG;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_CRLF") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_CRLF;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_CR") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_CR;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_LF") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_LF;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_U2028") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_U2028;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_U2029") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_U2029;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_SHEET") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_SHEET;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_RUBI") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_RUBI;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_PWD") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_PWD;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_OLE") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_OLE;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_OLE1") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_OLE1;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_OLE2") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_OLE2;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_OLE3") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_OLE3;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_OUT") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_OUT;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_LOOP") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_LOOP;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_SHEET1") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_SHEET1;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_CELL") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_CELL;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_SIZE") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_SIZE;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_CSV1") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_CSV1;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_CSV2") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_CSV2;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_PDFSYM") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_PDFSYM;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_OWNERPWD1") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_OWNERPWD1;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_OWNERPWD2") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_OWNERPWD2;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_OWNERPWD3") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_OWNERPWD3;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_OWNERPWD4") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_OWNERPWD4;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_OWNERPWD5") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_OWNERPWD5;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_ENDCODE") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_ENDCODE;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_NULL") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_NULL;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_SHFTAG") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_SHFTAG;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT_SHFHEAD") ) {
					pinfo->Option |= DMC_GETTEXT_OPT_SHFHEAD;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_TEMP") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_TEMP;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_INSERTF") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_INSERTF;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_INSERTF1") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_INSERTF1;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_INSERTF2") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_INSERTF2;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_INSERTF3") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_INSERTF3;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_COMPRESS") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_COMPRESS;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_COMPRESS1") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_COMPRESS1;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_COMPRESS2") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_COMPRESS2;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_COMPRESS3") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_COMPRESS3;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_COMPRESS4") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_COMPRESS4;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_TRACK") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_TRACK;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_COMPRESS5") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_COMPRESS5;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_INSERTF4") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_INSERTF4;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_TXCONV") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_TXCONV;
					break;
				}
				if( !strcmp(pCmd,"DMC_GETTEXT_OPT1_TXCONV2") ) {
					pinfo->Option1 |= DMC_GETTEXT_OPT1_TXCONV2;
					break;
				}
				break;
			case 'P':	/* old method */
				if( len == 2 ) pinfo->Option= (DWord)atoi(argv[i+1]);
				else {
					pCmd= &argv[i][2];
					pinfo->Option= (DWord)atoi(pCmd);
				}
				break;
			case 'm':
			case 'M':
				if( len == 2 ) {
					if( strlen(argv[i+1]) >1 ) {
						return DMC_FALSE;
					}
					switch( argv[i+1][0] ) {
					case '0':
						pinfo->bMultiThread= DMC_FALSE;
						break;
					case '1':
						pinfo->bMultiThread= DMC_TRUE;
						break;
					default:
						return DMC_FALSE;
					}
				}
				else {
					pCmd= &argv[i][2];
					if( strlen(pCmd) >1 ) {
						return DMC_FALSE;
					}
					switch( pCmd[0] ) {
					case '0':
						pinfo->bMultiThread= DMC_FALSE;
						break;
					case '1':
						pinfo->bMultiThread= DMC_TRUE;
						break;
					default:
						return DMC_FALSE;
					}
				}
				break;
			case 'f':
			case 'F':
				{
					int fn;
					char *p;
					if( len == 2 ) {
						p = argv[i + 1];
					} else {
						p = &argv[i][2];
					}
					fn = atoi(p);
					switch(fn) {
					case 0:
						pinfo->funcType = FT_GET_TEXT_V4;
						break;
					case 1:
						pinfo->funcType = FT_GET_PAGE_TEXT_V4;
						break;
					case 2:
						pinfo->funcType = FT_GET_PROPERTY_V4;
						break;
					case 3:
						pinfo->funcType = FT_GET_PWD_TEXT_V4;
						break;
					case 4:
						pinfo->funcType = FT_GET_PWD_PAGE_TEXT_V4;
						break;
					case 5:
						pinfo->funcType = FT_GET_PWD_PROPERTY_V4;
						break;
					case 6:
						pinfo->funcType = FT_GET_TEXT_STREAM_V4;
						break;
					case 7:
						pinfo->funcType = FT_GET_PAGE_TEXT_STREAM_V4;
						break;
					case 8:
						pinfo->funcType = FT_GET_TEXT;
						break;
					case 9:
						pinfo->funcType = FT_GET_PAGE_TEXT;
						break;
					case 10:
						pinfo->funcType = FT_GET_PROPERTY;
						break;
					case 11:
						pinfo->funcType = FT_GET_PWD_TEXT;
						break;
					case 12:
						pinfo->funcType = FT_GET_PWD_PAGE_TEXT;
						break;
					case 13:
						pinfo->funcType = FT_GET_PWD_PROPERTY;
						break;
					default:
						return DMC_FALSE;
					}
				}
				break;
			case 'n':
			case 'N':
				if( len == 2 ) pinfo->pages= (DWord)atoi(argv[i+1]);
				else {
					pCmd= &argv[i][2];
					pinfo->pages= (DWord)atoi(pCmd);
				}
				break;
			case 's':
			case 'S':
				if( len == 2 ) pinfo->size= (DWord)atoi(argv[i+1]);
				else {
					pCmd= &argv[i][2];
					pinfo->size= (DWord)atoi(pCmd);
				}
				if(pinfo->size > 0x80000000) pinfo->size = 0x7fffffff;
				break;
			case 'c':
			case 'C':
				if( len == 2 ) pinfo->Csv_c= (Word)atoi(argv[i+1]);
				else {
					pCmd= &argv[i][2];
					pinfo->Csv_c= (Word)atoi(pCmd);
				}
				break;
			case 'h':
			case 'H':
				if( len == 3){
					switch(argv[i][2]){
					case 'i':
					case 'I':
						pinfo->nThreadInterval = (int)atoi(argv[i+1]);
						bth = DMC_TRUE;
						break;
					case 'n':
					case 'N':
						pinfo->nThreadNumber = (int)atoi(argv[i+1]);
						bth = DMC_TRUE;
						break;
					}
				}
				else if( len > 3){
					switch(argv[i][2]){
					case 'i':
					case 'I':
						pCmd = pCmd= &argv[i][3];
						pinfo->nThreadInterval = (int)atoi(pCmd);
						break;
					case 'n':
					case 'N':
						pCmd = pCmd= &argv[i][3];
						pinfo->nThreadNumber = (int)atoi(pCmd);
						break;
					}
				}
				break;
			default:
				return DMC_FALSE;
			}
			if( len == 2 ) i++;
			else if( len == 3 ){
				if(bth == DMC_TRUE){
					i++;
					bth = DMC_FALSE;
				}
			}
			break;
		default:
			if( nFileCount == 0 ) nFilePos= i;
			if( i > nFilePos+nFileCount ) {
				return DMC_FALSE;
			}
			nFileCount++;
		}
	}
	if( nFileCount == 0 ) {
		return DMC_FALSE;
	}

	if(pinfo->Option == 0) pinfo->Option= DMC_GETTEXT_OPT_CRLF;
	pinfo->nFileCount= nFileCount;
	pinfo->nFilePos= nFilePos;
	return DMC_TRUE;
}

// パスの最後にパスデリミタがなければ、追加する
void addPathBreak(char *path)
{
	int n = strlen(path);
#if defined DMC_WIN
	char *peos = path + n - 1;
	if (n > 0 && _tcsrchr(path, '\\') != peos && _tcsrchr(path, '/') != peos && _tcsrchr(path, ':') != peos) {
		*(path + n++) = '\\';
		*(path + n) = '\0';
	}
#else
	if (n > 0 && path[n-1] != '/' ) strcat(path, "/");
#endif
}

void setupCmdInfo(CMDINFO* pCmdInfo, char** argv, int i) {
	int n;
	char* pCmd;
#if defined DMC_WIN
	char ext[_MAX_EXT];//quman for "_splitpath()" 021030
	char fname[_MAX_FNAME];//quman for "_splitpath()" 021030
	char fname_ext[_MAX_FNAME + _MAX_EXT];
	char txtDrive[_MAX_DRIVE];
	char txtDir[_MAX_DIR];
	char txtFname[_MAX_FNAME];
	char txtExt[_MAX_EXT];
#else
	int j;
#endif

	if( pCmdInfo->nFileCount > 1 || !pCmdInfo->bOU ) {
		strcpy(pCmdInfo->txtfile, pCmdInfo->sDstDir);
		pCmd= argv[pCmdInfo->nFilePos+i];
		n= strlen(pCmd);
#if defined DMC_WIN
		if(n > 0){
				memset(ext,0,_MAX_EXT);//quman for "_splitpath()" 021030
				memset(fname,0,_MAX_FNAME);
				_splitpath(pCmd, NULL, NULL, fname, ext);//quman for "_splitpath()" 021030
				strcpy(fname_ext, fname);
				strcat(fname_ext, ext);
				pCmd=fname_ext;
		}
		addPathBreak(pCmdInfo->txtfile);
		strcat(pCmdInfo->txtfile,pCmd);
		_splitpath(pCmdInfo->txtfile, txtDrive, txtDir, txtFname, txtExt);
		_makepath(pCmdInfo->txtfile, txtDrive, txtDir, txtFname, ".txt");
#else
		for( j=n-1; j>=0; j-- ) {
			if( pCmd[j] == '/' ) {
				pCmd= &pCmd[j+1];
				break;
			}
		}
		addPathBreak(pCmdInfo->txtfile);
		strcat(pCmdInfo->txtfile,pCmd);
		n= strlen(pCmdInfo->txtfile);
		for( j=n-1; j>0; j-- ) {
			if( pCmdInfo->txtfile[j] == '/' ) break;
			if( pCmdInfo->txtfile[j] == '.' ) {
				pCmdInfo->txtfile[j]= 0;
				break;
			}
		}
		strcat(pCmdInfo->txtfile,".txt");
#endif
	}
	else {
		addPathBreak(pCmdInfo->sDstDir);
		strcat(pCmdInfo->sDstDir,pCmdInfo->txtfile);
		strcpy(pCmdInfo->txtfile,pCmdInfo->sDstDir);
	}
}

void setupThreadData(CMDINFO* pCmdInfo, char** argv, int i, THR_DATA* pData, DMC_TEXTINFO* pTextInfo, DMC_TEXTINFO_V4* pTextInfo_V4) {
	if(pCmdInfo->funcType < FT_GET_TEXT) { // V4
		strcpy((char *)(pData->textInfo_V4.GroupName), (const char *)(pTextInfo_V4->GroupName));
		strcpy((char *)pData->textInfo_V4.DefLangName, (const char *)pTextInfo_V4->DefLangName);
		pData->textInfo_V4.bBigEndian	= pTextInfo_V4->bBigEndian;
		pData->textInfo_V4.Option		= pTextInfo_V4->Option;
		pData->textInfo_V4.Option1		= pTextInfo_V4->Option1;
		pData->textInfo_V4.Size			= pTextInfo_V4->Size;
		pData->textInfo_V4.Csv_c		= pTextInfo_V4->Csv_c;
//		pData->textInfo.pFunc			= 0;
		pData->pages					= pCmdInfo->pages;
	}
	else{ // V3
		pData->textInfo.GroupName	= pTextInfo->GroupName;
		pData->textInfo.DefLangName	= pTextInfo->DefLangName;
		pData->textInfo.bBigEndian	= pTextInfo->bBigEndian;
		pData->textInfo.Option		= pTextInfo->Option;
		pData->textInfo.Option1		= pTextInfo->Option1;
		pData->textInfo.Size		= pTextInfo->Size;
		pData->textInfo.Csv_c		= pTextInfo->Csv_c;
		pData->textInfo.pFunc		= 0;
		pData->pages				= pCmdInfo->pages; 
	}
	strcpy(pData->password, pCmdInfo->password);
	strcpy((char*)pData->appfile, argv[pCmdInfo->nFilePos+i]);
	strcpy((char*)pData->txtfile, pCmdInfo->txtfile);
	pData->bFinished = DMC_FALSE;
}

void setupTextInfoData(CMDINFO* pCmdInfo, DMC_TEXTINFO* pTextInfo, DMC_TEXTINFO_V4* pTextInfo_V4) {
	pTextInfo->GroupName	= (Byte*)(pCmdInfo->GroupName);
	pTextInfo->DefLangName= (Byte*)(pCmdInfo->DefLangName);
	pTextInfo->bBigEndian	= pCmdInfo->bBigEndian;
	pTextInfo->Option		= pCmdInfo->Option;
	pTextInfo->Option1		= pCmdInfo->Option1;
	pTextInfo->Size		= pCmdInfo->size;
	pTextInfo->Csv_c		= pCmdInfo->Csv_c;
	pTextInfo->pFunc		= 0;

	strcpy((char *)pTextInfo_V4->GroupName, (const char *)(pCmdInfo->GroupName));
	strcpy((char *)pTextInfo_V4->DefLangName,(const char *)(pCmdInfo->DefLangName));
	pTextInfo_V4->bBigEndian	= pCmdInfo->bBigEndian;
	pTextInfo_V4->Option		= pCmdInfo->Option;
	pTextInfo_V4->Option1		= pCmdInfo->Option1;
	pTextInfo_V4->Size		= pCmdInfo->size;
	pTextInfo_V4->Csv_c		= pCmdInfo->Csv_c;
//	pTextInfo->pFunc		= 0;
}

FuncPtr getFuncPtr(FUNC_TYPE funcType) {
	switch(funcType) {
		// DMC_V4 0412
	case FT_GET_TEXT_V4:
		return (FuncPtr)thr_GetText_V4;
	case FT_GET_PAGE_TEXT_V4:
		return (FuncPtr)thr_GetPageText_V4;
	case FT_GET_PROPERTY_V4:
		return (FuncPtr)thr_GetProperty_V4;
	case FT_GET_PWD_TEXT_V4:
		return (FuncPtr)thr_GetPwdText_V4;
	case FT_GET_PWD_PAGE_TEXT_V4:
		return (FuncPtr)thr_GetPwdPageText_V4;
	case FT_GET_PWD_PROPERTY_V4:
		return (FuncPtr)thr_GetPwdProperty_V4;
		// DMC_V4 GET STREAM TXT 0412
	case FT_GET_TEXT_STREAM_V4:
		return (FuncPtr)thr_GetTextStream_V4;
	case FT_GET_PAGE_TEXT_STREAM_V4://quman
		return (FuncPtr)thr_GetPageTextStream_V4;
		// DMC_V3
	case FT_GET_TEXT:
		return (FuncPtr)thr_GetText;
	case FT_GET_PAGE_TEXT:
		return (FuncPtr)thr_GetPageText;
	case FT_GET_PROPERTY:
		return (FuncPtr)thr_GetProperty;
	case FT_GET_PWD_TEXT:
		return (FuncPtr)thr_GetPwdText;
	case FT_GET_PWD_PAGE_TEXT:
		return (FuncPtr)thr_GetPwdPageText;
	case FT_GET_PWD_PROPERTY:
		return (FuncPtr)thr_GetPwdProperty;
	default:
		return (FuncPtr)thr_GetText_V4;
	}
}

int main(int argc, char* argv[])
{
	int i,m;
	CMDINFO cmdinfo;
	DMC_TEXTINFO textInfo;
	DMC_TEXTINFO_V4 textInfo_V4;
	DMC_FILEINFO fileInfo;
	FuncPtr  thr_func;
	THR_DATA *pData;
	int thrunnum, total_thread_count;
	int nThInterval = MAX_THREAD_INTERVAL;
	int nThNumber = MAX_THREAD_NUM;
#if defined DMC_WIN
	HANDLE   *pth;
	unsigned thread_id;
	time_t time_s, time_e;
#else
	pthread_t *pth;
	int time_s, time_e;
#endif

	memset(&cmdinfo, 0, sizeof(cmdinfo)); 	// 2006 5/31
	memset(&textInfo, 0, sizeof(textInfo)); 	// 2006 0928
	memset(&textInfo_V4, 0, sizeof(textInfo_V4)); 	// 2006 6/19
	memset(&fileInfo, 0, sizeof(fileInfo)); 	// 2006 0928

	/* translate command line information */
	if(!ParseCmdLine(argc,argv,&cmdinfo)) {
		WriteUsage();
		return 0;
	}

#if defined DMC_WIN
	if(strlen(cmdinfo.sDstDir)){
		DMC_DIR dir;
		memset(&dir,0,sizeof(DMC_DIR));
		dir.handle = _findfirst(cmdinfo.sDstDir,&(dir.ascentry));
		if (dir.handle == -1) {
			printf("The return error is %d!\n",FileCantWrite);
			exit(1);
		}
		_findclose(dir.handle);
	}//030324
#endif

	setupTextInfoData(&cmdinfo, &textInfo, &textInfo_V4);

	printf("\nGroupName: %s\n",textInfo.GroupName);
	printf("DefLangName: %s\n",textInfo.DefLangName);
	printf("bBigEndian: %d\n",textInfo.bBigEndian);
	printf("Option: %d\n",textInfo.Option);
	if(cmdinfo.funcType == FT_GET_PAGE_TEXT_V4 || cmdinfo.funcType == FT_GET_PAGE_TEXT) {
		printf("Pages: %d\n",cmdinfo.pages);
	}

	/* Working here ... */
#if defined DMC_WIN
	time(&time_s);
#else
	time_s=time(0);
#endif
	thr_func = getFuncPtr(cmdinfo.funcType);
	if( cmdinfo.bMultiThread ) {	/* Multi-thread */
		nThInterval = cmdinfo.nThreadInterval <= 0? 0: cmdinfo.nThreadInterval;
		if(cmdinfo.nThreadNumber > 0) nThNumber = cmdinfo.nThreadNumber;

		printf("\nSetting %d threads. Max number of running thread = %d\n", cmdinfo.nFileCount, nThNumber);
		pData= (THR_DATA*)malloc( cmdinfo.nFileCount*sizeof(THR_DATA) );
		if( !pData ) {
			printf("Not enough memory.\n");
			return -1;
		}
		memset(pData, 0, cmdinfo.nFileCount*sizeof(THR_DATA));
		int thr_alloc_size;
	#if defined DMC_WIN
		thr_alloc_size = cmdinfo.nFileCount*sizeof(HANDLE);
		pth= (HANDLE*)malloc(thr_alloc_size);
	#else
		thr_alloc_size = cmdinfo.nFileCount*sizeof(pthread_t);
		pth= (pthread_t*)malloc(thr_alloc_size);
	#endif
		if( !pth ) {
			printf("Not enough memory.\n");
			return -1;
		}
		memset(pth, 0, thr_alloc_size);
		total_thread_count = 0;
		thrunnum = 0;
		/* Create every thread */
		printf("Start creating and executing threads.\n");
		for( i=0; i<cmdinfo.nFileCount; i++ ) {
			setupCmdInfo(&cmdinfo, argv, i);
			setupThreadData(&cmdinfo, argv, i, &pData[i], &textInfo, &textInfo_V4);
			/* create and suspend */
		#if defined DMC_WIN
			pth[i] = (HANDLE)_beginthreadex(NULL, 0, thr_func, (void*)&pData[i], 0,&thread_id);
			if (pth[i] == 0) {
				printf("Failed to create thread!\n");
				exit(1);
			}
			printf("Created thread: ID = %x, number = %d, file = %s\n", thread_id, i, pData[i].appfile);
		#else
			int iRet;
			iRet = pthread_create(&pth[i], NULL, thr_func, (void*)&pData[i]);
			if (iRet != 0) {
				printf("Failed to create thread!\n");
				exit(1);
			}
			printf("Created thread: ID = %x, number = %d, file = %s\n", pth[i], i, pData[i].appfile);
		#endif
			total_thread_count++;
			if (nThInterval > 0) {
				printf("Main thread sleep %d seconds.\n", nThInterval);
		#if defined DMC_WIN
				Sleep(nThInterval * 1000); //default: sleep for 3 seconds
		#else
				sleep(nThInterval); //default: sleep for 3 seconds
		#endif
			}
			if(i > 0 && ((i + 1) % nThNumber) == 0){
				printf("Main thread is waiting for termination of %d threads.\n", nThNumber);
				for( m=thrunnum; m <= i; m++ ) {
					if (pth[m] != 0 && !pData[m].bFinished == DMC_TRUE){
					#if defined DMC_WIN
						WaitForSingleObject(pth[m],INFINITE);
						CloseHandle(pth[m]);
					#else
						pthread_join(pth[m],NULL);
					#endif
						pData[m].bFinished = DMC_TRUE;
						printf("Thread number %d finished.\n", m);
					}
				}
				thrunnum = i;
			}
		}
		printf("Total count of created threads = %i\n", total_thread_count);
		/* Wait for all thread terminate then main() can free resource and return */
		printf("Main thread is waiting for termination of all threads.\n");
		for( m=0; m<cmdinfo.nFileCount; m++ ) {
			if (pth[m] != 0 && !pData[m].bFinished == DMC_TRUE){
			#if defined DMC_WIN
				WaitForSingleObject(pth[m],INFINITE);
				CloseHandle(pth[m]);
			#else
				pthread_join(pth[m],NULL);
			#endif
				pData[m].bFinished = DMC_TRUE;
				printf("Thread number %d finished.\n", m);
			}
		}
		free(pData);
		free(pth);
	}
	else {	/* Single thread */
		THR_DATA thrData;
		pData = &thrData;
		if (pData == 0) {
			printf("Not enough memory.\n");
			return -1;
		}
		for( i=0; i<cmdinfo.nFileCount; i++ ) {
			setupCmdInfo(&cmdinfo, argv, i);
			int iRet;
			iRet= DMC_GetFileInfo_V4( (Byte*)argv[cmdinfo.nFilePos+i], &fileInfo );
			if( iRet == 0 ) {
				printf("\nDetect file %s\n",argv[cmdinfo.nFilePos+i]);
				printf("\tDocFormat: \"%s\"\n",fileInfo.DocFormat);
				printf("\tDocSubFormat: \"%s\"\n",fileInfo.DocSubFormat);
				printf("\tDocCountry: \"%s\"\n",fileInfo.DocCountry);
				printf("\tProtectCode: %d\n",fileInfo.ProtectCode);
				printf("\tFileType: %d\n",fileInfo.FileType);
			}
			else {
				printf("\nDetect file %s\n", argv[cmdinfo.nFilePos+i]);
				printf("DMC_GetFileInfo() return error code %d.\n", iRet);
				continue;
			}
			// call function
			memset(pData, 0, sizeof(THR_DATA));
			setupThreadData(&cmdinfo, argv, i, pData, &textInfo, &textInfo_V4);
			thr_func(pData);
		}
	}
#if defined DMC_WIN
	time(&time_e);
	printf("Elapsed time = %.0f seconds\n", difftime(time_e, time_s));
#else
	time_e=time(0);
	printf("Elapsed time = %ld second\n", time_e - time_s);
#endif
	return 0;
}
