using System.Globalization; using Npgsql; namespace pgLabII.PgUtils.ConnectionStrings; /// /// Shared helper utilities for codecs to reduce duplication (SSL mode mapping, host:port parsing/formatting, /// URL query parsing, and .NET/libpq quoting helpers). /// internal static class CodecCommon { // SSL mapping public static SslMode ParseSslModeLoose(string s) => s.Trim().ToLowerInvariant() switch { "disable" => SslMode.Disable, "allow" => SslMode.Allow, "prefer" => SslMode.Prefer, "require" => SslMode.Require, "verify-ca" or "verifyca" => SslMode.VerifyCA, "verify-full" or "verifyfull" => SslMode.VerifyFull, _ => throw new ArgumentException($"Not a valid SSL Mode: {s}") }; public static string FormatSslModeUrlLike(SslMode mode) => mode switch { SslMode.Disable => "disable", SslMode.Allow => "allow", SslMode.Prefer => "prefer", SslMode.Require => "require", SslMode.VerifyCA => "verify-ca", SslMode.VerifyFull => "verify-full", _ => "prefer" }; // host:port parsing for plain or [IPv6]:port public static void ParseHostPort(string hostPart, out string host, out ushort? port) { host = hostPart; port = null; if (string.IsNullOrWhiteSpace(hostPart)) return; if (hostPart[0] == '[') { int end = hostPart.IndexOf(']'); if (end > 0) { host = hostPart[1..end]; if (end + 1 < hostPart.Length && hostPart[end + 1] == ':') { string ps = hostPart[(end + 2)..]; if (ushort.TryParse(ps, NumberStyles.Integer, CultureInfo.InvariantCulture, out var p)) port = p; } } return; } int colon = hostPart.LastIndexOf(':'); if (colon > 0 && colon < hostPart.Length - 1) { var ps = hostPart.Substring(colon + 1); if (ushort.TryParse(ps, NumberStyles.Integer, CultureInfo.InvariantCulture, out var p)) { host = hostPart.Substring(0, colon); port = p; } } } public static string FormatHost(HostEndpoint h) { var host = h.Host; if (host.Contains(':') && !host.StartsWith("[")) host = "[" + host + "]"; // IPv6 return h.Port.HasValue ? host + ":" + h.Port.Value.ToString(CultureInfo.InvariantCulture) : host; } public static string[] SplitHosts(string hostList) => hostList.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); public static Dictionary ParseQuery(string query) { var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrEmpty(query)) return dict; foreach (var kv in query.Split('&', StringSplitOptions.RemoveEmptyEntries)) { var parts = kv.Split('=', 2); var key = Uri.UnescapeDataString(parts[0]); var val = parts.Length > 1 ? Uri.UnescapeDataString(parts[1]) : string.Empty; dict[key] = val; } return dict; } }