Skip to content

Commit a82a0b6

Browse files
committed
Data segments
1 parent 9919621 commit a82a0b6

3 files changed

Lines changed: 124 additions & 1 deletion

File tree

QrCodeAnalyzer/MainWindow.xaml

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
66
xmlns:local="clr-namespace:Net.Codecrete.QrCodeGenerator.Analyzer"
77
mc:Ignorable="d"
8-
Title="QR Code" Height="400" Width="600"
8+
Title="QR Code" Height="560" Width="600"
99
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
1010
<Grid Margin="20,16,20,16">
1111
<Grid.ColumnDefinitions>
@@ -15,6 +15,7 @@
1515
<Grid.RowDefinitions>
1616
<RowDefinition Height="1*"/>
1717
<RowDefinition Height="Auto"/>
18+
<RowDefinition Height="140"/>
1819
</Grid.RowDefinitions>
1920
<Image Source="{Binding Path=QrCodeImage}" Grid.Row="0" Grid.Column="0" Margin="0,0,0,16"
2021
RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.EdgeMode="Aliased"/>
@@ -76,5 +77,36 @@
7677
<Button x:Name="CopyButton" Content="Copy QR Code" Grid.Row="3" Margin="0,6,0,0"
7778
VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10,3" Click="CopyButton_Click"/>
7879
</StackPanel>
80+
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,12,0,0">
81+
<Grid.RowDefinitions>
82+
<RowDefinition Height="Auto"/>
83+
<RowDefinition Height="1*"/>
84+
</Grid.RowDefinitions>
85+
<Grid Grid.Row="0">
86+
<Grid.ColumnDefinitions>
87+
<ColumnDefinition Width="120"/>
88+
<ColumnDefinition Width="1*"/>
89+
</Grid.ColumnDefinitions>
90+
<TextBlock Grid.Column="0" Text="Mode" FontWeight="Bold" Padding="4,2"/>
91+
<TextBlock Grid.Column="1" Text="Content" FontWeight="Bold" Padding="4,2"/>
92+
<Border Grid.Column="0" Grid.ColumnSpan="2" BorderBrush="Gray" BorderThickness="0,0,0,1" VerticalAlignment="Bottom"/>
93+
</Grid>
94+
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
95+
<ItemsControl ItemsSource="{Binding Path=DataSegments}">
96+
<ItemsControl.ItemTemplate>
97+
<DataTemplate>
98+
<Grid>
99+
<Grid.ColumnDefinitions>
100+
<ColumnDefinition Width="120"/>
101+
<ColumnDefinition Width="1*"/>
102+
</Grid.ColumnDefinitions>
103+
<TextBlock Grid.Column="0" Text="{Binding Path=Mode}" FontFamily="Consolas, Cascadia Mono" Padding="4,2"/>
104+
<TextBlock Grid.Column="1" Text="{Binding Path=Content}" FontFamily="Consolas, Cascadia Mono" Padding="4,2" TextWrapping="Wrap"/>
105+
</Grid>
106+
</DataTemplate>
107+
</ItemsControl.ItemTemplate>
108+
</ItemsControl>
109+
</ScrollViewer>
110+
</Grid>
79111
</Grid>
80112
</Window>

QrCodeAnalyzer/MainWindowViewModel.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,20 @@
88
//
99

1010
using System;
11+
using System.Collections.Generic;
1112
using System.ComponentModel;
13+
using System.Linq;
1214
using System.Runtime.CompilerServices;
15+
using System.Text;
1316
using System.Windows.Media;
1417
using System.Windows.Media.Imaging;
1518

1619
namespace Net.Codecrete.QrCodeGenerator.Analyzer;
1720

1821
public enum HighlightKind { None, Blocks, HorizontalStreaks, VerticalStreaks }
1922

23+
public sealed record SegmentRow(string Mode, string Content);
24+
2025
public sealed class MainWindowViewModel : INotifyPropertyChanged
2126
{
2227
private readonly QrCodeBuilder.DebugInfo _debugInfo = new QrCodeBuilder.DebugInfo();
@@ -31,6 +36,7 @@ public sealed class MainWindowViewModel : INotifyPropertyChanged
3136
private int _selectedDataMaskPattern = -1;
3237
private QrCode? _currentQrCode;
3338
private HighlightKind _highlight = HighlightKind.None;
39+
private IReadOnlyList<SegmentRow> _dataSegments = Array.Empty<SegmentRow>();
3440

3541
public MainWindowViewModel()
3642
{
@@ -154,6 +160,16 @@ private set
154160
}
155161
}
156162

163+
public IReadOnlyList<SegmentRow> DataSegments
164+
{
165+
get => _dataSegments;
166+
private set
167+
{
168+
_dataSegments = value;
169+
OnPropertyChanged();
170+
}
171+
}
172+
157173
public HighlightKind Highlight
158174
{
159175
get => _highlight;
@@ -179,9 +195,65 @@ private void UpdateQrCode()
179195
_currentQrCode = qrCode;
180196
SelectedDataMaskPattern = qrCode.Mask;
181197
PenaltyDetails = _debugInfo.Penalties[qrCode.Mask];
198+
DataSegments = _debugInfo.DataSegments?.Select(BuildSegmentRow).ToArray()
199+
?? (IReadOnlyList<SegmentRow>)Array.Empty<SegmentRow>();
182200
RenderQrCodeImage();
183201
}
184202

203+
private static SegmentRow BuildSegmentRow(DataSegment segment)
204+
{
205+
return segment.Mode switch
206+
{
207+
DataSegmentMode.Numeric => new SegmentRow("Numeric", DecodeAscii(segment.DataBytes)),
208+
DataSegmentMode.Alphanumeric => new SegmentRow("Alphanumeric", DecodeAscii(segment.DataBytes)),
209+
DataSegmentMode.Binary => new SegmentRow("Byte", FormatByteContent(segment.DataBytes)),
210+
DataSegmentMode.Kanji => new SegmentRow("Kanji", FormatHex(segment.DataBytes)),
211+
DataSegmentMode.ECI => new SegmentRow("ECI", "TODO"),
212+
DataSegmentMode.StructuredAppend => new SegmentRow("Structured Append", "TODO"),
213+
_ => new SegmentRow(segment.Mode.ToString(), FormatHex(segment.DataBytes)),
214+
};
215+
}
216+
217+
private static string DecodeAscii(ArraySegment<byte> data)
218+
{
219+
return data.Array == null ? string.Empty : Encoding.ASCII.GetString(data.Array, data.Offset, data.Count);
220+
}
221+
222+
private static readonly UTF8Encoding StrictUtf8 = new UTF8Encoding(false, throwOnInvalidBytes: true);
223+
224+
private static string FormatByteContent(ArraySegment<byte> data)
225+
{
226+
if (data.Array == null || data.Count == 0) return string.Empty;
227+
try
228+
{
229+
var text = StrictUtf8.GetString(data.Array, data.Offset, data.Count);
230+
foreach (var c in text)
231+
{
232+
if (c < 0x20 && c != '\t' && c != '\r' && c != '\n')
233+
{
234+
return FormatHex(data);
235+
}
236+
}
237+
return text;
238+
}
239+
catch (DecoderFallbackException)
240+
{
241+
return FormatHex(data);
242+
}
243+
}
244+
245+
private static string FormatHex(ArraySegment<byte> data)
246+
{
247+
if (data.Array == null || data.Count == 0) return string.Empty;
248+
var sb = new StringBuilder(data.Count * 3);
249+
for (int i = 0; i < data.Count; i++)
250+
{
251+
if (i > 0) sb.Append(' ');
252+
sb.Append(data.Array[data.Offset + i].ToString("X2"));
253+
}
254+
return sb.ToString();
255+
}
256+
185257
private void RenderQrCodeImage()
186258
{
187259
if (_currentQrCode == null) return;

QrCodeAnalyzer/data-segments.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
The main windows should addititionally be able to display the data segments of the process. This is useful for debugging purposes, as it allows the user to see the contents of the data segments and how they are being used by the process.
2+
3+
They should be displayed in a sort of table with two columns:
4+
5+
1. Segment encoding mode
6+
2. Segment content
7+
8+
The table should be towards the bottom of the main window.
9+
10+
The content should be displayed as follows:
11+
12+
- Encoding mode Numeric and Alphanumeric: as text (decoded)
13+
- Encoding mode Byte: If it can be converted to a string using UTF-8, it should be displayed as text (decoded). Otherwise, it should be displayed as a hex dump.
14+
- Encoding mode Kanji: as hex dump
15+
- Encoding mode ECI: display the ECI number
16+
- Other encoding modes: as hex dump
17+
18+
The list of data segments is accessible via the DebugAccess object.
19+

0 commit comments

Comments
 (0)