/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.driver.system.acpi.aml; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; /** * ParseNode. * <p/> * <p> * Title: * </p> * <p> * Description: * </p> * <p> * Copyright: Copyright (c) 2003 * </p> * <p> * Company: * </p> * * @author not attributable * @version 1.0 */ public class ParseNode { private static final Logger log = Logger.getLogger(ParseNode.class); protected int opcode; protected NameString name = null; protected List<ParseNode> args = new ArrayList<ParseNode>(); protected Object value; protected ParseNode parent; protected ParseNode next; ByteBuffer data = null; public ParseNode() { } public ParseNode(int opcode) { this.opcode = opcode; } public ParseNode getNext() { return next; } public int getType() { return opcode; } public NameString getName() { return name; } public boolean isScope() { return opcode == Aml.AML_SCOPE; } public boolean isMethod() { return opcode == Aml.AML_METHOD; } public boolean isName() { return opcode == Aml.AML_NAME; } public String getNameToString() { if (name != null) return name.toString(); return null; } /** * use append arg for the other classes * * @param arg * private void addArg(ParseNode arg) { args.add(arg); }*/ /** * Gets the number of arguments * * @return int */ public int argCount() { return args.size(); } public boolean isNamedOpcode() { return Aml.isNamedOpcode(opcode); } /* * Append an argument to an op's argument list (a NULL arg is OK) */ /** * arg mayt be the head of a linked list args, not just one arg. * * @param arg */ public void appendArg(ParseNode arg) { if (arg == null) { return; } switch (opcode) { case Aml.AML_ZEROOP: case Aml.AML_ONEOP: case Aml.AML_ONESOP: case Aml.AML_BYTECONST: case Aml.AML_WORDCONST: case Aml.AML_DWORDCONST: case Aml.AML_STRING: case Aml.AML_STATICSTRING: case Aml.AML_NAMEPATH: case Aml.AML_NAMEDFIELD: case Aml.AML_RESERVEDFIELD: case Aml.AML_ACCESSFIELD: case Aml.AML_BYTELIST: case Aml.AML_LOCAL0: case Aml.AML_LOCAL1: case Aml.AML_LOCAL2: case Aml.AML_LOCAL3: case Aml.AML_LOCAL4: case Aml.AML_LOCAL5: case Aml.AML_LOCAL6: case Aml.AML_LOCAL7: case Aml.AML_ARG0: case Aml.AML_ARG1: case Aml.AML_ARG2: case Aml.AML_ARG3: case Aml.AML_ARG4: case Aml.AML_ARG5: case Aml.AML_ARG6: case Aml.AML_NOOP: case Aml.AML_BREAK: case Aml.AML_BREAKPOINT: case Aml.AML_EVENT: case Aml.AML_REVISION: case Aml.AML_DEBUG: // no arguments for these ops break; default: if (args.size() >= 1) { final ParseNode tmp = args.get(args.size() - 1); tmp.next = arg; args.add(arg); } else { // first argument args.add(arg); } while (arg != null) { arg.parent = this; arg = arg.next; } break; } } /* * Get op's children or NULL if none */ public ParseNode geChild() { ParseNode child = null; switch (opcode) { case Aml.AML_SCOPE: case Aml.AML_ELSE: case Aml.AML_DEVICE: case Aml.AML_THERMALZONE: case Aml.AML_METHODCALL: child = getArg(0); break; case Aml.AML_BUFFER: case Aml.AML_PACKAGE: case Aml.AML_METHOD: case Aml.AML_IF: case Aml.AML_WHILE: case Aml.AML_FIELD: child = getArg(1); break; case Aml.AML_POWERRES: case Aml.AML_INDEXFIELD: child = getArg(2); break; case Aml.AML_PROCESSOR: case Aml.AML_BANKFIELD: child = getArg(3); break; } return child; } /* * Get op's parent */ public ParseNode getParent() { ParseNode parent = this; while (parent != null) { switch (parent.opcode) { case Aml.AML_SCOPE: case Aml.AML_PACKAGE: case Aml.AML_METHOD: case Aml.AML_DEVICE: case Aml.AML_POWERRES: case Aml.AML_THERMALZONE: return parent.parent; } parent = parent.parent; } return parent; } /* * Get next op in tree (walking the tree in depth-first order) Return NULL when reaching * "origin" or when walking up from root */ public ParseNode getDepthNext(ParseNode current) { ParseNode nextTarget = null; // look for an argument or child if (current != null) { // look for a sibling nextTarget = current.getArg(0); if (nextTarget == null) { // look for a sibling of parent nextTarget = current.next; if (nextTarget == null) { ParseNode parentTarget = current.parent; while (parentTarget != null) { ParseNode arg = parentTarget.getArg(0); while (arg != null && !arg.equals(this) && !arg.equals(current)) { arg = arg.next; } if (arg.equals(this)) { // reached parent of origin // end search return null; } if (parentTarget.next != null) { // found sibling of parent return parentTarget.next; } current = parentTarget; parentTarget = parentTarget.parent; } } } } return nextTarget; } /* * Get specified op's argument or NULL if none */ public ParseNode getArg(int argn) { ParseNode arg = null; switch (opcode) { case Aml.AML_ZEROOP: case Aml.AML_ONEOP: case Aml.AML_ONESOP: case Aml.AML_BYTECONST: case Aml.AML_WORDCONST: case Aml.AML_DWORDCONST: case Aml.AML_STRING: case Aml.AML_STATICSTRING: case Aml.AML_FIELDFLAGS: case Aml.AML_REGIONSPACE: case Aml.AML_METHODFLAGS: case Aml.AML_SYNCFLAGS: case Aml.AML_NAMEPATH: case Aml.AML_NAMEDFIELD: case Aml.AML_RESERVEDFIELD: case Aml.AML_ACCESSFIELD: case Aml.AML_BYTELIST: case Aml.AML_LOCAL0: case Aml.AML_LOCAL1: case Aml.AML_LOCAL2: case Aml.AML_LOCAL3: case Aml.AML_LOCAL4: case Aml.AML_LOCAL5: case Aml.AML_LOCAL6: case Aml.AML_LOCAL7: case Aml.AML_ARG0: case Aml.AML_ARG1: case Aml.AML_ARG2: case Aml.AML_ARG3: case Aml.AML_ARG4: case Aml.AML_ARG5: case Aml.AML_ARG6: case Aml.AML_NOOP: case Aml.AML_BREAK: case Aml.AML_BREAKPOINT: case Aml.AML_EVENT: case Aml.AML_REVISION: case Aml.AML_DEBUG: // no arguments for these ops break; default: if (args != null) { if (argn < args.size()) { try { arg = (ParseNode) args.get(argn); } catch (Exception ex) { ParseNode tmp = this; while (tmp.parent != null) tmp = tmp.parent; log.debug(tmp, ex); } } } break; } return arg; } /* * Is opcode for a Field, IndexField, or BankField */ boolean isFieldOpcode() { return Aml.isFieldOpcode(opcode); } public void setName(String name) { NameString ns = new NameString(); ns.setNamePath(name); this.name = ns; } public void setName(NameString name) { this.name = name; } public ParseNode findName(NameString name, int opcode) { ParseNode child = this.geChild(); while (child != null) { if (child.isFieldOpcode()) { // field, search named fields ParseNode field = child.geChild(); while (field != null) { if (field.isNamedOpcode() && field.getName().equals(name) && (opcode != 0 || field.opcode == opcode)) { return field; } field = field.next; } } else if (child.isNamedOpcode() && child.getName().equals(name) && (opcode != 0 || child.opcode == opcode)) { break; } child = child.next; } return child; } public Object findNameValue(String name) { Object result = null; NameString ns = new NameString(); ns.setNamePath(name); ParseNode node = findName(ns, Aml.AML_NAME); if (node != null) { result = (node.args.get(0)).value; } return result; } public ParseNode find(NameString name, int opcode, boolean create) { boolean unprefixed = false; int seg_count; int name_op; String prefix = null; ParseNode searchedNode = this; ParseNode originNode = this; if (name == null) return null; // get prefix and starting scope prefix = name.getPrefix(); if (prefix != null && prefix.length() > 0) { for (int pos = 0; pos < prefix.length() && Aml.isPrefixChar((byte) prefix.charAt(pos)); pos++) { switch (prefix.charAt(pos)) { case '\\': while (originNode.parent != null) { originNode = originNode.parent; } break; case '^': if (originNode.getParent() != null) { originNode = originNode.getParent(); } break; } } } else unprefixed = true; // at this stage originNode contains the appropriate search origin // get name segment count seg_count = name.getSegCount(); // match each name segment int index = 0; while (originNode != null && seg_count != 0) { String nameseg = name.getNameseg(index); seg_count--; index++; name_op = seg_count != 0 ? 0 : opcode; searchedNode = originNode.findName(name, name_op); if (searchedNode == null) { if (create) { // create new scope level searchedNode = new ParseNode((seg_count != 0 ? Aml.AML_SCOPE : opcode)); if (searchedNode != null) { searchedNode.setName(nameseg); originNode.appendArg(searchedNode); } } else if (unprefixed) { // search scopes for unprefixed name //FIXME searchedNode is null in this case ! while (searchedNode != null && searchedNode.parent != null) { originNode = originNode.parent; searchedNode = originNode.findName(name, opcode); } } } unprefixed = false; originNode = searchedNode; } // for return searchedNode; } public String toString() { return toString(""); } public String toString(String prefix) { StringBuffer result = new StringBuffer(); String opcodeName = null; AmlOpcode opc = AmlOpcode.getAmlOpcode(opcode); if (opc == null) { switch (opcode) { case Aml.AML_BYTELIST: opcodeName = "Bytelist"; break; case Aml.AML_NAMEPATH: opcodeName = "Namepath"; break; case Aml.AML_SYNCFLAGS: opcodeName = "SyncLevel"; break; case Aml.AML_METHODFLAGS: opcodeName = "ArgCount"; break; default: opcodeName = "Opcode-" + opcode; break; } } else opcodeName = opc.name; result.append(prefix); result.append(opcodeName); String nameString = ""; if (this.name == null) { if (opcode == Aml.AML_SCOPE) { nameString = "\\"; } } else nameString = name.toString(); result.append(" "); result.append(nameString); if (value != null) { result.append(" = "); if (value instanceof Integer) result.append(Integer.toHexString(((Integer) value).intValue())); else result.append(value); } result.append('\n'); for (int i = 0; i < args.size(); i++) { if (getArg(i) != null) result.append(getArg(i).toString(prefix + " | ")); } return result.toString(); } public String toString3(String prefix) { StringBuffer result = new StringBuffer(); //String opcodeName = null; AmlOpcode opc = AmlOpcode.getAmlOpcode(opcode); if (opc != null) { switch (opcode) { case Aml.AML_NAME: if (this.parent.opcode == Aml.AML_PACKAGE) { return prefix + "currentPackage.add(\"" + value + "\");\n"; } else return prefix + "currentName=Name(\"" + name.toString() + "\");\n"; case Aml.AML_PACKAGE: result.setLength(0); result.append(prefix + "currentPackage=Package("); result.append(this.args.get(0).value); result.append(");\n"); result.append(prefix); result.append("currentName.add(currentPackage);\n"); return result.toString(); case Aml.AML_BUFFER: result.setLength(0); result.append(prefix); result.append("currentBuffer=Buffer("); result.append(this.args.get(0).value); result.append(");\n"); result.append(prefix); result.append("currentName.add(currentBuffer);\n"); return result.toString(); case Aml.AML_STRING: result.setLength(0); result.append(prefix); result.append("currentPackage.add(\""); result.append(value); result.append("\");\n"); return result.toString(); } } return "@"; } }