package php.runtime.loader.dump; import php.runtime.common.Messages; import php.runtime.env.Context; import php.runtime.env.Environment; import php.runtime.exceptions.support.ErrorType; import php.runtime.loader.dump.io.DumpException; import php.runtime.loader.dump.io.DumpInputStream; import php.runtime.loader.dump.io.DumpOutputStream; import php.runtime.reflection.*; import php.runtime.reflection.helper.GeneratorEntity; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; public class ClassDumper extends Dumper<ClassEntity> { protected final PropertyDumper propertyDumper = new PropertyDumper(context, env, debugInformation); protected final ConstantDumper constantDumper = new ConstantDumper(context, env, debugInformation); protected final MethodDumper methodDumper = new MethodDumper(context, env, debugInformation); protected final ModuleEntity module; public ClassDumper(Context context, ModuleEntity module, Environment env, boolean debugInformation) { super(context, env, debugInformation); this.module = module; } @Override public int getType() { return Types.CLASS; } @Override public void save(ClassEntity entity, OutputStream output) throws IOException { if (entity.getType() == ClassEntity.Type.CLASS && entity.getData() == null) throw new DumpException("Class '" + entity.getName() + "' not compiled"); DumpOutputStream printer = new DumpOutputStream(output); printer.writeBoolean(entity.isStatic()); // type printer.writeEnum(entity.getType()); printer.writeBoolean(entity.isAbstract()); printer.writeBoolean(entity.isFinal()); // print name printer.writeName(entity.getName()); printer.writeName(entity.getCompiledInternalName()); printer.writeTrace(debugInformation ? entity.getTrace() : null); // parent ClassEntity parent = entity.getParent(); if (entity.getParent() != null){ printer.writeName(parent.getName()); } else { printer.writeName(null); // write null } // constants List<ConstantEntity> constants = new ArrayList<ConstantEntity>(); for(ConstantEntity el : entity.getConstants()){ if (el.isOwned(entity)) constants.add(el); } printer.writeInt(constants.size()); for(ConstantEntity el : constants){ constantDumper.save(el, output); } // properties List<PropertyEntity> properties = new ArrayList<PropertyEntity>(); for(PropertyEntity el : entity.getStaticProperties()){ if (el.isOwned(entity)) properties.add(el); } for(PropertyEntity el : entity.getProperties()){ if (el.isOwned(entity)) properties.add(el); } printer.writeInt(properties.size()); for(PropertyEntity el : properties){ propertyDumper.save(el, output); } // methods printer.writeInt(entity.getMethodCounts()); List<MethodEntity> methods = entity.getOwnedMethods(); printer.writeInt(methods.size()); for (MethodEntity el : methods){ methodDumper.save(el, output); } // interfaces printer.writeInt(entity.getInterfaces().size()); for(ClassEntity el : entity.getInterfaces().values()){ printer.writeName(el.getName()); } // traits printer.writeInt(entity.getTraits().size()); for(ClassEntity el : entity.getTraits().values()){ printer.writeName(el.getName()); } if (includeData) { printer.writeRawData(entity.getData(), Integer.MAX_VALUE); } else { printer.writeRawData(null); } // addition raw data printer.writeRawData(null); } @Override public ClassEntity load(InputStream input) throws IOException { return load(input, ClassEntity.class); } public <T extends ClassEntity> T load(InputStream input, Class<T> clazz) throws IOException { DumpInputStream data = new DumpInputStream(input); T entity = null; try { entity = clazz.getConstructor(Context.class).newInstance(context); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } entity.setId(env.scope.nextClassIndex()); entity.setStatic(data.readBoolean()); entity.setType(data.readClassType()); entity.setAbstract(data.readBoolean()); entity.setFinal(data.readBoolean()); entity.setName(data.readName()); entity.setInternalName(data.readName()); entity.setTrace(data.readTrace(context)); // parent String parent = data.readName(); if (parent != null){ ClassEntity parentEntity = module == null ? null : module.findClass(parent); if (parentEntity == null) { parentEntity = env.fetchClass(parent, true); } if (parentEntity == null) { env.error(env.trace(), ErrorType.E_ERROR, Messages.ERR_CLASS_NOT_FOUND, parent); } else { ClassEntity.ExtendsResult result = entity.setParent(parentEntity, false); if (clazz != GeneratorEntity.class) result.check(env); } } // constants int constantCount = data.readInt(); for(int i = 0; i < constantCount; i++){ ConstantEntity el = constantDumper.load(input); el.setClazz(entity); entity.addConstant(el); } // properties int propertyCount = data.readInt(); for(int i = 0; i < propertyCount; i++){ PropertyEntity el = propertyDumper.load(input); el.setClazz(entity); ClassEntity.PropertyResult result = entity.addProperty(el); result.check(env); } // methods entity.__setMethodCounts(data.readInt()); int methodCount = data.readInt(); for(int i = 0; i < methodCount; i++){ MethodEntity el = methodDumper.load(input); el.setClazz(entity); ClassEntity.SignatureResult result = entity.addMethod(el, null); result.check(env); } entity.updateParentMethods().check(env); // interfaces int interfaceCount = data.readInt(); for(int i = 0; i < interfaceCount; i++){ String name = data.readName(); ClassEntity interfaceEntity = module == null ? null : module.findClass(name); if (interfaceEntity == null) interfaceEntity = env.fetchClass(name, true); if (interfaceEntity == null) env.error(env.trace(), ErrorType.E_ERROR, Messages.ERR_INTERFACE_NOT_FOUND, name); ClassEntity.ImplementsResult result = entity.addInterface(interfaceEntity); result.check(env); } int traitCount = data.readInt(); for(int i = 0; i < traitCount; i++) { String name = data.readName(); ClassEntity traitEntity = module == null ? null : module.findClass(name); if (traitEntity == null) traitEntity = env.fetchClass(name, true); if (traitEntity == null) env.error(env.trace(), ErrorType.E_ERROR, Messages.ERR_TRAIT_NOT_FOUND, name); else if (!traitEntity.isTrait()) env.error(env.trace(), ErrorType.E_ERROR, Messages.ERR_CANNOT_USE_NON_TRAIT, name); entity.addTrait(traitEntity); } entity.setData(data.readRawData(Integer.MAX_VALUE)); data.readRawData(); entity.doneDeclare(); return entity; } }