namespace Pdftract;
///
/// Represents a PDF source (file path, URL, or raw bytes).
///
public abstract class Source
{
///
/// Returns command-line arguments for the source.
///
internal abstract List ToArgs();
///
/// Performs cleanup (e.g., deletes temporary files).
///
internal virtual void Dispose() { }
///
/// Creates a Source from a local file path.
///
public static Source FromPath(string path) => new PathSource(path);
///
/// Creates a Source from a URL string.
///
public static Source FromUrl(string url) => new UrlSource(url);
///
/// Creates a Source from a URI.
///
public static Source FromUri(Uri uri) => new UrlSource(uri.ToString());
///
/// Creates a Source from a byte array.
///
public static Source FromBytes(byte[] data) => new BytesSource(data);
///
/// Creates a Source from a file by reading it into memory.
///
public static Source FromFileBytes(string path)
{
var data = File.ReadAllBytes(path);
return new BytesSource(data);
}
}
///
/// A local filesystem path source.
///
public sealed class PathSource : Source
{
private readonly string _path;
public PathSource(string path)
{
_path = Path.GetFullPath(path);
}
internal override List ToArgs()
{
return new() { _path };
}
}
///
/// A remote URL source.
///
public sealed class UrlSource : Source
{
private readonly string _url;
public UrlSource(string url)
{
if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
!url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("URL must start with http:// or https://", nameof(url));
}
_url = url;
}
internal override List ToArgs()
{
return new() { "--url", _url };
}
}
///
/// An in-memory byte array source.
/// Creates a temporary file that is cleaned up after use.
///
public sealed class BytesSource : Source
{
private readonly byte[] _data;
private string? _tmpPath;
public BytesSource(byte[] data)
{
_data = data ?? throw new ArgumentNullException(nameof(data));
}
internal override List ToArgs()
{
if (_tmpPath != null)
{
return new() { _tmpPath };
}
var tmpFile = Path.GetTempFileName();
File.WriteAllBytes(tmpFile, _data);
_tmpPath = tmpFile;
return new() { _tmpPath };
}
internal override void Dispose()
{
try
{
if (_tmpPath != null && File.Exists(_tmpPath))
{
File.Delete(_tmpPath);
}
}
catch
{
// Ignore cleanup errors
}
_tmpPath = null;
}
}