blob: ceb22d30a271071f2371fa9c3ec5754fde46f6d2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.axis2.corba.idl;
import org.apache.axis2.corba.exceptions.PreProcessorException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class PreProcessorInputStream extends InputStream {
public static int MAX_DEPTH = 99;
protected String[] userIncludePaths;
protected String[] systemIncludePaths;
protected String currentFile;
protected String parentPath;
protected StringBuffer idlContent;
protected int contentLength;
protected int lastRead = 0;
public PreProcessorInputStream(String parentPath, String idlFilename)
throws PreProcessorException {
this(parentPath, idlFilename, new String[] {}, new String[] {});
}
public PreProcessorInputStream(String parentPath, String idlFilename,
String[] userIncludePaths, String[] systemIncludePaths)
throws PreProcessorException {
this.userIncludePaths = userIncludePaths;
this.systemIncludePaths = systemIncludePaths;
this.parentPath = parentPath;
this.currentFile = parentPath + File.separator + idlFilename;
InputStream idlStream = getInputStream(parentPath, idlFilename);
if (idlFilename == null)
throw new PreProcessorException("Cannot find the file "
+ parentPath + File.separator + idlFilename);
idlContent = readIdl(idlStream, 0);
contentLength = idlContent.length();
}
protected StringBuffer readIdl(InputStream idlStream, int depth)
throws PreProcessorException {
StringBuffer buffer = new StringBuffer();
LineNumberReader lineNumberReader = new LineNumberReader(
new InputStreamReader(idlStream));
lineNumberReader.setLineNumber(1);
String line;
Map defs = new HashMap();
Stack ifdefValue = new Stack();
boolean validLine = true;
boolean elseNotValid = false;
String lastLine = null;
while (true) {
try {
line = lineNumberReader.readLine();
} catch (IOException e) {
throw new PreProcessorException("Error while reading next line"
+ getLineNoString(lineNumberReader), e);
}
if (line == null) {
break;
} else if (line.startsWith("#")) {
line = line.trim();
}
if (lastLine != null) {
line = lastLine + " " + line;
lastLine = null;
}
if (!ifdefValue.empty()
&& !((Boolean) ifdefValue.peek()).booleanValue()
&& !line.startsWith("#")) {
continue;
} else if (line.startsWith("#") && line.endsWith("\\")) {
lastLine = line.substring(0, line.lastIndexOf("\\"));
continue;
} else if (line.startsWith("#include") && validLine) {
if (depth < MAX_DEPTH) {
String inc = line.replaceAll("#include", "").trim();
addComment(buffer, line);
InputStream incis = resolveInclude(inc,
getLineNoString(lineNumberReader));
buffer.append(readIdl(incis, depth + 1));
addComment(buffer, "end of " + line);
} else {
throw new PreProcessorException("More than " + MAX_DEPTH
+ " nested #includes are not allowed"
+ getLineNoString(lineNumberReader));
}
} else if (line.startsWith("#define")) {
String def = line.replaceAll("#define", "").trim();
def = def.replaceAll("\"", "");
StringTokenizer tok = new StringTokenizer(def, " ");
if (tok.countTokens() == 1) {
def = tok.nextToken();
if (defs.containsKey(def))
throw new PreProcessorException("Variable " + def
+ " is already defined"
+ getLineNoString(lineNumberReader));
defs.put(def, null);
} else if (tok.countTokens() == 2) {
defs.put(tok.nextToken(), tok.nextToken());
}
addComment(buffer, line);
} else if (line.startsWith("#undef")) {
String def = line.replaceAll("#undef", "").trim();
def = def.replaceAll("\"", "");
if (defs.containsKey(def)) {
defs.remove(def);
} else {
throw new PreProcessorException("Undifined variable " + def
+ getLineNoString(lineNumberReader));
}
addComment(buffer, line);
} else if (line.startsWith("#ifdef")) {
String def = line.replaceAll("#ifdef", "").trim();
def = def.replaceAll("\"", "");
if (defs.containsKey(def)) {
ifdefValue.push(Boolean.TRUE);
} else {
validLine = false;
ifdefValue.push(Boolean.FALSE);
}
elseNotValid = false;
addComment(buffer, line);
} else if (line.startsWith("#ifndef")) {
String def = line.replaceAll("#ifndef", "").trim();
def = def.replaceAll("\"", "");
if (defs.containsKey(def)) {
validLine = false;
ifdefValue.push(Boolean.FALSE);
} else {
ifdefValue.push(Boolean.TRUE);
}
elseNotValid = false;
addComment(buffer, line);
} else if (line.startsWith("#else")) {
if (elseNotValid)
throw new PreProcessorException("Invalid #else preprocessor directive" + getLineNoString(lineNumberReader));
// invert last element
boolean lastval = ((Boolean) ifdefValue.peek()).booleanValue();
ifdefValue.setElementAt(new Boolean(!lastval), ifdefValue.size() - 1);
validLine = isAllTrue(ifdefValue);
elseNotValid = true;
addComment(buffer, line);
} else if (line.startsWith("#endif")) {
if (ifdefValue.empty())
throw new PreProcessorException("Invalid #endif preprocessor directive" + getLineNoString(lineNumberReader));
ifdefValue.pop();
validLine = isAllTrue(ifdefValue);
elseNotValid = false;
addComment(buffer, line);
} else if (line.startsWith("#")) {
// TODO: log
System.out
.println("Ignoring unsupported preprocessor directive "
+ line + getLineNoString(lineNumberReader));
} else if (validLine) {
buffer.append(line);
buffer.append('\n');
// System.out.println(line);
}
}
if (!ifdefValue.empty()) {
throw new PreProcessorException(
"One or more #ifdef/#ifndef preprocessor directives are not properly closed" + getLineNoString(lineNumberReader));
}
try {
lineNumberReader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return buffer;
}
protected InputStream resolveInclude(String include, String lineNoString)
throws PreProcessorException {
try {
File incFile;
if (include.startsWith("\"") && include.startsWith("\"")) {
include = include.replaceAll("\"", "");
incFile = new File(include);
if (incFile.exists()) {
currentFile = incFile.getAbsolutePath();
return new FileInputStream(incFile);
}
InputStream stream = getInputStream(parentPath, include);
if (stream != null)
return stream;
for (int i = 0; i < userIncludePaths.length; i++) {
if (userIncludePaths[i].endsWith(File.separator)) {
incFile = new File(userIncludePaths[i] + include);
} else {
incFile = new File(userIncludePaths[i] + File.separator
+ include);
}
if (incFile.exists()) {
currentFile = incFile.getAbsolutePath();
return new FileInputStream(incFile);
}
}
throw new PreProcessorException("Unable to resolve include "
+ include + lineNoString);
} else if (include.startsWith("<") && include.startsWith(">")) {
include = include.replaceAll("<", "");
include = include.replaceAll(">", "");
for (int i = 0; i < systemIncludePaths.length; i++) {
if (systemIncludePaths[i].endsWith(File.separator)) {
incFile = new File(systemIncludePaths[i] + include);
} else {
incFile = new File(systemIncludePaths[i]
+ File.separator + include);
}
if (incFile.exists()) {
currentFile = incFile.getAbsolutePath();
return new FileInputStream(incFile);
}
}
throw new PreProcessorException("Unable to resolve include "
+ include + lineNoString);
} else {
throw new PreProcessorException(
"Include name must be enclosed in '< >' or '\" \"'"
+ lineNoString);
}
} catch (FileNotFoundException e) {
throw new PreProcessorException("Unable to resolve include "
+ include + lineNoString, e);
}
}
protected InputStream getInputStream(String parent, String filename)
throws PreProcessorException {
File parentFile = new File(parent);
try {
if (parentFile.isDirectory()) {
return new FileInputStream(parent + File.separator + filename);
} else {
ZipInputStream zin = new ZipInputStream(new FileInputStream(
parentFile));
ZipEntry entry;
while ((entry = zin.getNextEntry()) != null) {
if (entry.getName().equalsIgnoreCase(filename)) {
return zin;
}
}
return null;
}
} catch (IOException e) {
throw new PreProcessorException("Unable to pre-process file " + parent
+ File.separator + filename, e);
}
}
private boolean isAllTrue(Stack stack) {
if (stack.empty()) {
return true;
} else {
for (Iterator iterator = stack.iterator(); iterator.hasNext();) {
Boolean value = (Boolean) iterator.next();
if (!value.booleanValue()) {
return false;
}
}
return true;
}
}
private void addComment(StringBuffer buffer, String line) {
buffer.append("/* ");
buffer.append(line);
buffer.append(" */\n");
}
private String getLineNoString(LineNumberReader lineNumberReader) {
if (lineNumberReader != null) {
int lineNo = lineNumberReader.getLineNumber();
if (lineNo > 0) {
return " (file:" + currentFile + ", line:" + (lineNo - 1) + ")";
}
}
return "";
}
public int read() throws IOException {
return (contentLength > lastRead) ? idlContent.charAt(lastRead++) : -1;
}
}