|
@@ -411,6 +411,7 @@ sub usb_device(&) {
|
|
|
|
|
|
my @langlist;
|
|
|
my %lang;
|
|
|
+my @lang_mask = (0xffff, 0x03ff, 0); # Masks for language codes
|
|
|
my $stringdata;
|
|
|
my %stringoffs; # Pointer into stringdata
|
|
|
|
|
@@ -433,23 +434,30 @@ sub usb_string(%) {
|
|
|
my(%strh) = @_;
|
|
|
|
|
|
my $descval = '';
|
|
|
- my @txts = (undef) x scalar(@langlist);
|
|
|
-
|
|
|
- my $found = $strh{''} ne ''; # Default string
|
|
|
+ my %txts;
|
|
|
+ my $found = 0;
|
|
|
|
|
|
foreach my $l (keys(%strh)) {
|
|
|
+ my $str = $strh{$l};
|
|
|
my $co = langid($l);
|
|
|
next unless (defined($co));
|
|
|
- $txts[$lang{$co}] = $strh{$l};
|
|
|
- $found += $strh{$l} ne '';
|
|
|
+
|
|
|
+ foreach my $m (@lang_mask) {
|
|
|
+ my $coi = $co & $m;
|
|
|
+ next unless (defined($lang{$coi}));
|
|
|
+ next if (defined($txts{$coi}));
|
|
|
+ $txts{$coi} = $str;
|
|
|
+ $found++;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return pack('C', 0) unless ($found);
|
|
|
|
|
|
- for (my $i = 0; $i < scalar(@langlist); $i++) {
|
|
|
- my $co = $langlist[$i];
|
|
|
- my $txt = $txts[$i];
|
|
|
- $txt = $strh{''} unless defined($txt);
|
|
|
+ foreach my $co (@langlist) {
|
|
|
+ my $txt;
|
|
|
+ foreach my $m (@lang_mask) {
|
|
|
+ last if (defined($txt = $txts{$co & $m}));
|
|
|
+ }
|
|
|
|
|
|
my $utf16str = $utf16le->encode($txt, Encode::FB_WARN);
|
|
|
unless (defined($stringoffs{$utf16str})) {
|
|
@@ -458,7 +466,7 @@ sub usb_string(%) {
|
|
|
$stringdata .= $utf16str;
|
|
|
}
|
|
|
|
|
|
- $descval .= pack('vv', $co, $stringoffs{$utf16str});
|
|
|
+ $descval .= pack('v', $stringoffs{$utf16str});
|
|
|
}
|
|
|
|
|
|
my $descindex = $strdesci{$descval};
|
|
@@ -516,13 +524,27 @@ sub usb_serial($;$) {
|
|
|
sub usb_languages(@) {
|
|
|
my @langs = @_;
|
|
|
|
|
|
+ # There are two differences between keys(%lang) and @langlist: the
|
|
|
+ # former lists all possible language codes for which a lookup is
|
|
|
+ # possible in no specific order, whereas @langlist is exactly the
|
|
|
+ # items wanted in order in string descriptor zero.
|
|
|
+ #
|
|
|
+ # In other words, %lang is a reverse mapping of langlist, *plus*
|
|
|
+ # permissible aliases.
|
|
|
%lang = ();
|
|
|
@langlist = ();
|
|
|
foreach my $l (@langs) {
|
|
|
my $co = langid($l);
|
|
|
if (defined($co) && !defined($lang{$co})) {
|
|
|
- $lang{$co} = scalar(@langlist);
|
|
|
+ my $nlang = scalar(@langlist);
|
|
|
push(@langlist, $co);
|
|
|
+
|
|
|
+ # Defaults for partial languages?
|
|
|
+ foreach my $m (@lang_mask) {
|
|
|
+ if (!defined($lang{$co & $m})) {
|
|
|
+ $lang{$co & $m} = $nlang;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -576,16 +598,23 @@ sub generate_data()
|
|
|
'len' => unpack('C', substr($stringdata, 0, 1))});
|
|
|
|
|
|
for (my $i = 1; $i < scalar(@strdescs); $i++) {
|
|
|
- my @sds = unpack("v*", $strdescs[$i]);
|
|
|
- while (scalar @sds >= 2) {
|
|
|
- my $co = shift(@sds);
|
|
|
- my $offs = shift(@sds);
|
|
|
+ my @sofs = unpack('v*', $strdescs[$i]);
|
|
|
+ for (my $j = 0; $j < scalar(@sofs); $j++) {
|
|
|
+ my $co = $langlist[$j];
|
|
|
+ my $of = $sofs[$j];
|
|
|
+ my $m = $lang_mask[0];
|
|
|
+
|
|
|
+ # Widen the mask as much as possible
|
|
|
+ foreach my $mx (@lang_mask) {
|
|
|
+ last unless ($lang{$co & $mx} == $lang{$co & $m});
|
|
|
+ $m = $mx;
|
|
|
+ }
|
|
|
|
|
|
push(@ptrs, {'type' => $DT{string}, 'dindex' => $i,
|
|
|
- 'windex' => $co, 'wimask' => 0x03ff, # FIX THIS
|
|
|
- 'offs' => $string_offs + $offs,
|
|
|
- 'len' =>
|
|
|
- unpack('C', substr($stringdata, $offs, 1))});
|
|
|
+ 'windex' => $co & $m,
|
|
|
+ 'wimask' => $m,
|
|
|
+ 'offs' => $string_offs + $of,
|
|
|
+ 'len' => unpack('C', substr($stringdata,$of,1))});
|
|
|
}
|
|
|
}
|
|
|
$data .= $stringdata;
|