1 /*
   2  * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  */
  28 
  29 /*
  30         Currently javac and load() method in java.util.Properties
  31         supports only Latin1 encoding input.
  32         But in Asian platforms programmer or message translator
  33         uses the editor which support othere than latin1 encoding
  34         to specify their native language string.
  35         So if programmer or message translator wants to use other than
  36         Latin1 character in his/her program source or properties file
  37         they must convert the file to ASCII plus \udddd notation.
  38         (javac/load() modification is not appropriate due to
  39          time constraints for JDK1.1)
  40         This utility is for the purpose of that conversion.
  41 
  42     NAME
  43         native2ascii - convert native encoding file to ascii file
  44                        include \udddd Unicode notation
  45 
  46     SYNOPSIS
  47         native2ascii [options] [inputfile [outputfile]]
  48 
  49     DESCRIPTION
  50         If outputfile is not described standard output is used as
  51         output file, and if inputfile is not also described
  52         stardard input is used as input file.
  53 
  54         Options
  55 
  56         -reverse
  57            convert ascii with \udddd notation to native encoding
  58 
  59         -encoding encoding_name
  60            Specify the encoding name which is used by conversion.
  61            8859_[1 - 9], JIS, EUCJIS, SJIS is currently supported.
  62            Default encoding is taken from System property "file.encoding".
  63 
  64 */
  65 
  66 package sun.tools.native2ascii;
  67 
  68 import java.io.*;
  69 import java.util.*;
  70 import java.text.MessageFormat;
  71 import java.nio.charset.CharsetEncoder;
  72 import java.nio.charset.Charset;
  73 import java.nio.charset.IllegalCharsetNameException;
  74 import java.nio.file.Files;
  75 import java.io.UnsupportedEncodingException;
  76 import java.nio.charset.UnsupportedCharsetException;
  77 import sun.tools.native2ascii.A2NFilter;
  78 import sun.tools.native2ascii.N2AFilter;
  79 
  80 /**
  81  * Main program of the native2ascii
  82  */
  83 
  84 public class Main {
  85 
  86     String inputFileName = null;
  87     String outputFileName = null;
  88     File tempFile = null;
  89     boolean reverse = false;
  90     static String encodingString = null;
  91     static String defaultEncoding = null;
  92     static CharsetEncoder encoder = null;
  93 
  94     /**
  95      * Run the converter
  96      */
  97     public synchronized boolean convert(String argv[]){
  98         List<String> v = new ArrayList<>(2);
  99         File outputFile = null;
 100         boolean createOutputFile = false;
 101 
 102         // Parse arguments
 103         for (int i = 0; i < argv.length; i++) {
 104             if (argv[i].equals("-encoding")) {
 105                 if ((i + 1) < argv.length){
 106                     encodingString = argv[++i];
 107                 } else {
 108                     error(getMsg("err.bad.arg"));
 109                     usage();
 110                     return false;
 111                 }
 112             } else if (argv[i].equals("-reverse")){
 113                 reverse = true;
 114             } else {
 115                 if (v.size() > 1) {
 116                     usage();
 117                     return false;
 118                 }
 119                 v.add(argv[i]);
 120             }
 121         }
 122         if (encodingString == null)
 123            defaultEncoding = Charset.defaultCharset().name();
 124 
 125         char[] lineBreak = System.getProperty("line.separator").toCharArray();
 126         try {
 127             initializeConverter();
 128 
 129             if (v.size() == 1)
 130                 inputFileName = v.get(0);
 131 
 132             if (v.size() == 2) {
 133                 inputFileName = v.get(0);
 134                 outputFileName = v.get(1);
 135                 createOutputFile = true;
 136             }
 137 
 138             if (createOutputFile) {
 139                 outputFile = new File(outputFileName);
 140                     if (outputFile.exists() && !outputFile.canWrite()) {
 141                         throw new Exception(formatMsg("err.cannot.write", outputFileName));
 142                     }
 143             }
 144 
 145             if (reverse){
 146                 BufferedReader reader = getA2NInput(inputFileName);
 147                 Writer osw = getA2NOutput(outputFileName);
 148                 String line;
 149 
 150                 while ((line = reader.readLine()) != null) {
 151                     osw.write(line.toCharArray());
 152                     osw.write(lineBreak);
 153                     if (outputFileName == null) { // flush stdout
 154                         osw.flush();
 155                     }
 156                 }
 157                 reader.close();  // Close the stream.
 158                 osw.close();
 159             } else {
 160              //N2A
 161                 String inLine;
 162                 BufferedReader in = getN2AInput(inputFileName);
 163                 BufferedWriter out = getN2AOutput(outputFileName);
 164 
 165                 while ((inLine = in.readLine()) != null) {
 166                     out.write(inLine.toCharArray());
 167                     out.write(lineBreak);
 168                     if (outputFileName == null) { // flush stdout
 169                         out.flush();
 170                     }
 171                 }
 172                 out.close();
 173             }
 174             // Since we are done rename temporary file to desired output file
 175             if (createOutputFile) {
 176                 if (outputFile.exists()) {
 177                     // Some win32 platforms can't handle atomic
 178                     // rename if source and target file paths are
 179                     // identical. To make things simple we just unconditionally
 180                     // delete the target file before calling renameTo()
 181                     outputFile.delete();
 182                 }
 183                 tempFile.renameTo(outputFile);
 184             }
 185 
 186         } catch(Exception e){
 187             error(e.toString());
 188             return false;
 189         }
 190 
 191         return true;
 192     }
 193 
 194     private void error(String msg){
 195         System.out.println(msg);
 196     }
 197 
 198     private void usage(){
 199         System.out.println(getMsg("usage"));
 200     }
 201 
 202 
 203     private BufferedReader getN2AInput(String inFile) throws Exception {
 204 
 205         InputStream forwardIn;
 206         if (inFile == null)
 207             forwardIn = System.in;
 208         else {
 209             File f = new File(inFile);
 210             if (!f.canRead()){
 211                 throw new Exception(formatMsg("err.cannot.read", f.getName()));
 212             }
 213 
 214             try {
 215                  forwardIn = new FileInputStream(inFile);
 216             } catch (IOException e) {
 217                throw new Exception(formatMsg("err.cannot.read", f.getName()));
 218             }
 219         }
 220 
 221         BufferedReader r = (encodingString != null) ?
 222             new BufferedReader(new InputStreamReader(forwardIn,
 223                                                      encodingString)) :
 224             new BufferedReader(new InputStreamReader(forwardIn));
 225         return r;
 226     }
 227 
 228 
 229     private BufferedWriter getN2AOutput(String outFile) throws Exception {
 230         Writer output;
 231         BufferedWriter n2aOut;
 232 
 233         if (outFile == null)
 234             output = new OutputStreamWriter(System.out,"US-ASCII");
 235 
 236         else {
 237             File f = new File(outFile);
 238 
 239             File tempDir = f.getParentFile();
 240 
 241             if (tempDir == null)
 242                 tempDir = new File(System.getProperty("user.dir"));
 243 
 244             tempFile = File.createTempFile("_N2A",
 245                                            ".TMP",
 246                                             tempDir);
 247             tempFile.deleteOnExit();
 248 
 249             try {
 250                 output = new FileWriter(tempFile);
 251             } catch (IOException e){
 252                 throw new Exception(formatMsg("err.cannot.write", tempFile.getName()));
 253             }
 254         }
 255 
 256         n2aOut = new BufferedWriter(new N2AFilter(output));
 257         return n2aOut;
 258     }
 259 
 260     private BufferedReader getA2NInput(String inFile) throws Exception {
 261         Reader in;
 262         BufferedReader reader;
 263 
 264         if (inFile == null)
 265             in = new InputStreamReader(System.in, "US-ASCII");
 266         else {
 267             File f = new File(inFile);
 268             if (!f.canRead()){
 269                 throw new Exception(formatMsg("err.cannot.read", f.getName()));
 270             }
 271 
 272             try {
 273                  in = new FileReader(inFile);
 274             } catch (Exception e) {
 275                throw new Exception(formatMsg("err.cannot.read", f.getName()));
 276             }
 277         }
 278 
 279         reader = new BufferedReader(new A2NFilter(in));
 280         return reader;
 281     }
 282 
 283     private Writer getA2NOutput(String outFile) throws Exception {
 284 
 285         OutputStreamWriter w = null;
 286         OutputStream output = null;
 287 
 288         if (outFile == null)
 289             output = System.out;
 290         else {
 291             File f = new File(outFile);
 292 
 293             File tempDir = f.getParentFile();
 294             if (tempDir == null)
 295                 tempDir = new File(System.getProperty("user.dir"));
 296             tempFile =  File.createTempFile("_N2A",
 297                                             ".TMP",
 298                                             tempDir);
 299             tempFile.deleteOnExit();
 300 
 301             try {
 302                 output = new FileOutputStream(tempFile);
 303             } catch (IOException e){
 304                 throw new Exception(formatMsg("err.cannot.write", tempFile.getName()));
 305             }
 306         }
 307 
 308         w = (encodingString != null) ?
 309             new OutputStreamWriter(output, encodingString) :
 310             new OutputStreamWriter(output);
 311 
 312         return (w);
 313     }
 314 
 315     private static Charset lookupCharset(String csName) {
 316         if (Charset.isSupported(csName)) {
 317            try {
 318                 return Charset.forName(csName);
 319            } catch (UnsupportedCharsetException x) {
 320                 throw new Error(x);
 321            }
 322         }
 323         return null;
 324     }
 325 
 326     public static boolean canConvert(char ch) {
 327         return (encoder != null && encoder.canEncode(ch));
 328     }
 329 
 330     private static void initializeConverter() throws UnsupportedEncodingException {
 331         Charset cs = null;
 332 
 333         try {
 334             cs = (encodingString == null) ?
 335                 lookupCharset(defaultEncoding):
 336                 lookupCharset(encodingString);
 337 
 338             encoder =  (cs != null) ?
 339                 cs.newEncoder() :
 340                 null;
 341         } catch (IllegalCharsetNameException e) {
 342             throw new Error(e);
 343         }
 344     }
 345 
 346     private static ResourceBundle rsrc;
 347 
 348     static {
 349         try {
 350             rsrc = ResourceBundle.getBundle(
 351                      "sun.tools.native2ascii.resources.MsgNative2ascii");
 352         } catch (MissingResourceException e) {
 353             throw new Error("Missing message file.");
 354         }
 355     }
 356 
 357     private String getMsg(String key) {
 358         try {
 359             return (rsrc.getString(key));
 360         } catch (MissingResourceException e) {
 361             throw new Error("Error in  message file format.");
 362         }
 363     }
 364 
 365     private String formatMsg(String key, String arg) {
 366         String msg = getMsg(key);
 367         return MessageFormat.format(msg, arg);
 368     }
 369 
 370 
 371     /**
 372      * Main program
 373      */
 374     public static void main(String argv[]){
 375         Main converter = new Main();
 376         System.exit(converter.convert(argv) ? 0 : 1);
 377     }
 378 }