| /* |
| * 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.endsWith("\"")) { |
| 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.endsWith(">")) { |
| 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; |
| } |
| } |