zplCore.comzplCore.com

32Diagnostics, source positions, limits & threads

Every ZplRenderResult has Diagnostics: ZplDiagnostic with a stable code, severity, message, command and position (offset, line, column). Warnings is kept and contains the messages of all warnings and errors.

Try it online on zplCloud.com: ZPL Linter

CodeSeverityMeaning
ZPL1001ErrorCommand with invalid parameters ignored (the rest of the label is rendered)
ZPL1002WarningField could not be drawn (e.g. invalid barcode data)
ZPL1003WarningBarcode data longer than any symbology can hold
ZPL1101Warning^GF larger than the label or MaxGraphicBytes
ZPL1102Warning^GF data cannot be decoded
ZPL1103Warning^XG/^IM references a graphic that is not stored
ZPL1201Warning^A@ font not found – font A is used, as on a Zebra
ZPL1301WarningFieldValues key without a matching ^FN (INVALID_FIELD_VALUE_KEY)
ZPL2001InfoAccepted, no effect on the image (^FE, ^FA, RFID operations other than writing)

With TraceElements, every element carries SourceOffset/SourceLength (its ^FO…^FS block); every parsed ZplCommand has Offset/Length, and ZplParser.LineColumn converts them. Missing ^A@ fonts can be supplied on demand by the FontProvider callback.

var renderer = new ZplRenderer(new ZplRenderSettings
{
    TraceElements = true,
    FontProvider = name => name == "E:BRAND.TTF" ? File.ReadAllBytes("fonts/Brand.ttf") : null,
});
foreach (var result in renderer.Render(zpl))
{
    foreach (ZplDiagnostic d in result.Diagnostics)          // e.g. "ZPL1201 warning (3:12): …"
        Console.WriteLine($"{d.Code} {d.Severity} {d.Command} Zeile {d.Line}, Spalte {d.Column}: {d.Message}");
    foreach (var e in result.Elements)                       // ^FO…^FS range in the source
        Console.WriteLine(zpl.Substring(e.SourceOffset, e.SourceLength));
    result.Bitmap.Dispose();
}

Limits for untrusted input & thread safety

Defaults: MaxLabelSide 32000, MaxLabelDots 64 million, MaxQuantity 10000, MaxLabels 100000, MaxGraphicBytes 32 MB (also the Z64 decompression limit against zip bombs), MaxFieldDataLength 1 million, ZplResourceStore.MaxTotalBytes 256 MB. ZplRenderer/EplRenderer hold printer state and are not thread-safe – use one renderer per thread; ZplResourceStore, FontManager, ZplCaches, PropertyPath and configured LabelBindings are. ConcurrencyTests compares the SHA-256 of all outputs from 16 threads with the single-threaded run; samples/FuzzRunner feeds the parser random and mutated input, samples/LeakTest renders 1 million labels and logs heap and RSS. Details: THREADING.md, DIAGNOSTICS.md.

var shared = new ZplResourceStore();                          // thread-safe, shareable by many renderers
var safe = new ZplRenderSettings
{
    MaxLabelSide = 8000, MaxLabelDots = 16_000_000, MaxQuantity = 100,
    MaxLabels = 1000, MaxGraphicBytes = 4 * 1024 * 1024, MaxFieldDataLength = 10_000,
};
Parallel.For(0, 8, _ =>
{
    var r = new ZplRenderer(safe) { Store = shared };         // one renderer per thread
    r.ProcessCommands(untrusted);
});