package org.develnext.jphp.debug.impl.command.support; import org.apache.commons.codec.binary.Base64; import org.develnext.jphp.debug.impl.Debugger; import org.w3c.dom.Document; import org.w3c.dom.Element; import php.runtime.Memory; import php.runtime.lang.ForeachIterator; import php.runtime.lang.IObject; import php.runtime.memory.ArrayMemory; import php.runtime.memory.ObjectMemory; import php.runtime.memory.StringMemory; import java.util.Arrays; import java.util.HashSet; import java.util.Set; public class ContextValueProvider { protected final Debugger debugger; protected final Document document; protected int maxData; protected int maxChildren; public ContextValueProvider(Debugger debugger, Document document) { this.debugger = debugger; this.document = document; this.maxData = 99; this.maxChildren = 30; if (debugger != null && debugger.ideFeatures.has("max_data")) { this.maxData = debugger.ideFeatures.getInteger("max_data"); } if (debugger != null && debugger.ideFeatures.has("max_children")) { this.maxChildren = debugger.ideFeatures.getInteger("max_children"); } } public int getMaxData() { return maxData; } public void setMaxData(int maxData) { this.maxData = maxData; } public int getMaxChildren() { return maxChildren; } public void setMaxChildren(int maxChildren) { this.maxChildren = maxChildren; } public Element getProperty(String name, Memory value) { return getProperty(name, value, new HashSet<Integer>()); } protected Element getProperty(String name, Memory value, Set<Integer> used) { Element property = document.createElement("property"); if (name != null) { property.setAttribute("name", "$" + name); property.setAttribute("fullname", "$" + name); } property.setAttribute("type", value.type.toString().toLowerCase()); property.setAttribute("constant", "0"); property.setAttribute("children", "0"); property.setAttribute("size", "1"); //property.setAttribute("address", String.valueOf(value.getPointer())); property.setAttribute("encoding", "base64"); switch (value.getRealType()) { case ARRAY: if (used.add(value.getPointer())) { processArray(property, value.toValue(ArrayMemory.class), used, false); used.remove(value.getPointer()); } else { property.appendChild(document.createCDATASection(Base64.encodeBase64String("**RECURSION**".getBytes()))); } break; case OBJECT: if (used.add(value.getPointer())) { processObject(property, value.toValue(ObjectMemory.class), used); used.remove(value.getPointer()); } else { property.appendChild(document.createCDATASection(Base64.encodeBase64String("**RECURSION**".getBytes()))); } break; case BOOL: property.setAttribute("type", "bool"); property.setAttribute("value", value.toBoolean() ? "1" : "0"); break; case NULL: break; case STRING: processString(property, value.toValue(StringMemory.class)); default: byte[] bytes = value.toString().getBytes(); if (maxData > 0 && bytes.length > maxData) { property.setAttribute("size", String.valueOf(bytes.length)); bytes = Arrays.copyOf(bytes, maxData); } property.appendChild(document.createCDATASection(Base64.encodeBase64String(bytes))); break; } return property; } protected void processObject(Element property, ObjectMemory objectMemory, Set<Integer> used) { IObject value = objectMemory.value; ArrayMemory properties = value.getProperties(); property.setAttribute("classname", value.getReflection().getName()); if (properties != null) { processArray(property, properties, used, true); } } protected void processString(Element property, StringMemory stringMemory) { property.setAttribute("size", String.valueOf(stringMemory.toString().length())); } protected void processArray(Element property, ArrayMemory array, Set<Integer> used, boolean forObjects) { if (array.size() != 0) { property.setAttribute("children", "1"); } property.setAttribute("numchildren", String.valueOf(array.size())); ForeachIterator iterator = array.foreachIterator(false, false); int count = 0; while (iterator.next()) { if (iterator.getValue().isUndefined()) { continue; } Element value = getProperty(null, iterator.getValue().toValue(), used); String key = iterator.getKey().toString(); if (forObjects) { key = key.replace('\0', '*'); if (key.startsWith("***")) { key = key.substring(3); } } value.setAttribute("name", key); property.appendChild(value); count++; if (maxChildren > 0 && count >= maxChildren) { break; } } } }