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