1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20package thrift 21 22import ( 23 "context" 24 "encoding/binary" 25 "errors" 26 "fmt" 27 "io" 28 "math" 29) 30 31const ( 32 COMPACT_PROTOCOL_ID = 0x082 33 COMPACT_VERSION = 1 34 COMPACT_VERSION_MASK = 0x1f 35 COMPACT_TYPE_MASK = 0x0E0 36 COMPACT_TYPE_BITS = 0x07 37 COMPACT_TYPE_SHIFT_AMOUNT = 5 38) 39 40type tCompactType byte 41 42const ( 43 COMPACT_BOOLEAN_TRUE = 0x01 44 COMPACT_BOOLEAN_FALSE = 0x02 45 COMPACT_BYTE = 0x03 46 COMPACT_I16 = 0x04 47 COMPACT_I32 = 0x05 48 COMPACT_I64 = 0x06 49 COMPACT_DOUBLE = 0x07 50 COMPACT_BINARY = 0x08 51 COMPACT_LIST = 0x09 52 COMPACT_SET = 0x0A 53 COMPACT_MAP = 0x0B 54 COMPACT_STRUCT = 0x0C 55 COMPACT_UUID = 0x0D 56) 57 58var ( 59 ttypeToCompactType map[TType]tCompactType 60) 61 62func init() { 63 ttypeToCompactType = map[TType]tCompactType{ 64 STOP: STOP, 65 BOOL: COMPACT_BOOLEAN_TRUE, 66 BYTE: COMPACT_BYTE, 67 I16: COMPACT_I16, 68 I32: COMPACT_I32, 69 I64: COMPACT_I64, 70 DOUBLE: COMPACT_DOUBLE, 71 STRING: COMPACT_BINARY, 72 LIST: COMPACT_LIST, 73 SET: COMPACT_SET, 74 MAP: COMPACT_MAP, 75 STRUCT: COMPACT_STRUCT, 76 UUID: COMPACT_UUID, 77 } 78} 79 80type TCompactProtocolFactory struct { 81 cfg *TConfiguration 82} 83 84// Deprecated: Use NewTCompactProtocolFactoryConf instead. 85func NewTCompactProtocolFactory() *TCompactProtocolFactory { 86 return NewTCompactProtocolFactoryConf(&TConfiguration{ 87 noPropagation: true, 88 }) 89} 90 91func NewTCompactProtocolFactoryConf(conf *TConfiguration) *TCompactProtocolFactory { 92 return &TCompactProtocolFactory{ 93 cfg: conf, 94 } 95} 96 97func (p *TCompactProtocolFactory) GetProtocol(trans TTransport) TProtocol { 98 return NewTCompactProtocolConf(trans, p.cfg) 99} 100 101func (p *TCompactProtocolFactory) SetTConfiguration(conf *TConfiguration) { 102 p.cfg = conf 103} 104 105type TCompactProtocol struct { 106 trans TRichTransport 107 origTransport TTransport 108 109 cfg *TConfiguration 110 111 // Used to keep track of the last field for the current and previous structs, 112 // so we can do the delta stuff. 113 lastField []int 114 lastFieldId int 115 116 // If we encounter a boolean field begin, save the TField here so it can 117 // have the value incorporated. 118 booleanFieldName string 119 booleanFieldId int16 120 booleanFieldPending bool 121 122 // If we read a field header, and it's a boolean field, save the boolean 123 // value here so that readBool can use it. 124 boolValue bool 125 boolValueIsNotNull bool 126 buffer [64]byte 127} 128 129// Deprecated: Use NewTCompactProtocolConf instead. 130func NewTCompactProtocol(trans TTransport) *TCompactProtocol { 131 return NewTCompactProtocolConf(trans, &TConfiguration{ 132 noPropagation: true, 133 }) 134} 135 136func NewTCompactProtocolConf(trans TTransport, conf *TConfiguration) *TCompactProtocol { 137 PropagateTConfiguration(trans, conf) 138 p := &TCompactProtocol{ 139 origTransport: trans, 140 cfg: conf, 141 } 142 if et, ok := trans.(TRichTransport); ok { 143 p.trans = et 144 } else { 145 p.trans = NewTRichTransport(trans) 146 } 147 148 return p 149} 150 151// 152// Public Writing methods. 153// 154 155// Write a message header to the wire. Compact Protocol messages contain the 156// protocol version so we can migrate forwards in the future if need be. 157func (p *TCompactProtocol) WriteMessageBegin(ctx context.Context, name string, typeId TMessageType, seqid int32) error { 158 err := p.writeByteDirect(COMPACT_PROTOCOL_ID) 159 if err != nil { 160 return NewTProtocolException(err) 161 } 162 err = p.writeByteDirect((COMPACT_VERSION & COMPACT_VERSION_MASK) | ((byte(typeId) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK)) 163 if err != nil { 164 return NewTProtocolException(err) 165 } 166 _, err = p.writeVarint32(seqid) 167 if err != nil { 168 return NewTProtocolException(err) 169 } 170 e := p.WriteString(ctx, name) 171 return e 172 173} 174 175func (p *TCompactProtocol) WriteMessageEnd(ctx context.Context) error { return nil } 176 177// Write a struct begin. This doesn't actually put anything on the wire. We 178// use it as an opportunity to put special placeholder markers on the field 179// stack so we can get the field id deltas correct. 180func (p *TCompactProtocol) WriteStructBegin(ctx context.Context, name string) error { 181 p.lastField = append(p.lastField, p.lastFieldId) 182 p.lastFieldId = 0 183 return nil 184} 185 186// Write a struct end. This doesn't actually put anything on the wire. We use 187// this as an opportunity to pop the last field from the current struct off 188// of the field stack. 189func (p *TCompactProtocol) WriteStructEnd(ctx context.Context) error { 190 if len(p.lastField) <= 0 { 191 return NewTProtocolExceptionWithType(INVALID_DATA, errors.New("WriteStructEnd called without matching WriteStructBegin call before")) 192 } 193 p.lastFieldId = p.lastField[len(p.lastField)-1] 194 p.lastField = p.lastField[:len(p.lastField)-1] 195 return nil 196} 197 198func (p *TCompactProtocol) WriteFieldBegin(ctx context.Context, name string, typeId TType, id int16) error { 199 if typeId == BOOL { 200 // we want to possibly include the value, so we'll wait. 201 p.booleanFieldName, p.booleanFieldId, p.booleanFieldPending = name, id, true 202 return nil 203 } 204 _, err := p.writeFieldBeginInternal(ctx, name, typeId, id, 0xFF) 205 return NewTProtocolException(err) 206} 207 208// The workhorse of writeFieldBegin. It has the option of doing a 209// 'type override' of the type header. This is used specifically in the 210// boolean field case. 211func (p *TCompactProtocol) writeFieldBeginInternal(ctx context.Context, name string, typeId TType, id int16, typeOverride byte) (int, error) { 212 // short lastField = lastField_.pop(); 213 214 // if there's a type override, use that. 215 var typeToWrite byte 216 if typeOverride == 0xFF { 217 typeToWrite = byte(p.getCompactType(typeId)) 218 } else { 219 typeToWrite = typeOverride 220 } 221 // check if we can use delta encoding for the field id 222 fieldId := int(id) 223 written := 0 224 if fieldId > p.lastFieldId && fieldId-p.lastFieldId <= 15 { 225 // write them together 226 err := p.writeByteDirect(byte((fieldId-p.lastFieldId)<<4) | typeToWrite) 227 if err != nil { 228 return 0, err 229 } 230 } else { 231 // write them separate 232 err := p.writeByteDirect(typeToWrite) 233 if err != nil { 234 return 0, err 235 } 236 err = p.WriteI16(ctx, id) 237 written = 1 + 2 238 if err != nil { 239 return 0, err 240 } 241 } 242 243 p.lastFieldId = fieldId 244 return written, nil 245} 246 247func (p *TCompactProtocol) WriteFieldEnd(ctx context.Context) error { return nil } 248 249func (p *TCompactProtocol) WriteFieldStop(ctx context.Context) error { 250 err := p.writeByteDirect(STOP) 251 return NewTProtocolException(err) 252} 253 254func (p *TCompactProtocol) WriteMapBegin(ctx context.Context, keyType TType, valueType TType, size int) error { 255 if size == 0 { 256 err := p.writeByteDirect(0) 257 return NewTProtocolException(err) 258 } 259 _, err := p.writeVarint32(int32(size)) 260 if err != nil { 261 return NewTProtocolException(err) 262 } 263 err = p.writeByteDirect(byte(p.getCompactType(keyType))<<4 | byte(p.getCompactType(valueType))) 264 return NewTProtocolException(err) 265} 266 267func (p *TCompactProtocol) WriteMapEnd(ctx context.Context) error { return nil } 268 269// Write a list header. 270func (p *TCompactProtocol) WriteListBegin(ctx context.Context, elemType TType, size int) error { 271 _, err := p.writeCollectionBegin(elemType, size) 272 return NewTProtocolException(err) 273} 274 275func (p *TCompactProtocol) WriteListEnd(ctx context.Context) error { return nil } 276 277// Write a set header. 278func (p *TCompactProtocol) WriteSetBegin(ctx context.Context, elemType TType, size int) error { 279 _, err := p.writeCollectionBegin(elemType, size) 280 return NewTProtocolException(err) 281} 282 283func (p *TCompactProtocol) WriteSetEnd(ctx context.Context) error { return nil } 284 285func (p *TCompactProtocol) WriteBool(ctx context.Context, value bool) error { 286 v := byte(COMPACT_BOOLEAN_FALSE) 287 if value { 288 v = byte(COMPACT_BOOLEAN_TRUE) 289 } 290 if p.booleanFieldPending { 291 // we haven't written the field header yet 292 _, err := p.writeFieldBeginInternal(ctx, p.booleanFieldName, BOOL, p.booleanFieldId, v) 293 p.booleanFieldPending = false 294 return NewTProtocolException(err) 295 } 296 // we're not part of a field, so just write the value. 297 err := p.writeByteDirect(v) 298 return NewTProtocolException(err) 299} 300 301// Write a byte. Nothing to see here! 302func (p *TCompactProtocol) WriteByte(ctx context.Context, value int8) error { 303 err := p.writeByteDirect(byte(value)) 304 return NewTProtocolException(err) 305} 306 307// Write an I16 as a zigzag varint. 308func (p *TCompactProtocol) WriteI16(ctx context.Context, value int16) error { 309 _, err := p.writeVarint32(p.int32ToZigzag(int32(value))) 310 return NewTProtocolException(err) 311} 312 313// Write an i32 as a zigzag varint. 314func (p *TCompactProtocol) WriteI32(ctx context.Context, value int32) error { 315 _, err := p.writeVarint32(p.int32ToZigzag(value)) 316 return NewTProtocolException(err) 317} 318 319// Write an i64 as a zigzag varint. 320func (p *TCompactProtocol) WriteI64(ctx context.Context, value int64) error { 321 _, err := p.writeVarint64(p.int64ToZigzag(value)) 322 return NewTProtocolException(err) 323} 324 325// Write a double to the wire as 8 bytes. 326func (p *TCompactProtocol) WriteDouble(ctx context.Context, value float64) error { 327 buf := p.buffer[0:8] 328 binary.LittleEndian.PutUint64(buf, math.Float64bits(value)) 329 _, err := p.trans.Write(buf) 330 return NewTProtocolException(err) 331} 332 333// Write a string to the wire with a varint size preceding. 334func (p *TCompactProtocol) WriteString(ctx context.Context, value string) error { 335 _, e := p.writeVarint32(int32(len(value))) 336 if e != nil { 337 return NewTProtocolException(e) 338 } 339 if len(value) == 0 { 340 return nil 341 } 342 _, e = p.trans.WriteString(value) 343 return e 344} 345 346// Write a byte array, using a varint for the size. 347func (p *TCompactProtocol) WriteBinary(ctx context.Context, bin []byte) error { 348 _, e := p.writeVarint32(int32(len(bin))) 349 if e != nil { 350 return NewTProtocolException(e) 351 } 352 if len(bin) > 0 { 353 _, e = p.trans.Write(bin) 354 return NewTProtocolException(e) 355 } 356 return nil 357} 358 359// Write a Tuuid to the wire as 16 bytes. 360func (p *TCompactProtocol) WriteUUID(ctx context.Context, value Tuuid) error { 361 _, err := p.trans.Write(value[:]) 362 return NewTProtocolException(err) 363} 364 365// 366// Reading methods. 367// 368 369// Read a message header. 370func (p *TCompactProtocol) ReadMessageBegin(ctx context.Context) (name string, typeId TMessageType, seqId int32, err error) { 371 var protocolId byte 372 373 _, deadlineSet := ctx.Deadline() 374 for { 375 protocolId, err = p.readByteDirect() 376 if deadlineSet && isTimeoutError(err) && ctx.Err() == nil { 377 // keep retrying I/O timeout errors since we still have 378 // time left 379 continue 380 } 381 // For anything else, don't retry 382 break 383 } 384 if err != nil { 385 return 386 } 387 388 if protocolId != COMPACT_PROTOCOL_ID { 389 e := fmt.Errorf("Expected protocol id %02x but got %02x", COMPACT_PROTOCOL_ID, protocolId) 390 return "", typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, e) 391 } 392 393 versionAndType, err := p.readByteDirect() 394 if err != nil { 395 return 396 } 397 398 version := versionAndType & COMPACT_VERSION_MASK 399 typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_BITS) 400 if version != COMPACT_VERSION { 401 e := fmt.Errorf("Expected version %02x but got %02x", COMPACT_VERSION, version) 402 err = NewTProtocolExceptionWithType(BAD_VERSION, e) 403 return 404 } 405 seqId, e := p.readVarint32() 406 if e != nil { 407 err = NewTProtocolException(e) 408 return 409 } 410 name, err = p.ReadString(ctx) 411 return 412} 413 414func (p *TCompactProtocol) ReadMessageEnd(ctx context.Context) error { return nil } 415 416// Read a struct begin. There's nothing on the wire for this, but it is our 417// opportunity to push a new struct begin marker onto the field stack. 418func (p *TCompactProtocol) ReadStructBegin(ctx context.Context) (name string, err error) { 419 p.lastField = append(p.lastField, p.lastFieldId) 420 p.lastFieldId = 0 421 return 422} 423 424// Doesn't actually consume any wire data, just removes the last field for 425// this struct from the field stack. 426func (p *TCompactProtocol) ReadStructEnd(ctx context.Context) error { 427 // consume the last field we read off the wire. 428 if len(p.lastField) <= 0 { 429 return NewTProtocolExceptionWithType(INVALID_DATA, errors.New("ReadStructEnd called without matching ReadStructBegin call before")) 430 } 431 p.lastFieldId = p.lastField[len(p.lastField)-1] 432 p.lastField = p.lastField[:len(p.lastField)-1] 433 return nil 434} 435 436// Read a field header off the wire. 437func (p *TCompactProtocol) ReadFieldBegin(ctx context.Context) (name string, typeId TType, id int16, err error) { 438 t, err := p.readByteDirect() 439 if err != nil { 440 return 441 } 442 443 // if it's a stop, then we can return immediately, as the struct is over. 444 if (t & 0x0f) == STOP { 445 return "", STOP, 0, nil 446 } 447 448 // mask off the 4 MSB of the type header. it could contain a field id delta. 449 modifier := int16((t & 0xf0) >> 4) 450 if modifier == 0 { 451 // not a delta. look ahead for the zigzag varint field id. 452 id, err = p.ReadI16(ctx) 453 if err != nil { 454 return 455 } 456 } else { 457 // has a delta. add the delta to the last read field id. 458 id = int16(p.lastFieldId) + modifier 459 } 460 typeId, e := p.getTType(tCompactType(t & 0x0f)) 461 if e != nil { 462 err = NewTProtocolException(e) 463 return 464 } 465 466 // if this happens to be a boolean field, the value is encoded in the type 467 if p.isBoolType(t) { 468 // save the boolean value in a special instance variable. 469 p.boolValue = (byte(t)&0x0f == COMPACT_BOOLEAN_TRUE) 470 p.boolValueIsNotNull = true 471 } 472 473 // push the new field onto the field stack so we can keep the deltas going. 474 p.lastFieldId = int(id) 475 return 476} 477 478func (p *TCompactProtocol) ReadFieldEnd(ctx context.Context) error { return nil } 479 480// Read a map header off the wire. If the size is zero, skip reading the key 481// and value type. This means that 0-length maps will yield TMaps without the 482// "correct" types. 483func (p *TCompactProtocol) ReadMapBegin(ctx context.Context) (keyType TType, valueType TType, size int, err error) { 484 size32, e := p.readVarint32() 485 if e != nil { 486 err = NewTProtocolException(e) 487 return 488 } 489 err = checkSizeForProtocol(size32, p.cfg) 490 if err != nil { 491 return 492 } 493 size = int(size32) 494 495 keyAndValueType := byte(STOP) 496 if size != 0 { 497 keyAndValueType, err = p.readByteDirect() 498 if err != nil { 499 return 500 } 501 } 502 keyType, _ = p.getTType(tCompactType(keyAndValueType >> 4)) 503 valueType, _ = p.getTType(tCompactType(keyAndValueType & 0xf)) 504 return 505} 506 507func (p *TCompactProtocol) ReadMapEnd(ctx context.Context) error { return nil } 508 509// Read a list header off the wire. If the list size is 0-14, the size will 510// be packed into the element type header. If it's a longer list, the 4 MSB 511// of the element type header will be 0xF, and a varint will follow with the 512// true size. 513func (p *TCompactProtocol) ReadListBegin(ctx context.Context) (elemType TType, size int, err error) { 514 size_and_type, err := p.readByteDirect() 515 if err != nil { 516 return 517 } 518 size = int((size_and_type >> 4) & 0x0f) 519 if size == 15 { 520 size2, e := p.readVarint32() 521 if e != nil { 522 err = NewTProtocolException(e) 523 return 524 } 525 size = int(size2) 526 } 527 err = checkSizeForProtocol(int32(size), p.cfg) 528 if err != nil { 529 return 530 } 531 elemType, e := p.getTType(tCompactType(size_and_type)) 532 if e != nil { 533 err = NewTProtocolException(e) 534 return 535 } 536 return 537} 538 539func (p *TCompactProtocol) ReadListEnd(ctx context.Context) error { return nil } 540 541// Read a set header off the wire. If the set size is 0-14, the size will 542// be packed into the element type header. If it's a longer set, the 4 MSB 543// of the element type header will be 0xF, and a varint will follow with the 544// true size. 545func (p *TCompactProtocol) ReadSetBegin(ctx context.Context) (elemType TType, size int, err error) { 546 return p.ReadListBegin(ctx) 547} 548 549func (p *TCompactProtocol) ReadSetEnd(ctx context.Context) error { return nil } 550 551// Read a boolean off the wire. If this is a boolean field, the value should 552// already have been read during readFieldBegin, so we'll just consume the 553// pre-stored value. Otherwise, read a byte. 554func (p *TCompactProtocol) ReadBool(ctx context.Context) (value bool, err error) { 555 if p.boolValueIsNotNull { 556 p.boolValueIsNotNull = false 557 return p.boolValue, nil 558 } 559 v, err := p.readByteDirect() 560 return v == COMPACT_BOOLEAN_TRUE, err 561} 562 563// Read a single byte off the wire. Nothing interesting here. 564func (p *TCompactProtocol) ReadByte(ctx context.Context) (int8, error) { 565 v, err := p.readByteDirect() 566 if err != nil { 567 return 0, NewTProtocolException(err) 568 } 569 return int8(v), err 570} 571 572// Read an i16 from the wire as a zigzag varint. 573func (p *TCompactProtocol) ReadI16(ctx context.Context) (value int16, err error) { 574 v, err := p.ReadI32(ctx) 575 return int16(v), err 576} 577 578// Read an i32 from the wire as a zigzag varint. 579func (p *TCompactProtocol) ReadI32(ctx context.Context) (value int32, err error) { 580 v, e := p.readVarint32() 581 if e != nil { 582 return 0, NewTProtocolException(e) 583 } 584 value = p.zigzagToInt32(v) 585 return value, nil 586} 587 588// Read an i64 from the wire as a zigzag varint. 589func (p *TCompactProtocol) ReadI64(ctx context.Context) (value int64, err error) { 590 v, e := p.readVarint64() 591 if e != nil { 592 return 0, NewTProtocolException(e) 593 } 594 value = p.zigzagToInt64(v) 595 return value, nil 596} 597 598// No magic here - just read a double off the wire. 599func (p *TCompactProtocol) ReadDouble(ctx context.Context) (value float64, err error) { 600 longBits := p.buffer[0:8] 601 _, e := io.ReadFull(p.trans, longBits) 602 if e != nil { 603 return 0.0, NewTProtocolException(e) 604 } 605 return math.Float64frombits(p.bytesToUint64(longBits)), nil 606} 607 608// Reads a []byte (via readBinary), and then UTF-8 decodes it. 609func (p *TCompactProtocol) ReadString(ctx context.Context) (value string, err error) { 610 length, e := p.readVarint32() 611 if e != nil { 612 return "", NewTProtocolException(e) 613 } 614 err = checkSizeForProtocol(length, p.cfg) 615 if err != nil { 616 return 617 } 618 if length == 0 { 619 return "", nil 620 } 621 if length < int32(len(p.buffer)) { 622 // Avoid allocation on small reads 623 buf := p.buffer[:length] 624 read, e := io.ReadFull(p.trans, buf) 625 return string(buf[:read]), NewTProtocolException(e) 626 } 627 628 buf, e := safeReadBytes(length, p.trans) 629 return string(buf), NewTProtocolException(e) 630} 631 632// Read a []byte from the wire. 633func (p *TCompactProtocol) ReadBinary(ctx context.Context) (value []byte, err error) { 634 length, e := p.readVarint32() 635 if e != nil { 636 return nil, NewTProtocolException(e) 637 } 638 err = checkSizeForProtocol(length, p.cfg) 639 if err != nil { 640 return 641 } 642 if length == 0 { 643 return []byte{}, nil 644 } 645 646 buf, e := safeReadBytes(length, p.trans) 647 return buf, NewTProtocolException(e) 648} 649 650// Read fixed 16 bytes as UUID. 651func (p *TCompactProtocol) ReadUUID(ctx context.Context) (value Tuuid, err error) { 652 buf := p.buffer[0:16] 653 _, e := io.ReadFull(p.trans, buf) 654 if e == nil { 655 copy(value[:], buf) 656 } 657 return value, NewTProtocolException(e) 658} 659 660func (p *TCompactProtocol) Flush(ctx context.Context) (err error) { 661 return NewTProtocolException(p.trans.Flush(ctx)) 662} 663 664func (p *TCompactProtocol) Skip(ctx context.Context, fieldType TType) (err error) { 665 return SkipDefaultDepth(ctx, p, fieldType) 666} 667 668func (p *TCompactProtocol) Transport() TTransport { 669 return p.origTransport 670} 671 672// 673// Internal writing methods 674// 675 676// Abstract method for writing the start of lists and sets. List and sets on 677// the wire differ only by the type indicator. 678func (p *TCompactProtocol) writeCollectionBegin(elemType TType, size int) (int, error) { 679 if size <= 14 { 680 return 1, p.writeByteDirect(byte(int32(size<<4) | int32(p.getCompactType(elemType)))) 681 } 682 err := p.writeByteDirect(0xf0 | byte(p.getCompactType(elemType))) 683 if err != nil { 684 return 0, err 685 } 686 m, err := p.writeVarint32(int32(size)) 687 return 1 + m, err 688} 689 690// Write an i32 as a varint. Results in 1-5 bytes on the wire. 691// TODO(pomack): make a permanent buffer like writeVarint64? 692func (p *TCompactProtocol) writeVarint32(n int32) (int, error) { 693 i32buf := p.buffer[0:5] 694 idx := 0 695 for { 696 if (n & ^0x7F) == 0 { 697 i32buf[idx] = byte(n) 698 idx++ 699 // p.writeByteDirect(byte(n)); 700 break 701 // return; 702 } else { 703 i32buf[idx] = byte((n & 0x7F) | 0x80) 704 idx++ 705 // p.writeByteDirect(byte(((n & 0x7F) | 0x80))); 706 u := uint32(n) 707 n = int32(u >> 7) 708 } 709 } 710 return p.trans.Write(i32buf[0:idx]) 711} 712 713// Write an i64 as a varint. Results in 1-10 bytes on the wire. 714func (p *TCompactProtocol) writeVarint64(n int64) (int, error) { 715 varint64out := p.buffer[0:10] 716 idx := 0 717 for { 718 if (n & ^0x7F) == 0 { 719 varint64out[idx] = byte(n) 720 idx++ 721 break 722 } else { 723 varint64out[idx] = byte((n & 0x7F) | 0x80) 724 idx++ 725 u := uint64(n) 726 n = int64(u >> 7) 727 } 728 } 729 return p.trans.Write(varint64out[0:idx]) 730} 731 732// Convert l into a zigzag long. This allows negative numbers to be 733// represented compactly as a varint. 734func (p *TCompactProtocol) int64ToZigzag(l int64) int64 { 735 return (l << 1) ^ (l >> 63) 736} 737 738// Convert l into a zigzag long. This allows negative numbers to be 739// represented compactly as a varint. 740func (p *TCompactProtocol) int32ToZigzag(n int32) int32 { 741 return (n << 1) ^ (n >> 31) 742} 743 744// Writes a byte without any possibility of all that field header nonsense. 745// Used internally by other writing methods that know they need to write a byte. 746func (p *TCompactProtocol) writeByteDirect(b byte) error { 747 return p.trans.WriteByte(b) 748} 749 750// 751// Internal reading methods 752// 753 754// Read an i32 from the wire as a varint. The MSB of each byte is set 755// if there is another byte to follow. This can read up to 5 bytes. 756func (p *TCompactProtocol) readVarint32() (int32, error) { 757 // if the wire contains the right stuff, this will just truncate the i64 we 758 // read and get us the right sign. 759 v, err := p.readVarint64() 760 return int32(v), err 761} 762 763// Read an i64 from the wire as a proper varint. The MSB of each byte is set 764// if there is another byte to follow. This can read up to 10 bytes. 765func (p *TCompactProtocol) readVarint64() (int64, error) { 766 shift := uint(0) 767 result := int64(0) 768 for { 769 b, err := p.readByteDirect() 770 if err != nil { 771 return 0, err 772 } 773 result |= int64(b&0x7f) << shift 774 if (b & 0x80) != 0x80 { 775 break 776 } 777 shift += 7 778 } 779 return result, nil 780} 781 782// Read a byte, unlike ReadByte that reads Thrift-byte that is i8. 783func (p *TCompactProtocol) readByteDirect() (byte, error) { 784 return p.trans.ReadByte() 785} 786 787// 788// encoding helpers 789// 790 791// Convert from zigzag int to int. 792func (p *TCompactProtocol) zigzagToInt32(n int32) int32 { 793 u := uint32(n) 794 return int32(u>>1) ^ -(n & 1) 795} 796 797// Convert from zigzag long to long. 798func (p *TCompactProtocol) zigzagToInt64(n int64) int64 { 799 u := uint64(n) 800 return int64(u>>1) ^ -(n & 1) 801} 802 803// Note that it's important that the mask bytes are long literals, 804// otherwise they'll default to ints, and when you shift an int left 56 bits, 805// you just get a messed up int. 806func (p *TCompactProtocol) bytesToUint64(b []byte) uint64 { 807 return binary.LittleEndian.Uint64(b) 808} 809 810// 811// type testing and converting 812// 813 814func (p *TCompactProtocol) isBoolType(b byte) bool { 815 return (b&0x0f) == COMPACT_BOOLEAN_TRUE || (b&0x0f) == COMPACT_BOOLEAN_FALSE 816} 817 818// Given a tCompactType constant, convert it to its corresponding 819// TType value. 820func (p *TCompactProtocol) getTType(t tCompactType) (TType, error) { 821 switch byte(t) & 0x0f { 822 case STOP: 823 return STOP, nil 824 case COMPACT_BOOLEAN_FALSE, COMPACT_BOOLEAN_TRUE: 825 return BOOL, nil 826 case COMPACT_BYTE: 827 return BYTE, nil 828 case COMPACT_I16: 829 return I16, nil 830 case COMPACT_I32: 831 return I32, nil 832 case COMPACT_I64: 833 return I64, nil 834 case COMPACT_DOUBLE: 835 return DOUBLE, nil 836 case COMPACT_BINARY: 837 return STRING, nil 838 case COMPACT_LIST: 839 return LIST, nil 840 case COMPACT_SET: 841 return SET, nil 842 case COMPACT_MAP: 843 return MAP, nil 844 case COMPACT_STRUCT: 845 return STRUCT, nil 846 case COMPACT_UUID: 847 return UUID, nil 848 } 849 return STOP, NewTProtocolException(fmt.Errorf("don't know what type: %v", t&0x0f)) 850} 851 852// Given a TType value, find the appropriate TCompactProtocol.Types constant. 853func (p *TCompactProtocol) getCompactType(t TType) tCompactType { 854 return ttypeToCompactType[t] 855} 856 857func (p *TCompactProtocol) SetTConfiguration(conf *TConfiguration) { 858 PropagateTConfiguration(p.trans, conf) 859 PropagateTConfiguration(p.origTransport, conf) 860 p.cfg = conf 861} 862 863var ( 864 _ TConfigurationSetter = (*TCompactProtocolFactory)(nil) 865 _ TConfigurationSetter = (*TCompactProtocol)(nil) 866) 867