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