001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: TransletOutput.java 468650 2006-10-28 07:03:30Z minchau $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import org.apache.bcel.generic.ConstantPoolGen;
025 import org.apache.bcel.generic.INVOKESTATIC;
026 import org.apache.bcel.generic.INVOKEVIRTUAL;
027 import org.apache.bcel.generic.InstructionList;
028 import org.apache.bcel.generic.PUSH;
029 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
030 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
031 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
032 import org.apache.xalan.xsltc.compiler.util.StringType;
033 import org.apache.xalan.xsltc.compiler.util.Type;
034 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
035 import org.apache.xalan.xsltc.compiler.util.Util;
036
037 /**
038 * @author Morten Jorgensen
039 */
040 final class TransletOutput extends Instruction {
041
042 private Expression _filename;
043 private boolean _append;
044
045 /**
046 * Displays the contents of this <xsltc:output> element.
047 */
048 public void display(int indent) {
049 indent(indent);
050 Util.println("TransletOutput: " + _filename);
051 }
052
053 /**
054 * Parse the contents of this <xsltc:output> element. The only attribute
055 * we recognise is the 'file' attribute that contains teh output filename.
056 */
057 public void parseContents(Parser parser) {
058 // Get the output filename from the 'file' attribute
059 String filename = getAttribute("file");
060
061 // If the 'append' attribute is set to "yes" or "true",
062 // the output is appended to the file.
063 String append = getAttribute("append");
064
065 // Verify that the filename is in fact set
066 if ((filename == null) || (filename.equals(EMPTYSTRING))) {
067 reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "file");
068 }
069
070 // Save filename as an attribute value template
071 _filename = AttributeValue.create(this, filename, parser);
072
073 if (append != null && (append.toLowerCase().equals("yes") ||
074 append.toLowerCase().equals("true"))) {
075 _append = true;
076 }
077 else
078 _append = false;
079
080 parseChildren(parser);
081 }
082
083 /**
084 * Type checks the 'file' attribute (must be able to convert it to a str).
085 */
086 public Type typeCheck(SymbolTable stable) throws TypeCheckError {
087 final Type type = _filename.typeCheck(stable);
088 if (type instanceof StringType == false) {
089 _filename = new CastExpr(_filename, Type.String);
090 }
091 typeCheckContents(stable);
092 return Type.Void;
093 }
094
095 /**
096 * Compile code that opens the give file for output, dumps the contents of
097 * the element to the file, then closes the file.
098 */
099 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
100 final ConstantPoolGen cpg = classGen.getConstantPool();
101 final InstructionList il = methodGen.getInstructionList();
102 final boolean isSecureProcessing = classGen.getParser().getXSLTC()
103 .isSecureProcessing();
104
105 if (isSecureProcessing) {
106 int index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
107 "unallowed_extension_elementF",
108 "(Ljava/lang/String;)V");
109 il.append(new PUSH(cpg, "redirect"));
110 il.append(new INVOKESTATIC(index));
111 return;
112 }
113
114 // Save the current output handler on the stack
115 il.append(methodGen.loadHandler());
116
117 final int open = cpg.addMethodref(TRANSLET_CLASS,
118 "openOutputHandler",
119 "(" + STRING_SIG + "Z)" +
120 TRANSLET_OUTPUT_SIG);
121
122 final int close = cpg.addMethodref(TRANSLET_CLASS,
123 "closeOutputHandler",
124 "("+TRANSLET_OUTPUT_SIG+")V");
125
126 // Create the new output handler (leave it on stack)
127 il.append(classGen.loadTranslet());
128 _filename.translate(classGen, methodGen);
129 il.append(new PUSH(cpg, _append));
130 il.append(new INVOKEVIRTUAL(open));
131
132 // Overwrite current handler
133 il.append(methodGen.storeHandler());
134
135 // Translate contents with substituted handler
136 translateContents(classGen, methodGen);
137
138 // Close the output handler (close file)
139 il.append(classGen.loadTranslet());
140 il.append(methodGen.loadHandler());
141 il.append(new INVOKEVIRTUAL(close));
142
143 // Restore old output handler from stack
144 il.append(methodGen.storeHandler());
145 }
146 }
147