Changeset View
Changeset View
Standalone View
Standalone View
src/parser/ArcanistBundle.php
| Show First 20 Lines • Show All 794 Lines • ▼ Show 20 Lines | if ($mode === null) { | ||||
| throw new Exception( | throw new Exception( | ||||
| pht( | pht( | ||||
| 'This patch has binary data. The PHP zlib extension is required '. | 'This patch has binary data. The PHP zlib extension is required '. | ||||
| 'to apply patches with binary data to git. Install the PHP zlib '. | 'to apply patches with binary data to git. Install the PHP zlib '. | ||||
| 'extension to continue.')); | 'extension to continue.')); | ||||
| } | } | ||||
| $input = gzcompress($data); | $input = gzcompress($data); | ||||
| $is_64bit = (PHP_INT_SIZE >= 8); | |||||
| } else { | } else { | ||||
| switch ($mode) { | switch ($mode) { | ||||
| case '32bit': | case '32bit': | ||||
| $input = $data; | $input = $data; | ||||
| $is_64bit = false; | |||||
| break; | break; | ||||
| case '64bit': | case '64bit': | ||||
| $input = $data; | $input = $data; | ||||
| $is_64bit = true; | |||||
| break; | break; | ||||
| default: | default: | ||||
| throw new Exception( | throw new Exception( | ||||
| pht( | pht( | ||||
| 'Unsupported base85 encoding mode "%s".', | 'Unsupported base85 encoding mode "%s".', | ||||
| $mode)); | $mode)); | ||||
| } | } | ||||
| } | } | ||||
| // See emit_binary_diff_body() in diff.c for git's implementation. | // See emit_binary_diff_body() in diff.c for git's implementation. | ||||
| $buf = ''; | |||||
| $lines = str_split($input, 52); | |||||
| foreach ($lines as $line) { | |||||
| $len = strlen($line); | |||||
| // The first character encodes the line length. | |||||
| if ($len <= 26) { | |||||
| $buf .= chr($len + ord('A') - 1); | |||||
| } else { | |||||
| $buf .= chr($len - 26 + ord('a') - 1); | |||||
| } | |||||
| $buf .= self::encodeBase85($line); | |||||
| $buf .= $eol; | |||||
| } | |||||
| return $buf; | |||||
| } | |||||
| private static function encodeBase85($data) { | |||||
| // This is implemented awkwardly in order to closely mirror git's | // This is implemented awkwardly in order to closely mirror git's | ||||
| // implementation in base85.c | // implementation in base85.c | ||||
| // It is also implemented awkwardly to work correctly on 32-bit machines. | // It is also implemented awkwardly to work correctly on 32-bit machines. | ||||
| // Broadly, this algorithm converts the binary input to printable output | // Broadly, this algorithm converts the binary input to printable output | ||||
| // by transforming each 4 binary bytes of input to 5 printable bytes of | // by transforming each 4 binary bytes of input to 5 printable bytes of | ||||
| // output, one piece at a time. | // output, one piece at a time. | ||||
| // | // | ||||
| Show All 11 Lines | public static function newBase85Data($data, $eol, $mode = null) { | ||||
| // However, PHP's float type is an IEEE 754 64-bit double precision float, | // However, PHP's float type is an IEEE 754 64-bit double precision float, | ||||
| // so we can safely store integers up to around 2^53 without loss of | // so we can safely store integers up to around 2^53 without loss of | ||||
| // precision. To work around the lack of an unsigned type, we just use a | // precision. To work around the lack of an unsigned type, we just use a | ||||
| // double and perform the modulus with fmod(). | // double and perform the modulus with fmod(). | ||||
| // | // | ||||
| // (Since PHP overflows integer operations into floats, we don't need much | // (Since PHP overflows integer operations into floats, we don't need much | ||||
| // additional casting.) | // additional casting.) | ||||
| // On 64 bit systems, we skip all this fanfare and just use integers. This | |||||
| // is significantly faster. | |||||
| static $map = array( | static $map = array( | ||||
| '0', | '0', | ||||
| '1', | '1', | ||||
| '2', | '2', | ||||
| '3', | '3', | ||||
| '4', | '4', | ||||
| '5', | '5', | ||||
| '6', | '6', | ||||
| ▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | static $map = array( | ||||
| '_', | '_', | ||||
| '`', | '`', | ||||
| '{', | '{', | ||||
| '|', | '|', | ||||
| '}', | '}', | ||||
| '~', | '~', | ||||
| ); | ); | ||||
| $len_map = array(); | |||||
| for ($ii = 0; $ii <= 52; $ii++) { | |||||
| if ($ii <= 26) { | |||||
| $len_map[$ii] = chr($ii + ord('A') - 1); | |||||
| } else { | |||||
| $len_map[$ii] = chr($ii - 26 + ord('a') - 1); | |||||
| } | |||||
| } | |||||
| $buf = ''; | $buf = ''; | ||||
| $lines = str_split($input, 52); | |||||
| $final = (count($lines) - 1); | |||||
| foreach ($lines as $idx => $line) { | |||||
| if ($idx === $final) { | |||||
| $len = strlen($line); | |||||
| } else { | |||||
| $len = 52; | |||||
| } | |||||
| // The first character encodes the line length. | |||||
| $buf .= $len_map[$len]; | |||||
| $pos = 0; | $pos = 0; | ||||
| $bytes = strlen($data); | while ($len) { | ||||
| while ($bytes) { | |||||
| $accum = 0; | $accum = 0; | ||||
| for ($count = 24; $count >= 0; $count -= 8) { | for ($count = 24; $count >= 0; $count -= 8) { | ||||
| $val = ord($data[$pos++]); | $val = ord($line[$pos++]); | ||||
| $val = $val * (1 << $count); | $val = $val * (1 << $count); | ||||
| $accum = $accum + $val; | $accum = $accum + $val; | ||||
| if (--$bytes == 0) { | if (--$len == 0) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| $slice = ''; | $slice = ''; | ||||
| // If we're in 64bit mode, we can just use integers. Otherwise, we | |||||
| // need to use floating point math to avoid overflows. | |||||
| if ($is_64bit) { | |||||
| for ($count = 4; $count >= 0; $count--) { | |||||
| $val = $accum % 85; | |||||
| $accum = $accum / 85; | |||||
| $slice .= $map[$val]; | |||||
| } | |||||
| } else { | |||||
| for ($count = 4; $count >= 0; $count--) { | for ($count = 4; $count >= 0; $count--) { | ||||
| $val = (int)fmod($accum, 85.0); | $val = (int)fmod($accum, 85.0); | ||||
| $accum = floor($accum / 85.0); | $accum = floor($accum / 85.0); | ||||
| $slice .= $map[$val]; | $slice .= $map[$val]; | ||||
| } | } | ||||
| } | |||||
| $buf .= strrev($slice); | $buf .= strrev($slice); | ||||
| } | } | ||||
| $buf .= $eol; | |||||
| } | |||||
| return $buf; | return $buf; | ||||
| } | } | ||||
| } | } | ||||