// TODO: Decode native nvlist static bool DecodeNvList(byte[] nvlist, out Dictionary <string, NVS_Item> decodedNvList, bool xdr, bool littleEndian) { decodedNvList = new Dictionary <string, NVS_Item>(); if (nvlist == null || nvlist.Length < 16) { return(false); } if (!xdr) { return(false); } int offset = 8; while (offset < nvlist.Length) { NVS_Item item = new NVS_Item(); int currOff = offset; item.encodedSize = BigEndianBitConverter.ToUInt32(nvlist, offset); // Finished if (item.encodedSize == 0) { break; } offset += 4; item.decodedSize = BigEndianBitConverter.ToUInt32(nvlist, offset); offset += 4; uint nameLength = BigEndianBitConverter.ToUInt32(nvlist, offset); offset += 4; if (nameLength % 4 > 0) { nameLength += 4 - nameLength % 4; } byte[] nameBytes = new byte[nameLength]; Array.Copy(nvlist, offset, nameBytes, 0, nameLength); item.name = StringHandlers.CToString(nameBytes); offset += (int)nameLength; item.dataType = (NVS_DataTypes)BigEndianBitConverter.ToUInt32(nvlist, offset); offset += 4; item.elements = BigEndianBitConverter.ToUInt32(nvlist, offset); offset += 4; if (item.elements == 0) { decodedNvList.Add(item.name, item); continue; } switch (item.dataType) { case NVS_DataTypes.DATA_TYPE_BOOLEAN: case NVS_DataTypes.DATA_TYPE_BOOLEAN_ARRAY: case NVS_DataTypes.DATA_TYPE_BOOLEAN_VALUE: if (item.elements > 1) { bool[] boolArray = new bool[item.elements]; for (int i = 0; i < item.elements; i++) { uint temp = BigEndianBitConverter.ToUInt32(nvlist, offset); boolArray[i] = temp > 0; offset += 4; } item.value = boolArray; } else { uint temp = BigEndianBitConverter.ToUInt32(nvlist, offset); item.value = temp > 0; offset += 4; } break; case NVS_DataTypes.DATA_TYPE_BYTE: case NVS_DataTypes.DATA_TYPE_BYTE_ARRAY: case NVS_DataTypes.DATA_TYPE_UINT8: case NVS_DataTypes.DATA_TYPE_UINT8_ARRAY: if (item.elements > 1) { byte[] byteArray = new byte[item.elements]; Array.Copy(nvlist, offset, byteArray, 0, item.elements); offset += (int)item.elements; if (item.elements % 4 > 0) { offset += 4 - (int)(item.elements % 4); } item.value = byteArray; } else { item.value = nvlist[offset]; offset += 4; } break; case NVS_DataTypes.DATA_TYPE_DOUBLE: if (item.elements > 1) { double[] doubleArray = new double[item.elements]; for (int i = 0; i < item.elements; i++) { double temp = BigEndianBitConverter.ToDouble(nvlist, offset); doubleArray[i] = temp; offset += 8; } item.value = doubleArray; } else { item.value = BigEndianBitConverter.ToDouble(nvlist, offset); offset += 8; } break; case NVS_DataTypes.DATA_TYPE_HRTIME: if (item.elements > 1) { DateTime[] hrtimeArray = new DateTime[item.elements]; for (int i = 0; i < item.elements; i++) { DateTime temp = DateHandlers.UnixHrTimeToDateTime(BigEndianBitConverter.ToUInt64(nvlist, offset)); hrtimeArray[i] = temp; offset += 8; } item.value = hrtimeArray; } else { item.value = DateHandlers.UnixHrTimeToDateTime(BigEndianBitConverter.ToUInt64(nvlist, offset)); offset += 8; } break; case NVS_DataTypes.DATA_TYPE_INT16: case NVS_DataTypes.DATA_TYPE_INT16_ARRAY: if (item.elements > 1) { short[] shortArray = new short[item.elements]; for (int i = 0; i < item.elements; i++) { short temp = BigEndianBitConverter.ToInt16(nvlist, offset); shortArray[i] = temp; offset += 4; } item.value = shortArray; } else { item.value = BigEndianBitConverter.ToInt16(nvlist, offset); offset += 4; } break; case NVS_DataTypes.DATA_TYPE_INT32: case NVS_DataTypes.DATA_TYPE_INT32_ARRAY: if (item.elements > 1) { int[] intArray = new int[item.elements]; for (int i = 0; i < item.elements; i++) { int temp = BigEndianBitConverter.ToInt32(nvlist, offset); intArray[i] = temp; offset += 4; } item.value = intArray; } else { item.value = BigEndianBitConverter.ToInt32(nvlist, offset); offset += 4; } break; case NVS_DataTypes.DATA_TYPE_INT64: case NVS_DataTypes.DATA_TYPE_INT64_ARRAY: if (item.elements > 1) { long[] longArray = new long[item.elements]; for (int i = 0; i < item.elements; i++) { long temp = BigEndianBitConverter.ToInt64(nvlist, offset); longArray[i] = temp; offset += 8; } item.value = longArray; } else { item.value = BigEndianBitConverter.ToInt64(nvlist, offset); offset += 8; } break; case NVS_DataTypes.DATA_TYPE_INT8: case NVS_DataTypes.DATA_TYPE_INT8_ARRAY: if (item.elements > 1) { sbyte[] sbyteArray = new sbyte[item.elements]; for (int i = 0; i < item.elements; i++) { sbyte temp = (sbyte)nvlist[offset]; sbyteArray[i] = temp; offset++; } item.value = sbyteArray; if (sbyteArray.Length % 4 > 0) { offset += 4 - sbyteArray.Length % 4; } } else { item.value = BigEndianBitConverter.ToInt64(nvlist, offset); offset += 4; } break; case NVS_DataTypes.DATA_TYPE_STRING: case NVS_DataTypes.DATA_TYPE_STRING_ARRAY: if (item.elements > 1) { string[] stringArray = new string[item.elements]; for (int i = 0; i < item.elements; i++) { uint strLength = BigEndianBitConverter.ToUInt32(nvlist, offset); offset += 4; byte[] strBytes = new byte[strLength]; Array.Copy(nvlist, offset, strBytes, 0, strLength); stringArray[i] = StringHandlers.CToString(strBytes); offset += (int)strLength; if (strLength % 4 > 0) { offset += 4 - (int)(strLength % 4); } } item.value = stringArray; } else { uint strLength = BigEndianBitConverter.ToUInt32(nvlist, offset); offset += 4; byte[] strBytes = new byte[strLength]; Array.Copy(nvlist, offset, strBytes, 0, strLength); item.value = StringHandlers.CToString(strBytes); offset += (int)strLength; if (strLength % 4 > 0) { offset += 4 - (int)(strLength % 4); } } break; case NVS_DataTypes.DATA_TYPE_UINT16: case NVS_DataTypes.DATA_TYPE_UINT16_ARRAY: if (item.elements > 1) { ushort[] ushortArray = new ushort[item.elements]; for (int i = 0; i < item.elements; i++) { ushort temp = BigEndianBitConverter.ToUInt16(nvlist, offset); ushortArray[i] = temp; offset += 4; } item.value = ushortArray; } else { item.value = BigEndianBitConverter.ToUInt16(nvlist, offset); offset += 4; } break; case NVS_DataTypes.DATA_TYPE_UINT32: case NVS_DataTypes.DATA_TYPE_UINT32_ARRAY: if (item.elements > 1) { uint[] uintArray = new uint[item.elements]; for (int i = 0; i < item.elements; i++) { uint temp = BigEndianBitConverter.ToUInt32(nvlist, offset); uintArray[i] = temp; offset += 4; } item.value = uintArray; } else { item.value = BigEndianBitConverter.ToUInt32(nvlist, offset); offset += 4; } break; case NVS_DataTypes.DATA_TYPE_UINT64: case NVS_DataTypes.DATA_TYPE_UINT64_ARRAY: if (item.elements > 1) { ulong[] ulongArray = new ulong[item.elements]; for (int i = 0; i < item.elements; i++) { ulong temp = BigEndianBitConverter.ToUInt64(nvlist, offset); ulongArray[i] = temp; offset += 8; } item.value = ulongArray; } else { item.value = BigEndianBitConverter.ToUInt64(nvlist, offset); offset += 8; } break; case NVS_DataTypes.DATA_TYPE_NVLIST: if (item.elements > 1) { goto default; } byte[] subListBytes = new byte[item.encodedSize - (offset - currOff)]; Array.Copy(nvlist, offset, subListBytes, 0, subListBytes.Length); if (DecodeNvList(subListBytes, out Dictionary <string, NVS_Item> subList, true, littleEndian)) { item.value = subList; } else { goto default; } offset = (int)(currOff + item.encodedSize); break; default: byte[] unknown = new byte[item.encodedSize - (offset - currOff)]; Array.Copy(nvlist, offset, unknown, 0, unknown.Length); item.value = unknown; offset = (int)(currOff + item.encodedSize); break; } decodedNvList.Add(item.name, item); } return(decodedNvList.Count > 0); }