// 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;
}
}
}