wstring StringConverter::ToWide (const string &str, bool noThrow)
	{
		try
		{
			mbstate_t mbState;
			Memory::Zero (&mbState, sizeof (mbState));
			const char *src = str.c_str();

			size_t size = mbsrtowcs (nullptr, &src, 0, &mbState);
			if (size == (size_t) -1)
				throw StringConversionFailed (SRC_POS);

			vector <wchar_t> buf (size + 1);
			Memory::Zero (&mbState, sizeof (mbState));

			if ((size = mbsrtowcs (&buf[0], &src, buf.size(), &mbState)) == (size_t) -1)
				throw StringConversionFailed (SRC_POS);

			wstring s;
			s.insert (s.begin(), buf.begin(), buf.begin() + size);
			return s;
		}
		catch (...)
		{
			if (noThrow)
				return L"";
			throw;
		}
	}
	void StringConverter::ToSingle (const wstring &wstr, string &str, bool noThrow)
	{
		try
		{
			mbstate_t mbState;
			Memory::Zero (&mbState, sizeof (mbState));
			const wchar_t *src = wstr.c_str();

			size_t size = wcsrtombs (nullptr, &src, 0, &mbState);
			if (size == (size_t) -1)
				throw StringConversionFailed (SRC_POS, wstr);

			vector <char> buf (size + 1);
			Memory::Zero (&mbState, sizeof (mbState));

			if ((size = wcsrtombs (&buf[0], &src, buf.size(), &mbState)) == (size_t) -1)
				throw StringConversionFailed (SRC_POS, wstr);

			str.clear();
			str.insert (0, &buf.front(), size);
			Memory::Erase (&buf.front(), buf.size());
		}
		catch (...)
		{
			if (!noThrow)
				throw;
		}
	}
	void EncryptionTestDialog::GetTextCtrlData (wxTextCtrl *textCtrl, Buffer &buffer) const
	{
		vector <byte> data;
		string dataStr = StringConverter::ToSingle (wstring (textCtrl->GetValue()));

		for (size_t i = 0; i < dataStr.size() / 2; ++i)
		{
			unsigned int dataByte;
			if (sscanf (dataStr.substr (i * 2, 2).c_str(), "%x", &dataByte) != 1)
			{
				textCtrl->SetFocus();
				throw StringConversionFailed (SRC_POS);
			}

			data.push_back ((byte) dataByte);
		}

		if (data.empty())
			return;

		buffer.CopyFrom (ConstBufferPtr (&data.front(), data.size()));
	}
	void EncryptionTestDialog::EncryptOrDecrypt (bool encrypt)
	{
		try
		{
			bool xts = XtsModeCheckBox->IsChecked();

			shared_ptr <EncryptionAlgorithm> ea = GetSelectedEncryptionAlgorithm();

			Buffer key;
			GetTextCtrlData (KeyTextCtrl, key);
			
			if (key.Size() != ea->GetKeySize())
				throw_err (LangString["TEST_KEY_SIZE"]);

			ea->SetKey (key);

			Buffer data;
			GetTextCtrlData (encrypt ? PlainTextTextCtrl : CipherTextTextCtrl, data);

			if (data.Size() != ea->GetMaxBlockSize())
				throw_err (LangString[encrypt ? "TEST_PLAINTEXT_SIZE" : "TEST_CIPHERTEXT_SIZE"]);

			if (xts)
			{
				Buffer secondaryKey;
				GetTextCtrlData (SecondaryKeyTextCtrl, secondaryKey);

				if (secondaryKey.Size() != ea->GetKeySize())
					throw_err (LangString["TEST_INCORRECT_SECONDARY_KEY_SIZE"]);

				uint64 dataUnitNumber;
				size_t blockNumber;

				try
				{
					dataUnitNumber = StringConverter::ToUInt64 (wstring (DataUnitNumberTextCtrl->GetValue()));
				}
				catch (...)
				{
					DataUnitNumberTextCtrl->SetFocus();
					throw StringConversionFailed (SRC_POS);
				}

				try
				{
					blockNumber = StringConverter::ToUInt32 (wstring (BlockNumberTextCtrl->GetValue()));
					if (blockNumber > 31)
					{
						blockNumber = 31;
						BlockNumberTextCtrl->SetValue (L"31");
					}
				}
				catch (...)
				{
					BlockNumberTextCtrl->SetFocus();
					throw StringConversionFailed (SRC_POS);
				}

				shared_ptr <EncryptionMode> xts (new EncryptionModeXTS);
				xts->SetKey (secondaryKey);
				ea->SetMode (xts);

				Buffer sector (ENCRYPTION_DATA_UNIT_SIZE);
				BufferPtr block = sector.GetRange (blockNumber * ea->GetMaxBlockSize(), ea->GetMaxBlockSize());
				
				block.CopyFrom (data);

				if (encrypt)
					ea->EncryptSectors (sector, dataUnitNumber, 1, sector.Size());
				else
					ea->DecryptSectors (sector, dataUnitNumber, 1, sector.Size());

				data.CopyFrom (block);
			}
			else
			{
				if (encrypt)
					ea->GetCiphers().front()->EncryptBlock (data);
				else
					ea->GetCiphers().front()->DecryptBlock (data);
			}

			SetTextCtrlData (encrypt ? CipherTextTextCtrl : PlainTextTextCtrl, data);
		}
		catch (exception &e)
		{
			Gui->ShowError (e);
		}
	}