dtdinstaller/bin/convert_file.pm
changeset 9 58764cb313d3
parent 5 b4183b61e0c7
child 10 621da59dafb4
child 26 a0303864c0d4
equal deleted inserted replaced
5:b4183b61e0c7 9:58764cb313d3
     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/\\"/&quot;/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/&#39;/'/g;    
       
   393     $$string =~ s/&#37\;/\%/g;
       
   394     $$string =~ s/&#38;/&/g;
       
   395     $$string =~ s/&#62;/>/g;
       
   396     $$string =~ s/&#60;/</g;
       
   397 }
       
   398 
       
   399 1;