/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source 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.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.servlets.ssi;
import com.caucho.util.ByteBuffer;
import com.caucho.vfs.Path;
import com.caucho.vfs.ReadStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Serves server-side include files.
*/
public class SSIParser {
private int _line;
private final SSIFactory _factory;
public SSIParser()
{
_factory = new SSIFactory();
}
public SSIParser(SSIFactory factory)
{
_factory = factory;
}
Statement parse(Path path)
throws IOException
{
ReadStream is = path.openRead();
try {
ArrayList<Statement> statements = new ArrayList<Statement>();
parse(is, statements);
return new BlockStatement(statements);
} finally {
is.close();
}
}
Statement parse(ReadStream is)
throws IOException
{
ArrayList<Statement> statements = new ArrayList<Statement>();
parse(is, statements);
return new BlockStatement(statements);
}
/**
* Parses a list of statements from the ssi stream.
*/
private void parse(ReadStream is, ArrayList<Statement> statements)
throws IOException
{
ByteBuffer bb = new ByteBuffer();
int ch;
while ((ch = is.read()) >= 0) {
if (ch != '<') {
if (ch == '\n')
_line++;
bb.append(ch);
}
else if ((ch = is.read()) != '!') {
bb.append('<');
is.unread();
}
else if ((ch = is.read()) != '-') {
bb.append('<');
bb.append('!');
is.unread();
}
else if ((ch = is.read()) != '-') {
bb.append('<');
bb.append('!');
bb.append('-');
is.unread();
}
else if ((ch = is.read()) != '#') {
bb.append('<');
bb.append('!');
bb.append('-');
bb.append('-');
is.unread();
}
else {
if (bb.getLength() > 0) {
TextStatement text;
text = new TextStatement(bb.getBuffer(), 0, bb.getLength());
statements.add(text);
bb.clear();
}
Statement stmt = parseCommand(is);
statements.add(stmt);
if (stmt instanceof IfStatement) {
parseIf(is, (IfStatement) stmt);
}
if (stmt instanceof ElifStatement) {
return;
}
else if (stmt instanceof ElseStatement) {
return;
}
else if (stmt instanceof EndifStatement) {
return;
}
}
}
if (bb.getLength() > 0) {
statements.add(new TextStatement(bb.getBuffer(), 0, bb.getLength()));
bb.clear();
}
}
private void parseIf(ReadStream is, IfStatement ifStmt)
throws IOException
{
ArrayList<Statement> trueBlock = new ArrayList<Statement>();
parse(is, trueBlock);
int size = trueBlock.size();
if (size > 0 && trueBlock.get(size - 1) instanceof ElifStatement) {
ElifStatement elifBlock = (ElifStatement) trueBlock.get(size - 1);
trueBlock.remove(size - 1);
ifStmt.setFalseBlock(elifBlock);
}
else if (size > 0 && trueBlock.get(size - 1) instanceof ElseStatement) {
ArrayList<Statement> falseBlock = new ArrayList<Statement>();
parse(is, falseBlock);
ifStmt.setFalseBlock(new BlockStatement(falseBlock));
}
ifStmt.setTrueBlock(new BlockStatement(trueBlock));
}
private Statement parseCommand(ReadStream is)
throws IOException
{
StringBuilder sb = new StringBuilder();
int ch;
while (Character.isLetterOrDigit((ch = is.read()))) {
sb.append((char) ch);
}
String cmd = sb.toString();
HashMap<String,String> attr = parseAttributes(is);
if ((ch = is.read()) != '-') {
}
else if ((ch = is.read()) != '-') {
}
else if ((ch = is.read()) != '>') {
}
Statement statement = _factory.createStatement(cmd, attr, is.getPath());
if (statement == null)
statement = new ErrorStatement("['" + cmd + "' is an unknown command.]");
return statement;
}
private HashMap<String,String> parseAttributes(ReadStream is)
throws IOException
{
HashMap<String,String> attr = new HashMap<String,String>();
while (true) {
int ch;
while (Character.isWhitespace((ch = is.read()))) {
}
StringBuilder key = new StringBuilder();
for (; Character.isLetterOrDigit(ch); ch = is.read()) {
key.append((char) ch);
}
for (; Character.isWhitespace(ch); ch = is.read()) {
}
if (ch != '=')
return attr;
for (ch = is.read(); Character.isWhitespace(ch); ch = is.read()) {
}
StringBuilder value = new StringBuilder();
if (ch == '\'' || ch == '"') {
int end = ch;
for (ch = is.read(); ch > 0 && ch != end; ch = is.read()) {
if (ch == '\\') {
ch = is.read();
if (ch == '\'' || ch == '\"')
value.append((char) ch);
else {
value.append('\\');
is.unread();
}
}
else
value.append((char) ch);
}
}
else {
for (; ch > 0 && ! Character.isWhitespace(ch); ch = is.read()) {
value.append((char) ch);
}
}
attr.put(key.toString(), value.toString());
}
}
}