blob: ce0d94dc4d3cf4cd6082a84708f16110b078337d [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data';
import 'package:zircon/zircon.dart';
import 'error.dart';
import 'message.dart';
// ignore_for_file: always_specify_types
// ignore_for_file: avoid_positional_boolean_parameters
// ignore_for_file: public_member_api_docs
const int _kAlignment = 8;
const int _kAlignmentMask = 0x7;
int _align(int size) =>
size + ((_kAlignment - (size & _kAlignmentMask)) & _kAlignmentMask);
void _throwIfNegative(int value) {
if (value < 0) {
throw new FidlError(
'Cannot encode a negative value for an unsigned type: $value');
}
}
const int _kInitialBufferSize = 1024;
class Encoder {
Message get message {
final ByteData trimmed = new ByteData.view(data.buffer, 0, _extent);
return new Message(trimmed, _handles, _extent, _handles.length);
}
ByteData data = new ByteData(_kInitialBufferSize);
final List<Handle> _handles = <Handle>[];
int _extent = 0;
void _grow(int newSize) {
final Uint8List newList = new Uint8List(newSize)
..setRange(0, data.lengthInBytes, data.buffer.asUint8List());
data = newList.buffer.asByteData();
}
void _claimMemory(int claimSize) {
_extent += claimSize;
if (_extent > data.lengthInBytes) {
int newSize = data.lengthInBytes + claimSize;
newSize += newSize >> 1;
_grow(newSize);
}
}
int alloc(int size) {
int offset = _extent;
_claimMemory(_align(size));
return offset;
}
int nextOffset() {
return _extent;
}
int countHandles() {
return _handles.length;
}
void addHandle(Handle value) {
_handles.add(value);
}
void encodeMessageHeader(int ordinal, int txid) {
alloc(kMessageHeaderSize);
encodeUint32(ordinal, kMessageOrdinalOffset);
encodeUint32(txid, kMessageTxidOffset);
}
void encodeBool(bool value, int offset) {
data.setInt8(offset, value ? 1 : 0);
}
void encodeInt8(int value, int offset) {
data.setInt8(offset, value);
}
void encodeUint8(int value, int offset) {
_throwIfNegative(value);
data.setUint8(offset, value);
}
void encodeInt16(int value, int offset) {
data.setInt16(offset, value, Endian.little);
}
void encodeUint16(int value, int offset) {
_throwIfNegative(value);
data.setUint16(offset, value, Endian.little);
}
void encodeInt32(int value, int offset) {
data.setInt32(offset, value, Endian.little);
}
void encodeUint32(int value, int offset) {
_throwIfNegative(value);
data.setUint32(offset, value, Endian.little);
}
void encodeInt64(int value, int offset) {
data.setInt64(offset, value, Endian.little);
}
void encodeUint64(int value, int offset) {
data.setUint64(offset, value, Endian.little);
}
void encodeFloat32(double value, int offset) {
data.setFloat32(offset, value, Endian.little);
}
void encodeFloat64(double value, int offset) {
data.setFloat64(offset, value, Endian.little);
}
}
class Decoder {
Decoder(Message message)
: _message = message,
data = message.data;
Message _message;
ByteData data;
int _nextOffset = 0;
int _nextHandle = 0;
int nextOffset() {
return _nextOffset;
}
int claimMemory(int size) {
final int result = _nextOffset;
_nextOffset += _align(size);
if (_nextOffset > _message.dataLength) {
throw new FidlError('Cannot access out of range memory');
}
return result;
}
int countClaimedHandles() {
return _nextHandle;
}
Handle claimHandle() {
if (_nextHandle >= _message.handlesLength) {
throw new FidlError('Cannot access out of range handle');
}
return _message.handles[_nextHandle++];
}
bool decodeBool(int offset) => data.getInt8(offset) != 0;
int decodeInt8(int offset) => data.getInt8(offset);
int decodeUint8(int offset) => data.getUint8(offset);
int decodeInt16(int offset) => data.getInt16(offset, Endian.little);
int decodeUint16(int offset) => data.getUint16(offset, Endian.little);
int decodeInt32(int offset) => data.getInt32(offset, Endian.little);
int decodeUint32(int offset) => data.getUint32(offset, Endian.little);
int decodeInt64(int offset) => data.getInt64(offset, Endian.little);
int decodeUint64(int offset) => data.getUint64(offset, Endian.little);
double decodeFloat32(int offset) => data.getFloat32(offset, Endian.little);
double decodeFloat64(int offset) => data.getFloat64(offset, Endian.little);
}