1/*
2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3 */
4
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *     http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xalan.internal.xsltc.compiler;
23
24import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
25import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
26import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
27import com.sun.org.apache.bcel.internal.generic.InstructionList;
28import com.sun.org.apache.bcel.internal.generic.PUSH;
29import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
30import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
31import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
32import com.sun.org.apache.xalan.internal.xsltc.compiler.util.StringType;
33import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
34import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
35import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
36import jdk.xml.internal.JdkXmlFeatures;
37
38/**
39 * @author Morten Jorgensen
40 */
41final class TransletOutput extends Instruction {
42
43    private Expression _filename;
44    private boolean _append;
45
46    /**
47     * Displays the contents of this <xsltc:output> element.
48     */
49    public void display(int indent) {
50        indent(indent);
51        Util.println("TransletOutput: " + _filename);
52    }
53
54    /**
55     * Parse the contents of this <xsltc:output> element. The only attribute
56     * we recognise is the 'file' attribute that contains teh output filename.
57     */
58    public void parseContents(Parser parser) {
59        // Get the output filename from the 'file' attribute
60        String filename = getAttribute("file");
61
62        // If the 'append' attribute is set to "yes" or "true",
63        // the output is appended to the file.
64        String append   = getAttribute("append");
65
66        // Verify that the filename is in fact set
67        if ((filename == null) || (filename.equals(EMPTYSTRING))) {
68            reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "file");
69        }
70
71        // Save filename as an attribute value template
72        _filename = AttributeValue.create(this, filename, parser);
73
74        if (append != null && (append.toLowerCase().equals("yes") ||
75            append.toLowerCase().equals("true"))) {
76          _append = true;
77        }
78        else
79          _append = false;
80
81        parseChildren(parser);
82    }
83
84    /**
85     * Type checks the 'file' attribute (must be able to convert it to a str).
86     */
87    public Type typeCheck(SymbolTable stable) throws TypeCheckError {
88        final Type type = _filename.typeCheck(stable);
89        if (type instanceof StringType == false) {
90            _filename = new CastExpr(_filename, Type.String);
91        }
92        typeCheckContents(stable);
93        return Type.Void;
94    }
95
96    /**
97     * Compile code that opens the give file for output, dumps the contents of
98     * the element to the file, then closes the file.
99     */
100    public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
101        final ConstantPoolGen cpg = classGen.getConstantPool();
102        final InstructionList il = methodGen.getInstructionList();
103        final boolean isSecureProcessing = classGen.getParser().getXSLTC()
104                                           .isSecureProcessing();
105        final boolean isExtensionFunctionEnabled = classGen.getParser().getXSLTC()
106                .getFeature(JdkXmlFeatures.XmlFeature.ENABLE_EXTENSION_FUNCTION);
107
108        if (isSecureProcessing && !isExtensionFunctionEnabled) {
109            int index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
110                                         "unallowed_extension_elementF",
111                                         "(Ljava/lang/String;)V");
112            il.append(new PUSH(cpg, "redirect"));
113            il.append(new INVOKESTATIC(index));
114            return;
115        }
116
117        // Save the current output handler on the stack
118        il.append(methodGen.loadHandler());
119
120        final int open =  cpg.addMethodref(TRANSLET_CLASS,
121                                           "openOutputHandler",
122                                           "(" + STRING_SIG + "Z)" +
123                                           TRANSLET_OUTPUT_SIG);
124
125        final int close =  cpg.addMethodref(TRANSLET_CLASS,
126                                            "closeOutputHandler",
127                                            "("+TRANSLET_OUTPUT_SIG+")V");
128
129        // Create the new output handler (leave it on stack)
130        il.append(classGen.loadTranslet());
131        _filename.translate(classGen, methodGen);
132        il.append(new PUSH(cpg, _append));
133        il.append(new INVOKEVIRTUAL(open));
134
135        // Overwrite current handler
136        il.append(methodGen.storeHandler());
137
138        // Translate contents with substituted handler
139        translateContents(classGen, methodGen);
140
141        // Close the output handler (close file)
142        il.append(classGen.loadTranslet());
143        il.append(methodGen.loadHandler());
144        il.append(new INVOKEVIRTUAL(close));
145
146        // Restore old output handler from stack
147        il.append(methodGen.storeHandler());
148    }
149}
150