package php.runtime.memory.output.serialization; import php.runtime.Memory; import php.runtime.env.Environment; import php.runtime.env.TraceInfo; import php.runtime.exceptions.support.ErrorType; import php.runtime.lang.ForeachIterator; import php.runtime.lang.IObject; import php.runtime.lang.spl.Serializable; import php.runtime.memory.*; import php.runtime.reflection.ClassEntity; import php.runtime.reflection.PropertyEntity; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; public class Serializer { protected final Environment env; protected final StringBuilder printer; protected final TraceInfo trace; public Serializer(Environment env, TraceInfo trace, StringBuilder writer) { this.env = env; this.trace = trace; this.printer = writer; } public void write(Memory memory){ switch (memory.type){ case NULL: writeNull(); break; case BOOL: writeBoolean(memory); break; case INT: writeLong((LongMemory)memory); break; case DOUBLE: writeDouble((DoubleMemory)memory); break; case STRING: writeString((StringMemory)memory); break; case ARRAY: writeArray((ArrayMemory)memory); break; case OBJECT: writeObject((ObjectMemory)memory, new HashSet<Integer>()); break; case REFERENCE: if (!memory.isShortcut()) write(memory.toValue()); else writeNull(); break; } } public void writeNull(){ printer.append("N;"); } public void writeLong(LongMemory memory){ printer.append("i:"); printer.append(memory.toString()); printer.append(";"); } public void writeDouble(DoubleMemory memory){ printer.append("d:"); printer.append(memory.toString()); printer.append(";"); } public void writeBoolean(Memory memory){ printer.append("b:") .append(memory.toBoolean() ? "1" : "0") .append(";"); } public void writeString(StringMemory memory){ String value = memory.toString(); printer.append("s:") .append(value.length()) .append(":\"") .append(value) .append("\";"); } public void writeArray(ArrayMemory memory){ writeArray(memory, new HashSet<Integer>(), true); } public void writeArray(ArrayMemory memory, Set<Integer> used, boolean appendType){ if (used.add(memory.getPointer())){ if (appendType) printer.append("a:"); printer.append(String.valueOf(memory.size())).append(":{"); ForeachIterator iterator = memory.foreachIterator(false, false); while (iterator.next()){ Memory key = iterator.getMemoryKey(); write(key); if (iterator.getValue().isReference()) writeNull(); else write(iterator.getValue()); } printer.append("}"); used.remove(memory.getPointer()); } else writeNull(); } public void writeObject(ObjectMemory memory, Set<Integer> used){ if (used.add(memory.getPointer())){ IObject object = memory.value; ClassEntity reflection = object.getReflection(); if (object instanceof Serializable){ Memory result; env.pushCall(trace, object, "serialize"); try { result = ((Serializable) object).serialize(env); if (result.isNull()){ writeNull(); return; } if (result.isString()){ String value = result.toString(); printer.append("C:") .append(reflection.getName().length()) .append(":\"") .append(reflection.getName()) .append("\":") .append(value.length()) .append(":{").append(value).append("}"); return; } else { env.exception(trace, reflection.getName() + "::serialize() must return a string or NULL"); } } finally { env.popCall(); } } ArrayMemory only = null; if (reflection.methodMagicSleep != null){ env.pushCall(trace, object, reflection.methodMagicSleep.getName()); try { Memory result = reflection.methodMagicSleep.invokeDynamic(object, env); if (!result.isArray()){ env.error( ErrorType.E_NOTICE, "serialize(): __sleep() should return an array only containing the names of instance-variables to serialize" ); writeNull(); return; } else { ForeachIterator iterator = result.getNewIterator(env, false, false); only = new ArrayMemory(true); ArrayMemory props = memory.getProperties(); Set<String> need = new LinkedHashSet<String>(); while (iterator.next()){ if (iterator.getValue().isNumber()) continue; need.add(iterator.getValue().toString()); } for(PropertyEntity e : reflection.getProperties()){ if (need.contains(e.getName())){ props.refOfIndex(e.getSpecificName()); } } iterator = result.getNewIterator(env, false, false); while (iterator.next()){ Memory value = iterator.getValue().toValue(); PropertyEntity entity = reflection.findProperty(value.toString()); value = entity == null ? props.valueOfIndex(value).toValue() : props.valueOfIndex(entity.getSpecificName()).toValue(); if (value == Memory.UNDEFINED){ env.error(trace, ErrorType.E_NOTICE, "serialize(): \"%s\" returned as member variable from __sleep() but does not exist", iterator.getValue().toString() ); } if (entity != null) only.put(entity.getSpecificName(), value); else only.refOfIndex(iterator.getValue()).assign(value); } } } catch (RuntimeException e){ throw e; } catch (Throwable throwable) { throw new RuntimeException(throwable); } finally { env.popCall(); } } printer.append("O:"); printer.append(String.valueOf(reflection.getName().length())); printer.append(":\""); printer.append(reflection.getName()); printer.append("\":"); if (reflection.getProperties() == null) writeArray(new ArrayMemory(), used, false); else writeArray(only == null ? object.getProperties() : only, used, false); } else writeNull(); } }