blob: 1f57029eb1384f61ff60db06a380fa40a2de3b9b [file] [log] [blame]
<?php
/**
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace google\net;
require_once 'google/appengine/runtime/proto/Decoder.php';
require_once 'google/appengine/runtime/proto/ProtocolBufferEncodeError.php';
/**
* Class to encode protocol buffer into serialized form. Used by protocol
* buffer implementation.
*/
class Encoder {
private $buf = "";
private function putVarInt32Internal($val) {
if ($val < 0) {
for ($i = 0; $i < 9; $i++) {
$this->buf .= pack('C1', ($val & 127) | 128);
$val >>= 7;
}
$this->buf .= pack('C1', 1);
} else {
while ($val != 0) {
$bits = $val & 127;
$val >>= 7;
if ($val != 0) {
$bits |= 128;
}
$this->buf .= pack('C1', $bits);
}
}
}
public function putVarInt32($val) {
if (($val & 127) == $val) {
$this->buf .= pack('C1', $val);
return;
}
// Cheaper approximate check, then more expensive precise check.
// On ia32 we cannot distinguish MAX_INT32 and values larger than
// MAX_INT32 without bcmath.
if ($val >= Decoder::MAX_INT32 && bccomp($val, Decoder::MAX_INT32) > 0) {
throw new ProtocolBufferEncodeError(
"Value out of sint32 range: " . $val);
}
// Similar check for negative numbers.
if ($val <= Decoder::MIN_INT32 && bccomp($val, Decoder::MIN_INT32) < 0) {
throw new ProtocolBufferEncodeError(
"Value out of sint32 range: " . $val);
}
$this->putVarInt32Internal($val);
}
public function putVarUint64Internal($val) {
while (bccomp($val, 0) != 0) {
$bits = bcmod($val, 128);
$val = bcdiv($val, 128);
if (bccomp($val, 0) != 0) {
$bits |= 128;
}
$this->buf .= pack('C1', $bits);
}
}
public function putVarUint32($val) {
if (($val & 127) == $val) {
$this->buf .= pack('C1', $val);
return;
}
if ($val < 0) {
throw new ProtocolBufferEncodeError(
"Value out of uint32 range: " . $val);
}
if ($val < Decoder::MAX_INT32) {
$this->putVarInt32Internal($val);
return;
}
if (bccomp($val, Decoder::RANGE_UINT32) >= 0) {
throw new ProtocolBufferEncodeError(
"Value out of uint32 range: " . $val);
}
$this->putVarUint64Internal($val);
}
public function putVarUint64($val) {
if ($val < 0) {
throw new ProtocolBufferEncodeError(
"Value out of uint64 range: " . $val);
}
if ($val < Decoder::MAX_INT32) {
$this->putVarInt32($val);
return;
}
if (bccomp($val, Decoder::RANGE_UINT64) >= 0) {
throw new ProtocolBufferEncodeError(
"Value out of uint64 range: " . $val);
}
$this->putVarUint64Internal($val);
}
public function putVarInt64($val) {
if (bccomp($val, 0) >= 0) {
if (bccomp($val, Decoder::MAX_INT64) > 0) {
throw new ProtocolBufferEncodeError(
"Value out of sint64 range: " . $val);
}
} else {
if (bccomp($val, Decoder::MIN_INT64) < 0) {
throw new ProtocolBufferEncodeError(
"Value out of sint64 range: " . $val);
}
$val = bcadd($val, Decoder::RANGE_UINT64);
}
$this->putVarUint64($val);
}
public function putBoolean($val) {
if ($val === true) {
$this->putVarInt32(1);
} elseif ($val === false) {
$this->putVarInt32(0);
} else {
throw new ProtocolBufferEncodeError("Bool proto value expected");
}
}
public function put32($val) {
if ($val < 0) {
throw new ProtocolBufferEncodeError(
"Value out of fixed32 range: " . $val);
}
if ($val >= Decoder::MIN_INT32 && bccomp($val, Decoder::RANGE_UINT32) >= 0) {
throw new ProtocolBufferEncodeError(
"Value out of fixed32 range: " . $val);
}
if (bccomp($val, Decoder::MAX_INT32) > 0) {
$val = bcsub($val, Decoder::RANGE_UINT32);
}
$this->buf .= pack('V1', $val);
}
public function put64($val) {
if ($val < 0) {
throw new ProtocolBufferEncodeError(
"Value out of fixed64 range: " . $val);
}
if (bccomp($val, Decoder::RANGE_UINT64) >= 0) {
throw new ProtocolBufferEncodeError(
"Value out of fixed64 range: " . $val);
}
$this->put32(bcmod($val, Decoder::RANGE_UINT32));
$this->put32(bcdiv($val, Decoder::RANGE_UINT32));
}
public function putFloat($val) {
// TODO: big endian not supported
$this->buf .= pack('f1', $val);
}
public function putDouble($val) {
// TODO: big endian not supported
$this->buf .= pack('d1', $val);
}
public function putPrefixedString($out) {
$this->putVarInt32(strlen($out));
$this->buf .= $out;
}
public function toString() {
return $this->buf;
}
}