【发布时间】:2014-03-22 23:51:44
【问题描述】:
我正在尝试从 Perl 中的 Civilization 2 savegame 文件中读取轮数。我有一个很草率的解决方案,但一定有更优雅的解决方案。
它们以两个字节的形式存储在偏移量 28 和 29(0x1C,0X1D)处。对于小于 256 的匝数,仅使用第一个字节 (0x1C)。对于更高的匝数,使用第二个字节。奇怪的是,它们似乎与我的预期相反。即第300圈存储为0x2C,0x01。这让我很难解析它们。
我糟糕(但有效)的解决方案是将每个字符串读取为字节,将每个字符串转换为十六进制字符串,使用正则表达式替换将字符串操作为正确的顺序,然后将此十六进制字符串转换回十进制值。这太糟糕了,我真的很尴尬;因此我想知道如何做得更好。
我的代码:
use Fcntl qw(:seek);
sub get_savegame_turn_number($);
sub read_file_hexdata_at_offset($$$);
sub get_savegame_turn_number($) {
my ($filename) = @_;
my $byteA = read_file_hexdata_at_offset($filename, 28, 1);
my $byteB = read_file_hexdata_at_offset($filename, 29, 1);
my $byteAhex = sprintf("%#02x", ord($byteA));
my $byteBhex = sprintf("%#02x", ord($byteB));
$byteAhex =~ s/^0x//;
my $bytestring = $byteBhex . $byteAhex;
return hex($bytestring);
}
sub read_file_hexdata_at_offset($$$) {
my ($filename, $byte_position, $length) = @_;
my($fh, $byte_value);
open($fh, "<", $filename)
|| die "can't open $filename: $!";
binmode($fh)
|| die "can't binmode $filename";
sysseek($fh, $byte_position, SEEK_CUR) # NB: 0-based
|| die "couldn't see to byte $byte_position in $filename: $!";
sysread($fh, $byte_value, $length) == $length
|| die "couldn't read byte from $filename: $!";
return $byte_value;
}
【问题讨论】:
-
关于工作的问题(但可能很混乱)通常属于 [代码审查](codereview.stackexchange.com/)。不过,这似乎是一个很好的问题。
标签: perl