File Coverage

blib/lib/Games/Rezrov/QChunk.pm
Criterion Covered Total %
statement 29 88 32.9
branch 4 18 22.2
condition n/a
subroutine 10 23 43.4
pod 0 22 0.0
total 43 151 28.4


line stmt bran cond sub pod time code
1             package Games::Rezrov::QChunk;
2              
3 1     1   5 use strict;
  1         2  
  1         974  
4              
5             #use SelfLoader;
6             #use Carp qw(confess);
7             1;
8              
9             #__DATA__
10              
11             sub new {
12 12     12 0 2574 my ($type, $chunk_type) = @_;
13 12         29 my $self = {};
14 12         39 bless $self, $type;
15 12 50       54 $self->id($chunk_type) if $chunk_type;
16 12         29 my $buf = "";
17 12         32 $self->buffer(\$buf);
18 12         40 return $self;
19             }
20              
21             sub pointer {
22             # return the current pointer position.
23             # with argument, increments the pointer that number of bytes
24             # (does NOT affect return value).
25 0 0   0 0 0 if (defined $_[1]) {
26 0         0 my $value = $_[0]->{"pointer"};
27 0         0 $_[0]->{"pointer"} = $value + $_[1];
28 0         0 return $value;
29             } else {
30 0         0 return $_[0]->{"pointer"};
31             }
32             }
33              
34             sub load {
35             # load a chunk from file.
36 0     0 0 0 my ($self, $fh) = @_;
37 0         0 $self->id(read_chunk_id($fh));
38 0         0 my $len = read_int_4($fh);
39 0         0 $self->reset_read_pointer();
40 0         0 my $buf;
41 0         0 my $read = read($fh, $buf, $len);
42 0 0       0 if ($read != $len) {
43             # error
44 0         0 print STDERR "Read $read, expected $len\n";
45 0         0 return -1;
46             } else {
47 0         0 $self->buffer(\$buf);
48             }
49 0         0 return $len;
50             }
51              
52             sub read_chunk_id {
53 0     0 0 0 my ($fh) = @_;
54 0         0 my $buf;
55 0         0 read($fh, $buf, 4);
56 0         0 return $buf;
57             }
58              
59             sub read_int_4 {
60             # read a signed 4-byte int
61 0     0 0 0 my ($fh) = @_;
62 0         0 my $buf;
63 0         0 read($fh, $buf, 4);
64 0         0 return unpack 'N', $buf;
65             }
66              
67             sub get_word {
68             # 1.2: 16-bit unsigned
69 0     0 0 0 my ($self) = @_;
70 0         0 my $buffer = $self->buffer();
71 0         0 my $pointer = $self->pointer(2);
72 0         0 my $result = unpack "x${pointer}n", $$buffer;
73             # $self->pointer($pointer + 2);
74 0         0 return $result;
75             }
76              
77             sub get_byte {
78             # get a single byte, incrementing pointer
79 0     0 0 0 return unpack "x" . $_[0]->pointer(1) . "C", ${$_[0]->buffer()};
  0         0  
80             }
81              
82             sub get_word_3 {
83 0     0 0 0 my ($self) = @_;
84 0         0 return ($self->get_byte() << 16 | $self->get_byte() << 8 | $self->get_byte());
85             }
86              
87             sub get_string {
88 0     0 0 0 my ($self, $length) = @_;
89 0         0 my $buffer = $self->buffer();
90 0         0 my $pointer = $self->pointer();
91 0         0 my $result = unpack "x${pointer}a$length", $$buffer;
92             # $self->pointer($pointer + $length);
93 0         0 $self->pointer($length);
94 0         0 return $result;
95             }
96              
97             sub reset_read_pointer {
98 12     12 0 234 $_[0]->{"pointer"} = 0;
99             }
100              
101             sub eof {
102             # return true if pointer at end of data
103 0 0   0 0 0 return ($_[0]->pointer() >= length(${$_[0]->buffer()}) ? 1 : 0);
  0         0  
104             }
105              
106             sub id {
107 12 50   12 0 66 return (defined $_[1] ? $_[0]->{"id"} = $_[1] : $_[0]->{"id"});
108             }
109              
110             sub buffer {
111 12 50   12 0 45 return (defined $_[1] ? $_[0]->{"buffer"} = $_[1] : $_[0]->{"buffer"});
112             }
113              
114             sub add_byte {
115 126     126 0 337 my $buf = $_[0]->{"buffer"};
116 126         296 $$buf .= pack 'C', $_[1];
117             }
118              
119             sub add_word {
120 269     269 0 1328 my ($self, $value) = @_;
121 269         448 my $buf = $_[0]->{"buffer"};
122             # confess unless defined $value;
123 269         853 $$buf .= pack 'n', $value;
124             }
125              
126             sub add_string {
127 4     4 0 10 my ($self, $value, $length) = @_;
128 4         13 my $buf = $_[0]->{"buffer"};
129 4 50       14 die if length($value) > $length;
130 4         27 $$buf .= sprintf "%${length}s", $value;
131             }
132              
133             sub add_word_3 {
134             # add a 3-byte unsigned word
135 23     23 0 112 my ($self, $value) = @_;
136 23         62 $self->add_byte($value >> 16 & 0xff);
137 23         50 $self->add_byte($value >> 8 & 0xff);
138 23         52 $self->add_byte($value & 0xff);
139             }
140              
141             sub add_data {
142             # add an arbitrary chunk
143 4     4 0 155 my ($self, $value) = @_;
144 4         147 my $buf = $_[0]->{"buffer"};
145 4         71 $$buf .= $value;
146             }
147              
148             sub get_chunk_length {
149             # return length of chunk, including id, byte count, and any required pad
150 0     0 0   my ($self) = @_;
151 0           my $buf = $self->buffer();
152 0           my $size = length $$buf;
153 0           return $size + 4 + 4 + ($size % 2);
154             # 4 for byte count, 4 for ID, plus optional pad byte
155             }
156              
157             sub get_data_length {
158             # return length of just the data
159 0     0 0   return length(${$_[0]->buffer()});
  0            
160             }
161              
162             sub get_data {
163             # return all data
164 0     0 0   return $_[0]->buffer();
165             }
166              
167             sub write {
168             # write this chunk to stream
169 0     0 0   my ($self, $fh) = @_;
170            
171 0           my ($i, $len, $data_len);
172            
173 0           my $buf = $self->buffer();
174 0           $data_len = length $$buf;
175            
176             # write chunk id:
177 0           my $id = $self->id();
178 0 0         die if length($id) != 4;
179 0           print $fh $id;
180            
181             # write data size (any pad is not included in length)
182 0           print $fh pack('N', $data_len);
183            
184 0           print $fh $$buf;
185            
186 0 0         if ($data_len % 2) {
187             # pad byte required; spec 8.4.1
188 0           print $fh pack('C', 0);
189             }
190             }
191              
192             1;