#region licence/info // OSC.NET - Open Sound Control for .NET // http://luvtechno.net/ // // Copyright (c) 2006, Yoshinori Kawasaki // All rights reserved. // // Changes and improvements: // Copyright (c) 2006-2014 Martin Kaltenbrunner // As included with http://reactivision.sourceforge.net/ // // Further implementations and specifications: // Copyright (c) 2013 Marko Ritter // As included with https://github.com/vvvv/vvvv-sdk/// // // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. // * Neither the name of "luvtechno.net" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY // WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion licence/info using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using System.Drawing; namespace OSC.NET { /// /// OSCPacket /// abstract public class OSCPacket { public static readonly Encoding ASCIIEncoding8Bit; public bool ExtendedVVVVMode { get; set; } static OSCPacket() { ASCIIEncoding8Bit = Encoding.ASCII;//Encoding.GetEncoding(1252); } public OSCPacket(bool extendedMode = false) { this.ExtendedVVVVMode = extendedMode; this.values = new ArrayList(); } protected static void addBytes(ArrayList data, byte[] bytes) { foreach(byte b in bytes) { data.Add(b); } } protected static void padNull(ArrayList data) { byte zero = 0; int pad = 4 - (data.Count % 4); for (int i = 0; i < pad; i++) { data.Add(zero); } } internal static byte[] swapEndian(byte[] data) { byte[] swapped = new byte[data.Length]; for(int i = data.Length - 1, j = 0 ; i >= 0 ; i--, j++) { swapped[j] = data[i]; } return swapped; } protected static byte[] packInt(int value) { byte[] data = BitConverter.GetBytes(value); if(BitConverter.IsLittleEndian) data = swapEndian(data); return data; } protected static byte[] packLong(long value) { byte[] data = BitConverter.GetBytes(value); if(BitConverter.IsLittleEndian) data = swapEndian(data); return data; } protected static byte[] packFloat(float value) { byte[] data = BitConverter.GetBytes(value); if(BitConverter.IsLittleEndian) data = swapEndian(data); return data; } protected static byte[] packDouble(double value) { byte[] data = BitConverter.GetBytes(value); if(BitConverter.IsLittleEndian) data = swapEndian(data); return data; } protected static byte[] packString(string value) { return ASCIIEncoding8Bit.GetBytes(value); } protected static byte[] packChar(char value) { byte[] data = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) data = swapEndian(data); return data; } private static void Copy(Stream src, Stream dst, int bufferSize = 81920) { byte[] array = new byte[bufferSize]; int count; while ((count = src.Read(array, 0, array.Length)) != 0) { dst.Write(array, 0, count); } } protected static byte[] packBlob(Stream value) { var mem = new MemoryStream(); value.Seek(0, SeekOrigin.Begin); //value.CopyTo(mem); Copy(value, mem); byte[] valueData = mem.ToArray(); var lData = new ArrayList(); var length = packInt(valueData.Length); lData.AddRange(length); lData.AddRange(valueData); return (byte[])lData.ToArray(typeof(byte)); } protected static byte[] packTimeTag(DateTime value) { var tag = new OscTimeTag(); tag.Set(value); return tag.ToByteArray(); ; } protected static byte[] packColor(Color col) { byte[] data = {col.R, col.G, col.B, col.A}; if (BitConverter.IsLittleEndian) data = swapEndian(data); return data; } abstract protected void pack(); protected byte[] binaryData; public byte[] BinaryData { get { pack(); return binaryData; } } protected static int unpackInt(byte[] bytes, ref int start) { byte[] data = new byte[4]; for(int i = 0 ; i < 4 ; i++, start++) data[i] = bytes[start]; if(BitConverter.IsLittleEndian) data = swapEndian(data); return BitConverter.ToInt32(data, 0); } protected static long unpackLong(byte[] bytes, ref int start) { byte[] data = new byte[8]; for(int i = 0 ; i < 8 ; i++, start++) data[i] = bytes[start]; if(BitConverter.IsLittleEndian) data = swapEndian(data); return BitConverter.ToInt64(data, 0); } protected static float unpackFloat(byte[] bytes, ref int start) { byte[] data = new byte[4]; for(int i = 0 ; i < 4 ; i++, start++) data[i] = bytes[start]; if(BitConverter.IsLittleEndian) data = swapEndian(data); return BitConverter.ToSingle(data, 0); } protected static double unpackDouble(byte[] bytes, ref int start) { byte[] data = new byte[8]; for(int i = 0 ; i < 8 ; i++, start++) data[i] = bytes[start]; if(BitConverter.IsLittleEndian) data = swapEndian(data); return BitConverter.ToDouble(data, 0); } protected static string unpackString(byte[] bytes, ref int start) { int count= 0; for(int index = start ; bytes[index] != 0 ; index++, count++) ; string s = ASCIIEncoding8Bit.GetString(bytes, start, count); start += count+1; start = (start + 3) / 4 * 4; return s; } protected static char unpackChar(byte[] bytes, ref int start) { byte[] data = {bytes[start]}; return BitConverter.ToChar(data, 0); } protected static Stream unpackBlob(byte[] bytes, ref int start) { int length = unpackInt(bytes, ref start); byte[] buffer = new byte[length]; Array.Copy(bytes, start, buffer, 0, length); start += length; start = (start + 3) / 4 * 4; return new MemoryStream(buffer); } protected static Color unpackColor(byte[] bytes, ref int start) { byte[] data = new byte[4]; for (int i = 0; i < 4; i++, start++) data[i] = bytes[start]; if (BitConverter.IsLittleEndian) data = swapEndian(data); return Color.FromArgb (data[3],data[0],data[1],data[2]); } protected static DateTime unpackTimeTag(byte[] bytes, ref int start) { byte[] data = new byte[8]; for (int i = 0; i < 8; i++, start++) data[i] = bytes[start]; var tag = new OscTimeTag(data); return tag.DateTime; } public static OSCPacket Unpack(byte[] bytes, bool extendedMode = false) { int start = 0; return Unpack(bytes, ref start, bytes.Length, extendedMode); } public static OSCPacket Unpack(byte[] bytes, ref int start, int end, bool extendedMode = false) { if(bytes[start] == '#') return OSCBundle.Unpack(bytes, ref start, end, extendedMode); else return OSCMessage.Unpack(bytes, ref start, extendedMode); } protected string address; public string Address { get { return address; } set { // TODO: validate address = value; } } protected ArrayList values; public ArrayList Values { get { return (ArrayList)values.Clone(); } } abstract public void Append(object value); abstract public bool IsBundle(); } }