/**
 * This is a php-implementation of a function that is similar to mb_convert_encoding() from mbstring extension.
 * The function converts a given string from one to another character encoding.
 * @param string $string					The string being converted.
 * @param string $to_encoding				The encoding that $string is being converted to.
 * @param string $from_encoding				The encoding that $string is being converted from.
 * @return string							Returns the converted string.
 */
function _api_convert_encoding(&$string, $to_encoding, $from_encoding)
{
    $str = (string) $string;
    static $character_map = array();
    static $utf8_compatible = array('UTF-8', 'US-ASCII');
    if (empty($str)) {
        return $str;
    }
    $to_encoding = api_refine_encoding_id($to_encoding);
    $from_encoding = api_refine_encoding_id($from_encoding);
    if (api_equal_encodings($to_encoding, $from_encoding)) {
        return $str;
    }
    if ($to_encoding == 'HTML-ENTITIES') {
        return api_htmlentities($str, ENT_QUOTES, $from_encoding);
    }
    if ($from_encoding == 'HTML-ENTITIES') {
        return api_html_entity_decode($str, ENT_QUOTES, $to_encoding);
    }
    $to = _api_get_character_map_name($to_encoding);
    $from = _api_get_character_map_name($from_encoding);
    if (empty($to) || empty($from) || $to == $from || in_array($to, $utf8_compatible) && in_array($from, $utf8_compatible)) {
        return $str;
    }
    if (!isset($character_map[$to])) {
        $character_map[$to] =& _api_parse_character_map($to);
    }
    if ($character_map[$to] === false) {
        return $str;
    }
    if (!isset($character_map[$from])) {
        $character_map[$from] =& _api_parse_character_map($from);
    }
    if ($character_map[$from] === false) {
        return $str;
    }
    if ($from != 'UTF-8') {
        $len = api_byte_count($str);
        $codepoints = array();
        for ($i = 0; $i < $len; $i++) {
            $ord = ord($str[$i]);
            if ($ord > 127) {
                if (isset($character_map[$from]['local'][$ord])) {
                    $codepoints[] = $character_map[$from]['local'][$ord];
                } else {
                    $codepoints[] = 0xfffd;
                    // U+FFFD REPLACEMENT CHARACTER is the general substitute character in the Unicode Standard.
                }
            } else {
                $codepoints[] = $ord;
            }
        }
    } else {
        $codepoints = _api_utf8_to_unicode($str);
    }
    if ($to != 'UTF-8') {
        foreach ($codepoints as $i => &$codepoint) {
            if ($codepoint > 127) {
                if (isset($character_map[$to]['unicode'][$codepoint])) {
                    $codepoint = chr($character_map[$to]['unicode'][$codepoint]);
                } else {
                    $codepoint = '?';
                    // Unknown character.
                }
            } else {
                $codepoint = chr($codepoint);
            }
        }
        $str = implode($codepoints);
    } else {
        $str = _api_utf8_from_unicode($codepoints);
    }
    return $str;
}
/**
 * Replaces text within a portion of a string.
 * @param string $string				The input string.
 * @param string $replacement			The replacement string.
 * @param int $start					The position from which replacing will begin.
 * Notes:
 * If $start is positive, the replacing will begin at the $start'th offset into the string.
 * If $start is negative, the replacing will begin at the $start'th character from the end of the string.
 * @param int $length (optional)		The position where replacing will end.
 * Notes:
 * If given and is positive, it represents the length of the portion of the string which is to be replaced.
 * If it is negative, it represents the number of characters from the end of string at which to stop replacing.
 * If it is not given, then it will default to api_strlen($string); i.e. end the replacing at the end of string.
 * If $length is zero, then this function will have the effect of inserting replacement into the string at the given start offset.
 * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
 * @return string						The result string is returned.
 * This function is aimed at replacing the function substr_replace() for human-language strings.
 * @link http://php.net/manual/function.substr-replace
 */
function api_substr_replace($string, $replacement, $start, $length = null, $encoding = null)
{
    if (empty($encoding)) {
        $encoding = _api_mb_internal_encoding();
    }
    if (_api_is_single_byte_encoding($encoding)) {
        if (is_null($length)) {
            return substr_replace($string, $replacement, $start);
        }
        return substr_replace($string, $replacement, $start, $length);
    }
    if (api_is_encoding_supported($encoding)) {
        if (is_null($length)) {
            $length = api_strlen($string);
        }
        if (!api_is_utf8($encoding)) {
            $string = api_utf8_encode($string, $encoding);
            $replacement = api_utf8_encode($replacement, $encoding);
        }
        $string = _api_utf8_to_unicode($string);
        array_splice($string, $start, $length, _api_utf8_to_unicode($replacement));
        $string = _api_utf8_from_unicode($string);
        if (!api_is_utf8($encoding)) {
            $string = api_utf8_decode($string, $encoding);
        }
        return $string;
    }
    if (is_null($length)) {
        return substr_replace($string, $replacement, $start);
    }
    return substr_replace($string, $replacement, $start, $length);
}