www.gusucode.com > 一款C++开源代码编辑器Notepad源代码-源码程序 > 一款C++开源代码编辑器Notepad源代码-源码程序\code\Plugins\HexEditor.v0.8.4\HexEditor\src\misc\MultiTypeCombo.cpp

    //Download by http://www.NewXing.com
/*
this file is part of HexEdit Plugin for Notepad++
Copyright (C)2006 Jens Lorenz <jens.plugin.npp@gmx.de>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "SysMsg.h"
#include "MultiTypeCombo.h"
#include "tables.h"
#include "Utf8_16.h"


extern char	hexMask[256][3];



MultiTypeCombo::MultiTypeCombo() : Window()
{
	_currDataType = HEX_CODE_ASCI;
	_comboItems.clear();
}


void MultiTypeCombo::init(HWND hCombo)
{
	_hCombo	= hCombo;

	::SetWindowLong(_hSelf, GWL_STYLE, WS_VISIBLE | WS_CHILD);
	::SetWindowLong(_hSelf, GWL_EXSTYLE, CBS_DROPDOWN | CBS_AUTOHSCROLL);

	/* subclass combo to get edit messages */
	COMBOBOXINFO	comboBoxInfo;
	comboBoxInfo.cbSize = sizeof(COMBOBOXINFO);

	::SendMessage(_hCombo, CB_GETCOMBOBOXINFO, 0, (LPARAM)&comboBoxInfo);
	::SetWindowLong(comboBoxInfo.hwndItem, GWL_USERDATA, reinterpret_cast<LONG>(this));
	_hDefaultComboProc = reinterpret_cast<WNDPROC>(::SetWindowLongW(comboBoxInfo.hwndItem, GWL_WNDPROC, reinterpret_cast<LONG>(wndDefaultProc)));

	_baseCoding = GetNppEncoding();
}


LRESULT MultiTypeCombo::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	switch (Message)
	{
		case WM_PASTE:
		{
			extern tClipboard g_clipboard;

			if (g_clipboard.text == NULL)
			{
				if ((_currDataType == HEX_CODE_ASCI) ||
					(_currDataType == HEX_CODE_HEX))
				{
					if (OpenClipboard(_hParent))
					{
						eCodingType coding	= HEX_CODE_ASCI;
						HGLOBAL		hglb	= NULL;

						if (IsClipboardFormatAvailable(CF_TEXT))
						{
							hglb   = GetClipboardData(CF_TEXT);
						}
						if (IsClipboardFormatAvailable(CF_UNICODETEXT))
						{
							hglb   = GetClipboardData(CF_UNICODETEXT);
							coding = HEX_CODE_UNI;
						}

						if (hglb != NULL) 
						{
							tComboInfo	info;

							info.length = (INT)::GlobalSize(hglb);
							memcpy(info.text, ::GlobalLock(hglb), info.length);

							decode(&info, coding);
							encode(&info, _currDataType);
							SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM)info.text);
							GlobalUnlock(hglb);
						}
						CloseClipboard();
						return 0;
					}
				}
			}
			else
			{
				tComboInfo	info;

				info.length = g_clipboard.length;
				memcpy(info.text, g_clipboard.text, info.length);
				encode(&info, _currDataType);

				if (_currDataType == HEX_CODE_UNI)
				{
					::SendMessageW(hwnd, EM_REPLACESEL, 0, (LPARAM)info.text);
				}
				else
				{
					::SendMessage(hwnd, EM_REPLACESEL, 0, (LPARAM)info.text);
				}
				return 0;
			}
			break;
		}
		case WM_CHAR:
		{
			if (_currDataType == HEX_CODE_HEX)
			{
				if ((getCLM() == TRUE) &&
					((wParam >= 0x61) && (wParam <= 0x66)))
				{
					wParam &= 0x0f;
					wParam |= 0x40;
				}
				if ((getCLM() == FALSE) &&
					((wParam >= 0x41) && (wParam <= 0x46)))
				{
					wParam &= 0x0f;
					wParam |= 0x60;
				}
				else if (((wParam > 0x20) && (wParam < 0x30)) ||
						 ((wParam > 0x39) && (wParam < 0x41)) || 
						 ((wParam > 0x46) && (wParam < 0x61)) ||
						  (wParam > 0x66))
					return FALSE;
			}
			break;
		}
		default :
			break;
	}
	return ::CallWindowProc(_hDefaultComboProc, hwnd, Message, wParam, lParam);
}


void MultiTypeCombo::addText(tComboInfo info)
{
	/* find item */
	INT		count		= (INT)_comboItems.size();
	INT		i			= 0;
	INT		hasFoundOn	= -1;

	for (; i < count; i++)
	{
		if (memcmp(info.text, _comboItems[i].text, info.length) == 0)
		{
			hasFoundOn = (LONG)count - (LONG)i - 1;
		}
	}

	tEncComboInfo	encInfo;

	encInfo.comboInfo	= info	;
	encInfo.codePage	= GetNppEncoding();

	/* item missed create new and select it correct */
	if (hasFoundOn == -1)
	{
		_comboItems.push_back(encInfo);

		::SendMessage(_hCombo, CB_RESETCONTENT, 0, 0);
		for (i = count; i >= 0 ; --i)
		{
			setComboText(_comboItems[i]);
		}
	}
	selectComboText(encInfo);
}


void MultiTypeCombo::setText(tComboInfo info)
{
	setComboText(info, WM_SETTEXT);
}


void MultiTypeCombo::getText(tComboInfo* info)
{
	getComboText(info->text);
	decode(info, _currDataType);
}


eCodingType MultiTypeCombo::setCodingType(eCodingType code)
{
	eCodingType	oldDataType = _currDataType;

	/* get current text */
	getText(&_currData);

	/* change data type and update filds */
	_currDataType = code;

	INT		i		= 0;
	INT		count	= _comboItems.size() - 1;
	INT		currSel = (INT)::SendMessage(_hCombo, CB_GETCURSEL, 0, 0);

	::SendMessage(_hCombo, CB_RESETCONTENT, 0, 0);

	/* convert entries and add it to the lists */
	for (i = count; i >= 0 ; --i)
	{
		setComboText(_comboItems[i]);
	}

	/* set correct text */
	if (currSel != -1)
	{
		tEncComboInfo	encInfo;

		encInfo.comboInfo	= _currData	;
		encInfo.codePage	= GetNppEncoding();
		selectComboText(encInfo);
	}
	else
	{
		setComboText(_currData, WM_SETTEXT);
	}

	return oldDataType;
}


BOOL MultiTypeCombo::setComboText(tComboInfo info, UINT message)
{	
	tEncComboInfo	encInfo;

	encInfo.comboInfo	= info;
	encInfo.codePage	= GetNppEncoding();
	return setComboText(encInfo, message);
}


BOOL MultiTypeCombo::setComboText(tEncComboInfo info, UINT message)
{
	BOOL	isAdd = TRUE;

	encode(&info, _currDataType);

	if (_currDataType == HEX_CODE_UNI)
	{
		/* if string not exists in combo, add to it */
		if (CB_ERR == ::SendMessageW(_hCombo, CB_FINDSTRINGEXACT, -1, (LPARAM)info.text))
			::SendMessageW(_hCombo, message, 0, (LPARAM)info.text);
		else
			isAdd = FALSE;
	}
	else
	{
		::SendMessage(_hCombo, message, 0, (LPARAM)info.text);
	}

	return isAdd;
}


void MultiTypeCombo::getComboText(char* str)
{
	if (_currDataType == HEX_CODE_UNI)
	{
		::SendMessageW(_hCombo, WM_GETTEXT, COMBO_STR_MAX, (LPARAM)str);
	}
	else
	{
		::SendMessage(_hCombo, WM_GETTEXT, COMBO_STR_MAX, (LPARAM)str);
	}
}


void MultiTypeCombo::selectComboText(tEncComboInfo info)
{
	LRESULT			lResult	= -1;

	encode(&info, _currDataType);
	if (_currDataType == HEX_CODE_UNI)
	{
		lResult = ::SendMessageW(_hCombo, CB_FINDSTRINGEXACT, -1, (LPARAM)info.text);
	}
	else
	{
		lResult = ::SendMessage(_hCombo, CB_FINDSTRINGEXACT, -1, (LPARAM)info.text);
	}
	::SendMessage(_hCombo, CB_SETCURSEL, lResult, 0);
}


/* store into the data base as ASCII, e.g. get text */
void MultiTypeCombo::decode(tComboInfo* info, eCodingType type)
{
	switch (type)
	{
		case HEX_CODE_ASCI:
		{
			info->length = (INT)strlen(info->text);
			break;
		}
		case HEX_CODE_UNI:
		{
			char			buffer[COMBO_STR_MAX * 2];
			UINT			length		= 0;
			eNppCoding		nppCoding	= GetNppEncoding();
			INT				uniMask		= IS_TEXT_UNICODE_NULL_BYTES;
			UINT			codePage	= 0;

			memset(buffer, 0, COMBO_STR_MAX);

			codePage = (IsTextUnicode(info->text, info->length, &uniMask) != 0) ? CP_ACP:CP_UTF8;

			length = ::WideCharToMultiByte(codePage, 0, (WCHAR*)info->text, -1, buffer, 256, NULL, NULL) - 1;

			if ((nppCoding == HEX_CODE_NPP_UTF8) || (nppCoding == HEX_CODE_NPP_ASCI))
			{
				memcpy(info->text, buffer, length);
				info->text[length] = 0;
				info->length = length;
			}
			else
			{
				Utf8_16_Write	uniConv;

				uniConv.disableBOM();

				if (nppCoding == HEX_CODE_NPP_USCBE)
				{
					uniConv.setEncoding(Utf8_16::eUtf16BigEndian);
					info->length = (INT)uniConv.convert(buffer, length);
				}
				else if (nppCoding == HEX_CODE_NPP_USCLE)
				{
					uniConv.setEncoding(Utf8_16::eUtf16LittleEndian);
					info->length = (INT)uniConv.convert(buffer, length);
				}				
				memcpy(info->text, uniConv.getNewBuf(), info->length);
			}			
			break;
		}
		case HEX_CODE_HEX:
		{
			INT	length = (INT)strlen(info->text);

			char *temp	= (char*)new char[length+1];
			char *corr	= (char*)new char[length+1];
			char *ptr   = NULL;

			/* makes string 'AA BB CC' -> 'AABBCC' */
			temp[0] = 0;
			strcpy(corr, info->text);
			ptr = strtok(corr, " ");

			while (ptr != NULL)
			{
				strcat(temp, ptr);
				ptr = strtok(NULL, " ");
			}
			delete [] corr;

			/* if sting is odd -> return */
			length = strlen(temp);
			if (length & 0x1)
			{
				HWND hWnd = ::GetActiveWindow();
				::MessageBox(hWnd, "There are odd digits. The data will be trunkated!", "", MB_ICONWARNING | MB_OK);
				length--;
			}

			for (INT i = length - 1; i >= 0; --i)
			{
				info->text[i] = 0;
				for (INT j = 0; j < 2; j++)
				{
					info->text[i] <<= 4;
					info->text[i] |= decMask[temp[2*i+j]];
				}
			}
			info->length = (INT)(length >> 1);
			info->text[info->length] = 0;
			delete [] temp;
			break;
		}
		default:
			DEBUG("Error!!!");
			break;
	}
}


/* convert it into the user requested type, e.g. UNI (UTF8) */
void MultiTypeCombo::encode(tComboInfo* info, eCodingType type)
{
	tEncComboInfo	encInfo;
	
	encInfo.comboInfo	= *info;
	encInfo.codePage	= GetNppEncoding();
	encode(&encInfo, type);
	*info = encInfo.comboInfo;
}

void MultiTypeCombo::encode(tEncComboInfo* info, eCodingType type)
{
	switch (type)
	{
		case HEX_CODE_ASCI:
		{
			break;
		}
		case HEX_CODE_UNI:
		{
			char			buffer[COMBO_STR_MAX * 2];
			size_t			length		= 0;
			UINT			codePage	= CP_ACP;

			memset(buffer, 0, COMBO_STR_MAX * 2);

			if ((info->codePage == HEX_CODE_NPP_UTF8) || (info->codePage == HEX_CODE_NPP_ASCI))
			{
				memcpy(buffer, info->text, info->length);
				length = info->length;
			}
			else
			{
				Utf8_16_Read	uniConv;

				uniConv.noBOM();

				if (info->codePage == HEX_CODE_NPP_USCBE)
				{
					uniConv.forceEncoding(Utf8_16::eUtf16BigEndian);
					length = uniConv.convert(info->text, info->length);
				}
				else if (info->codePage == HEX_CODE_NPP_USCLE)
				{
					uniConv.forceEncoding(Utf8_16::eUtf16LittleEndian);
					length = uniConv.convert(info->text, info->length);
				}
				memcpy(buffer, uniConv.getNewBuf(), length);
				codePage = CP_UTF8;
			}

			::MultiByteToWideChar(codePage, 0, buffer, -1, (WCHAR*)info->text, COMBO_STR_MAX);
			break;
		}
		case HEX_CODE_HEX:
		{
			if (info->length != 0)
			{
				char *temp	= (char*)new char[info->length+1];
				memcpy(temp, info->text, info->length);

				strcpy(info->text, hexMask[(UCHAR)temp[0]]);
				for (INT i = 1; (i < info->length) && ((i*3) < COMBO_STR_MAX); i++)
				{
					strcat(info->text, " ");
					strcat(info->text, hexMask[(UCHAR)temp[i]]);
				}
				info->length = (info->length * 3) - 1;
				delete [] temp;
			}
			break;
		}
		default:
			break;
	}
}