Preflight Plugins and XML MRR

pfXML serializes built-in checks, warnings, hints, stable rule IDs, specification references, and object, page, or byte locations into the versioned urn:hotpdf:preflight:mrr:1 vocabulary

CreatePreflightMRR adds trusted in-process plugins for feature extraction and custom validation rules, while ValidatePDFWithPluginBundle combines those rules with an existing THPDFValidationPolicy

Register a bounded plugin

function EvaluateVendorRules(
  const Context: THPDFPreflightPluginContext;
  out PluginResult: THPDFPreflightPluginResult;
  out ErrorMessage: AnsiString): Boolean;
begin
  SetLength(PluginResult.Findings, 1);
  PluginResult.Findings[0] := THPDFPreflightPluginFinding.Create(
    'vendor.metadata.required', 'Vendor metadata is present', True, ppsError);
  PluginResult.Findings[0].Scope := 'metadata';
  PluginResult.Findings[0].Path := '/Vendor';
  ErrorMessage := '';
  Result := True;
end;

Limits := THPDFPreflightPluginLimits.Default;
SetLength(Plugins, 1);
Plugins[0] := THPDFPreflightPluginDescriptor.Create(
  'vendor-policy', '1.0', [ppcValidationRules], EvaluateVendorRules);
XML := PDF.CreatePreflightMRR('Input.pdf', '', Plugins, Limits);

Determinism and trust boundary

HotPDF validates unique ASCII plugin IDs and ABI version 1, executes plugins in stable ID order, sorts returned features and findings, omits timing jitter from the report, escapes XML values, and rejects undeclared capabilities or invalid rule IDs

Limits bound plugin count, feature count, finding count, aggregate string bytes, XML output bytes, per-plugin elapsed time, and total elapsed time; a rejected plugin contributes a deterministic execution finding and does not consume shared feature, finding, or string budgets

Plugins run inside the caller process and receive the source path, password, base text report, policy name, limits, and cancellation token, so only trusted plugin code should be registered

Elapsed limits are checked after an evaluator returns because an in-process callback cannot be preempted safely; long-running evaluators should poll Context.CancellationToken and return promptly

See THotPDF.CreatePreflightMRR, THotPDF.ValidatePDFWithPluginBundle, THPDFPreflightPluginDescriptor, and THPDFPreflightPluginLimits