/*
* @(#) com/ivmaisoft/jpropjav/Main.java --
* a java properties file to java class source file converter utility.
**
* Copyright (C) 2007-2009 Ivan Maidanski <ivmai@mail.ru> All rights reserved.
*/
/*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
**
* This software is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License (GPL) for more details.
**
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
**
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under
* terms of your choice, provided that you also meet, for each linked
* independent module, the terms and conditions of the license of that
* module. An independent module is a module which is not derived from
* or based on this library. If you modify this library, you may extend
* this exception to your version of the library, but you are not
* obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
/**
* This utility reads standard java properties files and generates
* corresponding java class source files. Every generated class is
* a subclass of either the space-optimized StrListResourceBundle
* or the standard ListResourceBundle, and could be instantated by
* ResourceBundle class.
*/
package com.ivmaisoft.jpropjav;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Vector;
public final class Main
{
static /* final */ String PROGNAME = "JPropJav";
static /* final */ String VERSION = "1.2";
static /* final */ String DEFAULT_EXT = ".properties";
private Main() {}
public static final void main(String args[])
{
if (args.length == 0 || args[0].equals("-help"))
{
System.out.println(PROGNAME + " utility v" + VERSION);
System.out.println(
"Copyright (C) 2007-2009 Ivan Maidanski <ivmai@mail.ru>");
System.out.println("Free software. No warranties. All rights reserved.");
System.out.println();
System.out.println("This utility generates java class source files from" +
" the java properties files.");
System.out.println();
System.out.println("Arguments:" +
" [-l] -d <outdir> [-sourcepath <pathlist>] file1" + DEFAULT_EXT +
" ...");
System.out.println(
" Use \"-l\" option to produce classes extending ListResourceBundle");
System.out.println(
"(for compatibility only, not recommended for general use).");
System.out.println(
" It is also allowed to specify the java source file name or the");
System.out.println(
"corresponding java class name instead of a properties file name.");
System.out.println(
" To read command-line arguments (a list of the files to be processed)");
System.out.println("from a response file, prefix its name with '@'.");
return;
}
int i = 0;
File basedir = null;
String pathlist = "";
boolean isStrList = true;
do
{
String arg = args[i];
if (arg.equals("-l"))
{
if (!isStrList || i + 1 >= args.length)
{
System.err.println("Invalid arguments!");
System.exit(1);
}
isStrList = false;
}
else
{
if (arg.equals("-d"))
{
if (basedir != null || i + 2 >= args.length)
{
System.err.println("Invalid arguments!");
System.exit(1);
}
basedir = new File(args[++i]);
}
else
{
if (!arg.equals("-sourcepath"))
break;
if (i + 2 >= args.length)
{
System.err.println("Invalid arguments!");
System.exit(1);
}
i++;
pathlist = pathlist.length() > 0 ? pathlist +
File.pathSeparator + args[i] : args[i];
}
}
i++;
} while (true);
if (basedir == null)
{
System.err.println("Invalid arguments - no output directory specified!");
System.exit(1);
}
System.out.println("Reading properties files...");
Vector classNameList = new Vector();
Vector propLinesList = new Vector();
do
{
String arg = args[i];
if (arg.startsWith("@"))
{
Vector lines = readFileLines(new File(arg.length() == 1 &&
args.length - 1 > i ? args[++i] : arg.substring(1)));
for (int j = 0; lines.size() > j; j++)
{
String line = ((String) lines.elementAt(j)).trim();
if (line.length() > 0 && line.charAt(0) != '#')
classNameList.addElement(propFileRead(propLinesList, line, pathlist));
}
}
else classNameList.addElement(propFileRead(propLinesList, arg, pathlist));
} while (++i < args.length);
for (i = 0; classNameList.size() > i; i++)
generateFileFor((String) classNameList.elementAt(i),
(Vector) propLinesList.elementAt(i), basedir, isStrList);
System.out.println("Done.");
}
private static String propFileRead(Vector propLinesList, String propFName,
String pathlist)
{
String className = null;
if (propFName.endsWith(".java"))
propFName = propFName.substring(0, propFName.length() - 5) + DEFAULT_EXT;
else
{
if (!propFName.endsWith(DEFAULT_EXT) &&
(new File(propFName)).getPath().indexOf(File.separatorChar, 0) < 0)
{
className = propFName;
propFName = propFName.replace('.', File.separatorChar) + DEFAULT_EXT;
}
}
File propFile = searchFile(propFName, pathlist);
Vector propLines = readLatinOneFileLines(propFile);
if (className == null)
{
if (!propFName.endsWith(DEFAULT_EXT) || propFName.lastIndexOf('.',
propFName.length() - DEFAULT_EXT.length() - 1) >= 0)
{
System.err.println("Not a properties file: " + propFName);
System.exit(1);
}
className = makeClassName(propFile, countParentDirs(new File(propFName)));
}
propLinesList.addElement(propLines);
return className;
}
private static File searchFile(String name, String pathlist)
{
int pos = 0;
do
{
int next = pathlist.indexOf(File.pathSeparatorChar, pos);
if (next < 0)
next = pathlist.length();
if (pos != next)
{
File file = new File(pathlist.substring(pos, next), name);
if (file.exists())
return file;
}
pos = next + 1;
} while (pathlist.length() > pos);
return new File(name);
}
private static int countParentDirs(File file)
{
int count;
String parent;
for (count = 0; (parent = file.getParent()) != null; count++)
file = new File(parent);
return count;
}
private static String makeClassName(File file, int pkgCount)
{
try
{
file = new File(file.getCanonicalPath());
}
catch (IOException e) {}
String className = file.getName();
int dotPos = className.lastIndexOf('.');
if (dotPos >= 0)
className = className.substring(0, dotPos);
String parent;
while (pkgCount-- > 0 && (parent = file.getParent()) != null)
{
file = new File(parent);
className = file.getName() + "." + className;
}
return className;
}
private static void generateFileFor(String className, Vector propLines,
File basedir, boolean isStrList)
{
System.out.println("Generating file for class: " + className);
writeFileSafe(basedir, className.replace('.', File.separatorChar) + ".java",
producePropClass(className, propLines, isStrList));
}
private static Vector producePropClass(String className, Vector propLines,
boolean isStrList)
{
int lineInd = 0;
Vector lines = new Vector();
lines.addElement("/* DO NOT EDIT THIS FILE - it is machine generated (" +
PROGNAME + " v" + VERSION + ") */");
if (isStrList)
lines.addElement("/* Extends: StrListResourceBundle */");
lines.addElement("");
boolean isNext = false;
do
{
while (propLines.size() > lineInd &&
leftTrim((String) propLines.elementAt(lineInd)).length() == 0)
lineInd++;
int cnt;
for (cnt = 0; propLines.size() - cnt > lineInd; cnt++)
{
String line = leftTrim((String) propLines.elementAt(lineInd + cnt));
if (line.length() == 0)
break;
char ch;
if ((ch = line.charAt(0)) != '#' && ch != '!')
{
if (!isNext && (cnt == 0 || ((String) propLines.elementAt(
lineInd + cnt - 1)).trim().length() == 1))
break;
cnt = 0;
break;
}
}
if (cnt == 0)
break;
boolean isBlank = true;
do
{
String line =
((String) propLines.elementAt(lineInd++)).trim().substring(1);
if (line.length() > 0)
{
lines.addElement("/" + "/" + line);
isBlank = false;
}
else
{
if (!isBlank)
{
lines.addElement("");
isBlank = true;
}
}
} while (--cnt > 0);
isNext = true;
if (!isBlank)
lines.addElement("");
} while (true);
int lastDot = className.lastIndexOf('.');
if (lastDot >= 0)
{
lines.addElement("package " + className.substring(0, lastDot) + ";");
lines.addElement("");
}
lines.addElement("public final class " + className.substring(lastDot + 1));
lines.addElement(isStrList ?
" extends com.ivmaisoft.jpropjav.StrListResourceBundle" :
" extends java.util.ListResourceBundle");
lines.addElement("{");
lines.addElement("");
lines.addElement(" protected " + (isStrList ?
"java.lang.String" : "java.lang.Object[]") + "[] getContents()");
lines.addElement(" {");
lines.addElement(" " + " return contents;");
lines.addElement(" }");
lines.addElement("");
lines.addElement(" private static final " + (isStrList ?
"java.lang.String" : "java.lang.Object[]") + "[] contents =");
lines.addElement(" {");
while (propLines.size() > lineInd)
{
String line = leftTrim((String) propLines.elementAt(lineInd++));
if (line.length() > 0)
{
char ch = line.charAt(0);
if (ch == '#' || ch == '!')
lines.addElement("/" + "/" + line.trim().substring(1));
else
{
StringBuffer sb = new StringBuffer(line.length() + 12);
sb.append(' ');
if (!isStrList)
sb.append(" {");
sb.append(" \"");
int pos = 1;
boolean isValue = false;
do
{
if (ch == '\\')
{
if (line.length() == pos)
{
if (propLines.size() == lineInd)
break;
line += leftTrim((String) propLines.elementAt(lineInd++));
}
else
{
if ((ch = line.charAt(pos++)) == 't' || ch == 'n' || ch == 'f' ||
ch == 'r' || ch == 'u' || ch == '\\' || ch == '"')
{
sb.append('\\');
sb.append(ch);
}
else appendUnicodeChar(sb, ch);
}
}
else
{
if (!isValue && (ch == '=' || ch == ':' || isWhitespace(ch)))
{
if (ch == '=' || ch == ':')
isValue = true;
while (line.length() > pos)
{
ch = line.charAt(pos);
if (!isWhitespace(ch))
{
if (isValue || (ch != '=' && ch != ':'))
break;
isValue = true;
}
pos++;
}
sb.append("\", \"");
isValue = true;
}
else
{
if (ch == '"')
{
sb.append('\\');
sb.append('"');
}
else appendUnicodeChar(sb, ch);
}
}
if (line.length() == pos)
break;
ch = line.charAt(pos++);
} while (true);
if (!isValue)
sb.append("\", \"");
sb.append(isStrList ? "\"," : "\" },");
lines.addElement(sb.toString());
}
}
}
lines.addElement(" };");
lines.addElement("}");
return lines;
}
private static String leftTrim(String str)
{
int len = str.length();
int pos = 0;
while (pos < len && isWhitespace(str.charAt(pos)))
pos++;
return str.substring(pos);
}
private static boolean isWhitespace(char ch)
{
return ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\f' ||
ch == '\r');
}
private static void appendUnicodeChar(StringBuffer sb, char ch)
{
if (ch < ' ' || ch >= 0x7f)
{
sb.append("\\u");
String str = Integer.toHexString(ch);
sb.append("000".substring(str.length() - 1));
sb.append(str);
}
else sb.append(ch);
}
private static void writeFileSafe(File basedir, String filename,
Vector lines)
{
File file = new File(basedir, filename);
String parent = file.getParent();
if (parent != null && basedir.exists())
(new File(parent)).mkdirs();
writeFileLines(file, lines);
}
private static Vector readLatinOneFileLines(File file)
{
Vector lines = new Vector();
try
{
DataInputStream infile =
new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
String str;
while ((str = infile.readLine()) != null)
lines.addElement(str);
infile.close();
}
catch (IOException e)
{
System.err.println("Cannot read file: " + file.getPath());
System.exit(2);
}
return lines;
}
private static Vector readFileLines(File file)
{
Vector lines = new Vector();
try
{
BufferedReader infile = new BufferedReader(new FileReader(file));
String str;
while ((str = infile.readLine()) != null)
lines.addElement(str);
infile.close();
}
catch (IOException e)
{
System.err.println("Cannot read file: " + file.getPath());
System.exit(2);
}
return lines;
}
private static void writeFileLines(File file, Vector lines)
{
try
{
PrintStream outfile = new PrintStream(new BufferedOutputStream(
new FileOutputStream(file)));
for (int i = 0, count = lines.size(); i < count; i++)
outfile.println((String) lines.elementAt(i));
outfile.close();
}
catch (IOException e)
{
System.err.println("Cannot write file: " + file.getPath());
System.exit(3);
}
}
}