File Coverage

blib/lib/ICC/Profile/mluc.pm
Criterion Covered Total %
statement 69 124 55.6
branch 7 52 13.4
condition 0 18 0.0
subroutine 10 13 76.9
pod 1 7 14.2
total 87 214 40.6


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