File Coverage

blib/lib/Games/Rezrov/ZText.pm
Criterion Covered Total %
statement 59 59 100.0
branch 28 30 93.3
condition 1 3 33.3
subroutine 7 7 100.0
pod 0 2 0.0
total 95 101 94.0


line stmt bran cond sub pod time code
1             package Games::Rezrov::ZText;
2             # text decoder
3              
4 1     1   6 use Carp qw(cluck);
  1         4  
  1         74  
5 1     1   8 use strict;
  1         1  
  1         37  
6              
7 1     1   6 use Games::Rezrov::StoryFile;
  1         3  
  1         24  
8 1     1   6 use Games::Rezrov::Inliner;
  1         2  
  1         21  
9              
10 1     1   6 use constant SPACE => 32;
  1         2  
  1         330  
11              
12             my @alpha_table = (
13             [ 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' ],
14             [ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' ],
15             [ '_','^','0','1','2','3','4','5','6','7','8','9','.',',','!','?','_','#','\'','"','/','\\','-',':','(',')' ]
16             );
17              
18             my $INLINE_CODE = '
19             sub decode_text {
20             my ($self, $address, $buf_ref) = @_;
21             # decode and return text at this address; see spec section 3
22             # in array context, returns address after decoding.
23             my $buffer = "";
24             $buf_ref = \$buffer unless ($buf_ref);
25             # $buf_ref supplied if called recursively
26              
27             my ($word, $zshift, $zchar);
28             my $alphabet = 0;
29             my $abbreviation = 0;
30             my $two_bit_code = 0;
31             my $two_bit_flag = 0;
32             # spec 3.4
33             my $zh = Games::Rezrov::StoryFile::header();
34             my $flen = $zh->file_length();
35            
36             while (1) {
37             last if $address >= $flen;
38             $word = GET_WORD_AT($address);
39             $address += 2;
40             # spec 3.2
41             for ($zshift = 10; $zshift >= 0; $zshift -= 5) {
42             # break word into 3 zcharacters of 5 bytes each
43             $zchar = ($word >> $zshift) & 0x1f;
44             if ($two_bit_flag > 0) {
45             # spec 3.4
46             if ($two_bit_flag++ == 1) {
47             $two_bit_code = $zchar << 5; # first 5 bits
48             } else {
49             $two_bit_code |= $zchar; # last 5
50             # $receiver->write_zchar($two_bit_code);
51             $$buf_ref .= chr($two_bit_code);
52             $two_bit_code = $two_bit_flag = 0;
53             # done
54             }
55             } elsif ($abbreviation) {
56             # synonym/abbreviation; spec 3.3
57             my $entry = (32 * ($abbreviation - 1)) + $zchar;
58             # print STDERR "abbrev $abbreviation\n";
59             my $addr = $zh->get_abbreviation_addr($entry);
60             $self->decode_text($addr, $buf_ref);
61             $abbreviation = 0;
62             } elsif ($zchar < 6) {
63             if ($zchar == 0) {
64             # $receiver->write_zchar(SPACE);
65             $$buf_ref .= " ";
66             } elsif ($zchar == 4) {
67             # spec 3.2.3: shift character; alphabet 1
68             $alphabet = 1;
69             } elsif ($zchar == 5) {
70             # spec 3.2.3: shift character; alphabet 2
71             $alphabet = 2;
72             } elsif ($zchar >= 1 && $zchar <= 3) {
73             # spec 3.3: next zchar is an abbreviation code
74             $abbreviation = $zchar;
75             }
76             } else {
77             # spec 3.5: convert remaining chars from alpha table
78             $zchar -= 6;
79             # convert to string index
80             if ($alphabet < 2) {
81             $$buf_ref .= $alpha_table[$alphabet]->[$zchar];
82             } else {
83             # alphabet 2; some special cases (3.5.3)
84             if ($zchar == 0) {
85             $two_bit_flag = 1;
86             } elsif ($zchar == 1) {
87             $$buf_ref .= chr(Games::Rezrov::ZConst::Z_NEWLINE());
88             } else {
89             $$buf_ref .= $alpha_table[$alphabet]->[$zchar];
90             }
91             }
92             $alphabet = 0;
93             # applies to this character only (3.2.3)
94             }
95             # unset temp flags!
96             }
97             last if (($word & 0x8000) > 0);
98             }
99            
100             # print STDERR "dc at $address = \"$buffer\"\n";
101             return wantarray ? (\$buffer, $address) : \$buffer;
102             }
103             ';
104              
105             Games::Rezrov::Inliner::inline(\$INLINE_CODE);
106 1024 100 33 1024 0 2193 eval $INLINE_CODE;
  1024 50       1689  
  1024 100       3006  
  1024 100       1364  
  1024 100       1343  
  1024 100       1193  
  1024 50       1023  
  1024 100       954  
  1024 100       3383  
  1024 100       42296  
  1024 100       1398  
  2938 100       6308  
  2938 100       5356  
  2938 100       2938  
  2938 100       6925  
  8814         25442  
  8814         26476  
  6         15  
  3         8  
  3         5  
  3         8  
  3         12  
  190         316  
  190         1033  
  190         503  
  190         564  
  2450         6833  
  589         1381  
  338         781  
  1332         3201  
  191         448  
  6168         6843  
  6168         10418  
  6006         12484  
  162         386  
  3         5  
  6         15  
  153         436  
  6168         15148  
  2938         6764  
  1024         12841  
107             undef $INLINE_CODE;
108              
109             sub new {
110 72     72 0 156 my $self = [];
111 72         217 bless $self, shift;
112 72         3202 return $self;
113             }
114              
115             1;