<?php

/**

* A class that converts strings in ANSEL character set into Unicode (UTF-8).

*

* ANSEL is known as the American Library Association character set, and is until now

* (2009) still the main character set used in GEDCOM files, the standard format for

* exchanging genealogical data.

*

* The conversion is based on the work of Heiner Eichmann documented at his web page:

*      http://www.heiner-eichmann.de/gedcom/charintr.htm

* The conversion uses the mapping file that can be downloaded from here:

*      http://www.heiner-eichmann.de/gedcom/ans2uni.con.zip

*

* You are free to use this code and edit it to suit your needs, but let my parts of the

* commenting be intact. It is not legal to sell this piece of software.

* This class was published on my blog at http://www.gammelsaeter.com/

*

* @author Pål Gjerde Gammelsæter

* @license Free to use, illegal to sell.

* @version 2nd October 2009

*/

class Ansel2Unicode {

	// Huub: Commented this line because of errors in PHP 4, this line is not used???
	// private $_mapping;   // The character mappings



	/**

	* Constructor of the object.

	* Generates the table for ANSEL to Unicode mapping.

	* @param String $conversionFile  The name of the mapping file made by Heiner Eichmann.

	*                                 The file can be downloaded from this URL:

	*                                 http://www.heiner-eichmann.de/gedcom/ans2uni.con.zip

	*/

	public function __construct($conversionFile = 'include/ansel2unicode/ans2uni.con') {

		$temp_ini_file = 'mappings.ini';    // Name of temporary ini file



		/*

		if (file_exists($conversionFile)) {

			// Load file contents, convert into well-formed ini file for later parsing.

			// This is done because the original mapping file cannot be parsed by the

			// PHP function parse_ini_file.

			//print "<br>bef make temp ".date('h:i:s:u')."<br>";

			$file_contents = file_get_contents($conversionFile, 'FILE_BINARY'); // Load contents

			$file_contents = $this->stripComments($file_contents, '#');         // Strip comments

			file_put_contents($temp_ini_file, $file_contents);                  // Save contents

			//print "<br>after make temp ".date('h:i:s:u')."<br>";

		*/


		// Get ini contents

		$map = parse_ini_file($temp_ini_file);            // Parse ini file



		// Go through map to split up the mappings that contain more characters in the key,

		// so that mappings with one character goes into $this->mapping[1], those with two

		// characters goes to $this->mapping[2] etc.

		foreach ($map as $key => $value) {

			$characters = explode('+', $key);             // Split string where '+' occurrs

			$num_chars = count($characters);              // Count number of characters

			$this->_mapping[$num_chars][strtolower($key)] = $value;// Put mapping in right place

		}

		/*

		//print "<br>after mapsplit ".date('h:i:s:u')."<br>";

		// Delete temporary ini file efterwards if exists

		if (file_exists($temp_ini_file)) { unlink($temp_ini_file); }

		}

		else {

			echo '<p>No mapping file with name '.$conversionFile.' exists. Download this file '.

			'from <a href="http://www.heiner-eichmann.de/gedcom/ans2uni.con.zip">here</a>.';

		}

		*/

	}





	/**

	* Loops through string to look for matches in the mapping table and replaces the

	* characters that has a mapping. This will convert the given string to Unicode/UTF-8.

	*

	* @param String $string    String to convert to Unicode (ÙTF-8)

	* @return String

	*/

	public function convert($string) {

		$i          = 0;                                // Initialize counter in loop

		$output     = '';                               // String to output



		// Go through string, fetch next character, next two characters and next three characters

		// to check against mapping table if mapping exist.



		$convertit=0; // default - don't use the ANSEL conversion



		for($a=224; $a<=255; $a++) {  // look for special ANSEL diacritics in range chr(224) till chr (255)

			if(strpos($string,chr($a)) != false ) {

				$convertit=1; // there is at least one special diacritic - we need to do ANSEL conversion

				break;  // no need to look for further diacritics - we have to do ANSEL conversion anyway

			}

		}


		if($convertit==0) { $output=$string; }  // no diacritic in the string no need for ANSEL conversion



		while ($i <= (strlen($string) - 1) AND $convertit==1) { // do special ANSEL conversion for diacritics

			$remains = strlen($string) - $i;            // Characters that remains in string

			$key = array();                             // Initialize array



			// Get next, next two and next three characters (if number of remaing

			// characters allow it)

			if ($remains >= 3) { $key[3] = $this->getKeyMap($string, $i, 3); }

			if ($remains >= 2) { $key[2] = $this->getKeyMap($string, $i, 2); }

			if ($remains >= 1) { $key[1] = $this->getKeyMap($string, $i, 1); }



			// Check if next three characters exist in mapping, and replace them if they do

			if (count($key) == 3 && array_key_exists($key[3], $this->_mapping[3])) {

				$output .= chr(hexdec($this->_mapping[3][$key[3]]));

				$i += 3; // We mapped three bytes into one char, jump three forward for next loop

			}

			// Check if next two characters exist in mapping, and replace them if they do

			elseif (count($key) >= 2 && array_key_exists($key[2], $this->_mapping[2])) {

				$output .= chr(hexdec($this->_mapping[2][$key[2]]));

				$i += 2;

			}

			// Check if next character exist in mapping, and replace it if it does

			elseif (count($key) >= 1 && array_key_exists($key[1], $this->_mapping[1])) {

				$output .= chr(hexdec($this->_mapping[1][$key[1]]));

				$i++;

			}

			// No mapping found, just return the character we have

			else {

				$output .= chr(hexdec($key[1]));

				$i++;

			}

		}



		return utf8_encode($output); // Return the string with replacements

	}





	/**

	* Format a string to same format as the keys in mapping table. The characters are

	* formatted as hexadecimal and separated with a plus sign. Example:

	* "Gon" -> "47+6f+6e"

	*

	* @param String  $string  The string witch contains the characters to convert

	* @param int     $start   Start position for the characters to convert

	* @param int     $length  Number of characters to convert

	* @return String

	*/

	private function getKeyMap($string, $start, $length = 1) {

		$array = str_split(substr($string, $start, $length));

		foreach ($array as $key => $value) { $array[$key] = dechex(ord($value)); }

		return implode('+', $array);

	}





	/**

	* Strips comments off the end of each line in given string.

	*

	* @param String    $data           String where comments are being removed

	* @param String    $comment_char   The character indicating start of a comment

	* @return String[] The array of strings where comments are removed

	*/

	private function stripComments($string, $comment_char = '#') {

		$array = explode("\n", $string);                            // Split each line into array

		$return = array();

		foreach ($array as $i => $line) {

			$pos = strpos($line, $comment_char);                   // Get postition of first '#'

			if ($pos > 0) { $return[$i] = substr($line, 0, $pos); }// Get part before '#'

			else { $return[$i] = $line; }                          // No '#' found

		}

		return implode("\n", $return);                               // Merge together as a string

	}

}



?>