// Copyright (c) 2026 Duplicati Inc. All rights reserved. using System.Collections.Generic; using System.Linq; using System.Xml.Linq; namespace Duplicati.Proprietary.DiskImage.General; /// /// Helper methods for parsing macOS plist XML format output from diskutil commands. /// public static class PlistHelper { /// /// Gets a string value from a plist dict element. /// /// The plist dict element. /// The key to look up. /// The string value, or null if not found. public static string? GetStringValue(XElement dictElement, string key) { var keys = dictElement.Elements("key").ToList(); var values = dictElement.Elements().Where(e => e.Name != "key").ToList(); for (int i = 0; i < keys.Count && i < values.Count; i++) { if (keys[i].Value == key) return values[i].Value; } return null; } /// /// Gets an array element from a plist dict element. /// /// The plist dict element. /// The key to look up. /// The array element, or null if not found. public static XElement? GetArrayElement(XElement dictElement, string key) { var keys = dictElement.Elements("key").ToList(); var values = dictElement.Elements().Where(e => e.Name != "key").ToList(); for (int i = 0; i < keys.Count && i < values.Count; i++) { if (keys[i].Value == key && values[i].Name == "array") return values[i]; } return null; } /// /// Gets a long value from a plist dict element. /// /// The plist dict element. /// The key to look up. /// The long value, or 0 if not found or not parseable. public static long GetLongValue(XElement dictElement, string key) { var value = GetStringValue(dictElement, key); return long.TryParse(value, out var result) ? result : 0; } /// /// Gets a boolean value from a plist dict element. /// /// The plist dict element. /// The key to look up. /// True if the value is a "true" element, false otherwise. public static bool GetBoolValue(XElement dictElement, string key) { var keys = dictElement.Elements("key").ToList(); var values = dictElement.Elements().Where(e => e.Name != "key").ToList(); for (int i = 0; i < keys.Count && i < values.Count; i++) { if (keys[i].Value == key) return values[i].Name == "true"; } return false; } /// /// Parses a plist XML string and returns the root dict element. /// /// The plist XML string. /// The root dict element, or null if parsing fails. public static XElement? ParsePlistDict(string plistXml) { try { var plist = XDocument.Parse(plistXml); return plist.Element("plist")?.Element("dict"); } catch { return null; } } }