blob: d62509a561e20ec30932e1f68c18cf8a0bde3511 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
use 5.10.0;
use strict;
use warnings;
use Bit::Vector;
use Encode;
use Thrift;
use Thrift::Exception;
use Thrift::MessageType;
use Thrift::Protocol;
use Thrift::Type;
use utf8;
#
# Binary implementation of the Thrift protocol.
#
package Thrift::BinaryProtocol;
use base('Thrift::Protocol');
use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
use constant VERSION_MASK => 0xffff0000;
use constant VERSION_1 => 0x80010000;
use constant IS_BIG_ENDIAN => unpack('h*', pack('s', 1)) =~ m/01/;
sub new
{
my $classname = shift;
my $trans = shift;
my $self = $classname->SUPER::new($trans);
return bless($self,$classname);
}
sub writeMessageBegin
{
my $self = shift;
my ($name, $type, $seqid) = @_;
return
$self->writeI32(VERSION_1 | $type) +
$self->writeString($name) +
$self->writeI32($seqid);
}
sub writeMessageEnd
{
my $self = shift;
return 0;
}
sub writeStructBegin
{
my $self = shift;
my $name = shift;
return 0;
}
sub writeStructEnd
{
my $self = shift;
return 0;
}
sub writeFieldBegin
{
my $self = shift;
my ($fieldName, $fieldType, $fieldId) = @_;
return
$self->writeByte($fieldType) +
$self->writeI16($fieldId);
}
sub writeFieldEnd
{
my $self = shift;
return 0;
}
sub writeFieldStop
{
my $self = shift;
return $self->writeByte(Thrift::TType::STOP);
}
sub writeMapBegin
{
my $self = shift;
my ($keyType, $valType, $size) = @_;
return
$self->writeByte($keyType) +
$self->writeByte($valType) +
$self->writeI32($size);
}
sub writeMapEnd
{
my $self = shift;
return 0;
}
sub writeListBegin
{
my $self = shift;
my ($elemType, $size) = @_;
return
$self->writeByte($elemType) +
$self->writeI32($size);
}
sub writeListEnd
{
my $self = shift;
return 0;
}
sub writeSetBegin
{
my $self = shift;
my ($elemType, $size) = @_;
return
$self->writeByte($elemType) +
$self->writeI32($size);
}
sub writeSetEnd
{
my $self = shift;
return 0;
}
sub writeBool
{
my $self = shift;
my $value = shift;
my $data = pack('c', $value ? 1 : 0);
$self->{trans}->write($data, 1);
return 1;
}
sub writeByte
{
my $self = shift;
my $value= shift;
my $data = pack('c', $value);
$self->{trans}->write($data, 1);
return 1;
}
sub writeI16
{
my $self = shift;
my $value= shift;
my $data = pack('n', $value);
$self->{trans}->write($data, 2);
return 2;
}
sub writeI32
{
my $self = shift;
my $value= shift;
my $data = pack('N', $value);
$self->{trans}->write($data, 4);
return 4;
}
sub writeI64
{
my $self = shift;
my $value= shift;
my $data;
my $vec;
#stop annoying error
$vec = Bit::Vector->new_Dec(64, $value);
$data = pack 'NN', $vec->Chunk_Read(32, 32), $vec->Chunk_Read(32, 0);
$self->{trans}->write($data, 8);
return 8;
}
sub writeDouble
{
my $self = shift;
my $value= shift;
my $data = pack('d', $value);
if (IS_BIG_ENDIAN) {
$self->{trans}->write($data, 8);
}
else {
$self->{trans}->write(scalar reverse($data), 8);
}
return 8;
}
sub writeString{
my $self = shift;
my $value= shift;
if( utf8::is_utf8($value) ){
$value = Encode::encode_utf8($value);
}
my $len = length($value);
my $result = $self->writeI32($len);
if ($len) {
$self->{trans}->write($value,$len);
}
return $result + $len;
}
#
#All references
#
sub readMessageBegin
{
my $self = shift;
my ($name, $type, $seqid) = @_;
my $version = 0;
my $result = $self->readI32(\$version);
if (($version & VERSION_MASK) > 0) {
if (($version & VERSION_MASK) != VERSION_1) {
die Thrift::TProtocolException->new('Missing version identifier',
Thrift::TProtocolException::BAD_VERSION);
}
$$type = $version & 0x000000ff;
return
$result +
$self->readString($name) +
$self->readI32($seqid);
}
else { # old client support code
return
$result +
$self->readStringBody($name, $version) + # version here holds the size of the string
$self->readByte($type) +
$self->readI32($seqid);
}
}
sub readMessageEnd
{
my $self = shift;
return 0;
}
sub readStructBegin
{
my $self = shift;
my $name = shift;
$$name = '';
return 0;
}
sub readStructEnd
{
my $self = shift;
return 0;
}
sub readFieldBegin
{
my $self = shift;
my ($name, $fieldType, $fieldId) = @_;
my $result = $self->readByte($fieldType);
if ($$fieldType == Thrift::TType::STOP) {
$$fieldId = 0;
return $result;
}
$result += $self->readI16($fieldId);
return $result;
}
sub readFieldEnd() {
my $self = shift;
return 0;
}
sub readMapBegin
{
my $self = shift;
my ($keyType, $valType, $size) = @_;
return
$self->readByte($keyType) +
$self->readByte($valType) +
$self->readI32($size);
}
sub readMapEnd()
{
my $self = shift;
return 0;
}
sub readListBegin
{
my $self = shift;
my ($elemType, $size) = @_;
return
$self->readByte($elemType) +
$self->readI32($size);
}
sub readListEnd
{
my $self = shift;
return 0;
}
sub readSetBegin
{
my $self = shift;
my ($elemType, $size) = @_;
return
$self->readByte($elemType) +
$self->readI32($size);
}
sub readSetEnd
{
my $self = shift;
return 0;
}
sub readBool
{
my $self = shift;
my $value = shift;
my $data = $self->{trans}->readAll(1);
my @arr = unpack('c', $data);
$$value = $arr[0] == 1;
return 1;
}
sub readByte
{
my $self = shift;
my $value = shift;
my $data = $self->{trans}->readAll(1);
my @arr = unpack('c', $data);
$$value = $arr[0];
return 1;
}
sub readI16
{
my $self = shift;
my $value = shift;
my $data = $self->{trans}->readAll(2);
my @arr = unpack('n', $data);
$$value = $arr[0];
if ($$value > 0x7fff) {
$$value = 0 - (($$value - 1) ^ 0xffff);
}
return 2;
}
sub readI32
{
my $self = shift;
my $value= shift;
my $data = $self->{trans}->readAll(4);
my @arr = unpack('N', $data);
$$value = $arr[0];
if ($$value > 0x7fffffff) {
$$value = 0 - (($$value - 1) ^ 0xffffffff);
}
return 4;
}
sub readI64
{
my $self = shift;
my $value = shift;
my $data = $self->{trans}->readAll(8);
my ($hi,$lo)=unpack('NN',$data);
my $vec = Bit::Vector->new(64);
$vec->Chunk_Store(32,32,$hi);
$vec->Chunk_Store(32,0,$lo);
$$value = $vec->to_Dec();
return 8;
}
sub readDouble
{
my $self = shift;
my $value = shift;
my $data;
if (IS_BIG_ENDIAN) {
$data = $self->{trans}->readAll(8);
}
else {
$data = scalar reverse($self->{trans}->readAll(8));
}
my @arr = unpack('d', $data);
$$value = $arr[0];
return 8;
}
sub readString
{
my $self = shift;
my $value = shift;
my $len;
my $result = $self->readI32(\$len);
if ($len) {
$$value = $self->{trans}->readAll($len);
}
else {
$$value = '';
}
return $result + $len;
}
sub readStringBody
{
my $self = shift;
my $value = shift;
my $len = shift;
if ($len) {
$$value = $self->{trans}->readAll($len);
}
else {
$$value = '';
}
return $len;
}
#
# Binary Protocol Factory
#
package Thrift::BinaryProtocolFactory;
use base('Thrift::TProtocolFactory');
use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
sub new
{
my $classname = shift;
my $self = $classname->SUPER::new();
return bless($self,$classname);
}
sub getProtocol{
my $self = shift;
my $trans = shift;
return Thrift::BinaryProtocol->new($trans);
}
1;