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: ProcessingInstruction.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.ALOAD; 025 import org.apache.bcel.generic.ASTORE; 026 import org.apache.bcel.generic.ConstantPoolGen; 027 import org.apache.bcel.generic.GETFIELD; 028 import org.apache.bcel.generic.INVOKEINTERFACE; 029 import org.apache.bcel.generic.INVOKESTATIC; 030 import org.apache.bcel.generic.INVOKEVIRTUAL; 031 import org.apache.bcel.generic.InstructionList; 032 import org.apache.bcel.generic.LocalVariableGen; 033 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 034 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 035 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 036 import org.apache.xalan.xsltc.compiler.util.Type; 037 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 038 import org.apache.xalan.xsltc.compiler.util.Util; 039 import org.apache.xml.utils.XML11Char; 040 041 /** 042 * @author Jacek Ambroziak 043 * @author Santiago Pericas-Geertsen 044 */ 045 final class ProcessingInstruction extends Instruction { 046 047 private AttributeValue _name; // name treated as AVT (7.1.3) 048 private boolean _isLiteral = false; // specified name is not AVT 049 050 public void parseContents(Parser parser) { 051 final String name = getAttribute("name"); 052 053 if (name.length() > 0) { 054 _isLiteral = Util.isLiteral(name); 055 if (_isLiteral) { 056 if (!XML11Char.isXML11ValidNCName(name)) { 057 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_NCNAME_ERR, name, this); 058 parser.reportError(Constants.ERROR, err); 059 } 060 } 061 _name = AttributeValue.create(this, name, parser); 062 } 063 else 064 reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name"); 065 066 if (name.equals("xml")) { 067 reportError(this, parser, ErrorMsg.ILLEGAL_PI_ERR, "xml"); 068 } 069 parseChildren(parser); 070 } 071 072 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 073 _name.typeCheck(stable); 074 typeCheckContents(stable); 075 return Type.Void; 076 } 077 078 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 079 final ConstantPoolGen cpg = classGen.getConstantPool(); 080 final InstructionList il = methodGen.getInstructionList(); 081 082 if (!_isLiteral) { 083 // if the ncname is an AVT, then the ncname has to be checked at runtime if it is a valid ncname 084 LocalVariableGen nameValue = 085 methodGen.addLocalVariable2("nameValue", 086 Util.getJCRefType(STRING_SIG), 087 null); 088 089 // store the name into a variable first so _name.translate only needs to be called once 090 _name.translate(classGen, methodGen); 091 nameValue.setStart(il.append(new ASTORE(nameValue.getIndex()))); 092 il.append(new ALOAD(nameValue.getIndex())); 093 094 // call checkNCName if the name is an AVT 095 final int check = cpg.addMethodref(BASIS_LIBRARY_CLASS, "checkNCName", 096 "(" 097 +STRING_SIG 098 +")V"); 099 il.append(new INVOKESTATIC(check)); 100 101 // Save the current handler base on the stack 102 il.append(methodGen.loadHandler()); 103 il.append(DUP); // first arg to "attributes" call 104 105 // load name value again 106 nameValue.setEnd(il.append(new ALOAD(nameValue.getIndex()))); 107 } else { 108 // Save the current handler base on the stack 109 il.append(methodGen.loadHandler()); 110 il.append(DUP); // first arg to "attributes" call 111 112 // Push attribute name 113 _name.translate(classGen, methodGen);// 2nd arg 114 115 } 116 117 il.append(classGen.loadTranslet()); 118 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 119 "stringValueHandler", 120 STRING_VALUE_HANDLER_SIG))); 121 il.append(DUP); 122 il.append(methodGen.storeHandler()); 123 124 // translate contents with substituted handler 125 translateContents(classGen, methodGen); 126 127 // get String out of the handler 128 il.append(new INVOKEVIRTUAL(cpg.addMethodref(STRING_VALUE_HANDLER, 129 "getValueOfPI", 130 "()" + STRING_SIG))); 131 // call "processingInstruction" 132 final int processingInstruction = 133 cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 134 "processingInstruction", 135 "(" + STRING_SIG + STRING_SIG + ")V"); 136 il.append(new INVOKEINTERFACE(processingInstruction, 3)); 137 // Restore old handler base from stack 138 il.append(methodGen.storeHandler()); 139 } 140 }