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__ |