Кажется, что $dat[4]
неверные данные. По крайней мере, первое поле должно содержать второй байт, потому что D5
указывает, что после него есть по крайней мере еще один байт.
$dat[2]
также недопустимые данные, поскольку поле длины для 0x09
равно 0x03
, но само поле содержит четыре символа.
$dat[5]
содержит недопустимый шестнадцатеричный escape. Вместо \xEO
я использую \xE0
.
С этими двумя исправлениями вы можете анализировать входящие сообщения с помощью функции unpack :
my( $number, $name ) = unpack 'xwxC/ax', $d;
Шаблон для unpack
означает:
x
- выбросить этот байт (0x08)
w
- прочитать кодированный BER номер
x
- выбросить этот байт (0x09)
C
- прочитать этот байт и использовать его в качестве длины для следующей строки
a
- прочитать следующие байты и использовать их в качестве строковых символов
x
- выбросить этот байт (0x1A)
Если вы также хотите сохранить номера полей, используйте
unpack 'CwCC/aC', $d
По крайней мере, для показанных данных шаблон unpack
работает с предположениями, которые я высказал. Если это фактические данные ASN.1, тогда должно быть гораздо больше проверок и т. Д., И если разделители полей могут отсутствовать, подход на основе регулярных выражений, показанный @ikegami, безусловно, более надежен.
Фиксированный / динамический порядок полей
Шаблон опирается на фиксированный порядок полей. Если порядок полей не обязательно будет фиксированным, вам нужно будет определить шаблон (ы) unpack
на основе типа каждого поля в цикле. Это приближает подход распаковки к подходу ikegami.
my ($message_type), $d = unpack 'CA*', $d;
if( $message_type eq "\x08" ) {
my ($number), $d = unpack 'wA*', $d;
print "Field 0x08: $number\n";
} elsif ...
См. Следующую полную программу для фиксированного порядка полей:
#!perl
use strict;
use warnings;
my @dat;
$dat[1] = "\x08\xB3\xE3\x0C\x09\x07\x4D\x6F\x68\x61\x6D\x65\x64\x1A";
#$dat[2] = "\x08\x84\x03\x09\x03\x53\x6F\x6C\x6C\x1A";
$dat[3] = "\x08\xD4\xEA\x0E\x09\x03\x54\x6F\x6C\x1A";
#$dat[4] = "\x08\xD5\x09\x03\x55\x6F\x6C\x1A";
$dat[5] = "\x08\xD4\xEA\x09\x09\x03\x54\x6F\x6C\x1A";
$dat[6] = "\x08\xD4\xEA\x0E\x09\x09\x54\x6F\x6C\x61\x6D\x65\x64\x61\x61\x1A";
$dat[7] = "\x08\xD4\xEA\x09\x09\x09\x54\x6F\x6C\x61\x6D\x65\x64\x61\x61\x1A";
@dat = grep {defined } @dat;
use Data::Dumper;
for my $d (@dat) {
# Hardcoded message parser
print Dumper [
unpack 'CwCC/aC', $d
];
# Dynamic message parser
while( length $d ) {
(my ($message_type), $d) = unpack 'aa*', $d;
if( $message_type eq "\x08" ) {
(my ($number), $d) = unpack 'wa*', $d;
print "Field 0x08: $number\n";
} elsif ( $message_type eq "\x09" ) {
(my ($len)) = unpack 'C', $d;
(my ($name), $d) = unpack 'C/aa*', $d;
print "Field 0x09: $name\n";
} elsif ( $message_type eq "\x1A" ) {
# finished
print "Field 0x1A\n";
} else {
die sprintf "Unknown message type %08x", ord($message_type);
};
};
};
выход
$VAR1 = [
8,
848268,
9,
'Mohamed',
26
];
Field 0x08: 848268
Field 0x09: Mohamed
Field 0x1A
$VAR1 = [
8,
515,
9,
'Sol',
26
];
Field 0x08: 515
Field 0x09: Sol
Field 0x1A
$VAR1 = [
8,
1389838,
9,
'Tol',
26
];
Field 0x08: 1389838
Field 0x09: Tol
Field 0x1A
$VAR1 = [
8,
1389833,
9,
'Tol',
26
];
Field 0x08: 1389833
Field 0x09: Tol
Field 0x1A
$VAR1 = [
8,
1389838,
9,
'Tolamedaa',
26
];
Field 0x08: 1389838
Field 0x09: Tolamedaa
Field 0x1A
$VAR1 = [
8,
1389833,
9,
'Tolamedaa',
26
];
Field 0x08: 1389833
Field 0x09: Tolamedaa
Field 0x1A
Смотри также
функция распаковки
(un) параметры упаковки