-
Notifications
You must be signed in to change notification settings - Fork 1
/
Bitmap.pm
executable file
·124 lines (121 loc) · 3.04 KB
/
Bitmap.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package Bitmap;
use strict;
use warnings;
use Carp;
sub new {
my $a= (@_>1) ? $_[1] : "";
return bless \$a, $_[0];
}
sub set {
vec(${$_[0]}, ($_[1]&~7)+(7-($_[1]&7)), 1)=1;
}
sub test {
return vec(${$_[0]}, ($_[1]&~7)+(7-($_[1]&7)), 1);
}
sub size {
return 8*length(${$_[0]});
}
# sets inclusive range: $bitmap->set_range(first, last)
sub set_range {
my $bit;
if ($_[1]&7) {
for ($bit=$_[1] ; $bit < ($_[1]|7)+1 && $bit <= $_[2] ; $bit++)
{
$_[0]->set($bit);
}
}
else {
$bit=$_[1];
}
my $last;
if (($_[2]&7)!=7) {
for ($last=$_[2] ; $last >= ($_[2]&~7) && $last >=$_[1] ; $last--)
{
$_[0]->set($last);
}
}
else {
$last=$_[2];
$_[0]->set($last);
}
if ($bit < $last) {
substr(${$_[0]}, $bit/8, ($last+1-$bit)/8) = "\xff" x (($last+1-$bit)/8);
}
# $_[0]->set($_) for ($_[1]..$_[2]);
}
sub load {
my $bitmapfile= $_[1];
local $/;
open BM, "<$bitmapfile" or croak "$bitmapfile:$!\n";
binmode BM;
${$_[0]} = <BM>;
close BM;
}
sub readfromhandle {
my $hbitmap= $_[1];
$hbitmap->seek(0, 0);
my $ofs=0;
while (!$hbitmap->eof()) {
my $data;
$hbitmap->read($data, 0x100000);
substr(${$_[0]}, $ofs, length($data))= $data;
$ofs += length($data);
}
}
sub save {
my $bitmapfile= $_[1];
open BM, ">$bitmapfile" or croak "$bitmapfile:$!\n";
binmode BM;
print BM ${$_[0]};
close BM;
}
sub setblock { substr(${$_[0]}, $_[1], length($_[2]))= $_[2]; }
sub xor { return Bitmap->new(${$_[0]} ^ ${$_[1]}); }
sub or { return Bitmap->new(${$_[0]} | ${$_[1]}); }
sub and { return Bitmap->new(${$_[0]} & ${$_[1]}); }
sub clear { return Bitmap->new(${$_[0]} & ~${$_[1]}); }
sub negate { ${$_[0]} = ~${$_[0]}; }
sub add { ${$_[0]} |= ${$_[1]}; }
# todo:
# - add total calc
# - add skip \xff+ sequences
sub dump {
my $start;
my $notfirst;
for (my $bit=0 ; $bit<$_[0]->size() ; $bit++) {
if (($bit&7)==0) {
# skip to next non-nul byte
pos(${$_[0]})=$bit/8;
if (defined $start) {
if (${$_[0]}=~ /\G\xFF+/g) {
$bit=pos(${$_[0]})*8;
}
}
else {
if (${$_[0]}=~ /\G\x00+/g) {
$bit=pos(${$_[0]})*8;
}
}
}
if ($_[0]->test($bit)) {
if (!defined $start) {
$start= $bit;
}
}
else {
if (defined $start) {
printf(", ") if ($notfirst);
$notfirst=1;
if ($start==$bit-1) {
printf("%08x", $start);
}
else {
printf("%08x-%08x", $start, $bit-1);
}
}
undef $start;
}
}
}
# todo: implement range_iterate
1;