forked from BinaryKits/BinaryKits.Zpl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathZplAnalyzer.cs
203 lines (181 loc) · 8.45 KB
/
ZplAnalyzer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
using BinaryKits.Zpl.Label.Elements;
using BinaryKits.Zpl.Viewer.CommandAnalyzers;
using BinaryKits.Zpl.Viewer.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Application.UseCase.ZplToPdf;
namespace BinaryKits.Zpl.Viewer
{
public class ZplAnalyzer : IZplAnalyzer
{
private readonly VirtualPrinter _virtualPrinter;
private readonly IPrinterStorage _printerStorage;
private readonly IFormatMerger _formatMerger;
private readonly string _labelStartCommand = "^XA";
private readonly string _labelEndCommand = "^XZ";
public ZplAnalyzer(IPrinterStorage printerStorage, IFormatMerger formatMerger = null)
{
this._printerStorage = printerStorage;
this._formatMerger = formatMerger ?? new FormatMerger();
this._virtualPrinter = new VirtualPrinter();
}
public AnalyzeInfo Analyze(string zplData)
{
var zplCommands = this.SplitZplCommands(zplData);
var unknownCommands = new List<string>();
var errors = new List<string>();
var fieldDataAnalyzer = new FieldDataZplCommandAnalyzer(this._virtualPrinter);
var elementAnalyzers = new List<IZplCommandAnalyzer>
{
fieldDataAnalyzer,
new BarCodeFieldDefaultZplCommandAnalyzer(this._virtualPrinter),
new ChangeAlphanumericDefaultFontZplCommandAnalyzer(this._virtualPrinter),
new Code39BarcodeZplCommandAnalyzer(this._virtualPrinter),
new Code93BarcodeZplCommandAnalyzer(this._virtualPrinter),
new Code128BarcodeZplCommandAnalyzer(this._virtualPrinter),
new CodeEAN13BarcodeZplCommandAnalyzer(this._virtualPrinter),
new CommentZplCommandAnalyzer(this._virtualPrinter),
new DataMatrixZplCommandAnalyzer(this._virtualPrinter),
new DownloadFormatCommandAnalyzer(this._virtualPrinter),
new DownloadGraphicsZplCommandAnalyzer(this._virtualPrinter, this._printerStorage),
new DownloadObjectsZplCommandAnaylzer(this._virtualPrinter, this._printerStorage),
new FieldBlockZplCommandAnalyzer(this._virtualPrinter),
new FieldHexadecimalZplCommandAnalyzer(this._virtualPrinter),
new FieldNumberCommandAnalyzer(this._virtualPrinter),
new FieldVariableZplCommandAnalyzer(this._virtualPrinter),
new FieldReversePrintZplCommandAnalyzer(this._virtualPrinter),
new LabelReversePrintZplCommandAnalyzer(this._virtualPrinter),
new FieldSeparatorZplCommandAnalyzer(this._virtualPrinter, fieldDataAnalyzer),
new FieldTypesetZplCommandAnalyzer(this._virtualPrinter),
new FieldOriginZplCommandAnalzer(this._virtualPrinter),
new GraphicBoxZplCommandAnalyzer(this._virtualPrinter),
new GraphicCircleZplCommandAnalyzer(this._virtualPrinter),
new GraphicFieldZplCommandAnalyzer(this._virtualPrinter),
new Interleaved2of5BarcodeZplCommandAnalyzer(this._virtualPrinter),
new ImageMoveZplCommandAnalyzer(this._virtualPrinter),
new LabelHomeZplCommandAnalyzer(this._virtualPrinter),
new MaxiCodeBarcodeZplCommandAnalyzer(this._virtualPrinter),
new QrCodeBarcodeZplCommandAnalyzer(this._virtualPrinter),
new PDF417ZplCommandAnalyzer(this._virtualPrinter),
new RecallFormatCommandAnalyzer(this._virtualPrinter),
new RecallGraphicZplCommandAnalyzer(this._virtualPrinter),
new ScalableBitmappedFontZplCommandAnalyzer(this._virtualPrinter),
};
var labelInfos = new List<LabelInfo>();
var elements = new List<ZplElementBase>();
for (var i = 0; i < zplCommands.Length; i++)
{
var currentCommand = zplCommands[i];
if (this._labelStartCommand.Equals(currentCommand.Trim(), StringComparison.OrdinalIgnoreCase))
{
elements.Clear();
_virtualPrinter.ClearNextDownloadFormatName();
continue;
}
if (this._labelEndCommand.Equals(currentCommand.Trim(), StringComparison.OrdinalIgnoreCase))
{
labelInfos.Add(new LabelInfo
{
DownloadFormatName = _virtualPrinter.NextDownloadFormatName,
ZplElements = elements.ToArray()
});
continue;
}
var validAnalyzers = elementAnalyzers.Where(o => o.CanAnalyze(currentCommand));
if (!validAnalyzers.Any())
{
unknownCommands.Add(currentCommand);
continue;
}
try
{
elements.AddRange(validAnalyzers.Select(analyzer => analyzer.Analyze(currentCommand)).Where(o => o != null));
}
catch (Exception exception)
{
errors.Add($"Cannot analyze command {currentCommand} {exception}");
}
}
labelInfos = _formatMerger.MergeFormats(labelInfos);
var analyzeInfo = new AnalyzeInfo
{
LabelInfos = labelInfos.ToArray(),
UnknownCommands = unknownCommands.ToArray(),
Errors = errors.ToArray()
};
return analyzeInfo;
}
// When adding new commands: 1 per line, always upper case, comment why if possible
private string[] ignoredCommands = {
"CI", // may be implemented in the future, but for now always set to CI128
};
private string[] SplitZplCommands(string zplData)
{
if (string.IsNullOrWhiteSpace(zplData))
{
return Array.Empty<string>();
}
var cleanZpl = Regex.Replace(zplData, @"\r|\n", string.Empty);
char caret = '^';
char tilde = '~';
List<string> results = new(200);
StringBuilder buffer = new(2000);
HashSet<string> ignoredCommandsHS = new HashSet<string>(ignoredCommands);
for (int i = 0; i < cleanZpl.Length; i++)
{
char c = cleanZpl[i];
if (c == caret || c == tilde)
{
string command = buffer.ToString();
buffer.Clear();
// all commands have at least 3 chars, even ^A because of required font parameter
if (command.Length > 2)
{
PatchCommand(ref command, ref caret, ref tilde);
var commandLetters = command.Substring(1, 2).ToUpper();
if (commandLetters == "CT")
{
tilde = command[3];
}
else if (commandLetters == "CC")
{
caret = command[3];
}
else if (!ignoredCommandsHS.Contains(commandLetters))
{
results.Add(command);
}
}
// likely invalid command
else if (command.Trim().Length > 0)
{
results.Add(command.Trim());
}
// no else case, multiple ^ or ~ in a row should not be valid commands to be processed
}
buffer.Append(c);
}
string lastCommand = buffer.ToString();
if (lastCommand.Length > 0)
{
PatchCommand(ref lastCommand, ref caret, ref tilde);
results.Add(lastCommand);
}
return results.ToArray();
}
private void PatchCommand(ref string command, ref char caret, ref char tilde)
{
if (caret != '^' && command[0] == caret)
{
command = '^' + command.Remove(0, 1);
}
if (tilde != '~' && command[0] == tilde)
{
command = '~' + command.Remove(0, 1);
}
}
}
}