|  | // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | package bindings | 
|  |  | 
|  | import ( | 
|  | "encoding/binary" | 
|  | "fmt" | 
|  | "math" | 
|  |  | 
|  | "mojo/public/go/system" | 
|  | ) | 
|  |  | 
|  | // encodingState has information required to encode/decode a one-level value. | 
|  | type encodingState struct { | 
|  | // Index of the first unprocessed byte. | 
|  | offset int | 
|  |  | 
|  | // Index of the first unprocessed bit of buffer[offset] byte. | 
|  | bitOffset uint32 | 
|  |  | 
|  | // Index of the first byte after the claimed buffer block for the current | 
|  | // one-level value. | 
|  | limit int | 
|  |  | 
|  | // Element size in bits of the current one-level array, 0 for other types. | 
|  | elementBitSize uint32 | 
|  |  | 
|  | // Number of elements declared in the data header for the current one-level | 
|  | // value. | 
|  | elements uint32 | 
|  |  | 
|  | // Number of elements already encoded/decoded of the current one-level | 
|  | // value. | 
|  | elementsProcessed uint32 | 
|  | } | 
|  |  | 
|  | func (s *encodingState) alignOffsetToBytes() { | 
|  | if s.bitOffset > 0 { | 
|  | s.offset++ | 
|  | s.bitOffset = 0 | 
|  | } | 
|  | } | 
|  |  | 
|  | func (s *encodingState) skipBits(count uint32) { | 
|  | s.bitOffset += count | 
|  | s.offset += int(s.bitOffset >> 3) // equal to s.bitOffset / 8 | 
|  | s.bitOffset &= 7                  // equal to s.bitOffset % 8 | 
|  | } | 
|  |  | 
|  | func (s *encodingState) skipBytes(count int) { | 
|  | s.bitOffset = 0 | 
|  | s.offset += count | 
|  | } | 
|  |  | 
|  | // Encoder is a helper to encode mojo complex elements into mojo archive format. | 
|  | type Encoder struct { | 
|  | // Buffer containing encoded data. | 
|  | buf []byte | 
|  |  | 
|  | // Index of the first unclaimed byte in buf. | 
|  | end int | 
|  |  | 
|  | // Array containing encoded handles. | 
|  | handles []system.UntypedHandle | 
|  |  | 
|  | // A stack of encoder states matching current one-level value stack | 
|  | // of the encoding data structure. | 
|  | stateStack []encodingState | 
|  | } | 
|  |  | 
|  | func ensureElementBitSizeAndCapacity(state *encodingState, bitSize uint32) error { | 
|  | if state == nil { | 
|  | return fmt.Errorf("empty state stack") | 
|  | } | 
|  | if state.elementBitSize != 0 && state.elementBitSize != bitSize { | 
|  | return fmt.Errorf("unexpected element bit size: expected %d, but got %d", state.elementBitSize, bitSize) | 
|  | } | 
|  | if state.elementBitSize != 0 && state.elementsProcessed >= state.elements { | 
|  | return fmt.Errorf("can't process more than elements defined in header(%d)", state.elements) | 
|  | } | 
|  | byteSize := bytesForBits(uint64(state.bitOffset + bitSize)) | 
|  | if align(state.offset+byteSize, byteSize) > state.limit { | 
|  | return fmt.Errorf("buffer size limit exceeded") | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // claimData claims a block of |size| bytes for a one-level value, resizing | 
|  | // buffer if needed. | 
|  | func (e *Encoder) claimData(size int) { | 
|  | e.end += size | 
|  | if e.end < len(e.buf) { | 
|  | return | 
|  | } | 
|  | newLen := e.end | 
|  | if l := 2 * len(e.buf); newLen < l { | 
|  | newLen = l | 
|  | } | 
|  | tmp := make([]byte, newLen) | 
|  | copy(tmp, e.buf) | 
|  | e.buf = tmp | 
|  | } | 
|  |  | 
|  | func (e *Encoder) popState() { | 
|  | if len(e.stateStack) != 0 { | 
|  | e.stateStack = e.stateStack[:len(e.stateStack)-1] | 
|  | } | 
|  | } | 
|  |  | 
|  | func (e *Encoder) pushState(header DataHeader, elementBitSize uint32) { | 
|  | oldEnd := e.end | 
|  | e.claimData(align(int(header.Size), defaultAlignment)) | 
|  | elements := uint32(0) | 
|  | if elementBitSize != 0 { | 
|  | elements = header.ElementsOrVersion | 
|  | } | 
|  | e.stateStack = append(e.stateStack, encodingState{ | 
|  | offset:         oldEnd, | 
|  | limit:          e.end, | 
|  | elementBitSize: elementBitSize, | 
|  | elements:       elements, | 
|  | }) | 
|  | e.writeDataHeader(header) | 
|  | } | 
|  |  | 
|  | // state returns encoder state of the top-level value. | 
|  | func (e *Encoder) state() *encodingState { | 
|  | if len(e.stateStack) == 0 { | 
|  | return nil | 
|  | } | 
|  | return &e.stateStack[len(e.stateStack)-1] | 
|  | } | 
|  |  | 
|  | // NewEncoder returns a new instance of encoder. | 
|  | func NewEncoder() *Encoder { | 
|  | return &Encoder{} | 
|  | } | 
|  |  | 
|  | // StartArray starts encoding an array and writes its data header. | 
|  | // Note: it doesn't write a pointer to the encoded array. | 
|  | // Call |Finish()| after writing all array elements. | 
|  | func (e *Encoder) StartArray(length, elementBitSize uint32) { | 
|  | dataSize := dataHeaderSize + bytesForBits(uint64(length)*uint64(elementBitSize)) | 
|  | header := DataHeader{uint32(dataSize), length} | 
|  | e.pushState(header, elementBitSize) | 
|  | } | 
|  |  | 
|  | // StartMap starts encoding a map and writes its data header. | 
|  | // Note: it doesn't write a pointer to the encoded map. | 
|  | // Call |Finish()| after writing keys array and values array. | 
|  | func (e *Encoder) StartMap() { | 
|  | e.pushState(mapHeader, pointerBitSize) | 
|  | } | 
|  |  | 
|  | // StartStruct starts encoding a struct and writes its data header. | 
|  | // Note: it doesn't write a pointer to the encoded struct. | 
|  | // Call |Finish()| after writing all fields. | 
|  | func (e *Encoder) StartStruct(size, version uint32) { | 
|  | dataSize := dataHeaderSize + int(size) | 
|  | header := DataHeader{uint32(dataSize), version} | 
|  | e.pushState(header, 0) | 
|  | } | 
|  |  | 
|  | func (e *Encoder) writeDataHeader(header DataHeader) { | 
|  | binary.LittleEndian.PutUint32(e.buf[e.state().offset:], header.Size) | 
|  | binary.LittleEndian.PutUint32(e.buf[e.state().offset+4:], header.ElementsOrVersion) | 
|  | e.state().offset += 8 | 
|  | } | 
|  |  | 
|  | // Finish indicates the encoder that you have finished writing elements of | 
|  | // a one-level value. | 
|  | func (e *Encoder) Finish() error { | 
|  | if e.state() == nil { | 
|  | return fmt.Errorf("state stack is empty") | 
|  | } | 
|  | if e.state().elementBitSize != 0 && e.state().elementsProcessed != e.state().elements { | 
|  | return fmt.Errorf("unexpected number of elements written: defined in header %d, but written %d", e.state().elements, e.state().elementsProcessed) | 
|  | } | 
|  | e.popState() | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // Data returns an encoded message with attached handles. | 
|  | // Call this method after finishing encoding of a value. | 
|  | func (e *Encoder) Data() ([]byte, []system.UntypedHandle, error) { | 
|  | if len(e.stateStack) != 0 { | 
|  | return nil, nil, fmt.Errorf("can't return data when encoder has non-empty state stack") | 
|  | } | 
|  | return e.buf[:e.end], e.handles, nil | 
|  | } | 
|  |  | 
|  | // WriteBool writes a bool value. | 
|  | func (e *Encoder) WriteBool(value bool) error { | 
|  | if err := ensureElementBitSizeAndCapacity(e.state(), 1); err != nil { | 
|  | return err | 
|  | } | 
|  | if value { | 
|  | e.buf[e.state().offset] |= 1 << e.state().bitOffset | 
|  | } | 
|  | e.state().skipBits(1) | 
|  | e.state().elementsProcessed++ | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // WriteBool writes an int8 value. | 
|  | func (e *Encoder) WriteInt8(value int8) error { | 
|  | return e.WriteUint8(uint8(value)) | 
|  | } | 
|  |  | 
|  | // WriteUint8 writes an uint8 value. | 
|  | func (e *Encoder) WriteUint8(value uint8) error { | 
|  | if err := ensureElementBitSizeAndCapacity(e.state(), 8); err != nil { | 
|  | return err | 
|  | } | 
|  | e.state().alignOffsetToBytes() | 
|  | e.buf[e.state().offset] = value | 
|  | e.state().skipBytes(1) | 
|  | e.state().elementsProcessed++ | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // WriteInt16 writes an int16 value. | 
|  | func (e *Encoder) WriteInt16(value int16) error { | 
|  | return e.WriteUint16(uint16(value)) | 
|  | } | 
|  |  | 
|  | // WriteUint16 writes an uint16 value. | 
|  | func (e *Encoder) WriteUint16(value uint16) error { | 
|  | if err := ensureElementBitSizeAndCapacity(e.state(), 16); err != nil { | 
|  | return err | 
|  | } | 
|  | e.state().alignOffsetToBytes() | 
|  | e.state().offset = align(e.state().offset, 2) | 
|  | binary.LittleEndian.PutUint16(e.buf[e.state().offset:], value) | 
|  | e.state().skipBytes(2) | 
|  | e.state().elementsProcessed++ | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // WriteInt32 writes an int32 value. | 
|  | func (e *Encoder) WriteInt32(value int32) error { | 
|  | return e.WriteUint32(uint32(value)) | 
|  | } | 
|  |  | 
|  | // WriteUint32 writes an uint32 value. | 
|  | func (e *Encoder) WriteUint32(value uint32) error { | 
|  | if err := ensureElementBitSizeAndCapacity(e.state(), 32); err != nil { | 
|  | return err | 
|  | } | 
|  | e.state().alignOffsetToBytes() | 
|  | e.state().offset = align(e.state().offset, 4) | 
|  | binary.LittleEndian.PutUint32(e.buf[e.state().offset:], value) | 
|  | e.state().skipBytes(4) | 
|  | e.state().elementsProcessed++ | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // WriteInt64 writes an int64 value. | 
|  | func (e *Encoder) WriteInt64(value int64) error { | 
|  | return e.WriteUint64(uint64(value)) | 
|  | } | 
|  |  | 
|  | // WriteUint64 writes an uint64 value. | 
|  | func (e *Encoder) WriteUint64(value uint64) error { | 
|  | if err := ensureElementBitSizeAndCapacity(e.state(), 64); err != nil { | 
|  | return err | 
|  | } | 
|  | e.state().alignOffsetToBytes() | 
|  | e.state().offset = align(e.state().offset, 8) | 
|  | binary.LittleEndian.PutUint64(e.buf[e.state().offset:], value) | 
|  | e.state().skipBytes(8) | 
|  | e.state().elementsProcessed++ | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // WriteFloat32 writes a float32 value. | 
|  | func (e *Encoder) WriteFloat32(value float32) error { | 
|  | return e.WriteUint32(math.Float32bits(value)) | 
|  | } | 
|  |  | 
|  | // WriteFloat64 writes a float64 value. | 
|  | func (e *Encoder) WriteFloat64(value float64) error { | 
|  | return e.WriteUint64(math.Float64bits(value)) | 
|  | } | 
|  |  | 
|  | // WriteNullPointer writes a null pointer. | 
|  | func (e *Encoder) WriteNullPointer() error { | 
|  | return e.WriteUint64(0) | 
|  | } | 
|  |  | 
|  | // WriteString writes a string value. It doesn't write a pointer to the encoded | 
|  | // string. | 
|  | func (e *Encoder) WriteString(value string) error { | 
|  | bytes := []byte(value) | 
|  | e.StartArray(uint32(len(bytes)), 8) | 
|  | for _, b := range bytes { | 
|  | if err := e.WriteUint8(b); err != nil { | 
|  | return err | 
|  | } | 
|  | } | 
|  | return e.Finish() | 
|  | } | 
|  |  | 
|  | // WritePointer writes a pointer to first unclaimed byte index. | 
|  | func (e *Encoder) WritePointer() error { | 
|  | return e.WriteUint64(uint64(e.end - e.state().offset)) | 
|  | } | 
|  |  | 
|  | // WriteInvalidHandle an invalid handle. | 
|  | func (e *Encoder) WriteInvalidHandle() error { | 
|  | return e.WriteInt32(-1) | 
|  | } | 
|  |  | 
|  | // WriteHandle writes a handle and invalidates the passed handle object. | 
|  | func (e *Encoder) WriteHandle(handle system.Handle) error { | 
|  | if !handle.IsValid() { | 
|  | return fmt.Errorf("can't write an invalid handle") | 
|  | } | 
|  | UntypedHandle := handle.ToUntypedHandle() | 
|  | e.handles = append(e.handles, UntypedHandle) | 
|  | return e.WriteUint32(uint32(len(e.handles) - 1)) | 
|  | } |