From 788a09389ba58fae55502451e6fd2c44bed0a9a0 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sun, 26 Jan 2020 17:02:04 +0500 Subject: [PATCH 1/2] Fix CI build --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5a7b438..c1c96da 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,4 +15,6 @@ jobs: with: java-version: ${{ matrix.java }} - name: Build with Maven - run: mvn -B package --file pom.xml + run: | + mvn install:install-file -Dfile=lib/HexLib.jar -DgroupId=at.HexLib -DartifactId=HexLib -Dversion=0.0.0 -Dpackaging=jar -DlocalRepositoryPath=./lib + mvn -B package --file pom.xml From c07c0827760437c5e6f3d8ed18307fc001a76436 Mon Sep 17 00:00:00 2001 From: Mingun Date: Mon, 13 Jan 2020 00:22:34 +0500 Subject: [PATCH 2/2] Add support for types with parameters --- .../struct/visualizer/VisualizerPanel.java | 79 +++++++++++++++---- 1 file changed, 64 insertions(+), 15 deletions(-) diff --git a/src/main/java/io/kaitai/struct/visualizer/VisualizerPanel.java b/src/main/java/io/kaitai/struct/visualizer/VisualizerPanel.java index c7e2662..cbd8fa6 100644 --- a/src/main/java/io/kaitai/struct/visualizer/VisualizerPanel.java +++ b/src/main/java/io/kaitai/struct/visualizer/VisualizerPanel.java @@ -2,14 +2,19 @@ import java.awt.Point; import java.io.IOException; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import at.HexLib.library.HexLib; import at.HexLib.library.HexLibSelectionModel; + +import io.kaitai.struct.ByteBufferKaitaiStream; import io.kaitai.struct.CompileLog; +import io.kaitai.struct.KaitaiStream; import io.kaitai.struct.KaitaiStruct; import io.kaitai.struct.Main; import io.kaitai.struct.RuntimeConfig; @@ -34,7 +39,17 @@ public class VisualizerPanel extends JPanel { private static final String DEST_PACKAGE = "io.kaitai.struct.visualized"; - private static final Pattern TOP_CLASS_NAME = Pattern.compile("public class (.*?) extends KaitaiStruct"); + /** + * Regexp with 2 groups: class name and type parameters. Type parameters + * must be parsed with {@link #PARAMETER_NAME}. + */ + private static final Pattern TOP_CLASS_NAME_AND_PARAMETERS = Pattern.compile( + "public class (.+?) extends KaitaiStruct.*" + + "public \\1\\(KaitaiStream _io, KaitaiStruct _parent, \\1 _root(.*?)\\)", + Pattern.DOTALL + ); + /** Regexp, used to get parameter names from the generated source. */ + private static final Pattern PARAMETER_NAME = Pattern.compile(", \\S+ ([^,\\s]+)"); private final JTree tree = new JTree(); private final DefaultTreeModel model = new DefaultTreeModel(null); @@ -107,28 +122,62 @@ private static String compileKSY(String ksyFileName) { * static methods, etc. * @throws Exception */ - private static Class compileAndLoadJava(String javaSrc) throws Exception { - Matcher m = TOP_CLASS_NAME.matcher(javaSrc); - if (!m.find()) - throw new RuntimeException("Unable to find top-level class in compiled .java"); - String className = m.group(1); - return InMemoryJavaCompiler.compile(DEST_PACKAGE + "." + className, javaSrc); - } - private void parseFileWithKSY(String ksyFileName, String binaryFileName) throws Exception { - String javaSrc = compileKSY(ksyFileName); - Class ksyClass = compileAndLoadJava(javaSrc); + final String javaSrc = compileKSY(ksyFileName); + final Matcher m = TOP_CLASS_NAME_AND_PARAMETERS.matcher(javaSrc); + if (!m.find()) { + throw new RuntimeException("Unable to find top-level class in generated .java"); + } + // Parse parameter names + final ArrayList paramNames = new ArrayList<>(); + final Matcher p = PARAMETER_NAME.matcher(m.group(2)); + while (p.find()) { + paramNames.add(p.group(1)); + } - // Find and run "fromFile" helper method to - Method fromFileMethod = ksyClass.getMethod("fromFile", String.class); - Object kso = fromFileMethod.invoke(null, binaryFileName); - struct = (KaitaiStruct) kso; + final Class ksyClass = InMemoryJavaCompiler.compile(DEST_PACKAGE + "." + m.group(1), javaSrc); + struct = construct(ksyClass, paramNames, binaryFileName); // Find and run "_read" that does actual parsing // TODO: wrap this in try-catch block Method readMethod = ksyClass.getMethod("_read"); readMethod.invoke(struct); } + private static KaitaiStruct construct(Class ksyClass, List paramNames, String binaryFileName) throws Exception { + final Constructor c = findConstructor(ksyClass); + final Class[] types = c.getParameterTypes(); + final Object[] args = new Object[types.length]; + args[0] = new ByteBufferKaitaiStream(binaryFileName); + for (int i = 3; i < args.length; ++i) { + args[i] = getDefaultValue(types[i]); + } + // TODO: get parameters from user + return (KaitaiStruct)c.newInstance(args); + } + private static Constructor findConstructor(Class ksyClass) { + for (final Constructor c : ksyClass.getDeclaredConstructors()) { + final Class[] types = c.getParameterTypes(); + if (types.length >= 3 + && types[0] == KaitaiStream.class + && types[1] == KaitaiStruct.class + && types[2] == ksyClass + ) { + return c; + } + } + throw new IllegalArgumentException(ksyClass + " has no KaitaiStruct-generated constructor"); + } + private static Object getDefaultValue(Class clazz) { + if (clazz == boolean.class) return false; + if (clazz == char.class ) return (char)0; + if (clazz == byte.class ) return (byte)0; + if (clazz == short.class ) return (short)0; + if (clazz == int.class ) return 0; + if (clazz == long.class ) return 0L; + if (clazz == float.class ) return 0.0f; + if (clazz == double.class ) return 0.0; + return null; + } public class KaitaiTreeListener implements TreeWillExpandListener, TreeSelectionListener { @Override