| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Palm::PalmDoc; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
700
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
52
|
|
|
4
|
1
|
|
|
1
|
|
6
|
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
2968
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
require Exporter; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
|
9
|
|
|
|
|
|
|
@EXPORT = qw(); |
|
10
|
|
|
|
|
|
|
$VERSION = '0.13'; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# Palm::PalmDoc Constructor |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub new { |
|
15
|
0
|
|
|
0
|
1
|
|
my $proto = shift; |
|
16
|
0
|
|
0
|
|
|
|
my $class = ref($proto) || $proto; |
|
17
|
0
|
|
|
|
|
|
my $self = {}; |
|
18
|
0
|
|
|
|
|
|
$self->{TITLE} = "PalmDoc Document"; |
|
19
|
0
|
|
|
|
|
|
$self->{INFILE} = undef; |
|
20
|
0
|
|
|
|
|
|
$self->{OUTFILE} = undef; |
|
21
|
0
|
|
|
|
|
|
$self->{INFILEH} = undef; |
|
22
|
0
|
|
|
|
|
|
$self->{OUTFILEH} = undef; |
|
23
|
0
|
|
|
|
|
|
$self->{BODY} = undef; |
|
24
|
0
|
|
|
|
|
|
$self->{COMPRESS} = 0; |
|
25
|
0
|
|
|
|
|
|
$self->{BLOCK_SIZE} = []; |
|
26
|
0
|
|
|
|
|
|
$self->{IGNORENL} = 0; |
|
27
|
0
|
|
|
|
|
|
bless($self,$class); |
|
28
|
0
|
0
|
|
|
|
|
if (@_) |
|
29
|
0
|
|
|
|
|
|
{ my $ref = shift; |
|
30
|
0
|
|
|
|
|
|
my %params = (); |
|
31
|
0
|
0
|
|
|
|
|
if (ref $ref eq 'ARRAY') |
|
32
|
0
|
|
|
|
|
|
{ %params = @{$ref}; } |
|
|
0
|
|
|
|
|
|
|
|
33
|
0
|
0
|
|
|
|
|
if (ref $ref eq 'HASH') |
|
34
|
0
|
|
|
|
|
|
{ %params = %{$ref}; } |
|
|
0
|
|
|
|
|
|
|
|
35
|
0
|
0
|
|
|
|
|
if (ref $ref eq '') |
|
36
|
0
|
|
|
|
|
|
{ unshift @_,$ref; |
|
37
|
0
|
0
|
|
|
|
|
if (!(@_ % 2)) |
|
38
|
0
|
|
|
|
|
|
{ %params = @_; } |
|
39
|
|
|
|
|
|
|
} |
|
40
|
0
|
|
|
|
|
|
foreach (keys %params) { my $tkey = uc $_; my $tvalue = $params{$_}; delete $params{$_}; $params{$tkey} = $tvalue; } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
41
|
0
|
0
|
|
|
|
|
$self->infile($params{INFILE}) if exists $params{INFILE}; |
|
42
|
0
|
0
|
|
|
|
|
$self->outfile($params{OUTFILE}) if exists $params{OUTFILE}; |
|
43
|
0
|
0
|
|
|
|
|
$self->title($params{TITLE}) if exists $params{TITLE}; |
|
44
|
0
|
0
|
|
|
|
|
$self->compression($params{COMPRESS}) if exists $params{COMPRESS}; |
|
45
|
0
|
0
|
|
|
|
|
$self->ignorenl($params{IGNORENL}) if exists $params{IGNORENL}; |
|
46
|
0
|
0
|
|
|
|
|
$self->body($params{BODY}) if exists $params{BODY}; |
|
47
|
0
|
|
|
|
|
|
$self->compressed(0); |
|
48
|
|
|
|
|
|
|
} |
|
49
|
0
|
|
|
|
|
|
return $self; |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub body { |
|
53
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
54
|
0
|
0
|
|
|
|
|
if (@_) { |
|
55
|
0
|
|
|
|
|
|
$self->{BODY} = shift; |
|
56
|
0
|
0
|
|
|
|
|
if ($self->ignorenl) |
|
57
|
0
|
|
|
|
|
|
{ my @body = split(/\n/, $self->{BODY}); |
|
58
|
0
|
|
|
|
|
|
my $sep = ""; |
|
59
|
0
|
|
|
|
|
|
$self->{BODY} = ""; |
|
60
|
0
|
|
|
|
|
|
foreach (@body) |
|
61
|
0
|
0
|
|
|
|
|
{ if (/^\s*$/) |
|
62
|
0
|
|
|
|
|
|
{ $self->{BODY} .= "\n"; |
|
63
|
0
|
|
|
|
|
|
$sep = ""; |
|
64
|
|
|
|
|
|
|
} else |
|
65
|
0
|
|
|
|
|
|
{ $self->{BODY} .= "$sep$_"; |
|
66
|
0
|
|
|
|
|
|
$sep = " "; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
} |
|
69
|
0
|
0
|
|
|
|
|
if ($sep eq " ") |
|
70
|
0
|
|
|
|
|
|
{ $self->{BODY} .= "\n"; } |
|
71
|
|
|
|
|
|
|
} |
|
72
|
0
|
|
|
|
|
|
$self->length(CORE::length $self->{BODY}); |
|
73
|
0
|
0
|
0
|
|
|
|
if ($self->compression && !$self->compressed) { $self->compressed(1); $self->{BODY} = $self->compr_text($self->{BODY}); } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
} |
|
75
|
0
|
|
|
|
|
|
return($self->{BODY}); |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub length { |
|
79
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
80
|
0
|
0
|
|
|
|
|
if (@_) { $self->{LENGTH} = shift; } |
|
|
0
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
|
return($self->{LENGTH}); |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub title { |
|
85
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
86
|
0
|
0
|
|
|
|
|
if (@_) { $self->{TITLE} = shift; } |
|
|
0
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
|
return($self->{TITLE}); |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub compression { |
|
91
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
92
|
0
|
0
|
|
|
|
|
if (@_) { $self->{COMPRESS} = shift @_ ? 1 : 0; } |
|
|
0
|
0
|
|
|
|
|
|
|
93
|
0
|
|
|
|
|
|
return($self->{COMPRESS}); |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub compressed { |
|
97
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
98
|
0
|
0
|
|
|
|
|
if (@_) { $self->{COMPRESSED} = shift @_ ? 1 : 0; } |
|
|
0
|
0
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
|
return($self->{COMPRESSED}); |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub ignorenl { |
|
103
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
104
|
0
|
0
|
|
|
|
|
if (@_) { $self->{IGNORENL} = shift @_ ? 1 : 0; } |
|
|
0
|
0
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
|
return($self->{IGNORENL}); |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub infile { |
|
110
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
111
|
0
|
0
|
|
|
|
|
if (@_) |
|
112
|
0
|
|
|
|
|
|
{ $self->{INFILE} = shift; |
|
113
|
0
|
|
|
|
|
|
$self->{INFILE} =~ s/([;\`'\\\|"*~<>^\(\)\[\]\{\}\$\n\r\0\t\s])//g; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
0
|
|
|
|
|
|
return($self->{INFILE}); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub outfile { |
|
119
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
120
|
0
|
0
|
|
|
|
|
if (@_) { |
|
121
|
0
|
|
|
|
|
|
$self->{OUTFILE} = shift; |
|
122
|
0
|
|
|
|
|
|
$self->{OUTFILE} =~ s/([;\`'\\\|"*~<>^\(\)\[\]\{\}\$\n\r\0\t\s])//g; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
0
|
|
|
|
|
|
return($self->{OUTFILE}); |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub parse_from_file { |
|
128
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
129
|
0
|
0
|
|
|
|
|
$self->infile(shift) if @_; |
|
130
|
0
|
0
|
|
|
|
|
$self->outfile(shift) if @_; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub parse_from_filehandle { |
|
134
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
135
|
0
|
|
|
|
|
|
($self->{INFILEH},$self->{OUTFILEH}) = @_; |
|
136
|
0
|
|
0
|
|
|
|
$self->{INFILEH} ||= \*STDIN; |
|
137
|
0
|
|
0
|
|
|
|
$self->{OUTFILEH} ||= \*STDOUT; |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub read_text { |
|
141
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
142
|
0
|
0
|
|
|
|
|
if ($self->infile) |
|
143
|
0
|
0
|
|
|
|
|
{ open (IN, "<".$self->infile) || die "Can't open ".$self->infile.": $!\n"; |
|
144
|
0
|
|
|
|
|
|
{ local $/ = undef; |
|
|
0
|
|
|
|
|
|
|
|
145
|
0
|
|
|
|
|
|
$self->body(); |
|
146
|
|
|
|
|
|
|
} |
|
147
|
0
|
|
|
|
|
|
close (IN); |
|
148
|
0
|
0
|
0
|
|
|
|
if ($self->{INFILEH} && !$self->infile) |
|
149
|
0
|
|
|
|
|
|
{ local $/ = undef; |
|
150
|
0
|
|
|
|
|
|
$self->body(); |
|
151
|
|
|
|
|
|
|
} |
|
152
|
0
|
0
|
0
|
|
|
|
$self->{INFILEH} and close($self->{INFILEH}) || die "Can't close input filehandle after reading: $!"; |
|
153
|
0
|
0
|
0
|
|
|
|
if ($self->compression && !$self->compressed) { $self->compressed(1); $self->body($self->compr_text($self->body)); } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
|
return ($self->body); |
|
155
|
0
|
|
|
|
|
|
} else { return(0); } |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub write_text { |
|
159
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
160
|
0
|
0
|
|
|
|
|
if ($self->body) |
|
161
|
0
|
0
|
|
|
|
|
{ if ($self->outfile) |
|
162
|
0
|
0
|
|
|
|
|
{ open (OUT,">".$self->outfile) || die "Can't open ".$self->outfile.": $!\n"; |
|
163
|
0
|
|
|
|
|
|
binmode(OUT); |
|
164
|
0
|
|
|
|
|
|
print OUT $self->pdb_header(),$self->body; |
|
165
|
0
|
|
|
|
|
|
close (OUT); |
|
166
|
|
|
|
|
|
|
} |
|
167
|
0
|
0
|
0
|
|
|
|
if ($self->{OUTFILEH} && !$self->outfile) |
|
168
|
0
|
|
|
|
|
|
{ binmode($self->{OUTFILEH}); |
|
169
|
0
|
|
|
|
|
|
my $foo = $self->{OUTFILEH}; |
|
170
|
0
|
|
|
|
|
|
print $foo $self->pdb_header,$self->body; |
|
171
|
0
|
0
|
0
|
|
|
|
$self->{OUTFILEH} and close($self->{OUTFILEH}) || die "Can't close output filehandle after reading: $!"; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
0
|
|
|
|
|
|
return (1); |
|
174
|
0
|
|
|
|
|
|
} else { return(0); } |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub pdb_header { |
|
178
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
179
|
0
|
|
|
|
|
|
my $COUNT_BITS = 3; |
|
180
|
0
|
|
|
|
|
|
my $DISP_BITS = 11; |
|
181
|
0
|
|
|
|
|
|
my $DOC_CREATOR = "REAd"; |
|
182
|
0
|
|
|
|
|
|
my $DOC_TYPE = "TEXt"; |
|
183
|
0
|
|
|
|
|
|
my $RECORD_SIZE_MAX = 4096; # 4k record size |
|
184
|
0
|
|
|
|
|
|
my $dmDBNameLength = 32; # 31 chars + 1 null |
|
185
|
|
|
|
|
|
|
|
|
186
|
0
|
|
|
|
|
|
my $pdb_rec_offset; # PDB record offset |
|
187
|
0
|
|
|
|
|
|
my $header_buff = ""; # Temporary buffer to build the headers in. |
|
188
|
0
|
|
|
|
|
|
my $x; |
|
189
|
|
|
|
|
|
|
my $y; |
|
190
|
0
|
|
|
|
|
|
my $pdb_header_size = 78; |
|
191
|
0
|
|
|
|
|
|
my $pdb_attributes = 0; |
|
192
|
0
|
|
|
|
|
|
my $pdb_version = 0; |
|
193
|
0
|
|
|
|
|
|
my $pdb_create_time = 0x11111111; # Palm Desktop demands |
|
194
|
0
|
|
|
|
|
|
my $pdb_modify_time = 0x11111111; # a timestamp. |
|
195
|
0
|
|
|
|
|
|
my $pdb_backup_time = 0; |
|
196
|
0
|
|
|
|
|
|
my $pdb_modificationNumber = 0; |
|
197
|
0
|
|
|
|
|
|
my $pdb_appInfoID = 0; |
|
198
|
0
|
|
|
|
|
|
my $pdb_sortInfoID = 0; |
|
199
|
0
|
|
|
|
|
|
my $pdb_type = $DOC_TYPE; |
|
200
|
0
|
|
|
|
|
|
my $pdb_creator = $DOC_CREATOR; |
|
201
|
0
|
|
|
|
|
|
my $pdb_id_seed = 0; |
|
202
|
0
|
|
|
|
|
|
my $pdb_id_nextRecordList = 0; |
|
203
|
0
|
|
|
|
|
|
my $pdb_numRecords = (int ($self->length / 4096)) + 2; # +1 for record 0 |
|
204
|
|
|
|
|
|
|
# +1 for fractional part |
|
205
|
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
my $pdb_header = pack("a32nnNNNNNNa4a4NNn",substr($self->title,0,31)."\0",$pdb_attributes, |
|
207
|
|
|
|
|
|
|
$pdb_version,$pdb_create_time, |
|
208
|
|
|
|
|
|
|
$pdb_modify_time,$pdb_backup_time, |
|
209
|
|
|
|
|
|
|
$pdb_modificationNumber,$pdb_appInfoID, |
|
210
|
|
|
|
|
|
|
$pdb_sortInfoID,$pdb_type,$pdb_creator, |
|
211
|
|
|
|
|
|
|
$pdb_id_seed,$pdb_id_nextRecordList, |
|
212
|
|
|
|
|
|
|
$pdb_numRecords); |
|
213
|
|
|
|
|
|
|
|
|
214
|
0
|
0
|
|
|
|
|
if ( (CORE::length $pdb_header) != 78) { die "pdb_header malformed\n"; } |
|
|
0
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
my $doc_header_size = 16; |
|
217
|
0
|
|
|
|
|
|
my $doc_version = 1 + $self->compression; |
|
218
|
0
|
|
|
|
|
|
my $reserved1 = 0; |
|
219
|
0
|
|
|
|
|
|
my $doc_doc_size = $self->length; |
|
220
|
0
|
|
|
|
|
|
my $doc_rec_size = 4096; |
|
221
|
0
|
|
|
|
|
|
my $doc_num_recs = (int ($self->length / 4096)) + 1; |
|
222
|
0
|
|
|
|
|
|
my $doc_reserved2 = 0; |
|
223
|
|
|
|
|
|
|
|
|
224
|
0
|
|
|
|
|
|
my $doc_header = pack("nnNnnN",$doc_version,$reserved1,$doc_doc_size, |
|
225
|
|
|
|
|
|
|
$doc_num_recs,$doc_rec_size,$doc_reserved2); |
|
226
|
|
|
|
|
|
|
|
|
227
|
0
|
0
|
|
|
|
|
if ( (CORE::length $doc_header) != 16) { die "doc_header malformed\n"; } |
|
|
0
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
my $pdb_rec_header_size = 8; |
|
230
|
0
|
|
|
|
|
|
my $pdb_rec_attributes = 0x40; # We'll fake this, 0x40 = 'dirty' |
|
231
|
0
|
|
|
|
|
|
my $pdb_rec_uniqueID = 0x3D0; # Simple increment |
|
232
|
|
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
|
my $pdb_rec_header_template = "Nccn"; |
|
234
|
|
|
|
|
|
|
|
|
235
|
0
|
|
|
|
|
|
$pdb_rec_offset = $pdb_header_size + |
|
236
|
|
|
|
|
|
|
(($pdb_numRecords)* $pdb_rec_header_size) + 2; |
|
237
|
|
|
|
|
|
|
|
|
238
|
0
|
|
|
|
|
|
$header_buff = $pdb_header . pack($pdb_rec_header_template, |
|
239
|
|
|
|
|
|
|
$pdb_rec_offset, $pdb_rec_attributes, |
|
240
|
|
|
|
|
|
|
ord('a'),$pdb_rec_uniqueID ); |
|
241
|
0
|
|
|
|
|
|
$pdb_rec_offset += $doc_header_size; # Add offset for doc_header |
|
242
|
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
for ($x = 0; $x < $pdb_numRecords - 1; $x++) { |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# if ($x > 0 ) |
|
246
|
|
|
|
|
|
|
# { $self->{BLOCK_SIZE}[$x] = $RECORD_SIZE_MAX; } |
|
247
|
|
|
|
|
|
|
|
|
248
|
0
|
|
|
|
|
|
$pdb_rec_offset += $self->{BLOCK_SIZE}[$x]; |
|
249
|
0
|
|
|
|
|
|
++$pdb_rec_uniqueID; |
|
250
|
0
|
|
|
|
|
|
$header_buff .= pack($pdb_rec_header_template,$pdb_rec_offset, |
|
251
|
|
|
|
|
|
|
$pdb_rec_attributes,ord('a'),$pdb_rec_uniqueID); |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
|
|
254
|
0
|
|
|
|
|
|
$header_buff .= 0x00 . 0x00; |
|
255
|
|
|
|
|
|
|
|
|
256
|
0
|
|
|
|
|
|
$header_buff .= $doc_header; |
|
257
|
|
|
|
|
|
|
|
|
258
|
0
|
|
|
|
|
|
return ($header_buff); |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
sub compr_text { |
|
262
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
263
|
0
|
|
|
|
|
|
my $total_compr_size = 0; # Final compressed text size |
|
264
|
0
|
|
|
|
|
|
my $compr_buff = ""; # Temporary output buffer |
|
265
|
0
|
|
|
|
|
|
my $numrecords = (int($self->{LENGTH} / 4096) +1); # Number of blocks to compress. |
|
266
|
0
|
|
|
|
|
|
my $x; |
|
267
|
|
|
|
|
|
|
my $y; |
|
268
|
0
|
|
|
|
|
|
my $block_offset; |
|
269
|
0
|
|
|
|
|
|
my $block; # Contains the current 4096 byte block of text |
|
270
|
0
|
|
|
|
|
|
my $block_len; # Length of current block |
|
271
|
0
|
|
|
|
|
|
my $index; # Current scan position in block |
|
272
|
0
|
|
|
|
|
|
my $byte; # Char at index (for space + char compression) |
|
273
|
0
|
|
|
|
|
|
my $byte2; # Char at index+1 |
|
274
|
0
|
|
|
|
|
|
my $test; # Potentially compressible text for |
|
275
|
|
|
|
|
|
|
# LZ77 compression. |
|
276
|
|
|
|
|
|
|
|
|
277
|
0
|
|
|
|
|
|
my $frag_size; # Current size of above |
|
278
|
0
|
|
|
|
|
|
my $frag_size2; # Spare for lazy byte compression |
|
279
|
0
|
|
|
|
|
|
my $test2; # spare for above |
|
280
|
0
|
|
|
|
|
|
my $test3; # second spare |
|
281
|
0
|
|
|
|
|
|
my $pos; # Position (in $block) of reference text |
|
282
|
|
|
|
|
|
|
# for $test |
|
283
|
|
|
|
|
|
|
# to compress against. |
|
284
|
|
|
|
|
|
|
|
|
285
|
0
|
|
|
|
|
|
my $pos2; # spare for above |
|
286
|
0
|
|
|
|
|
|
my $pos3; # second spare |
|
287
|
0
|
|
|
|
|
|
my $back; # $index - pos |
|
288
|
0
|
|
|
|
|
|
my $mask; # Bitwise mask to do LZ77 'magic' |
|
289
|
0
|
|
|
|
|
|
my $compr_ratio; # Compression ratio |
|
290
|
0
|
|
|
|
|
|
my $done; |
|
291
|
0
|
|
|
|
|
|
my $comp_block_offset = 0; # The $compr_buff index |
|
292
|
|
|
|
|
|
|
# block begins. |
|
293
|
0
|
|
|
|
|
|
my $FRAG_MAX = 10; # Max LZ77 fragment size |
|
294
|
0
|
|
|
|
|
|
my $FRAG_MIN = 3; # Min LZ77 fragment size |
|
295
|
0
|
|
|
|
|
|
my $LAZY_BYTE_FRAG = $FRAG_MAX + $FRAG_MIN - 1; |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
|
|
298
|
0
|
|
|
|
|
|
$self->{BLOCK_SIZE}[0] = 0; # Record 0 is already written and |
|
299
|
|
|
|
|
|
|
# is not compressed. |
|
300
|
0
|
|
|
|
|
|
for ($x = 1; $x <= $numrecords; $x++) { |
|
301
|
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
$block_offset = ($x - 1) * 4096; |
|
303
|
0
|
|
|
|
|
|
$block = substr($_[0],$block_offset, 4096); |
|
304
|
0
|
0
|
|
|
|
|
if ($x >= $numrecords) { # Last block |
|
305
|
0
|
|
|
|
|
|
$block = substr($block,0,($self->{LENGTH} % 4096)); |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
} |
|
308
|
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
|
$block_len = CORE::length($block); |
|
310
|
|
|
|
|
|
|
|
|
311
|
0
|
|
|
|
|
|
$index = 0; |
|
312
|
|
|
|
|
|
|
|
|
313
|
0
|
|
|
|
|
|
while ( $index < $block_len ) { |
|
314
|
|
|
|
|
|
|
|
|
315
|
0
|
|
|
|
|
|
$byte = substr($block,$index,1); # Char at $index |
|
316
|
0
|
0
|
|
|
|
|
if ($byte =~ /[\200-\377]/) { # is high bit set? |
|
317
|
|
|
|
|
|
|
|
|
318
|
0
|
|
|
|
|
|
$y = 1; # found at least one! |
|
319
|
|
|
|
|
|
|
|
|
320
|
0
|
|
0
|
|
|
|
while ( (substr($block,$index + $y ,1) =~ |
|
321
|
|
|
|
|
|
|
/[\200-\377]/) && |
|
322
|
|
|
|
|
|
|
($y < 8) ) { |
|
323
|
|
|
|
|
|
|
|
|
324
|
0
|
|
|
|
|
|
++$y; # If found, increment counter |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
|
|
328
|
0
|
|
|
|
|
|
$compr_buff .= chr($y); # Write escape code |
|
329
|
0
|
|
|
|
|
|
$compr_buff .= substr($block,$index,$y); # Write text |
|
330
|
0
|
|
|
|
|
|
$index += $y; # Increment the index |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
} else { # Real compression routines |
|
333
|
|
|
|
|
|
|
|
|
334
|
0
|
|
|
|
|
|
$frag_size = $FRAG_MIN; # We don't care about anything less |
|
335
|
|
|
|
|
|
|
|
|
336
|
0
|
|
|
|
|
|
$test = substr($block,$index,$frag_size); # pull the current fragment |
|
337
|
0
|
|
|
|
|
|
$pos = rindex($block, $test, $index - 1); # check against the buffer |
|
338
|
|
|
|
|
|
|
|
|
339
|
0
|
0
|
0
|
|
|
|
if ( ($pos > 0) && |
|
|
|
|
0
|
|
|
|
|
|
340
|
|
|
|
|
|
|
($index - $pos <= 2047) && # Inside our 2047 byte window |
|
341
|
|
|
|
|
|
|
( $index < $block_len - $frag_size) ) { |
|
342
|
|
|
|
|
|
|
|
|
343
|
0
|
|
|
|
|
|
for ($y = 4; $y <= $FRAG_MAX; $y++ ) { |
|
344
|
0
|
|
|
|
|
|
++$frag_size ; |
|
345
|
0
|
|
|
|
|
|
$test2 = substr($block,$index,$frag_size); |
|
346
|
0
|
|
|
|
|
|
$pos2 = rindex($block, $test2, $index - 1); |
|
347
|
0
|
0
|
0
|
|
|
|
if (($pos2 > 0) && |
|
|
|
|
0
|
|
|
|
|
|
348
|
|
|
|
|
|
|
($index - $pos2 <= 2047) && |
|
349
|
|
|
|
|
|
|
($index < $block_len - $frag_size) ) { |
|
350
|
|
|
|
|
|
|
# found a match! |
|
351
|
0
|
|
|
|
|
|
$pos = $pos2; |
|
352
|
0
|
|
|
|
|
|
$test = $test2; |
|
353
|
|
|
|
|
|
|
} else { # no match, go back |
|
354
|
0
|
|
|
|
|
|
--$frag_size; |
|
355
|
0
|
|
|
|
|
|
last; |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
} |
|
360
|
|
|
|
|
|
|
# Sanity check |
|
361
|
0
|
0
|
|
|
|
|
if ($frag_size > $FRAG_MAX) |
|
362
|
0
|
|
|
|
|
|
{ die "frag_size too big!!!: $frag_size\n"; } |
|
363
|
|
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
|
$frag_size2 = $frag_size + 2; |
|
365
|
0
|
|
|
|
|
|
$test2 = substr($block,$index + 1, $frag_size2); |
|
366
|
0
|
|
|
|
|
|
$pos2 = rindex($block, $test2, $index - 1); |
|
367
|
0
|
0
|
0
|
|
|
|
if (($pos2 > 0) && |
|
|
|
|
0
|
|
|
|
|
|
368
|
|
|
|
|
|
|
($index - $pos2 <= 2047) && |
|
369
|
|
|
|
|
|
|
($index < $block_len - $frag_size2) ) { |
|
370
|
|
|
|
|
|
|
|
|
371
|
0
|
|
|
|
|
|
for ($y = $frag_size2;$y <= $LAZY_BYTE_FRAG; |
|
372
|
|
|
|
|
|
|
$y++ ) { # Look for more |
|
373
|
0
|
|
|
|
|
|
++$frag_size2; |
|
374
|
0
|
|
|
|
|
|
$test2 = substr($block,$index + 1, $frag_size2); |
|
375
|
0
|
|
|
|
|
|
$pos2 = rindex($block, $test2, $index - 1); |
|
376
|
0
|
0
|
0
|
|
|
|
if (($pos2 > 0) && |
|
|
|
|
0
|
|
|
|
|
|
377
|
|
|
|
|
|
|
($index - $pos2 <= 2047) && |
|
378
|
|
|
|
|
|
|
($index < $block_len - $frag_size2) ) { |
|
379
|
|
|
|
|
|
|
# found a match! |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
} else { # no match, go back |
|
382
|
0
|
|
|
|
|
|
--$frag_size2; |
|
383
|
0
|
|
|
|
|
|
last; |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
} |
|
386
|
|
|
|
|
|
|
} |
|
387
|
0
|
0
|
|
|
|
|
if ($frag_size2 < $LAZY_BYTE_FRAG) { |
|
388
|
|
|
|
|
|
|
|
|
389
|
0
|
|
|
|
|
|
$pos = 0; |
|
390
|
0
|
|
|
|
|
|
$compr_buff .= substr($block,$index,1); |
|
391
|
0
|
|
|
|
|
|
++$index; |
|
392
|
|
|
|
|
|
|
} |
|
393
|
|
|
|
|
|
|
} |
|
394
|
|
|
|
|
|
|
|
|
395
|
0
|
0
|
|
|
|
|
if ($pos > 0) { # Did we abort the compression? |
|
396
|
|
|
|
|
|
|
|
|
397
|
0
|
|
|
|
|
|
$back = $index - $pos; |
|
398
|
0
|
|
|
|
|
|
$mask = 0x8000 | int($frag_size - 3); |
|
399
|
|
|
|
|
|
|
|
|
400
|
0
|
|
|
|
|
|
$compr_buff .= pack("n",int($back << 3) | $mask); |
|
401
|
0
|
|
|
|
|
|
$index += $frag_size; |
|
402
|
|
|
|
|
|
|
} |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
} else { |
|
405
|
|
|
|
|
|
|
|
|
406
|
0
|
|
|
|
|
|
$byte = substr($block,$index,1); # Char at $index |
|
407
|
0
|
|
|
|
|
|
$byte2 = substr($block,$index + 1,1); # next char as well |
|
408
|
0
|
0
|
0
|
|
|
|
if ( ($byte eq " ") && |
|
|
|
|
0
|
|
|
|
|
|
409
|
|
|
|
|
|
|
($byte2 =~ /[\100-\176]/ ) && |
|
410
|
|
|
|
|
|
|
($index <= $block_len - 1)) { |
|
411
|
|
|
|
|
|
|
# Got a space + char |
|
412
|
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
# Set the high bit |
|
414
|
|
|
|
|
|
|
# and add to output |
|
415
|
|
|
|
|
|
|
# buffer. |
|
416
|
0
|
|
|
|
|
|
$compr_buff .= pack("C", ord ($byte2) | 0x80 ); |
|
417
|
0
|
|
|
|
|
|
$index += 2; # Compressed 2 bytes |
|
418
|
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
} else { |
|
420
|
0
|
|
|
|
|
|
$compr_buff .= $byte; # No compression |
|
421
|
0
|
|
|
|
|
|
++$index; |
|
422
|
|
|
|
|
|
|
} |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
} |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
0
|
|
|
|
|
|
$self->{BLOCK_SIZE}[$x] = (CORE::length ($compr_buff)) - $total_compr_size; |
|
428
|
0
|
|
|
|
|
|
$total_compr_size = CORE::length ($compr_buff); |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
} |
|
431
|
|
|
|
|
|
|
|
|
432
|
0
|
|
|
|
|
|
return ($compr_buff); |
|
433
|
|
|
|
|
|
|
} |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
1; |
|
437
|
|
|
|
|
|
|
__END__ |