File Coverage

blib/lib/ICC/Profile/mluc.pm
Criterion Covered Total %
statement 72 127 56.6
branch 7 52 13.4
condition 0 18 0.0
subroutine 11 14 78.5
pod 1 7 14.2
total 91 218 41.7


line stmt bran cond sub pod time code
1             package ICC::Profile::mluc;
2              
3 2     2   122947 use strict;
  2         14  
  2         54  
4 2     2   9 use Carp;
  2         4  
  2         130  
5              
6             our $VERSION = 0.13;
7              
8             # revised 2019-06-30
9             #
10             # Copyright © 2004-2019 by William B. Birkett
11              
12             # add development directory
13 2     2   496 use lib 'lib';
  2         646  
  2         13  
14              
15             # inherit from Shared
16 2     2   257 use parent qw(ICC::Shared);
  2         4  
  2         13  
17              
18             # support modules
19 2     2   665 use Encode; # Unicode module
  2         9993  
  2         2460  
20              
21             # create new mluc tag object
22             # use 'text' or 'array' methods to add additional entries
23             # parameters: ()
24             # parameters: (language_code, country_code, text)
25             # returns: (ref_to_object)
26             sub new {
27              
28             # get object class
29 1     1 0 1088 my $class = shift();
30            
31             # create empty mluc object
32 1         4 my $self = [
33             {}, # object header
34             12, # name record size
35             [] # array of name records
36             ];
37            
38             # if three parameters
39 1 50       7 if (@_ == 3) {
    50          
40            
41             # verify country and language codes
42 0 0 0     0 (length($_[0]) == 2 && length($_[1]) == 2) or croak('country or language code wrong length');
43            
44             # add name record
45 0         0 $self->[2][0] = [$_[0], $_[1], 0, 0, $_[2]];
46            
47             } elsif (@_) {
48            
49             # error
50 0         0 croak("wrong number parameters\n");
51            
52             }
53              
54             # bless object
55 1         3 bless($self, $class);
56              
57             # return object reference
58 1         3 return($self);
59              
60             }
61              
62             # create mluc tag object from ICC profile
63             # parameters: (ref_to_parent_object, file_handle, ref_to_tag_table_entry)
64             # returns: (ref_to_object)
65             sub new_fh {
66              
67             # get object class
68 1     1 0 781 my $class = shift();
69              
70             # create empty mluc object
71 1         3 my $self = [
72             {}, # object header
73             0, # name record size
74             [] # array of name records
75             ];
76              
77             # verify 3 parameters
78 1 50       4 (@_ == 3) or croak('wrong number of parameters');
79              
80             # read mluc data from profile
81 1         5 _readICCmluc($self, @_);
82              
83             # bless object
84 1         2756 bless($self, $class);
85              
86             # return object reference
87 1         10 return($self);
88              
89             }
90              
91             # writes mluc tag object to ICC profile
92             # parameters: (ref_to_parent_object, file_handle, ref_to_tag_table_entry)
93             sub write_fh {
94              
95             # verify 4 parameters
96 1 50   1 0 1251 (@_ == 4) or croak('wrong number of parameters');
97              
98             # write mluc data to profile
99 1         4 goto &_writeICCmluc;
100              
101             }
102              
103             # get tag size (for writing to profile)
104             # returns: (tag_size)
105             sub size {
106            
107             # get parameters
108 3     3 0 685 my ($self) = @_;
109            
110             # local variables
111 3         5 my ($text);
112            
113             # if count > 0
114 3 50       5 if (@{$self->[2]}) {
  3         13  
115            
116             # initialize text size
117 3         5 $text = 0;
118            
119             # for each name record
120 3         5 for my $rec (@{$self->[2]}) {
  3         6  
121            
122             # add text string size
123 3         8 $text += length($rec->[4]);
124            
125             }
126            
127             # return size (after Unicode encoding)
128 3         5 return(16 + @{$self->[2]} * 12 + $text * 2);
  3         29  
129            
130             } else {
131            
132             # return size
133 0         0 return(12);
134            
135             }
136            
137             }
138              
139             # get/set name record array reference
140             # parameters: ([ref_to_new_array])
141             # returns: (ref_to_array)
142             sub array {
143              
144             # get object reference
145 0     0 0 0 my $self = shift();
146              
147             # if one parameter supplied
148 0 0       0 if (@_ == 1) {
    0          
149            
150             # get array reference
151 0         0 my $array = shift();
152            
153             # verify parameter (2-D array)
154 0 0 0     0 (ref($array) eq 'ARRAY' && @{$array} == grep {ref($_) eq 'ARRAY'} @{$array}) or croak('invalid parameter');
  0         0  
  0         0  
  0         0  
155            
156             # init name record array
157 0         0 $self->[2] = [];
158            
159             # for each entry
160 0         0 for my $i (0 .. $#{$array}) {
  0         0  
161            
162             # verify entry
163 0 0 0     0 (@{$array->[$i]} == 5 && 5 == grep {! ref($_)} @{$array->[$i]}) or croak('invalid record entry');
  0         0  
  0         0  
  0         0  
164            
165             # verify country and language codes
166 0 0 0     0 (length($array->[$i][0]) == 2 && length($array->[$i][1]) == 2) or croak('country or language code wrong length');
167            
168             # add name record
169 0         0 $self->[2][$i] = [@{$array->[$i]}];
  0         0  
170            
171             }
172            
173             } elsif (@_) {
174            
175             # error
176 0         0 croak("too many parameters\n");
177            
178             }
179              
180             # return array reference
181 0         0 return($self->[2]);
182              
183             }
184              
185             # get/set Unicode mluc string
186             # updates text if language/country found
187             # otherwise, adds new table entry
188             # parameters: (language_code, country_code, [text])
189             # returns: (mluc_string)
190             sub text {
191              
192             # get parameters
193 0     0 0 0 my $self = shift();
194              
195             # local variables
196 0         0 my (@match);
197              
198             # if two parameters (get)
199 0 0       0 if (@_ == 2) {
    0          
200            
201             # return if name record count = 0
202 0 0       0 return if (@{$self->[2]} == 0);
  0         0  
203            
204             # match country and language codes
205 0 0       0 @match = grep {$_->[1] eq $_[1] && $_->[0] eq $_[0]} @{$self->[2]};
  0         0  
  0         0  
206            
207             # match country code
208 0 0       0 @match = grep {$_->[1] eq $_[1]} @{$self->[2]} if (@match == 0);
  0         0  
  0         0  
209              
210             # match language code
211 0 0       0 @match = grep {$_->[0] eq $_[0]} @{$self->[2]} if (@match == 0);
  0         0  
  0         0  
212            
213             # use first name record
214 0 0       0 @match = ($self->[2][0]) if (@match == 0);
215            
216             # return name record string
217 0         0 return($match[0][4]);
218            
219             # if three parameters (set)
220             } elsif (@_ == 3) {
221            
222             # match country and language codes
223 0 0       0 @match = grep {($_->[1] eq $_[1]) && ($_->[0] eq $_[0])} @{$self->[2]};
  0         0  
  0         0  
224            
225             # if match found
226 0 0       0 if (@match) {
227            
228             # set name record text
229 0         0 $match[0][4] = $_[2];
230            
231             } else {
232            
233             # verify country and language codes
234 0 0 0     0 (length($_[0]) == 2 && length($_[1]) == 2) or croak('country or language code wrong length');
235            
236             # add new name record
237 0         0 push(@{$self->[2]}, [$_[0], $_[1], 0, 0, $_[2]]);
  0         0  
238            
239             }
240            
241             # return name record string
242 0         0 return($_[2]);
243            
244             } else {
245            
246             # warning message
247 0         0 carp('wrong number of parameters');
248            
249             }
250            
251             }
252              
253             # print object contents to string
254             # format is an array structure
255             # parameter: ([format])
256             # returns: (string)
257             sub sdump {
258              
259             # get parameters
260 0     0 1 0 my ($self, $p) = @_;
261              
262             # local variables
263 0         0 my ($s, $fmt);
264              
265             # resolve parameter to an array reference
266 0 0       0 $p = defined($p) ? ref($p) eq 'ARRAY' ? $p : [$p] : [];
    0          
267              
268             # get format string
269 0 0 0     0 $fmt = defined($p->[0]) && ! ref($p->[0]) ? $p->[0] : 'undef';
270              
271             # set string to object ID
272 0         0 $s = sprintf("'%s' object, (0x%x)\n", ref($self), $self);
273              
274             # return
275 0         0 return($s);
276              
277             }
278              
279             # read mluc tag from ICC profile
280             # parameters: (ref_to_object, ref_to_parent_object, file_handle, ref_to_tag_table_entry)
281             sub _readICCmluc {
282            
283             # get parameters
284 1     1   4 my ($self, $parent, $fh, $tag) = @_;
285            
286             # local variables
287 1         2 my ($buf, $cnt);
288            
289             # save tag signature
290 1         3 $self->[0]{'signature'} = $tag->[0];
291            
292             # seek start of tag
293 1         12 seek($fh, $tag->[1], 0);
294            
295             # read type sig and count
296 1         11 read($fh, $buf, 12);
297            
298             # unpack name record count
299 1         4 $cnt = unpack('x8 N', $buf);
300            
301             # return if count = 0
302 1 50       4 return if ($cnt == 0);
303            
304             # read name record size
305 1         2 read($fh, $buf, 4);
306            
307             # unpack name record size
308 1         3 $self->[1] = unpack('N', $buf);
309            
310             # for each name record
311 1         4 for my $i (0 .. $cnt - 1) {
312            
313             # read name record
314 1         3 read($fh, $buf, $self->[1]);
315            
316             # unpack language/country codes, length and offset
317 1         6 $self->[2][$i] = [unpack('a2 a2 N N', $buf)];
318            
319             }
320            
321             # for each name record
322 1         2 for my $rec (@{$self->[2]}) {
  1         3  
323            
324             # seek text string
325 1         11 seek($fh, $tag->[1] + $rec->[3], 0);
326            
327             # read text string
328 1         10 read($fh, $buf, $rec->[2]);
329            
330             # save decoded Unicode data
331 1         7 $rec->[4] = decode('UTF-16BE', $buf);
332            
333             }
334            
335             }
336              
337             # write mluc tag to ICC profile
338             # parameters: (ref_to_object, ref_to_parent_object, file_handle, ref_to_tag_table_entry)
339             sub _writeICCmluc {
340              
341             # get parameters
342 1     1   4 my ($self, $parent, $fh, $tag) = @_;
343              
344             # local variables
345 1         2 my ($cnt, $offset);
346              
347             # get name record count
348 1         3 $cnt = @{$self->[2]};
  1         3  
349              
350             # seek start of tag
351 1         9 seek($fh, $tag->[1], 0);
352              
353             # write type sig and count
354 1         21 print $fh pack('a4 x4 N', 'mluc', $cnt);
355              
356             # return if count = 0
357 1 50       6 return if ($cnt == 0);
358              
359             # write name record size
360 1         4 print $fh pack('N', $self->[1]);
361              
362             # compute initial text string offset
363 1         3 $offset = 16 + $cnt * 12;
364              
365             # for each name record
366 1         3 for my $rec (@{$self->[2]}) {
  1         4  
367            
368             # write language/country codes, length and offset
369 1         3 print $fh pack('a2 a2 N N', @{$rec}[0 .. 1], length($rec->[4]) * 2, $offset);
  1         5  
370            
371             # update offset
372 1         3 $offset += length($rec->[4]) * 2;
373            
374             }
375            
376             # for each name record
377 1         2 for my $rec (@{$self->[2]}) {
  1         3  
378            
379             # write the Unicode string
380 1         5 print $fh encode('UTF-16BE', $rec->[4]);
381            
382             }
383            
384             }
385              
386             1;