blob: 9c2540b31464524bebd9a85856473477069c092a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.IO;
namespace Apache.NMS.Util
{
/// <summary>
/// A BinaryWriter that switches the endian orientation of the write operations so that they
/// are compatible across platforms.
/// </summary>
[CLSCompliant(false)]
public class EndianBinaryWriter : BinaryWriter
{
public const int MAXSTRINGLEN = short.MaxValue;
public EndianBinaryWriter(Stream output)
: base(output)
{
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="value">A long</param>
public override void Write(long value)
{
base.Write(EndianSupport.SwitchEndian(value));
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="value">An ushort</param>
public override void Write(ushort value)
{
base.Write(EndianSupport.SwitchEndian(value));
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="value">An int</param>
public override void Write(int value)
{
int x = EndianSupport.SwitchEndian(value);
base.Write(x);
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="chars">A char[]</param>
/// <param name="index">An int</param>
/// <param name="count">An int</param>
public override void Write(char[] chars, int index, int count)
{
char[] t = new char[count];
for (int i = 0; i < count; i++)
{
t[index + i] = EndianSupport.SwitchEndian(t[index + i]);
}
base.Write(t);
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="chars">A char[]</param>
public override void Write(char[] chars)
{
Write(chars, 0, chars.Length);
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="value">An uint</param>
public override void Write(uint value)
{
base.Write(EndianSupport.SwitchEndian(value));
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="ch">A char</param>
public override void Write(char ch)
{
base.Write((byte) ((ch >> 8) & 0xFF));
base.Write((byte) (ch & 0xFF));
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="value">An ulong</param>
public override void Write(ulong value)
{
base.Write(EndianSupport.SwitchEndian(value));
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="value">A short</param>
public override void Write(short value)
{
base.Write(EndianSupport.SwitchEndian(value));
}
/// <summary>
/// Method Write, writes a string to the output using the WriteString16
/// method.
/// </summary>
/// <param name="text">A string</param>
public override void Write(String text)
{
WriteString16(text);
}
/// <summary>
/// Method WriteString16, writes a string to the output using the Java
/// standard modified UTF-8 encoding with an unsigned short value written first to
/// indicate the length of the encoded data, the short is read as an unsigned
/// value so the max amount of data this method can write is 65535 encoded bytes.
///
/// Unlike the WriteString32 method this method does not encode the length
/// value to -1 if the string is null, this is to match the behaviour of
/// the Java DataOuputStream class's writeUTF method.
///
/// Because modified UTF-8 encding can result in a number of bytes greater that
/// the size of the String this method must first check that the encoding proces
/// will not result in a value that cannot be written becuase it is greater than
/// the max value of an unsigned short.
/// </summary>
/// <param name="text">A string</param>
public void WriteString16(String text)
{
if (text != null)
{
if (text.Length > ushort.MaxValue)
{
throw new IOException(
String.Format(
"Cannot marshall string longer than: {0} characters, supplied string was: " +
"{1} characters", ushort.MaxValue, text.Length));
}
char[] charr = text.ToCharArray();
uint utfLength = CountUtf8Bytes(charr);
if (utfLength > ushort.MaxValue)
{
throw new IOException(
String.Format(
"Cannot marshall an encoded string longer than: {0} bytes, supplied" +
"string requires: {1} characters to encode", ushort.MaxValue, utfLength));
}
byte[] bytearr = new byte[utfLength];
encodeUTF8toBuffer(charr, bytearr);
Write((ushort) utfLength);
Write(bytearr);
}
}
/// <summary>
/// Method WriteString32, writes a string to the output using the Openwire
/// standard modified UTF-8 encoding which an int value written first to
/// indicate the length of the encoded data, the int is read as an signed
/// value so the max amount of data this method can write is 2^31 encoded bytes.
///
/// In the case of a null value being passed this method writes a -1 to the
/// stream to indicate that the string is null.
///
/// Because modified UTF-8 encding can result in a number of bytes greater that
/// the size of the String this method must first check that the encoding proces
/// will not result in a value that cannot be written becuase it is greater than
/// the max value of an int.
/// </summary>
/// <param name="text">A string</param>
public void WriteString32(String text)
{
if (text != null)
{
char[] charr = text.ToCharArray();
uint utfLength = CountUtf8Bytes(charr);
if (utfLength > int.MaxValue)
{
throw new IOException(
String.Format(
"Cannot marshall an encoded string longer than: {0} bytes, supplied" +
"string requires: {1} characters to encode", int.MaxValue, utfLength));
}
byte[] bytearr = new byte[utfLength];
encodeUTF8toBuffer(charr, bytearr);
Write(utfLength);
Write(bytearr);
}
else
{
Write((int) -1);
}
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="value">A double</param>
public override void Write(float value)
{
base.Write(EndianSupport.SwitchEndian(value));
}
/// <summary>
/// Method Write
/// </summary>
/// <param name="value">A double</param>
public override void Write(double value)
{
base.Write(EndianSupport.SwitchEndian(value));
}
private static uint CountUtf8Bytes(char[] chars)
{
uint utfLength = 0;
int c = 0;
for (int i = 0; i < chars.Length; i++)
{
c = chars[i];
if ((c >= 0x0001) && (c <= 0x007F))
{
utfLength++;
}
else if (c > 0x07FF)
{
utfLength += 3;
}
else
{
utfLength += 2;
}
}
return utfLength;
}
private static void encodeUTF8toBuffer(char[] chars, byte[] buffer)
{
int c = 0;
int count = 0;
for (int i = 0; i < chars.Length; i++)
{
c = chars[i];
if ((c >= 0x0001) && (c <= 0x007F))
{
buffer[count++] = (byte) c;
}
else if (c > 0x07FF)
{
buffer[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
buffer[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
buffer[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
else
{
buffer[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
buffer[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
}
}
}
}