gt:             if (obj instanceof LazyObject) {
context: /*
   *  Copyright (C) 2010-2015 JPEXS, All rights reserved.
   *
   * 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 3.0 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.
   */
  package com.jpexs.decompiler.flash.exporters.swf;
  
  import com.jpexs.decompiler.flash.SWF;
  import com.jpexs.decompiler.flash.configuration.Configuration;
  import com.jpexs.decompiler.flash.helpers.CodeFormatting;
  import com.jpexs.decompiler.flash.helpers.FileTextWriter;
  import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
  import com.jpexs.decompiler.flash.helpers.LazyObject;
  import com.jpexs.decompiler.flash.tags.Tag;
  import com.jpexs.decompiler.flash.types.annotations.Internal;
  import com.jpexs.helpers.ByteArrayRange;
  import com.jpexs.helpers.Helper;
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.lang.reflect.Array;
  import java.lang.reflect.Field;
  import java.lang.reflect.Modifier;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.logging.Level;
  import java.util.logging.Logger;
  
  /**
   *
   * @author JPEXS
   */
  public class SwfJavaExporter {
  
      private static final String javaIndentString = "    ";
  
      private static final String[] allowedSubTypes = new String[]{"List", "String", "ByteArrayRange", "RECT", "MATRIX", "CXFORMWITHALPHA",
          "CXFORM", "CLIPEVENTFLAGS", "CLIPACTIONRECORD", "CLIPACTIONS", "COLORMATRIXFILTER", "RGBA", "ARGB", "RGB",
          "CONVOLUTIONFILTER", "BLURFILTER", "DROPSHADOWFILTER", "GLOWFILTER", "BEVELFILTER", "GRADIENTGLOWFILTER", "GRADIENTBEVELFILTER",
          "FILTERLIST", "FILTER", "BUTTONRECORD", "BUTTONCONDACTION", "GRADRECORD", "GRADIENT", "FOCALGRADIENT", "FILLSTYLE",
          "FILLSTYLEARRAY", "LINESTYLE", "LINESTYLE2", "LINESTYLEARRAY", "SHAPERECORD", "SHAPE", "SHAPEWITHSTYLE", "SHAPERECORDS",
          "SOUNDINFO", "SOUNDENVELOPE", "GLYPHENTRY", "TEXTRECORD", "MORPHGRADRECORD", "MORPHGRADIENT", "MORPHFOCALGRADIENT",
          "MORPHFILLSTYLE", "MORPHFILLSTYLEARRAY", "MORPHLINESTYLE", "MORPHLINESTYLE2", "MORPHLINESTYLEARRAY", "KERNINGRECORD",
          "LANGCODE", "ZONERECORD", "ZONEDATA", "PIX15", "PIX24", "COLORMAPDATA", "BITMAPDATA", "ALPHABITMAPDATA", "ALPHACOLORMAPDATA"};
  
      public List<File> exportJavaCode(SWF swf, String outdir) throws IOException {
          final File file = new File(outdir + File.separator + Helper.makeFileName("SwfFile.java"));
          CodeFormatting codeFormatting = Configuration.getCodeFormatting();
          codeFormatting.indentString = javaIndentString;
          try (FileTextWriter writer = new FileTextWriter(codeFormatting, new FileOutputStream(file))) {
              exportJavaCode(swf, writer);
          }
  
          List<File> ret = new ArrayList<>();
          ret.add(file);
          return ret;
      }
  
      public void exportJavaCode(SWF swf, GraphTextWriter writer) throws IOException {
          Map<String, Integer> objectNames = new HashMap<>();
          writer.append("package com.jpexs.decompiler.flash.exporters.swf;").newLine();
          writer.newLine();
          writer.append("import com.jpexs.decompiler.flash.SWF;").newLine();
          writer.append("import com.jpexs.decompiler.flash.SWFCompression;").newLine();
          writer.append("import com.jpexs.decompiler.flash.tags.*;").newLine();
          writer.append("import com.jpexs.decompiler.flash.types.*;").newLine();
          writer.append("import com.jpexs.decompiler.flash.types.filters.*;").newLine();
          writer.append("import com.jpexs.decompiler.flash.types.shaperecords.*;").newLine();
          writer.append("import com.jpexs.helpers.ByteArrayRange;").newLine();
          writer.append("import java.io.FileOutputStream;").newLine();
          writer.append("import java.io.IOException;").newLine();
          writer.append("import java.util.ArrayList;").newLine();
          writer.append("import java.util.List;").newLine();
          writer.newLine();
          writer.append("@SuppressWarnings(\"unchecked\")").newLine();
          writer.append("public class SwfFile {").newLine();
          writer.newLine();
          writer.indent();
          IndentedStringBuilder sb = new IndentedStringBuilder(javaIndentString);
          generateJavaCode(writer, sb, objectNames, swf, 0);
          writer.unindent();
          writer.append("    public SWF getSwf() {").newLine();
          writer.append("        SWF swf = swf();").newLine();
          writer.append("        swf.updateCharacters();").newLine();
          writer.append("        return swf;").newLine();
          writer.append("    }").newLine();
          writer.newLine();
          writer.append("    public void saveTo(String fileName) throws IOException {").newLine();
          writer.append("        SWF swf = getSwf();").newLine();
          writer.append("        swf.clearModified();").newLine();
          writer.append("        try (FileOutputStream fos = new FileOutputStream(fileName)) {").newLine();
          writer.append("            swf.saveTo(fos, SWFCompression.ZLIB);").newLine();
          writer.append("        }").newLine();
          writer.append("    }").newLine();
          writer.append("}").newLine();
      }
  
      private static String getNextId(Map<String, Integer> objectNames, String type) {
          Integer nextId = objectNames.get(type);
          if (nextId == null) {
              nextId = 0;
          } else {
              nextId++;
          }
  
          objectNames.put(type, nextId);
          return type + nextId;
      }
  
      private static String getIndent(int indent, String indentStr) {
          StringBuilder sb = new StringBuilder();
          for (int i = 0; i < indent; i++) {
              sb.append(indentStr);
          }
          return sb.toString();
      }
  
      private static Object generateJavaCode(GraphTextWriter writer, IndentedStringBuilder sb, Map<String, Integer> objectNames, Object obj, int level) {
          if (obj == null) {
              return null;
          }
  
          Class cls = obj.getClass();
          Object value = null;
  
          if (cls == Byte.class || cls == byte.class
                  || cls == Short.class || cls == short.class
                  || cls == Integer.class || cls == int.class
                  || cls == Long.class || cls == long.class
                  || cls == Float.class || cls == float.class
                  || cls == Double.class || cls == double.class
                  || cls == Boolean.class || cls == boolean.class
                  || cls == Character.class || cls == char.class
                  || cls == String.class) {
              value = obj;
              if (value instanceof Float) {
                  value = value + "f";
              } else if (value instanceof String) {
                  value = "\"" + Helper.escapeJavaString((String) value) + "\"";
              }
          } else if (cls.isEnum()) {
              value = cls.getSimpleName() + "." + obj;
          } else if (obj instanceof ByteArrayRange) {
              ByteArrayRange range = (ByteArrayRange) obj;
              String className = "ByteArrayRange";
              String tagObjName = getNextId(objectNames, "objByteArrayRange");
              byte[] data = range.getRangeData();
              StringBuilder sb2 = new StringBuilder();
              final int maxBytePerString = 32767;
              boolean isLong = data.length > maxBytePerString;
              if (isLong) {
                  // string should be splitted to avoid "constant string too long" compile error
                  sb2.append("String.join(\"\", ");
              }
  
              int stringCount = (int) Math.ceil(data.length / (double) maxBytePerString);
              for (int i = 0; i < stringCount; i++) {
                  if (i != 0) {
                      sb2.append(", ");
                  }
  
                  sb2.append("\"");
                  int from = i * maxBytePerString;
                  int to = Math.min(from + maxBytePerString, data.length);
                  for (int j = from; j < to; j++) {
                      sb2.append(Helper.byteToHex(data[j]));
                  }
  
                  sb2.append("\"");
              }
  
              if (isLong) {
                  sb2.append(")");
              }
  
              sb.appendLine(className + " " + tagObjName + " = new ByteArrayRange(" + sb2.toString() + ");");
              value = tagObjName;
          } else if (List.class.isAssignableFrom(cls)) {
              List list = (List) obj;
              String tagObjName = getNextId(objectNames, "objList");
              sb.appendLine("List " + tagObjName + " = new ArrayList();");
              for (int i = 0; i < list.size(); i++) {
                  Object val = generateJavaCode(writer, sb, objectNames, list.get(i), level + 1);
                  sb.appendLine(tagObjName + ".add(" + val + ");");
              }
              value = tagObjName;
          } else if (cls.isArray()) {
              String tagObjName = getNextId(objectNames, "objArray");
              String arrayType = cls.getComponentType().getSimpleName();
              int length = Array.getLength(obj);
              sb.appendLine(arrayType + "[] " + tagObjName + " = new " + arrayType + "[" + length + "];");
              for (int i = 0; i < length; i++) {
                  Object val = generateJavaCode(writer, sb, objectNames, Array.get(obj, i), level + 1);
                  sb.appendLine(tagObjName + "[" + i + "] = " + val + ";");
              }
              value = tagObjName;
          } else {
  