S7WString.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. using System;
  2. using System.Text;
  3. namespace S7.Net.Types
  4. {
  5. /// <summary>
  6. /// Contains the methods to convert from S7 wstrings to C# strings
  7. /// An S7 WString has a preceding 4 byte header containing its capacity and length
  8. /// </summary>
  9. public static class S7WString
  10. {
  11. /// <summary>
  12. /// Converts S7 bytes to a string
  13. /// </summary>
  14. /// <param name="bytes"></param>
  15. /// <returns></returns>
  16. public static string FromByteArray(byte[] bytes)
  17. {
  18. if (bytes.Length < 4)
  19. {
  20. throw new PlcException(ErrorCode.ReadData, "Malformed S7 WString / too short");
  21. }
  22. int size = (bytes[0] << 8) | bytes[1];
  23. int length = (bytes[2] << 8) | bytes[3];
  24. if (length > size)
  25. {
  26. throw new PlcException(ErrorCode.ReadData, "Malformed S7 WString / length larger than capacity");
  27. }
  28. try
  29. {
  30. return Encoding.BigEndianUnicode.GetString(bytes, 4, length * 2);
  31. }
  32. catch (Exception e)
  33. {
  34. throw new PlcException(ErrorCode.ReadData,
  35. $"Failed to parse {VarType.S7WString} from data. Following fields were read: size: '{size}', actual length: '{length}', total number of bytes (including header): '{bytes.Length}'.",
  36. e);
  37. }
  38. }
  39. /// <summary>
  40. /// Converts a <see cref="T:string"/> to S7 wstring with 4-byte header.
  41. /// </summary>
  42. /// <param name="value">The string to convert to byte array.</param>
  43. /// <param name="reservedLength">The length (in characters) allocated in PLC for the string.</param>
  44. /// <returns>A <see cref="T:byte[]" /> containing the string header and string value with a maximum length of <paramref name="reservedLength"/> + 4.</returns>
  45. public static byte[] ToByteArray(string? value, int reservedLength)
  46. {
  47. if (value is null)
  48. {
  49. throw new ArgumentNullException(nameof(value));
  50. }
  51. if (reservedLength > 16382) throw new ArgumentException("The maximum string length supported is 16382.");
  52. var buffer = new byte[4 + reservedLength * 2];
  53. buffer[0] = (byte)((reservedLength >> 8) & 0xFF);
  54. buffer[1] = (byte)(reservedLength & 0xFF);
  55. buffer[2] = (byte)((value.Length >> 8) & 0xFF);
  56. buffer[3] = (byte)(value.Length & 0xFF);
  57. var stringLength = Encoding.BigEndianUnicode.GetBytes(value, 0, value.Length, buffer, 4) / 2;
  58. if (stringLength > reservedLength) throw new ArgumentException($"The provided string length ({stringLength} is larger than the specified reserved length ({reservedLength}).");
  59. return buffer;
  60. }
  61. }
  62. }