/* Copyright (C) 2003-2011 JabRef contributors.
This program 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 of the License, or
(at your option) any later version.
This program 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 for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package net.sf.jabref.export.layout;
import java.io.IOException;
import java.io.PushbackReader;
import java.io.Reader;
import java.util.Vector;
/**
* Helper class to get a Layout object.
*
* <code>
* LayoutHelper helper = new LayoutHelper(...a reader...);
* Layout layout = helper.getLayoutFromText();
* </code>
*
*/
public class LayoutHelper {
public static final int IS_LAYOUT_TEXT = 1;
public static final int IS_SIMPLE_FIELD = 2;
public static final int IS_FIELD_START = 3;
public static final int IS_FIELD_END = 4;
public static final int IS_OPTION_FIELD = 5;
public static final int IS_GROUP_START = 6;
public static final int IS_GROUP_END = 7;
public static final int IS_ENCODING_NAME = 8;
public static final int IS_FILENAME = 9;
public static final int IS_FILEPATH = 10;
private static String currentGroup = null;
private PushbackReader _in;
private Vector<StringInt> parsedEntries = new Vector<StringInt>();
private boolean _eof = false;
private int line = 1;
public LayoutHelper(Reader in)
{
if (in == null)
{
throw new NullPointerException();
}
_in = new PushbackReader(in);
}
public Layout getLayoutFromText(String classPrefix) throws Exception
{
parse();
StringInt si;
for (int i = 0; i < parsedEntries.size(); i++)
{
si = parsedEntries.get(i);
if ((si.i == IS_SIMPLE_FIELD) || (si.i == IS_FIELD_START) ||
(si.i == IS_FIELD_END) || (si.i == IS_GROUP_START) ||
(si.i == IS_GROUP_END))
{
si.s = si.s.trim().toLowerCase();
}
}
Layout layout = new Layout(parsedEntries, classPrefix);
return layout;
}
public static String getCurrentGroup() {
return currentGroup;
}
public static void setCurrentGroup(String newGroup) {
currentGroup = newGroup;
}
private String getBracketedField(int _field) throws IOException
{
StringBuffer buffer = null;
int c;
boolean start = false;
while (!_eof)
{
c = read();
//System.out.println((char)c);
if (c == -1)
{
_eof = true;
if (buffer != null)
{
//myStrings.add(buffer.toString());
parsedEntries.add(new StringInt(buffer.toString(), _field));
//System.out.println("\nbracketedEOF: " + buffer.toString());
}
//myStrings.add(buffer.toString());
//System.out.println("aha: " + buffer.toString());
return null;
}
if ((c == '{') || (c == '}'))
{
if (c == '}')
{
if (buffer != null)
{
//myStrings.add(buffer.toString());
parsedEntries.add(new StringInt(buffer.toString(),
_field));
//System.out.println("\nbracketed: " + buffer.toString());
return null;
}
}
else
{
start = true;
}
}
else
{
if (buffer == null)
{
buffer = new StringBuffer(100);
}
if (start)
{
if (c == '}')
{
}
else
{
buffer.append((char) c);
}
}
}
}
return null;
}
/**
*
*/
private String getBracketedOptionField(int _field)
throws IOException
{
StringBuffer buffer = null;
int c;
boolean start = false;
boolean inQuotes = false;
boolean doneWithOptions = false;
String option = null;
String tmp;
while (!_eof)
{
c = read();
//System.out.println((char)c);
if (c == -1)
{
_eof = true;
if (buffer != null)
{
//myStrings.add(buffer.toString());
if (option != null)
{
tmp = buffer.toString() + "\n" + option;
}
else
{
tmp = buffer.toString();
}
parsedEntries.add(new StringInt(tmp, IS_OPTION_FIELD));
//System.out.println("\nbracketedOptionEOF: " + buffer.toString());
}
return null;
}
if (!inQuotes && ((c == ']') || (c == '[') || (doneWithOptions && ((c == '{') || (c == '}')))))
//if ((c == '{') || (c == '}') || (c == ']') || (c == '['))
{
if ((c == ']') || (doneWithOptions && (c == '}')))
{
// changed section start - arudert
// buffer may be null for parameters
//if (buffer != null)
//{
if (c == ']' && buffer != null)
{
// changed section end - arudert
option = buffer.toString();
buffer = null;
start = false;
doneWithOptions = true;
}
//myStrings.add(buffer.toString());
//System.out.println("\nbracketedOption: " + buffer.toString());
// changed section begin - arudert
// bracketed option must be followed by an (optionally empty) parameter
// if empty, the parameter is set to " " (whitespace to avoid that the tokenizer that
// splits the string later on ignores the empty parameter)
//if (buffer != null)
else if (c == '}')
{
String parameter = buffer == null ? " " : buffer.toString();
if (option != null)
{
tmp = parameter + "\n" + option;
}
else
{
tmp = parameter;
}
//System.out.println("FORMAT: '"+tmp+"'");
parsedEntries.add(new StringInt(tmp, IS_OPTION_FIELD));
return null;
}
// changed section end - arudert
// changed section start - arudert
// }
// changed section end - arudert
}
else
{
start = true;
}
}
else if (c == '"') {
if (!inQuotes)
inQuotes = true;
else inQuotes = false;
if (buffer == null)
buffer = new StringBuffer(100);
buffer.append('"');
}
else
{
if (buffer == null)
{
buffer = new StringBuffer(100);
}
if (start)
{
// changed section begin - arudert
// keep the backslash so we know wether this is a fieldname or an ordinary parameter
//if (c != '\\')
//{
buffer.append((char) c);
//}
// changed section end - arudert
}
}
}
return null;
}
private Object parse() throws IOException {
skipWhitespace();
int c;
StringBuffer buffer = null;
boolean escaped = false;
while (!_eof) {
c = read();
if (c == -1) {
_eof = true;
/*
* CO 2006-11-11: Added check for null, otherwise a Layout that
* finishs with a curly brace throws a NPE
*/
if (buffer != null)
parsedEntries.add(new StringInt(buffer.toString(), IS_LAYOUT_TEXT));
return null;
}
if ((c == '\\') && (peek() != '\\') && !escaped) {
if (buffer != null) {
parsedEntries.add(new StringInt(buffer.toString(), IS_LAYOUT_TEXT));
buffer = null;
}
parseField();
// To make sure the next character, if it is a backslash,
// doesn't get ignored, since "previous" now holds a backslash:
escaped = false;
} else {
if (buffer == null) {
buffer = new StringBuffer(100);
}
if ((c != '\\') || escaped)// (previous == '\\')))
{
buffer.append((char) c);
}
escaped = (c == '\\') && !escaped;
}
}
return null;
}
/**
*
*/
private void parseField() throws IOException
{
int c;
StringBuffer buffer = null;
String name;
while (!_eof)
{
c = read();
// System.out.print((char)c);
if (c == -1)
{
_eof = true;
}
if (!Character.isLetter((char) c) && (c != '_') && (c != '-'))
{
unread(c);
//System.out.println("\n#" + (char) c);
name = buffer != null ? buffer.toString() : "";
//System.out.println("NAME:" + name);
buffer = null;
if (name.charAt(0) == 'b')
{
if (name.equalsIgnoreCase("begin"))
{
// get field name
getBracketedField(IS_FIELD_START);
return;
}
else if (name.equalsIgnoreCase("begingroup"))
{
// get field name
getBracketedField(IS_GROUP_START);
return;
}
}
else if (name.charAt(0) == 'f')
{
if (name.equalsIgnoreCase("format"))
{
if (c == '[')
{
// get format parameter
// get field name
getBracketedOptionField(IS_OPTION_FIELD);
return;
}
else
{
// get field name
getBracketedField(IS_OPTION_FIELD);
return;
}
}
else if (name.equalsIgnoreCase("filename"))
{
// Print the name of the database bib file.
// This is only supported in begin/end layouts, not in
// entry layouts.
parsedEntries.add(new StringInt(name, IS_FILENAME));
return;
}
else if (name.equalsIgnoreCase("filepath"))
{
// Print the full path of the database bib file.
// This is only supported in begin/end layouts, not in
// entry layouts.
parsedEntries.add(new StringInt(name, IS_FILEPATH));
return;
}
}
else if (name.charAt(0) == 'e')
{
if (name.equalsIgnoreCase("end"))
{
// get field name
getBracketedField(IS_FIELD_END);
return;
}
else if (name.equalsIgnoreCase("endgroup"))
{
// get field name
getBracketedField(IS_GROUP_END);
return;
}
else if (name.equalsIgnoreCase("encoding"))
{
// Print the name of the current encoding used for export.
// This is only supported in begin/end layouts, not in
// entry layouts.
parsedEntries.add(new StringInt(name, IS_ENCODING_NAME));
return;
}
}
// for all other cases
parsedEntries.add(new StringInt(name, IS_SIMPLE_FIELD));
//System.out.println(name);
return;
}
else
{
if (buffer == null)
{
buffer = new StringBuffer(100);
}
buffer.append((char) c);
}
}
}
private int peek() throws IOException
{
int c = read();
unread(c);
return c;
}
private int read() throws IOException
{
int c = _in.read();
if (c == '\n')
{
line++;
}
//System.out.print((char) c);
return c;
}
private void skipWhitespace() throws IOException
{
int c;
while (true)
{
c = read();
if ((c == -1) || (c == 65535))
{
_eof = true;
return;
}
if (Character.isWhitespace((char) c))
{
continue;
}
else
{
unread(c);
}
break;
}
}
private void unread(int c) throws IOException
{
if (c == '\n')
{
line--;
}
_in.unread(c);
}
}