#!/usr/bin/perl use strict; my $msg_ctr = 0; my %messages; my %devices; sub add_message { my $msg = shift; my $val = $messages{$msg}; defined($val) or do { $val = $msg_ctr++; $messages{$msg} = $val; }; return $val; } sub add_device($) { my $id = shift; my $dev = {}; my $match; $id =~ /^(\w{4}:\w{4})(:.*)?/ or do { warn "Invalid device ID string $id\n"; return $dev; }; $id = $1; $match = $2 or $match = "*"; $devices{$id} or $devices{$id} = {}; $devices{$id}->{$match} = $dev; return $dev; } sub add_hex { $_[0] =~ s/^0x//; return hex($_[0]); } sub add_mode { $_[1] =~ s/^(\w+)Mode$/$1/; return $_[1]; } sub add_modeval { return unless ($_[1] && $_[1] =~ /^\d+$/); $_[0]->{"ModeValue"} = $_[1]; } my $hex_option = [ undef, \&add_hex ]; my $msg_option = [ undef, \&add_message ]; my $mode_option = [ "Mode", \&add_mode ]; my $value_mode_option = [ "Mode", \&add_mode, \&add_modeval ]; my %options = ( TargetVendor => $hex_option, TargetProductList => [ "TargetProduct", sub { return [ map(hex,split(/,/, $_[0])) ]; } ], TargetProduct => [ "TargetProduct", sub { return [ hex($_[0]) ]; } ], TargetClass => $hex_option, MessageContent => $msg_option, MessageContent2 => $msg_option, MessageContent3 => $msg_option, WaitBefore => [ ], DetachStorageOnly => [ ], MBIM => $mode_option, HuaweiMode => $mode_option, HuaweiNewMode => $mode_option, QuantaMode => $mode_option, BlackberryMode => $mode_option, PantechMode => $value_mode_option, OptionMode => $mode_option, SierraMode => $mode_option, SonyMode => $mode_option, QisdaMode => $mode_option, GCTMode => $mode_option, KobilMode => $mode_option, SequansMode => $mode_option, MobileActionMode => $mode_option, CiscoMode => $mode_option, StandardEject => $mode_option, NoDriverLoading => [], MessageEndpoint => $hex_option, ReleaseDelay => [], NeedResponse => [], ResponseEndpoint => $hex_option, ResetUSB => [], InquireDevice => [], CheckSuccess => $hex_option, Interface => $hex_option, Configuration => $hex_option, AltSetting => $hex_option, ); sub parse_file($) { my $file = shift; my $id; $id = $file; $file =~ /\/?([^\/]+)$/ and $id = $1; my $dev = add_device($id); open FILE, "<$file" or die "Cannot open file '$file'\n"; while () { chomp; s/^\s*(.+?)\s*$/$1/; s/#.+$//; next unless /\w/; /(\w+)\s*=\s*(.+)\s*/ or do { warn "Invalid Line: $_"; next; }; my ($var, $val) = ($1, $2); $val =~ s/^"(.+)"$/$1/; my $opt = $options{$var}; $opt or do { warn "Unrecognized option $var in file $file\n"; next; }; $opt->[2] and &{$opt->[2]}($dev, $val, $var); $opt->[1] and $val = &{$opt->[1]}($val, $var); $opt->[0] and $var = $opt->[0]; $dev->{$var} = $val; } } foreach my $file (@ARGV) { parse_file $file; } sub json_chr { my $chr = shift; $chr eq "\b" and return "\\b"; $chr eq "\n" and return "\\n"; $chr eq "\r" and return "\\r"; $chr eq "\t" and return "\\t"; $chr eq "\\" and return "\\\\"; $chr eq "\"" and return "\\\""; $chr eq '/' and return "\\/"; return sprintf("\\u%04x", ord($chr)); }; sub json_str { $_[0] =~ s/([\x00- \/"\\])/json_chr($1)/eg; return $_[0]; } sub json_val($$) { my ($val, $type) = (shift, shift); $type eq 'bool' and $val = $val > 0 ? "true" : "false"; $type eq 'string' and $val = "\"$val\""; return $val; } sub dev_opt { my ($val, $name, $type, $sep) = (shift, shift, shift, shift); return unless defined($val); if ($type =~ /array:(.+)/) { $type = $1; my @val = @$val; undef $val; foreach my $elem (@val) { my $json = json_val($elem, $type); next unless defined $json; if (defined $val) { $val = "$val, $json" } else { $val = $json; } } $val = "[ $val ]"; } else { $val = json_val($val, $type); } print "$$sep\t\t\t\t\"".json_str($name)."\": $val"; $$sep = ",\n"; } print < $messages{$b} } keys %messages) { print "$suffix\t\t\"".json_str($msg)."\""; $suffix = ",\n"; } print <{$match}; my $sep = ""; print "$match_sep\t\t\t\"".json_str($match)."\": {\n"; $match_sep = ",\n"; dev_opt($cur->{TargetVendor}, "t_vendor", "int", \$sep); dev_opt($cur->{TargetProduct}, "t_product", "array:int", \$sep); dev_opt($cur->{TargetClass}, "t_class", "int", \$sep); dev_opt($cur->{DetachStorageOnly}, "detach_storage", "bool", \$sep); dev_opt($cur->{Mode}, "mode", "string", \$sep); dev_opt($cur->{ModeValue}, "modeval", "int", \$sep); dev_opt($cur->{NoDriverLoading}, "no_driver", "bool", \$sep); dev_opt($cur->{MessageEndpoint}, "msg_endpoint", "int", \$sep); my $msg = [ $cur->{MessageContent}, $cur->{MessageContent2}, $cur->{MessageContent3} ]; dev_opt($msg, "msg", "array:int", \$sep); dev_opt($cur->{WaitBefore}, "wait", "int", \$sep); dev_opt($cur->{ReleaseDelay}, "release_delay", "int", \$sep); dev_opt($cur->{NeedResponse}, "response", "bool", \$sep); dev_opt($cur->{ResponseEndpoint}, "response_endpoint", "int", \$sep); dev_opt($cur->{ResetUSB}, "reset", "bool", \$sep); dev_opt($cur->{InquireDevice}, "inquire", "int", \$sep); dev_opt($cur->{CheckSuccess}, "check", "bool", \$sep); dev_opt($cur->{Interface}, "interface", "int", \$sep); dev_opt($cur->{Configuration}, "config", "int", \$sep); dev_opt($cur->{AltSetting}, "alt", "int", \$sep); print "\n\t\t\t}"; } print "\n\t\t}" } print <