* $base = new BaseX('0123456789ABCDEF', false, ' '); * * * @throws GTException * @param string $alphabet the encoding alphabet * @param boolean $caseSensitive if true both the encoder/decoder will be case sensitive * @param string $pad the padding characters used to even out the encoded output * * @see GTBase16, GTBase32, GTBase64 */ public function __construct($alphabet, $caseSensitive, $pad) { $this->bits = 1; while ((1 << $this->bits) < strlen($alphabet)) { $this->bits++; } if ((1 << $this->bits) != strlen($alphabet)) { throw new GTException("The size of the encoding alphabet is not a power of 2"); } $this->block = 8 / GTUtil::gcd(8, $this->bits); $this->chars = GTUtil::toArray($alphabet); $this->min = -1; $this->max = -1; if ($caseSensitive) { $this->addMinMax($alphabet); $this->values = array(); for ($i = 0; $i < ($this->max - $this->min) + 1; $i++) { array_push($this->values, -1); } $this->addChars($alphabet); } else { $this->addMinMax(strtoupper($alphabet)); $this->addMinMax(strtolower($alphabet)); $this->values = array(); for ($i = 0; $i < ($this->max - $this->min) + 1; $i++) { array_push($this->values, -1); } $this->addChars(strtolower($alphabet)); $this->addChars(strtoupper($alphabet)); } if ($pad >= $this->min && $pad <= $this->max && $this->values[$pad - $this->min] != -1) { throw new GTException("The padding character appears in the encoding alphabet"); } $this->pad = $pad; } /** * Encodes the given bytes into a base-X string. * * This method also optionally inserts a separator into the result with given frequency. * * @throws GTException * @param array $bytes the bytes to encode * @param int $offset the start offset in bytes array * @param int $length the number of bytes to encode * @param string $separator if separator is not null it's inserted into the encoded string at frequency * @param int $frequency if separator is not null it's inserted into the encoded string at frequency * @return string string containing the encoded data */ public function encode($bytes, $offset = null, $length = null, $separator = null, $frequency = null) { if (empty($bytes)) { throw new GTException("parameter bytes is required"); } if (!is_array($bytes)) { throw new GTException("parameter bytes must be an array of bytes"); } if ($offset == null) { $offset = 0; } if ($length == null) { $length = count($bytes); } $offset = (int) $offset; $length = (int) $length; if ($offset < 0 || $offset > count($bytes)) { throw new GTException("parameter offset out of bounds"); } if ($length < 0 || $offset + $length > count($bytes)) { throw new GTException("parameter length out of bounds"); } if ($separator == null) { $frequency = 0; } else { for ($i = 0; $i < strlen($separator); $i++) { $c = $separator{$i}; if ($c >= $this->min && $c <= $this->max && $this->values[$c - $this->min] != -1) { throw new GTException("parameter separator contains characters from the encoding alphabet"); } } } $result = ""; $i = 0; // number of output characters produced $j = 0; // number of input bytes consumed $buff = 0; // buffer of input bits not yet sent to output $size = 0; // number of bits in the buffer $mask = (1 << $this->bits) - 1; while ($this->bits * $i < 8 * $length) { if ($frequency > 0 && $i > 0 && $i % $frequency == 0) { $result .= $separator; } while ($size < $this->bits) { $next = ($j < $length ? $bytes[$offset + $j] : 0); $j++; $buff = ($buff << 8) | ($next & 0xff); $size += 8; } $result .= $this->chars[($buff >> ($size - $this->bits)) & $mask]; $size -= $this->bits; $i++; } // pad while ($i % $this->block != 0) { if ($frequency > 0 && $i > 0 && $i % $frequency == 0) { $result .= $separator; } $result .= $this->pad; $i++; } return $result; } /** * Decodes the given base-X string into bytes. * * This method silently ignores any non-base-X characters. * * @throws GTException * @param string $string the string to decode * @return array decoded bytes */ public function decode($string) { if (empty($string)) { throw new GTException("parameter string is required"); } $result = array(); $i = 0; // number of output bytes produced $j = 0; // number of input bytes consumed $buff = 0; // buffer of input bits not yet sent to output $size = 0; // number of bits in the buffer while ($j < strlen($string)) { $next = ord($string{$j}); $j++; if ($next < $this->min || $next > $this->max) { continue; } $next = $this->values[$next - $this->min]; if ($next == -1) { continue; } $buff = ($buff << $this->bits) | $next; $size += $this->bits; while ($size >= 8) { $result[$i] = (($buff >> ($size - 8)) & 0xff); $size -= 8; $i++; } } return $result; } /** * Updates $this->min and $this->max so that the range [$this->min .. $this->max] includes all values from $string * * @param string $string characters to process * @return void */ private function addMinMax($string) { for ($i = 0; $i < strlen($string); $i++) { $c = ord($string{$i}); if ($this->min == -1 || $this->min > $c) { $this->min = $c; } if ($this->max == -1 || $this->max < $c) { $this->max = $c; } } } /** * Adds the characters from the given string to $this->values lookup table. * * @throws GTException * @param string $string characters to process * @return void */ private function addChars($string) { for ($i = 0; $i < strlen($string); $i++) { $c = ord($string{$i}) - $this->min; if ($this->values[$c] != -1 && $this->values[$c] != $i) { throw new GTException("Duplicate character in encoding alphabet"); } $this->values[$c] = $i; } } } ?>