/* godotOscSharp Copyright (C) 2023 Cassandra de la Cruz-Munoz This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ using System; #nullable enable namespace godotOscSharp { // A class that represents a DWord public class OscArgument { // The value of the DWord as an unsigned integer public char Type { get; } private object? Value { get; } public static OscArgument CreateFromParams(object? value, char type) { switch (type) { case 'i': case 'f': case 's': case 'h': case 'd': return new OscArgument(value, type); case 'T': return new OscArgument(true, type); case 'F': return new OscArgument(false, type); case 'N': return new OscArgument(null, type); default: throw new ArgumentException($"Invalid argument type: {type}"); } } // The constructor that takes an unsigned integer as the value private OscArgument(object? value, char type) { Value = value; Type = type; } // A method that parses a byte array to a DWord public static OscArgument Parse(byte[] data, ref int index, char type) { // Use BitConverter to get the unsigned integer from the bytes at the given index in little-endian order object? value = null; var start = index; switch (type) { case 'i': value = BitConverter.ToInt32(data, index); index += 4; break; case 'f': value = BitConverter.ToSingle(data, index); index += 4; break; case 's': while (data[index] != 0) // Find the null terminator { index++; } value = System.Text.Encoding.ASCII.GetString(data, start, index - start); while (data[index] == 0 && index < data.Length) { index++; } break; case 'h': value = BitConverter.ToInt64(data, index); index += 8; break; case 'd': value = BitConverter.ToDouble(data, index); index += 8; break; case 'T': value = true; break; case 'F': value = false; break; case 'N': value = null; break; } return new OscArgument(value, type); } public Int32 GetAsInt32() { if (Type != 'i') { throw new InvalidDataTypeException('i', Type); } return (Int32)Value!; } public float GetAsFloat() { if (Type != 'f') { throw new InvalidDataTypeException('f', Type); } return (float)Value!; } public String GetAsString() { if (Type != 's') { throw new InvalidDataTypeException('s', Type); } return (String)Value!; } public Int64 GetAsInt64() { if (Type != 'h') { throw new InvalidDataTypeException('h', Type); } return (Int64)Value!; } public Double GetAsDouble() { if (Type != 'd') { throw new InvalidDataTypeException('d', Type); } return (Double)Value!; } public bool GetAsBool() { switch (Type) { case 'T': return true; case 'F': return false; default: throw new InvalidDataTypeException("{T, F}", Type); } } public object? GetAsNull() { if (Type != 'N') { throw new InvalidDataTypeException('N', Type); } return null; } public byte[] ToBytes() { switch (Type) { case 'i': return BitConverter.GetBytes((int)Value!); case 'f': return BitConverter.GetBytes((float)Value!); case 's': var result = new System.Collections.Generic.List(); result.AddRange(System.Text.Encoding.ASCII.GetBytes((string)Value!)); result.Add(0); var padding = 4 - (result.Count % 4); for (int i = 0; i < padding; i++) { result.Add(0); } return result.ToArray(); case 'h': return BitConverter.GetBytes((long)Value!); case 'd': return BitConverter.GetBytes((double)Value!); } return new byte[0]; } public override string ToString() { return Value?.ToString()!; } } }