| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Thrift::JSONProtocol; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | =head1 NAME | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | Thrift::JSONProtocol | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | JSON protocol implementation for thrift. | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | This is a full-featured protocol supporting write and read. | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | This code was adapted from the Java implementation. | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | Please see the C++ class header for a detailed description of the protocol's wire format. | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | =cut | 
| 18 |  |  |  |  |  |  |  | 
| 19 | 1 |  |  | 1 |  | 57223 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 52 |  | 
| 20 | 1 |  |  | 1 |  | 9 | use warnings; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 38 |  | 
| 21 | 1 |  |  | 1 |  | 7 | use Thrift; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 23 |  | 
| 22 | 1 |  |  | 1 |  | 7 | use Thrift::Protocol; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 28 |  | 
| 23 | 1 |  |  | 1 |  | 6 | use base qw(Thrift::Protocol Class::Accessor); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 231 |  | 
| 24 |  |  |  |  |  |  |  | 
| 25 | 1 |  |  | 1 |  | 6 | use utf8; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 9 |  | 
| 26 | 1 |  |  | 1 |  | 29 | use Encode; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 112 |  | 
| 27 | 1 |  |  | 1 |  | 996 | use MIME::Base64; | 
|  | 1 |  |  |  |  | 894 |  | 
|  | 1 |  |  |  |  | 289 |  | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | __PACKAGE__->mk_accessors(qw(trans context_ reader_)); | 
| 30 | 43 |  |  | 43 | 0 | 193 | sub transport { shift->{trans} } | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | use constant { | 
| 33 | 1 |  |  |  |  | 7059 | COMMA     => ',', | 
| 34 |  |  |  |  |  |  | COLON     => ':', | 
| 35 |  |  |  |  |  |  | LBRACE    => '{', | 
| 36 |  |  |  |  |  |  | RBRACE    => '}', | 
| 37 |  |  |  |  |  |  | LBRACKET  => '[', | 
| 38 |  |  |  |  |  |  | RBRACKET  => ']', | 
| 39 |  |  |  |  |  |  | QUOTE     => '"', | 
| 40 |  |  |  |  |  |  | BACKSLASH => '\\', | 
| 41 |  |  |  |  |  |  | ZERO      => '0', | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | ESCSEQ => join('','\\','u','0','0'), | 
| 44 |  |  |  |  |  |  | VERSION => 1, | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | JSON_CHAR_TABLE => [ | 
| 47 |  |  |  |  |  |  | # 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F | 
| 48 |  |  |  |  |  |  | 0,  0,  0,  0,  0,  0,  0,  0,'b','t','n',  0,'f','r',  0,  0, # 0 | 
| 49 |  |  |  |  |  |  | 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, # 1 | 
| 50 |  |  |  |  |  |  | 1,  1,'"',  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, # 2 | 
| 51 |  |  |  |  |  |  | ], | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | ESCAPE_CHARS => "\"\\bfnrt", | 
| 54 |  |  |  |  |  |  | ESCAPE_CHAR_VALS => [ '"', '\\', "\b", "\f", "\n", "\r", "\t", ], | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | NAME_BOOL   => 'tf', | 
| 57 |  |  |  |  |  |  | NAME_BYTE   => 'i8', | 
| 58 |  |  |  |  |  |  | NAME_I16    => 'i16', | 
| 59 |  |  |  |  |  |  | NAME_I32    => 'i32', | 
| 60 |  |  |  |  |  |  | NAME_I64    => 'i64', | 
| 61 |  |  |  |  |  |  | NAME_DOUBLE => 'dbl', | 
| 62 |  |  |  |  |  |  | NAME_STRUCT => 'rec', | 
| 63 |  |  |  |  |  |  | NAME_STRING => 'str', | 
| 64 |  |  |  |  |  |  | NAME_MAP    => 'map', | 
| 65 |  |  |  |  |  |  | NAME_LIST   => 'lst', | 
| 66 |  |  |  |  |  |  | NAME_SET    => 'set', | 
| 67 | 1 |  |  | 1 |  | 8 | }; | 
|  | 1 |  |  |  |  | 3 |  | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | my %_getTypeNameForTypeID = ( | 
| 70 |  |  |  |  |  |  | TType::BOOL   => NAME_BOOL, | 
| 71 |  |  |  |  |  |  | TType::BYTE   => NAME_BYTE, | 
| 72 |  |  |  |  |  |  | TType::I16    => NAME_I16, | 
| 73 |  |  |  |  |  |  | TType::I32    => NAME_I32, | 
| 74 |  |  |  |  |  |  | TType::I64    => NAME_I64, | 
| 75 |  |  |  |  |  |  | TType::DOUBLE => NAME_DOUBLE, | 
| 76 |  |  |  |  |  |  | TType::STRING => NAME_STRING, | 
| 77 |  |  |  |  |  |  | TType::STRUCT => NAME_STRUCT, | 
| 78 |  |  |  |  |  |  | TType::MAP    => NAME_MAP, | 
| 79 |  |  |  |  |  |  | TType::SET    => NAME_SET, | 
| 80 |  |  |  |  |  |  | TType::LIST   => NAME_LIST, | 
| 81 |  |  |  |  |  |  | ); | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | ## | 
| 84 |  |  |  |  |  |  | ## Class methods | 
| 85 |  |  |  |  |  |  | ## | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | sub new { | 
| 88 | 1 |  |  | 1 | 1 | 426 | my $class = shift; | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 1 |  |  |  |  | 15 | my $self = $class->SUPER::new(@_); | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | # Stack of nested contexts that we may be in | 
| 93 | 1 |  |  |  |  | 19 | $self->{contextStack_} = []; | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | # Current context that we are in | 
| 96 | 1 |  |  |  |  | 11 | $self->{context_}      = Thrift::JSONProtocol::JSONBaseContext->new( protocol => $self ); | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | # Reader that manages a 1-byte buffer | 
| 99 | 1 |  |  |  |  | 15 | $self->{reader_}       = Thrift::JSONProtocol::LookaheadReader->new( protocol => $self ); | 
| 100 |  |  |  |  |  |  |  | 
| 101 | 1 |  |  |  |  | 4 | return $self; | 
| 102 |  |  |  |  |  |  | } | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | sub getTypeNameForTypeID { | 
| 105 | 2 |  |  | 2 | 0 | 6 | my ($typeID) = @_; | 
| 106 |  |  |  |  |  |  |  | 
| 107 | 2 | 50 |  |  |  | 1225 | if (my $typeName = $_getTypeNameForTypeID{$typeID}) { | 
| 108 | 2 |  |  |  |  | 11 | return $typeName; | 
| 109 |  |  |  |  |  |  | } | 
| 110 | 0 |  |  |  |  | 0 | die TProtocolException->new( "Unrecognized type $typeID", TProtocolException::UNKNOWN ) | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | sub getTypeIDForTypeName { | 
| 114 | 0 |  |  | 0 | 0 | 0 | my ($name) = @_; | 
| 115 | 0 |  |  |  |  | 0 | my $result = TType::STOP; | 
| 116 | 0 |  |  |  |  | 0 | my @name = split //, $name; | 
| 117 | 0 | 0 |  |  |  | 0 | if (int(@name) > 1) { | 
| 118 | 0 | 0 |  |  |  | 0 | if ($name[0] eq 'd') { $result = TType::DOUBLE } | 
|  | 0 | 0 |  |  |  | 0 |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | elsif ($name[0] eq 'i') { | 
| 120 | 0 | 0 |  |  |  | 0 | if ($name[1] eq '8') { $result = TType::BYTE } | 
|  | 0 | 0 |  |  |  | 0 |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 121 | 0 |  |  |  |  | 0 | elsif ($name[1] eq '1') { $result = TType::I16 } | 
| 122 | 0 |  |  |  |  | 0 | elsif ($name[1] eq '3') { $result = TType::I32 } | 
| 123 | 0 |  |  |  |  | 0 | elsif ($name[1] eq '6') { $result = TType::I64 } | 
| 124 |  |  |  |  |  |  | } | 
| 125 | 0 |  |  |  |  | 0 | elsif ($name[0] eq 'l') { $result = TType::LIST   } | 
| 126 | 0 |  |  |  |  | 0 | elsif ($name[0] eq 'm') { $result = TType::MAP    } | 
| 127 | 0 |  |  |  |  | 0 | elsif ($name[0] eq 'r') { $result = TType::STRUCT } | 
| 128 |  |  |  |  |  |  | elsif ($name[0] eq 's') { | 
| 129 | 0 | 0 |  |  |  | 0 | if ($name[1] eq 't') { $result = TType::STRING } | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 130 | 0 |  |  |  |  | 0 | elsif ($name[1] eq 'e') { $result = TType::SET } | 
| 131 |  |  |  |  |  |  | } | 
| 132 | 0 |  |  |  |  | 0 | elsif ($name[0] eq 't') { $result = TType::BOOL } | 
| 133 |  |  |  |  |  |  | } | 
| 134 | 0 | 0 |  |  |  | 0 | if ($result == TType::STOP) { | 
| 135 | 0 |  |  |  |  | 0 | die TProtocolException->new("Unrecognized type", TProtocolException::UNKNOWN); | 
| 136 |  |  |  |  |  |  | } | 
| 137 | 0 |  |  |  |  | 0 | return $result; | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | sub check_utf8 { | 
| 141 | 8 |  |  | 8 | 0 | 11 | my ($string_ref) = @_; | 
| 142 |  |  |  |  |  |  |  | 
| 143 | 8 | 50 |  |  |  | 31 | return if ! utf8::is_utf8($$string_ref); | 
| 144 | 0 |  |  |  |  | 0 | $$string_ref = Encode::encode_utf8($$string_ref); | 
| 145 |  |  |  |  |  |  | } | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | ## | 
| 148 |  |  |  |  |  |  | ## Object methods | 
| 149 |  |  |  |  |  |  | ## | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | # | 
| 152 |  |  |  |  |  |  | # Helper methods | 
| 153 |  |  |  |  |  |  | # | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | # Push a new JSON context onto the stack. | 
| 156 |  |  |  |  |  |  | sub pushContext { | 
| 157 | 4 |  |  | 4 | 0 | 6 | my ($self, $context) = @_; | 
| 158 | 4 |  |  |  |  | 7 | push @{ $self->{contextStack_} }, delete $self->{context_}; | 
|  | 4 |  |  |  |  | 13 |  | 
| 159 | 4 |  |  |  |  | 11 | $self->{context_} = $context; | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | # Pop the last JSON context off the stack | 
| 163 |  |  |  |  |  |  | sub popContext { | 
| 164 | 4 |  |  | 4 | 0 | 6 | my ($self) = @_; | 
| 165 | 4 |  |  |  |  | 3 | my $context = pop @{ $self->{contextStack_} }; | 
|  | 4 |  |  |  |  | 9 |  | 
| 166 | 4 |  |  |  |  | 9 | $self->{context_} = $context; | 
| 167 | 4 |  |  |  |  | 37 | return $context; | 
| 168 |  |  |  |  |  |  | } | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | # Read a byte that must match $expected; otherwise an excpetion is thrown. | 
| 171 |  |  |  |  |  |  | sub readJSONSyntaxChar { | 
| 172 | 0 |  |  | 0 | 0 | 0 | my ($self, $expected) = @_; | 
| 173 | 0 |  |  |  |  | 0 | my $got = $self->{reader_}->read(); | 
| 174 | 0 | 0 |  |  |  | 0 | if ($got ne $expected) { | 
| 175 | 0 |  |  |  |  | 0 | die TProtocolException->new("Unexpected character: $got", TProtocolException::INVALID_DATA); | 
| 176 |  |  |  |  |  |  | } | 
| 177 | 0 |  |  |  |  | 0 | return length $got; | 
| 178 |  |  |  |  |  |  | } | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | # Convenience method for writing and getting the length of the string written | 
| 181 |  |  |  |  |  |  | sub write { | 
| 182 | 34 |  |  | 34 | 0 | 44 | my ($self, $string) = @_; | 
| 183 | 34 |  |  |  |  | 71 | $self->transport->write($string); | 
| 184 | 34 |  |  |  |  | 331 | return length $string; | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | # | 
| 188 |  |  |  |  |  |  | # Read/write JSON methods | 
| 189 |  |  |  |  |  |  | # | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | # Write the bytes in array buf as a JSON characters, escaping as needed | 
| 192 |  |  |  |  |  |  | sub writeJSONString { | 
| 193 | 3 |  |  | 3 | 0 | 8 | my ($self, $string) = @_; | 
| 194 | 3 |  |  |  |  | 19 | my @b = split //, $string; | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 3 |  |  |  |  | 8 | my $xfer = 0; | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 3 |  |  |  |  | 14 | $xfer += $self->context_->write(); | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 3 |  |  |  |  | 12 | $xfer += $self->write(QUOTE); | 
| 201 |  |  |  |  |  |  |  | 
| 202 | 3 |  |  |  |  | 7 | my $len = int @b; | 
| 203 | 3 |  |  |  |  | 16 | for (my $i = 0; $i < $len; $i++) { | 
| 204 | 9 |  |  |  |  | 18 | my $ord = ord($b[$i]); | 
| 205 | 9 | 50 |  |  |  | 26 | if (($ord & 0x00FF) >= 0x30) { | 
| 206 | 9 | 50 |  |  |  | 20 | if ($b[$i] eq BACKSLASH) { | 
| 207 | 0 |  |  |  |  | 0 | $xfer += $self->write(BACKSLASH . BACKSLASH); | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  | else { | 
| 210 | 9 |  |  |  |  | 25 | $xfer += $self->write($b[$i]); | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  | else { | 
| 214 | 0 |  |  |  |  | 0 | my $tmp = JSON_CHAR_TABLE->[$ord]; | 
| 215 | 0 | 0 |  |  |  | 0 | if ($tmp eq '1') { | 
|  |  | 0 |  |  |  |  |  | 
| 216 | 0 |  |  |  |  | 0 | $xfer += $self->write($b[$i]); | 
| 217 |  |  |  |  |  |  | } | 
| 218 |  |  |  |  |  |  | elsif ($tmp eq '0') { | 
| 219 | 0 |  |  |  |  | 0 | my $hex = unpack 'H*', chr($ord); | 
| 220 | 0 |  |  |  |  | 0 | $xfer += $self->write(ESCSEQ . $hex); | 
| 221 |  |  |  |  |  |  | } | 
| 222 |  |  |  |  |  |  | else { | 
| 223 | 0 |  |  |  |  | 0 | $xfer += $self->write(BACKSLASH . $tmp); | 
| 224 |  |  |  |  |  |  | } | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  | } | 
| 227 |  |  |  |  |  |  |  | 
| 228 | 3 |  |  |  |  | 8 | $xfer += $self->write(QUOTE); | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 3 |  |  |  |  | 8 | return $xfer; | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | # Read in a JSON string, unescaping as appropriate.. Skip reading from the | 
| 234 |  |  |  |  |  |  | # context if skipContext is true. | 
| 235 |  |  |  |  |  |  | sub readJSONString { | 
| 236 | 0 |  |  | 0 | 0 | 0 | my ($self, $string, $skipContext) = @_; | 
| 237 |  |  |  |  |  |  |  | 
| 238 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 239 |  |  |  |  |  |  |  | 
| 240 | 0 | 0 |  |  |  | 0 | $xfer += $self->context_->read() if ! $skipContext; | 
| 241 |  |  |  |  |  |  |  | 
| 242 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONSyntaxChar(QUOTE); | 
| 243 |  |  |  |  |  |  |  | 
| 244 | 0 |  |  |  |  | 0 | $$string = ''; | 
| 245 |  |  |  |  |  |  |  | 
| 246 | 0 |  |  |  |  | 0 | while (1) { | 
| 247 | 0 |  |  |  |  | 0 | my $ch = $self->reader_->read(); | 
| 248 | 0 |  |  |  |  | 0 | $xfer++; | 
| 249 | 0 | 0 |  |  |  | 0 | if ($ch eq QUOTE) { | 
| 250 | 0 |  |  |  |  | 0 | last; | 
| 251 |  |  |  |  |  |  | } | 
| 252 | 0 | 0 |  |  |  | 0 | if ($ch eq substr ESCSEQ, 0, 1) { | 
| 253 | 0 |  |  |  |  | 0 | $ch = $self->reader_->read(); | 
| 254 | 0 |  |  |  |  | 0 | $xfer++; | 
| 255 | 0 | 0 |  |  |  | 0 | if ($ch eq substr ESCSEQ, 1, 1) { | 
| 256 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONSyntaxChar(ZERO); | 
| 257 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONSyntaxChar(ZERO); | 
| 258 | 0 |  |  |  |  | 0 | my $tmp = $self->transport->readAll(2); | 
| 259 | 0 |  |  |  |  | 0 | $ch = chr(hex($tmp)); | 
| 260 | 0 |  |  |  |  | 0 | $xfer += 2; | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  | else { | 
| 263 | 0 |  |  |  |  | 0 | my $off = index ESCAPE_CHARS, $ch; | 
| 264 | 0 | 0 |  |  |  | 0 | if ($off == -1) { | 
| 265 | 0 |  |  |  |  | 0 | die TProtocolException->new("Expected control char, got '$ch'", TProtocolException::INVALID_DATA); | 
| 266 |  |  |  |  |  |  | } | 
| 267 | 0 |  |  |  |  | 0 | $ch = ESCAPE_CHAR_VALS->[$off]; | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  | } | 
| 270 | 0 |  |  |  |  | 0 | $$string .= $ch; | 
| 271 |  |  |  |  |  |  | } | 
| 272 |  |  |  |  |  |  |  | 
| 273 | 0 |  |  |  |  | 0 | return $xfer; | 
| 274 |  |  |  |  |  |  | } | 
| 275 |  |  |  |  |  |  |  | 
| 276 |  |  |  |  |  |  | # Write out number as a JSON value. If the context dictates so, it will be | 
| 277 |  |  |  |  |  |  | # wrapped in quotes to output as a JSON string. | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | sub writeJSONInteger { | 
| 280 | 7 |  |  | 7 | 0 | 13 | my ($self, $num) = @_; | 
| 281 | 7 |  |  |  |  | 10 | my $xfer = 0; | 
| 282 | 7 |  |  |  |  | 23 | $xfer += $self->context_->write; | 
| 283 | 7 |  |  |  |  | 19 | my $str = $num . ''; | 
| 284 | 7 |  |  |  |  | 18 | check_utf8(\$str); | 
| 285 | 7 |  |  |  |  | 19 | my $escapeNum = $self->context_->escapeNum(); | 
| 286 |  |  |  |  |  |  |  | 
| 287 | 7 | 100 |  |  |  | 46 | $xfer += $self->write(QUOTE) if $escapeNum; | 
| 288 | 7 |  |  |  |  | 17 | $xfer += $self->write($str); | 
| 289 | 7 | 100 |  |  |  | 22 | $xfer += $self->write(QUOTE) if $escapeNum; | 
| 290 | 7 |  |  |  |  | 16 | return $xfer; | 
| 291 |  |  |  |  |  |  | } | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | # Return true if the given byte could be a valid part of a JSON number. | 
| 294 |  |  |  |  |  |  | sub isJSONNumeric { | 
| 295 | 0 |  |  | 0 | 0 | 0 | my ($char) = @_; | 
| 296 | 0 | 0 |  |  |  | 0 | return $char =~ m{^[-+.0-9Ee]$} ? 1 : 0; | 
| 297 |  |  |  |  |  |  | } | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | # Read in a sequence of characters that are all valid in JSON numbers. Does | 
| 300 |  |  |  |  |  |  | # not do a complete regex check to validate that this is actually a number. | 
| 301 |  |  |  |  |  |  | sub readJSONNumericChars { | 
| 302 | 0 |  |  | 0 | 0 | 0 | my ($self, $str) = @_; | 
| 303 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 304 | 0 |  |  |  |  | 0 | while (1) { | 
| 305 | 0 |  |  |  |  | 0 | my $ch; | 
| 306 | 0 |  |  |  |  | 0 | eval { | 
| 307 | 0 |  |  |  |  | 0 | $ch = $self->reader_->peek(); | 
| 308 |  |  |  |  |  |  | }; | 
| 309 | 0 | 0 |  |  |  | 0 | if (my $ex = $@) { | 
| 310 | 0 | 0 | 0 |  |  | 0 | if ($ex->isa('TTransportException') && $ex->{code} == TTransportException::END_OF_FILE) { | 
| 311 | 0 |  |  |  |  | 0 | last; | 
| 312 |  |  |  |  |  |  | } | 
| 313 | 0 |  |  |  |  | 0 | die $ex; | 
| 314 |  |  |  |  |  |  | } | 
| 315 | 0 | 0 |  |  |  | 0 | if (! isJSONNumeric($ch)) { | 
| 316 | 0 |  |  |  |  | 0 | last; | 
| 317 |  |  |  |  |  |  | } | 
| 318 | 0 |  |  |  |  | 0 | $$str .= $self->reader_->read(); | 
| 319 | 0 |  |  |  |  | 0 | $xfer++; | 
| 320 |  |  |  |  |  |  | } | 
| 321 | 0 |  |  |  |  | 0 | return $xfer; | 
| 322 |  |  |  |  |  |  | } | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | # Read in a JSON number. If the context dictates, read in enclosing quotes. | 
| 325 |  |  |  |  |  |  | sub readJSONInteger { | 
| 326 | 0 |  |  | 0 | 0 | 0 | my ($self, $int) = @_; | 
| 327 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 328 | 0 |  |  |  |  | 0 | $xfer += $self->context_->read(); | 
| 329 | 0 |  |  |  |  | 0 | my $escapeNum = $self->context_->escapeNum(); | 
| 330 |  |  |  |  |  |  |  | 
| 331 | 0 |  |  |  |  | 0 | my $str; | 
| 332 | 0 | 0 |  |  |  | 0 | $xfer += $self->readJSONSyntaxChar(QUOTE) if $escapeNum; | 
| 333 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONNumericChars(\$str); | 
| 334 | 0 | 0 |  |  |  | 0 | $xfer += $self->readJSONSyntaxChar(QUOTE) if $escapeNum; | 
| 335 |  |  |  |  |  |  |  | 
| 336 | 0 |  |  |  |  | 0 | $$int = $str * 1; | 
| 337 | 0 |  |  |  |  | 0 | return $xfer; | 
| 338 |  |  |  |  |  |  | } | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | # Write out a double as a JSON value. If it is NaN or infinity or if the | 
| 341 |  |  |  |  |  |  | # context dictates escaping, write out as JSON string. | 
| 342 |  |  |  |  |  |  | sub writeJSONDouble { | 
| 343 | 0 |  |  | 0 | 0 | 0 | my ($self, $num) = @_; | 
| 344 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 345 | 0 |  |  |  |  | 0 | $xfer += $self->context_->write(); | 
| 346 | 0 |  |  |  |  | 0 | my $str = $num . ''; | 
| 347 | 0 |  |  |  |  | 0 | check_utf8(\$str); | 
| 348 | 0 | 0 |  |  |  | 0 | my $special = $str =~ m{^-?(N|I)} ? 1 : 0; | 
| 349 | 0 |  | 0 |  |  | 0 | my $escapeNum = $special || $self->context_->escapeNum; | 
| 350 |  |  |  |  |  |  |  | 
| 351 | 0 | 0 |  |  |  | 0 | $xfer += $self->write(QUOTE) if $escapeNum; | 
| 352 | 0 |  |  |  |  | 0 | $xfer += $self->write($str); | 
| 353 | 0 | 0 |  |  |  | 0 | $xfer += $self->write(QUOTE) if $escapeNum; | 
| 354 | 0 |  |  |  |  | 0 | return $xfer; | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  |  | 
| 357 |  |  |  |  |  |  | # Read in a JSON double value. Throw if the value is not wrapped in quotes | 
| 358 |  |  |  |  |  |  | # when expected or if wrapped in quotes when not expected. | 
| 359 |  |  |  |  |  |  | sub readJSONDouble { | 
| 360 | 0 |  |  | 0 | 0 | 0 | my ($self, $dub) = @_; | 
| 361 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 362 | 0 |  |  |  |  | 0 | $xfer += $self->context_->read(); | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 0 | 0 |  |  |  | 0 | if ($self->reader_->peek() eq QUOTE) { | 
| 365 | 0 |  |  |  |  | 0 | my $str; | 
| 366 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONString(\$str, 1); | 
| 367 | 0 | 0 |  |  |  | 0 | my $special = $str =~ m{^-?(N|I)} ? 1 : 0; | 
| 368 | 0 | 0 | 0 |  |  | 0 | if (! $self->context_->escapeNum && ! $special) { | 
| 369 |  |  |  |  |  |  | # Throw exception -- we should not be in a string in this case | 
| 370 | 0 |  |  |  |  | 0 | die TProtocolException->new( | 
| 371 |  |  |  |  |  |  | "Numeric data unexpectedly quoted", | 
| 372 |  |  |  |  |  |  | TProtocolException::INVALID_DATA, | 
| 373 |  |  |  |  |  |  | ); | 
| 374 |  |  |  |  |  |  | } | 
| 375 | 0 |  |  |  |  | 0 | $$dub = $str; | 
| 376 |  |  |  |  |  |  | } | 
| 377 |  |  |  |  |  |  | else { | 
| 378 | 0 | 0 |  |  |  | 0 | if ($self->context_->escapeNum()) { | 
| 379 |  |  |  |  |  |  | # This will throw - we should have had a quote if escapeNum == true | 
| 380 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONSyntaxChar(QUOTE); | 
| 381 |  |  |  |  |  |  | } | 
| 382 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONNumericChars($dub); | 
| 383 |  |  |  |  |  |  | } | 
| 384 | 0 |  |  |  |  | 0 | return $xfer; | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  |  | 
| 387 |  |  |  |  |  |  | # Write out contents of byte array b as a JSON string with base-64 encoded | 
| 388 |  |  |  |  |  |  | # data | 
| 389 |  |  |  |  |  |  | sub writeJSONBase64 { | 
| 390 | 0 |  |  | 0 | 0 | 0 | my ($self, $string) = @_; | 
| 391 | 0 |  |  |  |  | 0 | return $self->writeJSONString( encode_base64($string, '') ); | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  |  | 
| 394 |  |  |  |  |  |  | # Read in a JSON string containing base-64 encoded data and decode it. | 
| 395 |  |  |  |  |  |  | sub readJSONBase64 { | 
| 396 | 0 |  |  | 0 | 0 | 0 | my ($self, $string) = @_; | 
| 397 |  |  |  |  |  |  |  | 
| 398 | 0 |  |  |  |  | 0 | my $xfer = $self->readJSONString($string); | 
| 399 | 0 |  |  |  |  | 0 | my $tmp = decode_base64($$string); | 
| 400 | 0 |  |  |  |  | 0 | $$string = $tmp; | 
| 401 | 0 |  |  |  |  | 0 | return $xfer; | 
| 402 |  |  |  |  |  |  | } | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | sub writeJSONObjectStart { | 
| 405 | 3 |  |  | 3 | 0 | 8 | my ($self) = @_; | 
| 406 | 3 |  |  |  |  | 6 | my $xfer = 0; | 
| 407 | 3 |  |  |  |  | 11 | $xfer += $self->context_->write(); | 
| 408 | 3 |  |  |  |  | 11 | $xfer += $self->write(LBRACE); | 
| 409 | 3 |  |  |  |  | 19 | $self->pushContext( | 
| 410 |  |  |  |  |  |  | Thrift::JSONProtocol::JSONPairContext->new( protocol => $self ) | 
| 411 |  |  |  |  |  |  | ); | 
| 412 | 3 |  |  |  |  | 5 | return $xfer; | 
| 413 |  |  |  |  |  |  | } | 
| 414 |  |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | sub readJSONObjectStart { | 
| 416 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 417 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 418 | 0 |  |  |  |  | 0 | $xfer += $self->context_->read(); | 
| 419 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONSyntaxChar(LBRACE); | 
| 420 | 0 |  |  |  |  | 0 | $self->pushContext( | 
| 421 |  |  |  |  |  |  | Thrift::JSONProtocol::JSONPairContext->new( protocol => $self ) | 
| 422 |  |  |  |  |  |  | ); | 
| 423 | 0 |  |  |  |  | 0 | return $xfer; | 
| 424 |  |  |  |  |  |  | } | 
| 425 |  |  |  |  |  |  |  | 
| 426 |  |  |  |  |  |  | sub writeJSONObjectEnd { | 
| 427 | 3 |  |  | 3 | 0 | 6 | my ($self) = @_; | 
| 428 | 3 |  |  |  |  | 9 | $self->popContext(); | 
| 429 | 3 |  |  |  |  | 8 | return $self->write(RBRACE); | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | sub readJSONObjectEnd { | 
| 433 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 434 | 0 |  |  |  |  | 0 | $self->popContext(); | 
| 435 | 0 |  |  |  |  | 0 | return $self->readJSONSyntaxChar(RBRACE); | 
| 436 |  |  |  |  |  |  | } | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | sub writeJSONArrayStart { | 
| 439 | 1 |  |  | 1 | 0 | 2 | my ($self) = @_; | 
| 440 | 1 |  |  |  |  | 3 | my $xfer = 0; | 
| 441 | 1 |  |  |  |  | 7 | $xfer += $self->context_->write(); | 
| 442 | 1 |  |  |  |  | 5 | $xfer += $self->write(LBRACKET); | 
| 443 | 1 |  |  |  |  | 11 | $self->pushContext( | 
| 444 |  |  |  |  |  |  | Thrift::JSONProtocol::JSONListContext->new( protocol => $self ) | 
| 445 |  |  |  |  |  |  | ); | 
| 446 | 1 |  |  |  |  | 2 | return $xfer; | 
| 447 |  |  |  |  |  |  | } | 
| 448 |  |  |  |  |  |  |  | 
| 449 |  |  |  |  |  |  | sub readJSONArrayStart { | 
| 450 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 451 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 452 | 0 |  |  |  |  | 0 | $xfer += $self->context_->read(); | 
| 453 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONSyntaxChar(LBRACKET); | 
| 454 | 0 |  |  |  |  | 0 | $self->pushContext( | 
| 455 |  |  |  |  |  |  | Thrift::JSONProtocol::JSONListContext->new( protocol => $self ) | 
| 456 |  |  |  |  |  |  | ); | 
| 457 | 0 |  |  |  |  | 0 | return $xfer; | 
| 458 |  |  |  |  |  |  | } | 
| 459 |  |  |  |  |  |  |  | 
| 460 |  |  |  |  |  |  | sub writeJSONArrayEnd { | 
| 461 | 1 |  |  | 1 | 0 | 2 | my ($self) = @_; | 
| 462 | 1 |  |  |  |  | 3 | $self->popContext(); | 
| 463 | 1 |  |  |  |  | 3 | return $self->write(RBRACKET); | 
| 464 |  |  |  |  |  |  | } | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | sub readJSONArrayEnd { | 
| 467 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 468 | 0 |  |  |  |  | 0 | $self->popContext(); | 
| 469 | 0 |  |  |  |  | 0 | return $self->readJSONSyntaxChar(RBRACKET); | 
| 470 |  |  |  |  |  |  | } | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | # | 
| 473 |  |  |  |  |  |  | # Thrift::Protocol methods | 
| 474 |  |  |  |  |  |  | # | 
| 475 |  |  |  |  |  |  |  | 
| 476 |  |  |  |  |  |  | sub writeMessageBegin { | 
| 477 | 1 |  |  | 1 | 0 | 506 | my ($self, $name, $type, $seqid) = @_; | 
| 478 |  |  |  |  |  |  |  | 
| 479 | 1 |  |  |  |  | 8 | check_utf8(\$name); | 
| 480 |  |  |  |  |  |  |  | 
| 481 | 1 |  |  |  |  | 2 | my $xfer = 0; | 
| 482 | 1 |  |  |  |  | 7 | $xfer += $self->writeJSONArrayStart(); | 
| 483 | 1 |  |  |  |  | 6 | $xfer += $self->writeJSONInteger(VERSION); | 
| 484 | 1 |  |  |  |  | 5 | $xfer += $self->writeJSONString($name); | 
| 485 | 1 |  |  |  |  | 6 | $xfer += $self->writeJSONInteger($type); | 
| 486 | 1 |  |  |  |  | 6 | $xfer += $self->writeJSONInteger($seqid); | 
| 487 | 1 |  |  |  |  | 4 | return $xfer; | 
| 488 |  |  |  |  |  |  | } | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | sub readMessageBegin { | 
| 491 | 0 |  |  | 0 | 0 | 0 | my ($self, $name, $type, $seqid) = @_; | 
| 492 |  |  |  |  |  |  |  | 
| 493 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 494 |  |  |  |  |  |  |  | 
| 495 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONArrayStart(); | 
| 496 | 0 |  |  |  |  | 0 | my $version; | 
| 497 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONInteger(\$version); | 
| 498 |  |  |  |  |  |  |  | 
| 499 | 0 | 0 |  |  |  | 0 | if ($version != VERSION) { | 
| 500 | 0 |  |  |  |  | 0 | die TProtocolException->new("Message contained bad version.", TProtocolException::BAD_VERSION); | 
| 501 |  |  |  |  |  |  | } | 
| 502 |  |  |  |  |  |  |  | 
| 503 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONString($name); | 
| 504 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONInteger($type); | 
| 505 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONInteger($seqid); | 
| 506 | 0 |  |  |  |  | 0 | return $xfer; | 
| 507 |  |  |  |  |  |  | } | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | sub writeMessageEnd { | 
| 510 | 1 |  |  | 1 | 0 | 2 | my ($self) = @_; | 
| 511 | 1 |  |  |  |  | 5 | $self->writeJSONArrayEnd(); | 
| 512 |  |  |  |  |  |  | } | 
| 513 |  |  |  |  |  |  |  | 
| 514 |  |  |  |  |  |  | sub readMessageEnd { | 
| 515 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 516 | 0 |  |  |  |  | 0 | $self->readJSONArrayEnd(); | 
| 517 |  |  |  |  |  |  | } | 
| 518 |  |  |  |  |  |  |  | 
| 519 |  |  |  |  |  |  | sub writeStructBegin { | 
| 520 | 1 |  |  | 1 | 0 | 3 | my ($self) = @_; | 
| 521 | 1 |  |  |  |  | 5 | $self->writeJSONObjectStart(); | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | sub readStructBegin { | 
| 525 | 0 |  |  | 0 | 0 | 0 | my ($self, $name) = @_; | 
| 526 | 0 |  |  |  |  | 0 | $self->readJSONObjectStart(); | 
| 527 |  |  |  |  |  |  | } | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | sub writeStructEnd { | 
| 530 | 1 |  |  | 1 | 0 | 2 | my ($self) = @_; | 
| 531 | 1 |  |  |  |  | 3 | $self->writeJSONObjectEnd(); | 
| 532 |  |  |  |  |  |  | } | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | sub readStructEnd { | 
| 535 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 536 | 0 |  |  |  |  | 0 | $self->readJSONObjectEnd(); | 
| 537 |  |  |  |  |  |  | } | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  | sub writeFieldBegin { | 
| 540 | 2 |  |  | 2 | 0 | 37 | my ($self, $fieldName, $fieldType, $fieldId) = @_; | 
| 541 | 2 |  |  |  |  | 4 | my $xfer = 0; | 
| 542 | 2 |  |  |  |  | 7 | $xfer += $self->writeJSONInteger($fieldId); | 
| 543 | 2 |  |  |  |  | 8 | $xfer += $self->writeJSONObjectStart(); | 
| 544 | 2 |  |  |  |  | 9 | $xfer += $self->writeJSONString(getTypeNameForTypeID($fieldType)); | 
| 545 | 2 |  |  |  |  | 8 | return $xfer; | 
| 546 |  |  |  |  |  |  | } | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | sub readFieldBegin { | 
| 549 | 0 |  |  | 0 | 0 | 0 | my ($self, $name, $fieldType, $fieldId) = @_; | 
| 550 |  |  |  |  |  |  |  | 
| 551 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 552 | 0 |  |  |  |  | 0 | my $ch = $self->reader_->peek(); | 
| 553 | 0 | 0 |  |  |  | 0 | if ($ch eq RBRACE) { | 
| 554 | 0 |  |  |  |  | 0 | $$fieldType = TType::STOP; | 
| 555 |  |  |  |  |  |  | } | 
| 556 |  |  |  |  |  |  | else { | 
| 557 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONInteger($fieldId); | 
| 558 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONObjectStart(); | 
| 559 | 0 |  |  |  |  | 0 | my $type; | 
| 560 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONString(\$type); | 
| 561 | 0 |  |  |  |  | 0 | $$fieldType = getTypeIDForTypeName($type); | 
| 562 |  |  |  |  |  |  | } | 
| 563 | 0 |  |  |  |  | 0 | return $xfer; | 
| 564 |  |  |  |  |  |  | } | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | sub writeFieldEnd { | 
| 567 | 2 |  |  | 2 | 0 | 5 | my ($self) = @_; | 
| 568 | 2 |  |  |  |  | 7 | $self->writeJSONObjectEnd(); | 
| 569 |  |  |  |  |  |  | } | 
| 570 |  |  |  |  |  |  |  | 
| 571 |  |  |  |  |  |  | sub readFieldEnd { | 
| 572 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 573 | 0 |  |  |  |  | 0 | $self->readJSONObjectEnd(); | 
| 574 |  |  |  |  |  |  | } | 
| 575 |  |  |  |  |  |  |  | 
| 576 | 1 |  |  | 1 | 0 | 3 | sub writeFieldStop { 0 } | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | sub writeMapBegin { | 
| 579 | 0 |  |  | 0 | 0 | 0 | my ($self, $keyType, $valType, $size) = @_; | 
| 580 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 581 | 0 |  |  |  |  | 0 | $xfer += $self->writeJSONArrayStart(); | 
| 582 | 0 |  |  |  |  | 0 | $xfer += $self->writeJSONString(getTypeNameForTypeID($keyType)); | 
| 583 | 0 |  |  |  |  | 0 | $xfer += $self->writeJSONString(getTypeNameForTypeID($valType)); | 
| 584 | 0 |  |  |  |  | 0 | $xfer += $self->writeJSONInteger($size); | 
| 585 | 0 |  |  |  |  | 0 | $xfer += $self->writeJSONObjectStart(); | 
| 586 | 0 |  |  |  |  | 0 | return $xfer; | 
| 587 |  |  |  |  |  |  | } | 
| 588 |  |  |  |  |  |  |  | 
| 589 |  |  |  |  |  |  | sub readMapBegin { | 
| 590 | 0 |  |  | 0 | 0 | 0 | my ($self, $keyType, $valType, $size) = @_; | 
| 591 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 592 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONArrayStart(); | 
| 593 |  |  |  |  |  |  |  | 
| 594 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONString($keyType); | 
| 595 | 0 |  |  |  |  | 0 | $$keyType = getTypeIDForTypeName($$keyType); | 
| 596 |  |  |  |  |  |  |  | 
| 597 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONString($valType); | 
| 598 | 0 |  |  |  |  | 0 | $$valType = getTypeIDForTypeName($$valType); | 
| 599 |  |  |  |  |  |  |  | 
| 600 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONInteger($size); | 
| 601 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONObjectStart(); | 
| 602 | 0 |  |  |  |  | 0 | return $xfer; | 
| 603 |  |  |  |  |  |  | } | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | sub writeMapEnd { | 
| 606 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 607 | 0 |  |  |  |  | 0 | return $self->writeJSONObjectEnd() + $self->writeJSONArrayEnd(); | 
| 608 |  |  |  |  |  |  | } | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  | sub readMapEnd { | 
| 611 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 612 | 0 |  |  |  |  | 0 | return $self->readJSONObjectEnd() + $self->readJSONArrayEnd(); | 
| 613 |  |  |  |  |  |  | } | 
| 614 |  |  |  |  |  |  |  | 
| 615 |  |  |  |  |  |  | sub writeListBegin { | 
| 616 | 0 |  |  | 0 | 0 | 0 | my ($self, $elemType, $size) = @_; | 
| 617 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 618 | 0 |  |  |  |  | 0 | $xfer += $self->writeJSONArrayStart(); | 
| 619 | 0 |  |  |  |  | 0 | $xfer += $self->writeJSONString(getTypeNameForTypeID($elemType)); | 
| 620 | 0 |  |  |  |  | 0 | $xfer += $self->writeJSONInteger($size); | 
| 621 | 0 |  |  |  |  | 0 | return $xfer; | 
| 622 |  |  |  |  |  |  | } | 
| 623 |  |  |  |  |  |  |  | 
| 624 |  |  |  |  |  |  | sub readListBegin { | 
| 625 | 0 |  |  | 0 | 0 | 0 | my ($self, $elemType, $size) = @_; | 
| 626 | 0 |  |  |  |  | 0 | my $xfer = 0; | 
| 627 |  |  |  |  |  |  |  | 
| 628 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONArrayStart(); | 
| 629 |  |  |  |  |  |  |  | 
| 630 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONString($elemType); | 
| 631 | 0 |  |  |  |  | 0 | $$elemType = getTypeIDForTypeName($$elemType); | 
| 632 |  |  |  |  |  |  |  | 
| 633 | 0 |  |  |  |  | 0 | $xfer += $self->readJSONInteger($size); | 
| 634 |  |  |  |  |  |  |  | 
| 635 | 0 |  |  |  |  | 0 | return $xfer; | 
| 636 |  |  |  |  |  |  | } | 
| 637 |  |  |  |  |  |  |  | 
| 638 |  |  |  |  |  |  | sub writeListEnd { | 
| 639 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 640 | 0 |  |  |  |  | 0 | $self->writeJSONArrayEnd(); | 
| 641 |  |  |  |  |  |  | } | 
| 642 |  |  |  |  |  |  |  | 
| 643 |  |  |  |  |  |  | sub readListEnd { | 
| 644 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 645 | 0 |  |  |  |  | 0 | $self->readJSONArrayEnd(); | 
| 646 |  |  |  |  |  |  | } | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | sub writeSetBegin { | 
| 649 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 650 | 0 |  |  |  |  | 0 | $self->writeListBegin(@_); | 
| 651 |  |  |  |  |  |  | } | 
| 652 |  |  |  |  |  |  |  | 
| 653 |  |  |  |  |  |  | sub readSetBegin { | 
| 654 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 655 | 0 |  |  |  |  | 0 | $self->readListBegin(@_); | 
| 656 |  |  |  |  |  |  | } | 
| 657 |  |  |  |  |  |  |  | 
| 658 |  |  |  |  |  |  | sub writeSetEnd { | 
| 659 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 660 | 0 |  |  |  |  | 0 | $self->writeListEnd(); | 
| 661 |  |  |  |  |  |  | } | 
| 662 |  |  |  |  |  |  |  | 
| 663 |  |  |  |  |  |  | sub readSetEnd { | 
| 664 | 0 |  |  | 0 | 0 | 0 | my ($self) = @_; | 
| 665 | 0 |  |  |  |  | 0 | $self->readListEnd(); | 
| 666 |  |  |  |  |  |  | } | 
| 667 |  |  |  |  |  |  |  | 
| 668 |  |  |  |  |  |  | sub writeBool { | 
| 669 | 0 |  |  | 0 | 0 | 0 | my ($self, $b) = @_; | 
| 670 | 0 | 0 |  |  |  | 0 | $self->writeJSONInteger($b ? 1 : 0); | 
| 671 |  |  |  |  |  |  | } | 
| 672 |  |  |  |  |  |  |  | 
| 673 |  |  |  |  |  |  | sub readBool { | 
| 674 | 0 |  |  | 0 | 0 | 0 | my ($self, $b) = @_; | 
| 675 | 0 |  |  |  |  | 0 | my $xfer = $self->readJSONInteger($b); | 
| 676 | 0 | 0 |  |  |  | 0 | $$b = $$b ? 1 : 0; | 
| 677 | 0 |  |  |  |  | 0 | return $xfer; | 
| 678 |  |  |  |  |  |  | } | 
| 679 |  |  |  |  |  |  |  | 
| 680 |  |  |  |  |  |  | sub writeByte { | 
| 681 | 0 |  |  | 0 | 0 | 0 | my ($self, $b) = @_; | 
| 682 | 0 |  |  |  |  | 0 | $self->writeJSONInteger(ord($b)); | 
| 683 |  |  |  |  |  |  | } | 
| 684 |  |  |  |  |  |  |  | 
| 685 |  |  |  |  |  |  | sub readByte { | 
| 686 | 0 |  |  | 0 | 0 | 0 | my ($self, $b) = @_; | 
| 687 | 0 |  |  |  |  | 0 | my $xfer = $self->readJSONInteger($b); | 
| 688 | 0 |  |  |  |  | 0 | $$b = chr($$b); | 
| 689 | 0 |  |  |  |  | 0 | return $xfer; | 
| 690 |  |  |  |  |  |  | } | 
| 691 |  |  |  |  |  |  |  | 
| 692 |  |  |  |  |  |  | sub writeI16 { | 
| 693 | 0 |  |  | 0 | 0 | 0 | my ($self, $i16) = @_; | 
| 694 | 0 |  |  |  |  | 0 | $self->writeJSONInteger($i16); | 
| 695 |  |  |  |  |  |  | } | 
| 696 |  |  |  |  |  |  |  | 
| 697 |  |  |  |  |  |  | sub readI16 { | 
| 698 | 0 |  |  | 0 | 0 | 0 | my ($self, $i16) = @_; | 
| 699 | 0 |  |  |  |  | 0 | $self->readJSONInteger($i16); | 
| 700 |  |  |  |  |  |  | } | 
| 701 |  |  |  |  |  |  |  | 
| 702 |  |  |  |  |  |  | sub writeI32 { | 
| 703 | 2 |  |  | 2 | 0 | 256 | my ($self, $i32) = @_; | 
| 704 | 2 |  |  |  |  | 12 | $self->writeJSONInteger($i32); | 
| 705 |  |  |  |  |  |  | } | 
| 706 |  |  |  |  |  |  |  | 
| 707 |  |  |  |  |  |  | sub readI32 { | 
| 708 | 0 |  |  | 0 | 0 | 0 | my ($self, $i32) = @_; | 
| 709 | 0 |  |  |  |  | 0 | $self->readJSONInteger($i32); | 
| 710 |  |  |  |  |  |  | } | 
| 711 |  |  |  |  |  |  |  | 
| 712 |  |  |  |  |  |  | sub writeI64 { | 
| 713 | 0 |  |  | 0 | 0 | 0 | my ($self, $i64) = @_; | 
| 714 | 0 |  |  |  |  | 0 | $self->writeJSONInteger($i64); | 
| 715 |  |  |  |  |  |  | } | 
| 716 |  |  |  |  |  |  |  | 
| 717 |  |  |  |  |  |  | sub readI64 { | 
| 718 | 0 |  |  | 0 | 0 | 0 | my ($self, $i64) = @_; | 
| 719 | 0 |  |  |  |  | 0 | $self->readJSONInteger($i64); | 
| 720 |  |  |  |  |  |  | } | 
| 721 |  |  |  |  |  |  |  | 
| 722 |  |  |  |  |  |  | sub writeDouble { | 
| 723 | 0 |  |  | 0 | 0 | 0 | my ($self, $dub) = @_; | 
| 724 | 0 |  |  |  |  | 0 | $self->writeJSONDouble($dub); | 
| 725 |  |  |  |  |  |  | } | 
| 726 |  |  |  |  |  |  |  | 
| 727 |  |  |  |  |  |  | sub readDouble { | 
| 728 | 0 |  |  | 0 | 0 | 0 | my ($self, $dub) = @_; | 
| 729 | 0 |  |  |  |  | 0 | $self->readJSONDouble($dub); | 
| 730 |  |  |  |  |  |  | } | 
| 731 |  |  |  |  |  |  |  | 
| 732 |  |  |  |  |  |  | sub writeString { | 
| 733 | 0 |  |  | 0 | 0 | 0 | my ($self, $str) = @_; | 
| 734 | 0 |  |  |  |  | 0 | check_utf8(\$str); | 
| 735 | 0 |  |  |  |  | 0 | $self->writeJSONString($str); | 
| 736 |  |  |  |  |  |  | } | 
| 737 |  |  |  |  |  |  |  | 
| 738 |  |  |  |  |  |  | sub readString { | 
| 739 | 0 |  |  | 0 | 0 | 0 | my ($self, $str) = @_; | 
| 740 | 0 |  |  |  |  | 0 | $self->readJSONString($str); | 
| 741 |  |  |  |  |  |  | } | 
| 742 |  |  |  |  |  |  |  | 
| 743 |  |  |  |  |  |  | sub writeBinary { | 
| 744 | 0 |  |  | 0 | 0 | 0 | my ($self, $str) = @_; | 
| 745 | 0 |  |  |  |  | 0 | $self->writeJSONBase64($str); | 
| 746 |  |  |  |  |  |  | } | 
| 747 |  |  |  |  |  |  |  | 
| 748 |  |  |  |  |  |  | sub readBinary { | 
| 749 | 0 |  |  | 0 | 0 | 0 | my ($self, $str) = @_; | 
| 750 | 0 |  |  |  |  | 0 | $self->readJSONBase64($str); | 
| 751 |  |  |  |  |  |  | } | 
| 752 |  |  |  |  |  |  | # | 
| 753 |  |  |  |  |  |  | # Other related packages | 
| 754 |  |  |  |  |  |  | # | 
| 755 |  |  |  |  |  |  |  | 
| 756 |  |  |  |  |  |  | { | 
| 757 |  |  |  |  |  |  | package Thrift::JSONProtocolFactory; | 
| 758 |  |  |  |  |  |  |  | 
| 759 | 1 |  |  | 1 |  | 17 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 50 |  | 
| 760 | 1 |  |  | 1 |  | 7 | use warnings; | 
|  | 1 |  |  |  |  | 11 |  | 
|  | 1 |  |  |  |  | 46 |  | 
| 761 | 1 |  |  | 1 |  | 5 | use base qw(TProtocolFactory); | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 1057 |  | 
| 762 |  |  |  |  |  |  |  | 
| 763 |  |  |  |  |  |  | sub getProtocol { | 
| 764 | 0 |  |  | 0 |  | 0 | my ($self, $transport) = @_; | 
| 765 | 0 |  |  |  |  | 0 | return Thrift::JSONProtocol->new($transport); | 
| 766 |  |  |  |  |  |  | } | 
| 767 |  |  |  |  |  |  | } | 
| 768 |  |  |  |  |  |  |  | 
| 769 |  |  |  |  |  |  | { | 
| 770 |  |  |  |  |  |  | # Base class for tracking JSON contexts that may require inserting/reading | 
| 771 |  |  |  |  |  |  | # additional JSON syntax characters | 
| 772 |  |  |  |  |  |  | # This base context does nothing. | 
| 773 |  |  |  |  |  |  | package Thrift::JSONProtocol::JSONBaseContext; | 
| 774 |  |  |  |  |  |  |  | 
| 775 | 1 |  |  | 1 |  | 9 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 32 |  | 
| 776 | 1 |  |  | 1 |  | 6 | use warnings; | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 40 |  | 
| 777 | 1 |  |  | 1 |  | 6 | use base qw(Class::Accessor); | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 224 |  | 
| 778 |  |  |  |  |  |  | BEGIN { | 
| 779 | 1 |  |  | 1 |  | 12 | __PACKAGE__->mk_accessors(qw(protocol)); | 
| 780 |  |  |  |  |  |  | }; | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | sub new { | 
| 783 | 5 |  |  | 5 |  | 19 | my ($class, %self) = @_; | 
| 784 | 5 |  |  |  |  | 24 | return bless \%self, $class; | 
| 785 |  |  |  |  |  |  | } | 
| 786 |  |  |  |  |  |  |  | 
| 787 | 1 |  |  | 1 |  | 20 | sub write { 0 } | 
| 788 | 0 |  |  | 0 |  | 0 | sub read  { 0 } | 
| 789 | 3 |  |  | 3 |  | 31 | sub escapeNum { 0 } | 
| 790 |  |  |  |  |  |  | } | 
| 791 |  |  |  |  |  |  |  | 
| 792 |  |  |  |  |  |  | { | 
| 793 |  |  |  |  |  |  | # Context for JSON lists. Will insert/read commas before each item except | 
| 794 |  |  |  |  |  |  | # for the first one | 
| 795 |  |  |  |  |  |  | package Thrift::JSONProtocol::JSONListContext; | 
| 796 |  |  |  |  |  |  |  | 
| 797 | 1 |  |  | 1 |  | 6454 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 38 |  | 
| 798 | 1 |  |  | 1 |  | 5 | use warnings; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 30 |  | 
| 799 | 1 |  |  | 1 |  | 5 | use base qw(Thrift::JSONProtocol::JSONBaseContext); | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 765 |  | 
| 800 |  |  |  |  |  |  | BEGIN { | 
| 801 | 1 |  |  | 1 |  | 18 | __PACKAGE__->mk_accessors(qw(first_)); | 
| 802 |  |  |  |  |  |  | }; | 
| 803 |  |  |  |  |  |  |  | 
| 804 |  |  |  |  |  |  | sub new { | 
| 805 | 1 |  |  | 1 |  | 3 | my $class = shift; | 
| 806 | 1 |  |  |  |  | 8 | my $self = $class->SUPER::new(@_); | 
| 807 | 1 |  |  |  |  | 6 | $self->first_(1); | 
| 808 | 1 |  |  |  |  | 25 | return $self; | 
| 809 |  |  |  |  |  |  | } | 
| 810 |  |  |  |  |  |  |  | 
| 811 |  |  |  |  |  |  | sub write { | 
| 812 | 5 |  |  | 5 |  | 111 | my ($self) = @_; | 
| 813 | 5 | 100 |  |  |  | 14 | if ($self->first_) { | 
| 814 | 1 |  |  |  |  | 20 | $self->first_(0); | 
| 815 | 1 |  |  |  |  | 8 | return 0; | 
| 816 |  |  |  |  |  |  | } | 
| 817 |  |  |  |  |  |  | else { | 
| 818 | 4 |  |  |  |  | 43 | $self->protocol->transport->write(Thrift::JSONProtocol::COMMA); | 
| 819 | 4 |  |  |  |  | 24 | return length Thrift::JSONProtocol::COMMA; | 
| 820 |  |  |  |  |  |  | } | 
| 821 |  |  |  |  |  |  | } | 
| 822 |  |  |  |  |  |  |  | 
| 823 |  |  |  |  |  |  | sub read { | 
| 824 | 0 |  |  | 0 |  | 0 | my ($self) = @_; | 
| 825 | 0 | 0 |  |  |  | 0 | if ($self->first_) { | 
| 826 | 0 |  |  |  |  | 0 | $self->first_(0); | 
| 827 | 0 |  |  |  |  | 0 | return 0; | 
| 828 |  |  |  |  |  |  | } | 
| 829 |  |  |  |  |  |  | else { | 
| 830 | 0 |  |  |  |  | 0 | $self->protocol->readJSONSyntaxChar(Thrift::JSONProtocol::COMMA); | 
| 831 | 0 |  |  |  |  | 0 | return length Thrift::JSONProtocol::COMMA; | 
| 832 |  |  |  |  |  |  | } | 
| 833 |  |  |  |  |  |  | } | 
| 834 |  |  |  |  |  |  | } | 
| 835 |  |  |  |  |  |  |  | 
| 836 |  |  |  |  |  |  | { | 
| 837 |  |  |  |  |  |  | # Context for JSON records. Will insert/read colons before the value portion | 
| 838 |  |  |  |  |  |  | # of each record pair, and commas before each key except the first. In | 
| 839 |  |  |  |  |  |  | # addition, will indicate that numbers in the key position need to be | 
| 840 |  |  |  |  |  |  | # escaped in quotes (since JSON keys must be strings). | 
| 841 |  |  |  |  |  |  | package Thrift::JSONProtocol::JSONPairContext; | 
| 842 |  |  |  |  |  |  |  | 
| 843 | 1 |  |  | 1 |  | 614 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 38 |  | 
| 844 | 1 |  |  | 1 |  | 5 | use warnings; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 37 |  | 
| 845 | 1 |  |  | 1 |  | 7 | use base qw(Thrift::JSONProtocol::JSONBaseContext); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 647 |  | 
| 846 |  |  |  |  |  |  | BEGIN { | 
| 847 | 1 |  |  | 1 |  | 14 | __PACKAGE__->mk_accessors(qw(first_ colon_)); | 
| 848 |  |  |  |  |  |  | }; | 
| 849 |  |  |  |  |  |  |  | 
| 850 |  |  |  |  |  |  | sub new { | 
| 851 | 3 |  |  | 3 |  | 7 | my $class = shift; | 
| 852 | 3 |  |  |  |  | 16 | my $self = $class->SUPER::new(@_); | 
| 853 | 3 |  |  |  |  | 11 | $self->first_(1); | 
| 854 | 3 |  |  |  |  | 42 | $self->colon_(1); | 
| 855 | 3 |  |  |  |  | 28 | return $self; | 
| 856 |  |  |  |  |  |  | } | 
| 857 |  |  |  |  |  |  |  | 
| 858 |  |  |  |  |  |  | sub write { | 
| 859 | 8 |  |  | 8 |  | 81 | my ($self) = @_; | 
| 860 |  |  |  |  |  |  |  | 
| 861 | 8 | 100 |  |  |  | 26 | if ($self->first_) { | 
| 862 | 3 |  |  |  |  | 38 | $self->first_(0); | 
| 863 | 3 |  |  |  |  | 31 | $self->colon_(1); | 
| 864 | 3 |  |  |  |  | 23 | return 0; | 
| 865 |  |  |  |  |  |  | } | 
| 866 |  |  |  |  |  |  | else { | 
| 867 | 5 | 100 |  |  |  | 49 | my $string = $self->colon_ ? Thrift::JSONProtocol::COLON : Thrift::JSONProtocol::COMMA; | 
| 868 | 5 |  |  |  |  | 62 | $self->protocol->transport->write($string); | 
| 869 | 5 | 100 |  |  |  | 37 | $self->colon_($self->colon_ ? 0 : 1); | 
| 870 | 5 |  |  |  |  | 162 | return length $string; | 
| 871 |  |  |  |  |  |  | } | 
| 872 |  |  |  |  |  |  | } | 
| 873 |  |  |  |  |  |  |  | 
| 874 |  |  |  |  |  |  | sub read { | 
| 875 | 0 |  |  | 0 |  | 0 | my ($self) = @_; | 
| 876 |  |  |  |  |  |  |  | 
| 877 | 0 | 0 |  |  |  | 0 | if ($self->first_) { | 
| 878 | 0 |  |  |  |  | 0 | $self->first_(0); | 
| 879 | 0 |  |  |  |  | 0 | $self->colon_(1); | 
| 880 | 0 |  |  |  |  | 0 | return 0; | 
| 881 |  |  |  |  |  |  | } | 
| 882 |  |  |  |  |  |  | else { | 
| 883 | 0 | 0 |  |  |  | 0 | my $string = $self->colon_ ? Thrift::JSONProtocol::COLON : Thrift::JSONProtocol::COMMA; | 
| 884 | 0 |  |  |  |  | 0 | $self->protocol->readJSONSyntaxChar($string); | 
| 885 | 0 | 0 |  |  |  | 0 | $self->colon_($self->colon_ ? 0 : 1); | 
| 886 | 0 |  |  |  |  | 0 | return length $string; | 
| 887 |  |  |  |  |  |  | } | 
| 888 |  |  |  |  |  |  | } | 
| 889 |  |  |  |  |  |  |  | 
| 890 |  |  |  |  |  |  | sub escapeNum { | 
| 891 | 4 |  |  | 4 |  | 35 | my ($self) = @_; | 
| 892 | 4 |  |  |  |  | 11 | return $self->colon_; | 
| 893 |  |  |  |  |  |  | } | 
| 894 |  |  |  |  |  |  | } | 
| 895 |  |  |  |  |  |  |  | 
| 896 |  |  |  |  |  |  | { | 
| 897 |  |  |  |  |  |  | # Holds up to one byte from the transport | 
| 898 |  |  |  |  |  |  | package Thrift::JSONProtocol::LookaheadReader; | 
| 899 |  |  |  |  |  |  |  | 
| 900 | 1 |  |  | 1 |  | 11380 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 43 |  | 
| 901 | 1 |  |  | 1 |  | 7 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 58 |  | 
| 902 | 1 |  |  | 1 |  | 6 | use base qw(Class::Accessor); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 451 |  | 
| 903 |  |  |  |  |  |  | BEGIN { | 
| 904 | 1 |  |  | 1 |  | 11 | __PACKAGE__->mk_accessors(qw(protocol hasData_ data_)); | 
| 905 |  |  |  |  |  |  | }; | 
| 906 |  |  |  |  |  |  |  | 
| 907 |  |  |  |  |  |  | sub new { | 
| 908 | 1 |  |  | 1 |  | 4 | my ($class, %self) = @_; | 
| 909 | 1 |  |  |  |  | 7 | return bless \%self, $class; | 
| 910 |  |  |  |  |  |  | } | 
| 911 |  |  |  |  |  |  |  | 
| 912 |  |  |  |  |  |  | # Return and consume the next byte to be read, either taking it from the | 
| 913 |  |  |  |  |  |  | # data buffer if present or getting it from the transport otherwise. | 
| 914 |  |  |  |  |  |  | sub read { | 
| 915 | 0 |  |  | 0 |  |  | my ($self) = @_; | 
| 916 | 0 | 0 |  |  |  |  | if ($self->hasData_) { | 
| 917 | 0 |  |  |  |  |  | $self->hasData_(0); | 
| 918 |  |  |  |  |  |  | } | 
| 919 |  |  |  |  |  |  | else { | 
| 920 | 0 |  |  |  |  |  | $self->data_( $self->protocol->transport->readAll(1) ); | 
| 921 |  |  |  |  |  |  | } | 
| 922 | 0 |  |  |  |  |  | return $self->data_; | 
| 923 |  |  |  |  |  |  | } | 
| 924 |  |  |  |  |  |  |  | 
| 925 |  |  |  |  |  |  | # Return the next byte to be read without consuming, filling the data | 
| 926 |  |  |  |  |  |  | # buffer if it has not been filled already. | 
| 927 |  |  |  |  |  |  | sub peek { | 
| 928 | 0 |  |  | 0 |  |  | my ($self) = @_; | 
| 929 | 0 | 0 |  |  |  |  | if (! $self->hasData_) { | 
| 930 | 0 |  |  |  |  |  | $self->data_( $self->protocol->transport->readAll(1) ); | 
| 931 |  |  |  |  |  |  | } | 
| 932 | 0 |  |  |  |  |  | $self->hasData_(1); | 
| 933 | 0 |  |  |  |  |  | return $self->data_; | 
| 934 |  |  |  |  |  |  | } | 
| 935 |  |  |  |  |  |  | } | 
| 936 |  |  |  |  |  |  |  | 
| 937 |  |  |  |  |  |  | 1; |