1 # |
|
2 # Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 # All rights reserved. |
|
4 # This component and the accompanying materials are made available |
|
5 # under the terms of "Eclipse Public License v1.0" |
|
6 # which accompanies this distribution, and is available |
|
7 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 # |
|
9 # Initial Contributors: |
|
10 # Nokia Corporation - initial contribution. |
|
11 # |
|
12 # Contributors: |
|
13 # |
|
14 # Description: |
|
15 # |
|
16 package Convert_file; |
|
17 |
|
18 # Hash of file meta information (name etc.). |
|
19 my %file_meta_info; |
|
20 |
|
21 # List of logical name entries. |
|
22 my @entries = (); |
|
23 |
|
24 sub convert_file { |
|
25 my $file_to_process = shift; |
|
26 |
|
27 %file_meta_info = (); |
|
28 @entries = (); |
|
29 |
|
30 # Convert LOC file to DTD... |
|
31 if ($file_to_process =~ /\.loc$/) { |
|
32 (my $file_to_write = $file_to_process) =~ s/\.loc$/.dtd/; |
|
33 (my $file_log = $file_to_process) =~ s/\.loc$/.log/; |
|
34 &read_loc_file($file_to_process); |
|
35 &write_dtd_file($file_to_process, $file_to_write, $file_log); |
|
36 } |
|
37 # Convert DTD file to LOC... |
|
38 elsif ($file_to_process =~ /\.dtd$/) { |
|
39 (my $file_to_write = $file_to_process) =~ s/\.dtd$/.loc/; |
|
40 (my $file_log = $file_to_process) =~ s/\.dtd$/.log/; |
|
41 &read_dtd_file($file_to_process); |
|
42 &write_loc_file($file_to_process, $file_to_write, $file_log); |
|
43 } |
|
44 else { |
|
45 print "Unknown file format.\n"; |
|
46 } |
|
47 } |
|
48 |
|
49 # This subroutine reads DTD file into a data structure. Reading is done line |
|
50 # by line. |
|
51 # Adding extra complexity to this subroutine is the fact that ENTITY tag can |
|
52 # either be declared before attribute definitions or after them. |
|
53 sub read_dtd_file { |
|
54 my $file_to_process = shift; |
|
55 |
|
56 open(FILE, $file_to_process) |
|
57 or die "Can't open `$file_to_process' for reading: $!"; |
|
58 |
|
59 my %entry; |
|
60 my $attribute_read = "FALSE"; |
|
61 my $entity_read = "FALSE"; |
|
62 |
|
63 while (my $line = <FILE>) { |
|
64 # NCR notation is used in DTD files. This is removed since it's not |
|
65 # used in LOC files. |
|
66 #&remove_NCR_notation(\$line); |
|
67 chomp($line); |
|
68 |
|
69 SWITCH: { |
|
70 # Extract file meta data. |
|
71 # Matches eg. <FileName: "<name_of_dtd_file>"> |
|
72 if ($line =~ /\s*(<FileName|<PartOf|<FileDescription|<FileVersion)\s*:\s*".[^"]*/) { |
|
73 (my $item_name, my $content) = |
|
74 $line =~ /\s*<(.[^\s]*)\s*:\s*"(.[^"]*)/; |
|
75 $file_meta_info{$item_name} = $content; |
|
76 last SWITCH; |
|
77 } |
|
78 # Matches ENTITY tag eg. |
|
79 # <!ENTITY <logical_name> "<engineering_english_string>"> |
|
80 if ($line =~ /\s*<!ENTITY\s*.[^\s]*\s*".[^"]*/) |
|
81 { |
|
82 # Case entity -> attributes -> entity |
|
83 if ($attribute_read eq "TRUE" && $entity_read eq "TRUE") { |
|
84 my %temp = %entry; |
|
85 %entry = (); |
|
86 push @entries, \%temp; |
|
87 $attribute_read = "FALSE"; |
|
88 $entity_read = "TRUE"; |
|
89 |
|
90 (my $loc_name, my $translation) = |
|
91 $line =~ /\s*<!ENTITY\s*(.[^\s]*)\s*"(.[^"]*)/; |
|
92 |
|
93 $entry{'logical_name'} = $loc_name; |
|
94 $entry{'translation'} = $translation; |
|
95 } |
|
96 # Case attributes -> entity |
|
97 elsif ($attribute_read eq "TRUE" && $entity_read eq "FALSE") { |
|
98 (my $loc_name, my $translation) = |
|
99 $line =~ /\s*<!ENTITY\s*(.[^\s]*)\s*"(.[^"]*)/; |
|
100 |
|
101 $entry{'logical_name'} = $loc_name; |
|
102 $entry{'translation'} = $translation; |
|
103 |
|
104 my %temp = %entry; |
|
105 %entry = (); |
|
106 push @entries, \%temp; |
|
107 $attribute_read = "FALSE"; |
|
108 $entity_read = "FALSE"; |
|
109 } |
|
110 # Case: nothing has been read yet. |
|
111 elsif ($attribute_read eq "FALSE" && $entity_read eq "FALSE") { |
|
112 (my $loc_name, my $translation) = |
|
113 $line =~ /\s*<!ENTITY\s*(.[^\s]*)\s*"(.[^"]*)/; |
|
114 |
|
115 $entry{'logical_name'} = $loc_name; |
|
116 $entry{'translation'} = $translation; |
|
117 $entity_read = "TRUE"; |
|
118 } |
|
119 |
|
120 last SWITCH; |
|
121 } |
|
122 # Matches attributes e.g. |
|
123 # <logical_name>.layout "<layout>" |
|
124 if ($line =~ /\s*.[^\.]*(.layout|.description|.recycled|.release|.grammar|.term|.refers|.islocalizable|.item_type|.action_before|.action_after|.variables|.parents)\s*".[^"]*/) { |
|
125 (my $item_name, my $content) = |
|
126 $line =~ /\s*.[^\.]*.(.[^\s]*)\s*"(.[^"]*)/; |
|
127 |
|
128 $item_name =~ s/parents/Parents/; |
|
129 $item_name =~ s/variables/Variables/; |
|
130 |
|
131 $entry{$item_name} = $content; |
|
132 last SWITCH; |
|
133 } |
|
134 # Matches attribute tag. |
|
135 if ($line =~ /\s*.[^\.]*.attributes/) { |
|
136 # Case: entity -> attributes -> attributes |
|
137 if ($entity_read eq "TRUE" && $attribute_read eq "TRUE") { |
|
138 my %temp = %entry; |
|
139 %entry = (); |
|
140 push @entries, \%temp; |
|
141 $entity_read = "FALSE"; |
|
142 } |
|
143 $attribute_read = "TRUE"; |
|
144 |
|
145 last SWITCH; |
|
146 } |
|
147 } |
|
148 } |
|
149 |
|
150 # Include last entry also to results. This happens if file ends with an |
|
151 # entry where attributes are defined after ENTITY. |
|
152 if ($attribute_read eq "TRUE" && $entity_read eq "TRUE") { |
|
153 my %temp = %entry; |
|
154 %entry = (); |
|
155 push @entries, \%temp; |
|
156 } |
|
157 |
|
158 close FILE; |
|
159 } |
|
160 |
|
161 # This subroutine reads LOC file into a data structure. Reading is done line |
|
162 # by line. |
|
163 sub read_loc_file { |
|
164 my $file_to_process = shift; |
|
165 |
|
166 chmod ($file_to_process, 0777); # Make sure that file can be read, before trying to open it |
|
167 |
|
168 open(FILE, $file_to_process) |
|
169 or die "Can't open `$file_to_process' for reading: $!"; |
|
170 |
|
171 my %entry; |
|
172 |
|
173 while (my $line = <FILE>) { |
|
174 # NCR notation is used in DTD files. Not allowed characters are |
|
175 # converted to NCR. |
|
176 #&add_NCR_notation(\$line); |
|
177 chomp($line); |
|
178 |
|
179 # Each line with #define defines a logical name/translation pair. This |
|
180 # is saved to the data structure. |
|
181 if ($line =~ /\s*#define\s*.[^\s]*\s*".[^"]*/) { |
|
182 (my $item_name, my $content) = |
|
183 $line =~ /\s*#define\s*(.[^\s]*)\s*"(.*)"$/; |
|
184 |
|
185 $entry{'logical_name'} = $item_name; |
|
186 $entry{'translation'} = $content; |
|
187 my %temp = %entry; |
|
188 %entry = (); |
|
189 push @entries, \%temp; |
|
190 } |
|
191 } |
|
192 |
|
193 close FILE; |
|
194 } |
|
195 |
|
196 # This subroutine writes the data into a LOC file. |
|
197 sub write_loc_file { |
|
198 my $file_to_process = shift; |
|
199 my $file_to_write = shift; |
|
200 my $file_log = shift; |
|
201 |
|
202 open(my $file_handle, ">$file_to_write") |
|
203 or die "Can't open `$file_to_write' for writing: $!"; |
|
204 |
|
205 open(my $log_file_handle, ">$file_log") |
|
206 or die "Can't open `$file_log' for writing: $!"; |
|
207 |
|
208 my $tstamp = localtime(time); |
|
209 |
|
210 print $log_file_handle "Log created $tstamp:\n" . |
|
211 "Errors and warnings for conversion of " . |
|
212 "$file_to_process to $file_to_write\n\n"; |
|
213 |
|
214 # Write file header info. Mostly static text. |
|
215 &write_loc_header($file_handle); |
|
216 |
|
217 print $file_handle "\n"; |
|
218 |
|
219 # This array defines the order in which attributes are written to a LOC |
|
220 # file. |
|
221 my @fields = ("item_type", "action_before", "action_after", "grammar", |
|
222 "refers", "Parents", "Variables"); |
|
223 |
|
224 for my $i (0 .. $#entries) { |
|
225 # Analyze entry for correctness and report possible errors. |
|
226 &print_dtd_errors_and_warnings(\%{$entries[$i]}, $log_file_handle); |
|
227 |
|
228 # Seach for attributes and write them to output if found. |
|
229 for my $y (0 .. $#fields) { |
|
230 if (exists($entries[$i]{$fields[$y]})) { |
|
231 print $file_handle |
|
232 "//d: [$fields[$y]] : \"$entries[$i]{$fields[$y]}\"\n"; |
|
233 } |
|
234 } |
|
235 |
|
236 print $file_handle "//d: $entries[$i]{'description'}\n"; |
|
237 print $file_handle "//l: $entries[$i]{'layout'}\n"; |
|
238 print $file_handle "//r: $entries[$i]{'release'}\n"; |
|
239 |
|
240 print $file_handle "#define $entries[$i]{'logical_name'}" . |
|
241 " \"$entries[$i]{'translation'}\"\n\n"; |
|
242 } |
|
243 |
|
244 close $file_handle; |
|
245 close $log_file_handle; |
|
246 } |
|
247 |
|
248 sub print_dtd_errors_and_warnings { |
|
249 my $entry_ref = shift; |
|
250 my $log_file_handle = shift; |
|
251 |
|
252 # Either description or item_type and action_before should be defined. |
|
253 if (!exists($entry_ref->{'description'}) && |
|
254 !(exists($entry_ref->{'item_type'}) && |
|
255 exists($entry_ref->{'action_before'}))) |
|
256 { |
|
257 print $log_file_handle "ERROR: $entry_ref->{'logical_name'} " . |
|
258 "does not have any description data!\n"; |
|
259 } |
|
260 if (!exists($entry_ref->{'layout'})) { |
|
261 print $log_file_handle "ERROR: $entry_ref->{'logical_name'} " . |
|
262 "missing layout definition!\n"; |
|
263 } |
|
264 if (!exists($entry_ref->{'release'})) { |
|
265 print $log_file_handle "ERROR: $entry_ref->{'logical_name'} " . |
|
266 "missing release information!\n"; |
|
267 } |
|
268 if (!exists($entry_ref->{'Parents'})) { |
|
269 print $log_file_handle "ERROR: $entry_ref->{'logical_name'} " . |
|
270 "missing parent reference!\n"; |
|
271 } |
|
272 # Grammar should be defined if translation is a single word. |
|
273 if (!($entry_ref->{'translation'} =~ /\s/) && |
|
274 !exists($entry_ref->{'grammar'})) { |
|
275 print $log_file_handle "\tWARNING: $entry_ref->{'logical_name'} " . |
|
276 "is a single word, but no grammar data is " . |
|
277 "given!\n"; |
|
278 } |
|
279 # Variables should be defined if translation contains variables. |
|
280 if ($entry_ref->{'translation'} =~ /\%/ && |
|
281 !exists($entry_ref->{'Variables'})) { |
|
282 print $log_file_handle "\tWARNING: $entry_ref->{'logical_name'} " . |
|
283 "has a variable or parameter, but no variable " . |
|
284 "data is given!\n"; |
|
285 } |
|
286 } |
|
287 |
|
288 # This subroutine writes the data into a DTD file. Only ENTITY definitions are |
|
289 # written i.e. no attribute definitions. |
|
290 sub write_dtd_file { |
|
291 my $file_to_process = shift; |
|
292 my $file_to_write = shift; |
|
293 my $file_log = shift; |
|
294 |
|
295 open(my $file_handle, ">$file_to_write") |
|
296 or die "Can't open `$file_to_write' for writing: $!"; |
|
297 |
|
298 open(my $log_file_handle, ">$file_log") |
|
299 or die "Can't open `$file_log' for writing: $!"; |
|
300 |
|
301 my $tstamp = localtime(time); |
|
302 |
|
303 print $log_file_handle "Log created $tstamp:\n" . |
|
304 "Errors and warnings for conversion of " . |
|
305 "$file_to_process to $file_to_write\n\n"; |
|
306 |
|
307 # Write file header info. Mostly static text. |
|
308 my $file_name = ""; |
|
309 if ($file_to_process =~ /\//) { |
|
310 ($file_name) = $file_to_process =~ /\/(.[^\/]*)$/; |
|
311 } |
|
312 else { |
|
313 $file_name = $file_to_process; |
|
314 } |
|
315 &write_dtd_header($file_handle, $file_name); |
|
316 |
|
317 for my $i (0 .. $#entries) { |
|
318 print $log_file_handle "Found $entries[$i]{'logical_name'}\n"; |
|
319 |
|
320 $entries[$i]{'translation'} =~ s/\\"/"/g; |
|
321 |
|
322 print $file_handle "<!ENTITY $entries[$i]{'logical_name'}" . |
|
323 " \"$entries[$i]{'translation'}\">\n"; |
|
324 } |
|
325 |
|
326 close $file_handle; |
|
327 close $log_file_handle; |
|
328 } |
|
329 |
|
330 sub write_loc_header { |
|
331 my $file_handle = shift; |
|
332 print $file_handle <<EOT; |
|
333 CHARACTER_SET UTF8 |
|
334 // This file is best viewed with a non-proportian font, such as Courier |
|
335 // Or copied into a spreadsheet application. |
|
336 /* |
|
337 * ============================================================================ |
|
338 * Name : $file_meta_info{'FileName'} |
|
339 * Part Of : $file_meta_info{'PartOf'} |
|
340 * Version : $file_meta_info{'FileVersion'} |
|
341 * |
|
342 * Description : $file_meta_info{'FileDescription'} |
|
343 * |
|
344 * Copyright © 2005 Nokia Corporation. This material, including |
|
345 * documentation and any related computer programs, is protected by |
|
346 * copyright controlled by Nokia Corporation. All rights are reserved. |
|
347 * Copying, including reproducing, storing, adapting or translating, any |
|
348 * or all of this material requires the prior written consent of Nokia |
|
349 * Corporation. This material also contains confidential information |
|
350 * which may not be disclosed to others without the prior written consent |
|
351 * of Nokia Corporation. |
|
352 * ============================================================================ |
|
353 */ |
|
354 EOT |
|
355 } |
|
356 |
|
357 sub write_dtd_header { |
|
358 my $file_handle = shift; |
|
359 my $file_to_process = shift; |
|
360 |
|
361 my $tstamp = localtime(time); |
|
362 |
|
363 print $file_handle <<EOT; |
|
364 <?xml version="1.0" encoding="UTF-8"?> |
|
365 <!-- |
|
366 DTD file generated from $file_to_process |
|
367 $tstamp |
|
368 by LocDTDConverter |
|
369 --> |
|
370 EOT |
|
371 } |
|
372 |
|
373 # Subroutine to add NCR notation to string. |
|
374 sub add_NCR_notation { |
|
375 my $string = shift; |
|
376 # Replace characters with NCR notation. 'eh' is used to denote &# character |
|
377 # sequence. If this is not used then &# sequence would be also replaced with |
|
378 # NCR. |
|
379 $$string =~ s/'/eh39;/g; |
|
380 $$string =~ s/\%/eh37;/g; |
|
381 $$string =~ s/>/eh62;/g; |
|
382 $$string =~ s/</eh60;/g; |
|
383 $$string =~ s/&/eh38;/g; |
|
384 |
|
385 $$string =~ s/eh(\d{2});/&#$1;/g; |
|
386 } |
|
387 |
|
388 # Subroutine to remove NCR notation from a string. |
|
389 sub remove_NCR_notation { |
|
390 my $string = shift; |
|
391 |
|
392 $$string =~ s/'/'/g; |
|
393 $$string =~ s/%\;/\%/g; |
|
394 $$string =~ s/&/&/g; |
|
395 $$string =~ s/>/>/g; |
|
396 $$string =~ s/</</g; |
|
397 } |
|
398 |
|
399 1; |
|