1 /*
   2  * Copyright (c) 1996, 2011, 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.io.UnsupportedEncodingException;
  75 import java.nio.charset.UnsupportedCharsetException;
  76 import sun.tools.native2ascii.A2NFilter;
  77 import sun.tools.native2ascii.N2AFilter;
  78 
  79 /**
  80  * Main program of the native2ascii
  81  */
  82 
  83 public class Main {
  84 
  85     String inputFileName = null;
  86     String outputFileName = null;
  87     File tempFile = null;
  88     boolean reverse = false;
  89     static String encodingString = null;
  90     static String defaultEncoding = null;
  91     static CharsetEncoder encoder = null;
  92 
  93     /**
  94      * Run the converter
  95      */
  96     public synchronized boolean convert(String argv[]){
  97         List<String> v = new ArrayList<>(2);
  98         File outputFile = null;
  99         boolean createOutputFile = false;
 100 
 101         // Parse arguments
 102         for (int i = 0; i < argv.length; i++) {
 103             if (argv[i].equals("-encoding")) {
 104                 if ((i + 1) < argv.length){
 105                     encodingString = argv[++i];
 106                 } else {
 107                     error(getMsg("err.bad.arg"));
 108                     usage();
 109                     return false;
 110                 }
 111             } else if (argv[i].equals("-reverse")){
 112                 reverse = true;
 113             } else {
 114                 if (v.size() > 1) {
 115                     usage();
 116                     return false;
 117                 }
 118                 v.add(argv[i]);
 119             }
 120         }
 121         if (encodingString == null)
 122            defaultEncoding = Charset.defaultCharset().name();
 123 
 124         char[] lineBreak = System.getProperty("line.separator").toCharArray();
 125         try {
 126             initializeConverter();
 127 
 128             if (v.size() == 1)
 129                 inputFileName = v.get(0);
 130 
 131             if (v.size() == 2) {
 132                 inputFileName = v.get(0);
 133                 outputFileName = v.get(1);
 134                 createOutputFile = true;
 135             }
 136 
 137             if (createOutputFile) {
 138                 outputFile = new File(outputFileName);
 139                     if (outputFile.exists() && !outputFile.canWrite()) {
 140                         throw new Exception(formatMsg("err.cannot.write", outputFileName));
 141                     }
 142             }
 143 
 144             if (reverse){
 145                 BufferedReader reader = getA2NInput(inputFileName);
 146                 Writer osw = getA2NOutput(outputFileName);
 147                 String line;
 148 
 149                 while ((line = reader.readLine()) != null) {
 150                     osw.write(line.toCharArray());
 151                     osw.write(lineBreak);
 152                     if (outputFileName == null) { // flush stdout
 153                         osw.flush();
 154                     }
 155                 }
 156                 reader.close();  // Close the stream.
 157                 osw.close();
 158             } else {
 159              //N2A
 160                 String inLine;
 161                 BufferedReader in = getN2AInput(inputFileName);
 162                 BufferedWriter out = getN2AOutput(outputFileName);
 163 
 164                 while ((inLine = in.readLine()) != null) {
 165                     out.write(inLine.toCharArray());
 166                     out.write(lineBreak);
 167                     if (outputFileName == null) { // flush stdout
 168                         out.flush();
 169                     }
 170                 }
 171                 out.close();
 172             }
 173             // Since we are done rename temporary file to desired output file
 174             if (createOutputFile) {
 175                 if (outputFile.exists()) {
 176                     // Some win32 platforms can't handle atomic
 177                     // rename if source and target file paths are
 178                     // identical. To make things simple we just unconditionally
 179                     // delete the target file before calling renameTo()
 180                     outputFile.delete();
 181                 }
 182                 tempFile.renameTo(outputFile);
 183             }
 184 
 185         } catch(Exception e){
 186             error(e.toString());
 187             return false;
 188         }
 189 
 190         return true;
 191     }
 192 
 193     private void error(String msg){
 194         System.out.println(msg);
 195     }
 196 
 197     private void usage(){
 198         System.out.println(getMsg("usage"));
 199     }
 200 
 201 
 202     private BufferedReader getN2AInput(String inFile) throws Exception {
 203 
 204         InputStream forwardIn;
 205         if (inFile == null)
 206             forwardIn = System.in;
 207         else {
 208             File f = new File(inFile);
 209             if (!f.canRead()){
 210                 throw new Exception(formatMsg("err.cannot.read", f.getName()));
 211             }
 212 
 213             try {
 214                  forwardIn = new FileInputStream(inFile);
 215             } catch (IOException e) {
 216                throw new Exception(formatMsg("err.cannot.read", f.getName()));
 217             }
 218         }
 219 
 220         BufferedReader r = (encodingString != null) ?
 221             new BufferedReader(new InputStreamReader(forwardIn,
 222                                                      encodingString)) :
 223             new BufferedReader(new InputStreamReader(forwardIn));
 224         return r;
 225     }
 226 
 227 
 228     private BufferedWriter getN2AOutput(String outFile) throws Exception {
 229         Writer output;
 230         BufferedWriter n2aOut;
 231 
 232         if (outFile == null)
 233             output = new OutputStreamWriter(System.out,"US-ASCII");
 234 
 235         else {
 236             File f = new File(outFile);
 237 
 238             File tempDir = f.getParentFile();
 239 
 240             if (tempDir == null)
 241                 tempDir = new File(System.getProperty("user.dir"));
 242 
 243             tempFile = File.createTempFile("_N2A",
 244                                            ".TMP",
 245                                             tempDir);
 246             tempFile.deleteOnExit();
 247 
 248             try {
 249                 output = new FileWriter(tempFile);
 250             } catch (IOException e){
 251                 throw new Exception(formatMsg("err.cannot.write", tempFile.getName()));
 252             }
 253         }
 254 
 255         n2aOut = new BufferedWriter(new N2AFilter(output));
 256         return n2aOut;
 257     }
 258 
 259     private BufferedReader getA2NInput(String inFile) throws Exception {
 260         Reader in;
 261         BufferedReader reader;
 262 
 263         if (inFile == null)
 264             in = new InputStreamReader(System.in, "US-ASCII");
 265         else {
 266             File f = new File(inFile);
 267             if (!f.canRead()){
 268                 throw new Exception(formatMsg("err.cannot.read", f.getName()));
 269             }
 270 
 271             try {
 272                  in = new FileReader(inFile);
 273             } catch (Exception e) {
 274                throw new Exception(formatMsg("err.cannot.read", f.getName()));
 275             }
 276         }
 277 
 278         reader = new BufferedReader(new A2NFilter(in));
 279         return reader;
 280     }
 281 
 282     private Writer getA2NOutput(String outFile) throws Exception {
 283 
 284         OutputStreamWriter w = null;
 285         OutputStream output = null;
 286 
 287         if (outFile == null)
 288             output = System.out;
 289         else {
 290             File f = new File(outFile);
 291 
 292             File tempDir = f.getParentFile();
 293             if (tempDir == null)
 294                 tempDir = new File(System.getProperty("user.dir"));
 295             tempFile =  File.createTempFile("_N2A",
 296                                             ".TMP",
 297                                             tempDir);
 298             tempFile.deleteOnExit();
 299 
 300             try {
 301                 output = new FileOutputStream(tempFile);
 302             } catch (IOException e){
 303                 throw new Exception(formatMsg("err.cannot.write", tempFile.getName()));
 304             }
 305         }
 306 
 307         w = (encodingString != null) ?
 308             new OutputStreamWriter(output, encodingString) :
 309             new OutputStreamWriter(output);
 310 
 311         return (w);
 312     }
 313 
 314     private static Charset lookupCharset(String csName) {
 315         if (Charset.isSupported(csName)) {
 316            try {
 317                 return Charset.forName(csName);
 318            } catch (UnsupportedCharsetException x) {
 319                 throw new Error(x);
 320            }
 321         }
 322         return null;
 323     }
 324 
 325     public static boolean canConvert(char ch) {
 326         return (encoder != null && encoder.canEncode(ch));
 327     }
 328 
 329     private static void initializeConverter() throws UnsupportedEncodingException {
 330         Charset cs = null;
 331 
 332         try {
 333             cs = (encodingString == null) ?
 334                 lookupCharset(defaultEncoding):
 335                 lookupCharset(encodingString);
 336 
 337             encoder =  (cs != null) ?
 338                 cs.newEncoder() :
 339                 null;
 340         } catch (IllegalCharsetNameException e) {
 341             throw new Error(e);
 342         }
 343     }
 344 
 345     private static ResourceBundle rsrc;
 346 
 347     static {
 348         try {
 349             rsrc = ResourceBundle.getBundle(
 350                      "sun.tools.native2ascii.resources.MsgNative2ascii");
 351         } catch (MissingResourceException e) {
 352             throw new Error("Missing message file.");
 353         }
 354     }
 355 
 356     private String getMsg(String key) {
 357         try {
 358             return (rsrc.getString(key));
 359         } catch (MissingResourceException e) {
 360             throw new Error("Error in  message file format.");
 361         }
 362     }
 363 
 364     private String formatMsg(String key, String arg) {
 365         String msg = getMsg(key);
 366         return MessageFormat.format(msg, arg);
 367     }
 368 
 369 
 370     /**
 371      * Main program
 372      */
 373     public static void main(String argv[]){
 374         Main converter = new Main();
 375         System.exit(converter.convert(argv) ? 0 : 1);
 376     }
 377 }