// Mała klasa pisana dla projektu ActiveDocument podczas pracy w DNet.
// Jej zadaniem było dokonywać konwersji z zapisu HEX (dwa znaki na bajt)
// do formatu binarnego. Lokalna aplikacja pisana w C++ działająca na
// komputerze klienta służyła do podpisywania plików
// binarnych/sprawdzania podpisów i wysyłała do aplikacji na serwerze
// pliki podpisów wraz z dodatkowymi danymi.
// 
// Aby zapewnić przenośność przygotowałem prosty format tekstowy, w
// którym przy pomocy zapisu HEX przenosiłem pliki binarne pomiędzy
// klientem (C++) a serwerem (Java).
// 
// Proszę zwrócić uwagę na metodę selfTest(), która sprawdza poprawność
// klasy i służy jako dokumentacja użycia klasy.
//
// Dariusz Cieślak, cieslakd at gazeta.pl

package activeDocument;

import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.BufferedOutputStream;

public class HexConverter
{
	String m_sHexBody;

	public HexConverter(String sHexBody)
	{
		m_sHexBody = sHexBody;
	}

	private static int _hexToByte(char ch) throws Exception
	{
		final int nBASE = 16;
		int n = Character.digit(ch, nBASE);

		if(n == -1)
			throw new Exception("bad hex digit: '" + ch + "'");

		return n;
	}

	/** zapisuje podanyc w kontruktorze ciąg HEX do formatu
	    binarnego */
	public void saveBinary(String sOutputFile) throws Exception
	{
		BufferedOutputStream bos =
			new BufferedOutputStream(
				new FileOutputStream(sOutputFile));

		// one byte written as two hex digits
		int nChars = m_sHexBody.length();

		// length should be even
		should((nChars & 1) == 0, "Length should be even:" + nChars);

		int nChar = 0;
		while(nChar < nChars)
		{
			bos.write(
				_hexToByte(m_sHexBody.charAt(nChar)) * 16 +
				_hexToByte(m_sHexBody.charAt(nChar + 1)));
			nChar += 2;
		}

		bos.close();
	}


	public static void selfTest() throws Exception
	{
		should(_hexToByte('f') == 0xf);
		should(_hexToByte('0') == 0x0);
		should(_hexToByte('a') == 0xa);

		final String sFILE = "c:/temp/c.txt";

		HexConverter hc = new HexConverter("12fc6f");

		hc.saveBinary(sFILE);

		BufferedInputStream bis = new BufferedInputStream(
				new FileInputStream(sFILE));

		should(bis.read() == 0x12);
		should(bis.read() == 0xfc);
		should(bis.read() == 0x6f);
		should(bis.read() == -1);

		bis.close();
	}

	/** raises error when condition isn't true */
	static void should(boolean boCond,String sText) throws Exception
	{
		if(!boCond)
			throw new Exception(sText);
	}

	/** raises error when condition isn't true */
	static void should(boolean boCond) throws Exception
	{
		if(!boCond)
			throw new Exception();
	}
}
