diff options
author | Daniel Friesel <derf@finalrewind.org> | 2021-12-25 18:07:25 +0100 |
---|---|---|
committer | Daniel Friesel <derf@finalrewind.org> | 2021-12-25 18:08:53 +0100 |
commit | 16b712e0233cfd7b60668927067885f7e3551b92 (patch) | |
tree | eccf0a9c9d3afd65864fee799265eb1f88384b0d /src/object | |
parent | d23e540ea2868cf9a511dad8eba105496542140e (diff) |
rename os/object to object
Diffstat (limited to 'src/object')
-rw-r--r-- | src/object/cpp_helpers.cc | 9 | ||||
-rw-r--r-- | src/object/framebuffer.cc | 151 | ||||
-rw-r--r-- | src/object/outputstream.cc | 247 | ||||
-rw-r--r-- | src/object/xdr16input.cc | 104 | ||||
-rw-r--r-- | src/object/xdr16stream.cc | 164 | ||||
-rw-r--r-- | src/object/xdrinput.cc | 94 | ||||
-rw-r--r-- | src/object/xdrstream.cc | 166 |
7 files changed, 935 insertions, 0 deletions
diff --git a/src/object/cpp_helpers.cc b/src/object/cpp_helpers.cc new file mode 100644 index 0000000..59e1e97 --- /dev/null +++ b/src/object/cpp_helpers.cc @@ -0,0 +1,9 @@ +/* + * Copyright 2020 Daniel Friesel + * + * SPDX-License-Identifier: BSD-2-Clause + */ +extern "C" void __cxa_pure_virtual() +{ + //while (1); +} diff --git a/src/object/framebuffer.cc b/src/object/framebuffer.cc new file mode 100644 index 0000000..e7b914d --- /dev/null +++ b/src/object/framebuffer.cc @@ -0,0 +1,151 @@ +#include "object/framebuffer.h" + +#ifdef MULTIPASS_ARCH_arduino_nano +#include <avr/pgmspace.h> +#endif + +#ifdef CONFIG_framebuffer_in_text_segment +__attribute__ ((section(".text"))) +#endif +static unsigned char framebuffer[(unsigned long int)CONFIG_framebuffer_width * (unsigned long int)CONFIG_framebuffer_height / 8]; + +void Framebuffer::clear() +{ + for (unsigned int i = 0; i < width * (height / 8); i++) { + data[i] = 0; + } +} + +void Framebuffer::fillBox(unsigned int x, unsigned int y, unsigned int w, unsigned int h) +{ + if (w == 0 || h == 0) { + return; + } + w -= 1; + h -= 1; + if ((x+w) >= width || (y+h) >= height) { + return; + } + + unsigned int x1 = (height/8)*x; + unsigned int x2 = (height/8)*(x+w); + unsigned int y2 = height-1-y; + unsigned int y1 = y2-h; + unsigned char y2_mask = 0xff << (8 - (y2 % 8)); // bits from 0 to y2%8 must be filled + unsigned char y1_mask = 0xff >> (y1 % 8); // bits from y1%8 to 7 must be filled + y1 = y1/8; + y2 = y2/8; + + if (y1 == y2) { + // y1_mask and y2_mask overlap + for (unsigned int pos_x = x1; pos_x < x2; pos_x += height/8) { + data[pos_x + y1] |= y1_mask & y2_mask; + } + } else { + if (y1_mask != 0xff) { + for (unsigned int pos_x = x1; pos_x < x2; pos_x += height/8) { + data[pos_x + y1] |= y1_mask; + } + y1++; + } + for (unsigned int pos_x = x1; pos_x < x2; pos_x += height/8) { + for (unsigned int pos_y = y1; pos_y < y2; pos_y++) { + data[pos_x + pos_y] = 0xff; + } + } + if (y2_mask) { + for (unsigned int pos_x = x1; pos_x < x2; pos_x += height/8) { + data[pos_x + y2] |= y2_mask; + } + } + } +} + +void Framebuffer::drawAt(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned char *image) +{ + y /= 8; + for (unsigned int pos_x = 0; pos_x < w; pos_x++) { + for (unsigned int pos_y = 0; pos_y < h/8; pos_y++) { + data[(x + pos_x) * (height/8) + y + pos_y] = image[pos_x * (h/8) + pos_y]; + } + } +} + +void Framebuffer::drawBattery(unsigned int x, unsigned int y, unsigned char percent, bool charging) +{ + for (unsigned char i = 0; i < 13; i++) { + data[(x+i) * (height/8) + y] = 0x81 | (0xff * (percent*2 >= i*15)); + } + data[(x+11) * (height/8) + y/8] |= 0xe7; + data[(x+12) * (height/8) + y/8] &= ~0x81; + data[(x+12) * (height/8) + y/8] |= 0x24; + data[(x+13) * (height/8) + y/8] = 0x3c; + + if (charging) { + data[(x+2) * (height/8) + y/8] ^= 0x7e; + data[(x+3) * (height/8) + y/8] ^= 0x3c; + data[(x+4) * (height/8) + y/8] ^= 0x18; + data[(x+7) * (height/8) + y/8] ^= 0x7e; + data[(x+8) * (height/8) + y/8] ^= 0x3c; + data[(x+9) * (height/8) + y/8] ^= 0x18; + } +} + +void Framebuffer::scroll() +{ + for (unsigned int pos_x = 0; pos_x < width; pos_x++) { + for (unsigned int pos_y = fontSize; pos_y < height/8; pos_y++) { + data[pos_x * (height/8) + pos_y - fontSize] = data[pos_x * (height/8) + pos_y]; + } + for (unsigned int pos_y = 1; pos_y <= fontSize; pos_y++) { + data[pos_x * (height/8) + height/8 - pos_y] = 0; + } + } + if (fontY >= 8*fontSize) { + fontY -= 8*fontSize; + } +} + +void Framebuffer::put(char c) +{ + if (font == 0) { + return; + } + if (c == '\n') { + fontX = 0; + fontY += 8*fontSize; + return; + } + if ((c < 32) || (c > 126)) { + c = '?'; + } +#ifdef MULTIPASS_ARCH_arduino_nano + uint8_t *glyph_addr = (uint8_t *)pgm_read_ptr(&font[c - 32]); + const unsigned char glyph_w = pgm_read_byte(&glyph_addr[0]); +#else + glyph_t glyph = font[c - 32]; + const unsigned char glyph_w = glyph[0]; +#endif + + if (fontX + glyph_w + 1 >= width) { + put('\n'); + } + if (fontY + 8*fontSize > height) { + scroll(); + } + for (unsigned char i = 0; i < glyph_w; i++) { + unsigned char x = i / fontSize; + unsigned char y = i % fontSize; +#ifdef MULTIPASS_ARCH_arduino_nano + data[(height/8) * (fontX + x) + fontY/8 + y] = pgm_read_byte(&glyph_addr[i+1]); +#else + data[(height/8) * (fontX + x) + fontY/8 + y] = glyph[i+1]; +#endif + } + for (unsigned char i = 0; i < fontSize; i++) { + data[(height/8) * (fontX + glyph_w + 1) + fontY/8] = 0; + } + fontX += (glyph_w / fontSize) + 2; +} + +Framebuffer fb(framebuffer); diff --git a/src/object/outputstream.cc b/src/object/outputstream.cc new file mode 100644 index 0000000..3960a3e --- /dev/null +++ b/src/object/outputstream.cc @@ -0,0 +1,247 @@ +/* + * Copyright 2020 Daniel Friesel + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include "object/outputstream.h" + +OutputStream & OutputStream::operator<<(unsigned char c) +{ + *this << (unsigned long long)c; + return *this; +} + +OutputStream & OutputStream::operator<<(char c) +{ + put(c); + return *this; +} + +OutputStream & OutputStream::operator<<(unsigned short number) +{ + *this << (unsigned long long)number; + return *this; +} + +OutputStream & OutputStream::operator<<(short number) +{ + *this << (long long)number; + return *this; +} + +OutputStream & OutputStream::operator<<(unsigned int number) +{ + *this << (unsigned long long)number; + return *this; +} + +OutputStream & OutputStream::operator<<(int number) +{ + *this << (long long)number; + return *this; +} + +OutputStream & OutputStream::operator<<(unsigned long number) +{ + *this << (unsigned long long)number; + return *this; +} + +OutputStream & OutputStream::operator<<(long number) +{ + *this << (long long)number; + return *this; +} + +OutputStream & OutputStream::operator<<(unsigned long long number) +{ + switch (base) { + case 2: + put('0'); + put('b'); + break; + case 8: + put('0'); + break; + case 16: + if (number < 16) { + put('0'); + } + break; + } + + if (number == 0) { + put('0'); + return *this; + } + + signed int i = 0; + while (number > 0) { + if (base == 16 && number % base > 9) { + digit_buffer[i] = 'a' + (number % base) - 10; + } else { + digit_buffer[i] = '0' + (number % base); + } + number /= base; + i++; + } + i--; + for (; i >= 0; i--) { + put(digit_buffer[i]); + } + return *this; + +} + +OutputStream & OutputStream::operator<<(long long number) +{ + if (number < 0) { + put('-'); + number *= -1; + } + *this << (unsigned long long)number; + + return *this; +} + +OutputStream & OutputStream::operator<<(double number) +{ + *this << (float)number; + return *this; +} + +OutputStream & OutputStream::operator<<(float number) +{ + printf_float(number); + return *this; +} + +OutputStream & OutputStream::operator<<(void *pointer) +{ + unsigned char temp_base = base; + *this << hex << (long)pointer; + switch (temp_base) { + case 2: + *this << bin; break; + case 8: + *this << oct; break; + case 10: + *this << dec; break; + } + return *this; +} + +OutputStream & OutputStream::operator<<(const char *text) +{ + int i = 0; + while (text[i] != '\0') { + put(text[i++]); + } + return *this; +} + +OutputStream & OutputStream::operator<<(OutputStream & (*fkt) (OutputStream &)) +{ + return fkt(*this); +} + +#ifdef CONFIG_ostream +OutputStream & OutputStream::operator<<(std::string s) +{ + for (auto c : s) { + put(c); + } + return *this; +} +#endif + +void OutputStream::setBase(uint8_t b) +{ + if (b == 2 || b == 8 || b == 10 || b == 16) { + base = b; + } +} + +static inline char format_hex_nibble(uint8_t num) +{ + if (num > 9) { + return 'a' + num - 10; + } + return '0' + num; +} + +void OutputStream::printf_uint8(uint8_t num) +{ + put(format_hex_nibble(num / 16)); + put(format_hex_nibble(num % 16)); +} + +void OutputStream::printf_float(float num) +{ + if (num < 0) { + put('-'); + num *= -1; + } + if (num > 1000) { + put('0' + (((unsigned int)num % 10000) / 1000)); + } + if (num > 100) { + put('0' + (((unsigned int)num % 1000) / 100)); + } + if (num > 10) { + put('0' + (((unsigned int)num % 100) / 10)); + } + put('0' + ((unsigned int)num % 10)); + put('.'); + put('0' + ((unsigned int)(num * 10) % 10)); + put('0' + ((unsigned int)(num * 100) % 10)); +} + +OutputStream & flush(OutputStream & os) +{ + os.flush(); + return os; +} + +OutputStream & endl(OutputStream & os) +{ + os.put('\n'); + os.flush(); + return os; +} + +OutputStream & bin(OutputStream & os) +{ + os.setBase(2); + return os; +} + +OutputStream & oct(OutputStream & os) +{ + os.setBase(8); + return os; +} + +OutputStream & dec(OutputStream & os) +{ + os.setBase(10); + return os; +} + +OutputStream & hex(OutputStream & os) +{ + os.setBase(16); + return os; +} + +OutputStream & term(OutputStream & os) +{ + os.put('\0'); + os.flush(); + return os; +} + +OutputStream::OutputStream() +{ + base = 10; +} diff --git a/src/object/xdr16input.cc b/src/object/xdr16input.cc new file mode 100644 index 0000000..2247c29 --- /dev/null +++ b/src/object/xdr16input.cc @@ -0,0 +1,104 @@ +/* + * Copyright 2020 Daniel Friesel + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include "object/xdr16input.h" + +uint16_t XDRInput::get_uint16() +{ + uint32_t ret = ((uint8_t)data[pos]<<8) | (uint8_t)data[pos+1]; + pos += 2; + return ret; +} + +int16_t XDRInput::get_int16() +{ + int32_t ret = (data[pos]<<8) | data[pos+1]; + pos += 2; + return ret; +} + +uint32_t XDRInput::get_uint32() +{ + uint32_t ret = ((uint8_t)data[pos]<<24) | ((uint8_t)data[pos+1]<<16) + | ((uint8_t)data[pos+2]<<8) | (uint8_t)data[pos+3]; + pos += 4; + return ret; +} + +int32_t XDRInput::get_int32() +{ + int32_t ret = (data[pos]<<24) | (data[pos+1]<<16) | (data[pos+2]<<8) | data[pos+3]; + pos += 4; + return ret; +} + +uint64_t XDRInput::get_uint64() +{ + uint64_t ret0 = ((uint8_t)data[pos]<<24) | ((uint8_t)data[pos+1]<<16) + | ((uint8_t)data[pos+2]<<8) | (uint8_t)data[pos+3]; + pos += 4; + uint64_t ret1 = ((uint8_t)data[pos]<<24) | ((uint8_t)data[pos+1]<<16) + | ((uint8_t)data[pos+2]<<8) | (uint8_t)data[pos+3]; + pos += 4; + return (ret0 << 32) | ret1; +} + +int64_t XDRInput::get_int64() +{ + int64_t ret0 = (data[pos]<<24) | (data[pos+1]<<16) | (data[pos+2]<<8) | data[pos+3]; + pos += 4; + int64_t ret1 = (data[pos]<<24) | (data[pos+1]<<16) | (data[pos+2]<<8) | data[pos+3]; + pos += 4; + return (ret0 << 32) | ret1; +} + +float XDRInput::get_float() +{ + union { + uint32_t i; + float f; + } v; + v.i = get_uint32(); + return v.f; +} + +double XDRInput::get_double() +{ + union { + uint64_t i; + double d; + } v; + v.i = get_uint64(); + return v.d; +} + +uint16_t XDRInput::get_opaque_length() +{ + return get_uint16(); +} + +char *XDRInput::get_opaque(uint16_t length) +{ + char *ret = data + pos; + pos += length; + if (length % 2) { + pos += 2 - (length % 2); + } + return ret; +} + +void XDRInput::get_string(char* target) +{ + uint16_t length = get_opaque_length(); + uint16_t i; + for (i = 0; i < length; i++) { + target[i] = data[pos + i]; + } + target[i] = 0; + pos += length; + if (length % 2) { + pos += 2 - (length % 2); + } +} diff --git a/src/object/xdr16stream.cc b/src/object/xdr16stream.cc new file mode 100644 index 0000000..7f2a414 --- /dev/null +++ b/src/object/xdr16stream.cc @@ -0,0 +1,164 @@ +/* + * Copyright 2020 Daniel Friesel + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include "object/xdr16stream.h" + +XDRStream & XDRStream::operator<<(unsigned char c) +{ + *this << (uint16_t)c; + return *this; +} + +XDRStream & XDRStream::operator<<(char c) +{ + *this << (int16_t)c; + return *this; +} + +XDRStream & XDRStream::operator<<(uint16_t number) +{ + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(int16_t number) +{ + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(uint32_t number) +{ + put((number >> 24) & 0xffU); + put((number >> 16) & 0xffU); + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(int32_t number) +{ + put((number >> 24) & 0xffU); + put((number >> 16) & 0xffU); + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(uint64_t number) +{ + put((number >> 56) & 0xffU); + put((number >> 48) & 0xffU); + put((number >> 40) & 0xffU); + put((number >> 32) & 0xffU); + put((number >> 24) & 0xffU); + put((number >> 16) & 0xffU); + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(int64_t number) +{ + put((number >> 56) & 0xffU); + put((number >> 48) & 0xffU); + put((number >> 40) & 0xffU); + put((number >> 32) & 0xffU); + put((number >> 24) & 0xffU); + put((number >> 16) & 0xffU); + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(float number) +{ + union { + uint32_t i; + float f; + } v; + v.f = number; + *this << v.i; + return *this; +} + +XDRStream & XDRStream::operator<<(double number) +{ + union { + uint64_t i; + double d; + } v; + v.d = number; + *this << v.i; + return *this; +} + +XDRStream & XDRStream::operator<<(char const *data){ + if (!is_fixed_length) { + *this << next_array_len; + } + uint32_t i; + for (i = 0; i < next_array_len; i++) { + put(data[i]); + } + while ((i++) % 2 != 0){ + put('\0'); + } + return *this; +} + +template<uint16_t TSize> +XDRStream & XDRStream::operator<<(char const (&data)[TSize]){ + if (!is_fixed_length) { + *this << TSize; + } + uint32_t i; + for (i = 0; i < TSize; i++) { + put(data[i]); + } + while ((i++) % 2 != 0){ + put('\0'); + } + return *this; +} + +XDRStream & XDRStream::operator<<(XDRStream & (*fkt) (XDRStream &)) +{ + return fkt(*this); +} + +XDRStream & flush(XDRStream & os) +{ + os.flush(); + return os; +} + +XDRStream & term(XDRStream & os) +{ + os.put('\0'); + os.flush(); + return os; +} + +template<int N> +XDRStream & opaque(XDRStream & os) +{ + os.setNextArrayLen(N); + return os; +} + +XDRStream & fixed(XDRStream & os) +{ + os.setFixedLength(); + return os; +} + +XDRStream & variable(XDRStream & os) +{ + os.setVariableLength(); + return os; +} diff --git a/src/object/xdrinput.cc b/src/object/xdrinput.cc new file mode 100644 index 0000000..c98c110 --- /dev/null +++ b/src/object/xdrinput.cc @@ -0,0 +1,94 @@ +/* + * Copyright 2020 Daniel Friesel + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include "object/xdrinput.h" + +uint32_t XDRInput::get_uint32() +{ + uint32_t ret = ((uint8_t)data[pos]<<24) | ((uint8_t)data[pos+1]<<16) + | ((uint8_t)data[pos+2]<<8) | (uint8_t)data[pos+3]; + pos += 4; + return ret; +} + +int32_t XDRInput::get_int32() +{ + int32_t ret = (data[pos]<<24) | (data[pos+1]<<16) | (data[pos+2]<<8) | data[pos+3]; + pos += 4; + return ret; +} + +uint64_t XDRInput::get_uint64() +{ + uint64_t ret0 = ((uint8_t)data[pos]<<24) | ((uint8_t)data[pos+1]<<16) + | ((uint8_t)data[pos+2]<<8) | (uint8_t)data[pos+3]; + pos += 4; + uint64_t ret1 = ((uint8_t)data[pos]<<24) | ((uint8_t)data[pos+1]<<16) + | ((uint8_t)data[pos+2]<<8) | (uint8_t)data[pos+3]; + pos += 4; + return (ret0 << 32) | ret1; +} + +int64_t XDRInput::get_int64() +{ + int64_t ret0 = (data[pos]<<24) | (data[pos+1]<<16) | (data[pos+2]<<8) | data[pos+3]; + pos += 4; + int64_t ret1 = (data[pos]<<24) | (data[pos+1]<<16) | (data[pos+2]<<8) | data[pos+3]; + pos += 4; + return (ret0 << 32) | ret1; +} + +float XDRInput::get_float() +{ + union { + uint32_t i; + float f; + } v; + // Setting one member of a union and then reading another is undefined + // behaviour, but works as intended in nearly any (embedded) compiler + v.i = get_uint32(); + return v.f; +} + +double XDRInput::get_double() +{ + union { + uint64_t i; + double d; + } v; + // Setting one member of a union and then reading another is undefined + // behaviour, but works as intended in nearly any (embedded) compiler + v.i = get_uint64(); + return v.d; +} + +uint32_t XDRInput::get_opaque_length() +{ + return get_uint32(); +} + +char *XDRInput::get_opaque(uint32_t length) +{ + char *ret = data + pos; + pos += length; + if (length % 4) { + pos += 4 - (length % 4); + } + return ret; +} + +void XDRInput::get_string(char* target) +{ + uint16_t length = get_opaque_length(); + uint16_t i; + for (i = 0; i < length; i++) { + target[i] = data[pos + i]; + } + target[i] = 0; + pos += length; + if (length % 4) { + pos += 4 - (length % 4); + } +} diff --git a/src/object/xdrstream.cc b/src/object/xdrstream.cc new file mode 100644 index 0000000..9dc5a1b --- /dev/null +++ b/src/object/xdrstream.cc @@ -0,0 +1,166 @@ +/* + * Copyright 2020 Daniel Friesel + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include "object/xdrstream.h" + +XDRStream & XDRStream::operator<<(unsigned char c) +{ + *this << (uint32_t)c; + return *this; +} + +XDRStream & XDRStream::operator<<(char c) +{ + *this << (int32_t)c; + return *this; +} + +XDRStream & XDRStream::operator<<(uint16_t number) +{ + *this << (uint32_t)number; + return *this; +} + +XDRStream & XDRStream::operator<<(int16_t number) +{ + *this << (int32_t)number; + return *this; +} + +XDRStream & XDRStream::operator<<(uint32_t number) +{ + put((number >> 24) & 0xffU); + put((number >> 16) & 0xffU); + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(int32_t number) +{ + put((number >> 24) & 0xffU); + put((number >> 16) & 0xffU); + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(uint64_t number) +{ + put((number >> 56) & 0xffU); + put((number >> 48) & 0xffU); + put((number >> 40) & 0xffU); + put((number >> 32) & 0xffU); + put((number >> 24) & 0xffU); + put((number >> 16) & 0xffU); + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(int64_t number) +{ + put((number >> 56) & 0xffU); + put((number >> 48) & 0xffU); + put((number >> 40) & 0xffU); + put((number >> 32) & 0xffU); + put((number >> 24) & 0xffU); + put((number >> 16) & 0xffU); + put((number >> 8) & 0xffU); + put(number & 0xffU); + return *this; +} + +XDRStream & XDRStream::operator<<(float number) +{ + union { + uint32_t i; + float f; + } v; + // Setting one member of a struct and then reading another is undefined + // behaviour, but works as intended in nearly any (embedded) compiler + v.f = number; + *this << v.i; + return *this; +} + +XDRStream & XDRStream::operator<<(double number) +{ + union { + uint64_t i; + double d; + } v; + // Setting one member of a union and then reading another is undefined + // behaviour, but works as intended in nearly any (embedded) compiler + v.d = number; + *this << v.i; + return *this; +} + +XDRStream & XDRStream::operator<<(char const *data){ + if (!is_fixed_length) { + *this << next_array_len; + } + uint32_t i; + for (i = 0; i < next_array_len; i++) { + put(data[i]); + } + while ((i++) % 4 != 0){ + put('\0'); + } + return *this; +} + +template<uint32_t TSize> +XDRStream & XDRStream::operator<<(char const (&data)[TSize]){ + if (!is_fixed_length) { + *this << TSize; + } + uint32_t i; + for (i = 0; i < TSize; i++) { + put(data[i]); + } + while ((i++) % 4 != 0){ + put('\0'); + } + return *this; +} + +XDRStream & XDRStream::operator<<(XDRStream & (*fkt) (XDRStream &)) +{ + return fkt(*this); +} + +XDRStream & flush(XDRStream & os) +{ + os.flush(); + return os; +} + +XDRStream & term(XDRStream & os) +{ + os.put('\0'); + os.flush(); + return os; +} + +template<int N> +XDRStream & opaque(XDRStream & os) +{ + os.setNextArrayLen(N); + return os; +} + +XDRStream & fixed(XDRStream & os) +{ + os.setFixedLength(); + return os; +} + +XDRStream & variable(XDRStream & os) +{ + os.setVariableLength(); + return os; +} |