using System.Text; namespace SabreTools.Data.Extensions { public static class CFBExtensions { /// /// Decode a MIME-encoded stream name stored as a byte array /// /// Byte array to decode /// Decoded string on success, null otherwise /// Adapted from LibMSI public static string? DecodeStreamName(this byte[]? input) { // Ignore invalid inputs if (input is null) return null; else if (input.Length == 0) return string.Empty; int count = 0; int p = 0; // inputBytes[0] byte[] output = new byte[input.Length + 1]; int q = 0; // output[0] while (p < input.Length && input[p] != 0) { byte ch = input[p]; if ((ch == 0xe3 && input[p + 1] >= 0xa0) || (ch == 0xe4 && input[p + 1] < 0xa0)) { // UTF-8 encoding of 0x3800..0x47ff. output[q++] = (byte)Mime2Utf(input[p + 2] & 0x7f); output[q++] = (byte)Mime2Utf(input[p + 1] ^ 0xa0); p += 3; count += 2; continue; } if (ch == 0xe4 && input[p + 1] == 0xa0) { // UTF-8 encoding of 0x4800..0x483f. output[q++] = (byte)Mime2Utf(input[p + 2] & 0x7f); p += 3; count++; continue; } output[q++] = input[p++]; if (ch >= 0xc1) output[q++] = input[p++]; if (ch >= 0xe0) output[q++] = input[p++]; if (ch >= 0xf0) output[q++] = input[p++]; count++; } output[q] = 0; return Encoding.UTF8.GetString(output); } /// /// Decode a MIME-encoded stream name stored as a string /// /// String to decode /// Decoded string on success, null otherwise /// Adapted from LibMSI public static string? DecodeStreamName(this string? input) { // Ignore invalid inputs if (input is null) return null; else if (input.Length == 0) return string.Empty; byte[] inputBytes = Encoding.UTF8.GetBytes(input); return inputBytes.DecodeStreamName(); } /// /// Decode a single MIME-encoded byte /// /// Byte to decode /// Decoded byte on success, `_` otherwise /// Adapted from LibMSI private static int Mime2Utf(int b) { return b switch { < 10 => b + '0', < 10 + 26 => b - 10 + 'A', < 10 + 26 + 26 => b - 10 - 26 + 'a', 10 + 26 + 26 => '.', _ => '_' }; } } }