diff --git a/.gitignore b/.gitignore index 7e65dc8e..cb2f51b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,42 +1,30 @@ /**/target/ /target/ /nbproject/ -/.idea/ +/**/.idea/ *.iml /jbbp-plugins/jbbp-gradle/.gradle/ /jbbp-plugins/jbbp-gradle/build/ /jbbp/BenchmarkList /jbbp/CompilerHints /jbbp/nb-configuration.xml -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/common/converters/Java16Converter.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/common/converters/JBBPScriptTranslator$Parameters.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/common/converters/JBBPScriptTranslator.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/common/converters/ParserFlags.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/common/converters/Target.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/common/utils/CommonUtils.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/mvn/AbstractJBBPMojo.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/mvn/HelpMojo.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/mvn/JBBPCleanMojo.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojo$1.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojo.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/META-INF/maven/com.igormaznitsa/jbbp-maven-plugin/plugin-help.xml -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/classes/META-INF/maven/plugin.xml -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/generated-sources/plugin/com/igormaznitsa/jbbp/plugin/mvn/HelpMojo.java -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/maven-archiver/pom.properties -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/surefire-reports/TEST-com.igormaznitsa.jbbp.plugin.mvn.JBBPGenerateMojoTest.xml -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/test-classes/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojoTest.class -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/test-classes/com/igormaznitsa/jbbp/plugin/mvn/mojoConfig.xml -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/jbbp-maven-plugin-2.0.0-SNAPSHOT.jar -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/jbbp-maven-plugin-2.0.0-SNAPSHOT-bundle.jar -/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/target/maven-plugin-help.properties +/jbbp-plugins/**/target/ /jbbp/jmh-out.txt /jbbp/jmh-result.json /jbbp-plugins/jbbp-gradle/.settings/ /jbbp-plugins/jbbp-gradle/bin/ /jbbp-plugins/jbbp-gradle/.classpath /jbbp-plugins/jbbp-gradle/.project -/.vscode/ +/**/.vscode/ +/jbbp-plugins/jbbp-gradle/gradle/wrapper/ +/jbbp-plugins/jbbp-gradle/gradlew +/jbbp-plugins/jbbp-gradle/gradlew.bat +/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/build/ +/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/.gradle/ +/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/.gradle/ +/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/build/ +/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/.gradle/ +/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/build/ +/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/.gradle/ +/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/build/ +/jbbp/uber-pom.xml diff --git a/.projectKnowledge/JBBP.mmd b/.projectKnowledge/JBBP.mmd index 2aa92079..4f9496d7 100644 --- a/.projectKnowledge/JBBP.mmd +++ b/.projectKnowledge/JBBP.mmd @@ -1,8 +1,8 @@ -Mind Map generated by NB MindMap plugin +[Scia Reto](https://sciareto.org) mind map > __version__=`1.1`,showJumps=`true` --- -# Java Binary
Block Parser
v 2\.0\.1 +# Java Binary
Block Parser
v 3\.0\.1 ## License > fillColor=`#33CC00`,leftSide=`true` @@ -16,11 +16,11 @@ Mind Map generated by NB MindMap plugin > fillColor=`#CCCCFF`,leftSide=`true` -### Java 1\.8\+ +### Java 11\+ > fillColor=`#3399FF`,textColor=`#FFFFCC` -### Android 3\.0\+ +### Android 12\+ > fillColor=`#3399FF`,textColor=`#FFFFCC` diff --git a/.projectKnowledge/JBBP_Types.mmd b/.projectKnowledge/JBBP_Types.mmd index 1cfc8826..1fa5bdc4 100644 --- a/.projectKnowledge/JBBP_Types.mmd +++ b/.projectKnowledge/JBBP_Types.mmd @@ -82,6 +82,22 @@ Mind Map generated by NB MindMap plugin > fillColor=`#99FFFF` +#### uint +> fillColor=`#9999FF` + + +##### 32 bit unsigned field +> fillColor=`#99FFFF` + + +###### requires long representation +> fillColor=`#FF6666`,mmd.emoticon=`error` + + +###### can throw error in expression if value can\\t be represented as zero or positive int +> fillColor=`#FF6666`,mmd.emoticon=`error` + + #### long > fillColor=`#9999FF` diff --git a/README.md b/README.md index 05b8329b..8523e1c2 100644 --- a/README.md +++ b/README.md @@ -1,128 +1,183 @@ +![JBBP Logo](https://github.com/raydac/java-binary-block-parser/blob/master/logo.png) + [![License Apache 2.0](https://img.shields.io/badge/license-Apache%20License%202.0-green.svg)](http://www.apache.org/licenses/LICENSE-2.0) -[![Maven central](https://maven-badges.herokuapp.com/maven-central/com.igormaznitsa/jbbp/badge.svg)](http://search.maven.org/#artifactdetails|com.igormaznitsa|jbbp|2.0.1|jar) -[![Java 1.8+](https://img.shields.io/badge/java-1.8%2b-green.svg)](http://www.oracle.com/technetwork/java/javase/downloads/index.html) -[![Android 3.0+](https://img.shields.io/badge/android-3.0%2b-green.svg)](http://developer.android.com/sdk/index.html) -[![PayPal donation](https://img.shields.io/badge/donation-PayPal-red.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AHWJHJFBAWGL2) -[![Yandex.Money donation](https://img.shields.io/badge/donation-Я.деньги-yellow.svg)](http://yasobe.ru/na/iamoss) +[![Maven central](https://maven-badges.herokuapp.com/maven-central/com.igormaznitsa/jbbp/badge.svg)](http://search.maven.org/#artifactdetails|com.igormaznitsa|jbbp|3.0.1|jar) +[![Java 11+](https://img.shields.io/badge/java-11%2b-green.svg)](http://www.oracle.com/technetwork/java/javase/downloads/index.html) +[![Android 12+](https://img.shields.io/badge/android-12%2b-green.svg)](http://developer.android.com/sdk/index.html) +[![Arthur's acres sanctuary donation](docs/arthur_sanctuary_banner.png)](https://www.arthursacresanimalsanctuary.org/donate) -![JBBP Logo](https://github.com/raydac/java-binary-block-parser/blob/master/logo.png) # Introduction -Java has some embedded features to parse binary data (for instance ByteBuffer), but sometime it is needed to work on bit level and describe binary structures through some DSL(domain specific language). I was impressed by the [the Python Struct package](https://docs.python.org/2/library/struct.html) package and wanted to get something like that for Java. So I developed the JBBP library.
+ +Java has some embedded features to parse binary data (for instance ByteBuffer), but sometime it is needed to work on bit +level and describe binary structures through some DSL(domain specific language). I was impressed by +the [the Python Struct package](https://docs.python.org/2/library/struct.html) package and wanted to get something like +that for Java. So I developed the JBBP library.
![Use cases](https://github.com/raydac/java-binary-block-parser/blob/master/docs/jbbp_mm.png) # Change log -- **2.0.1 (04-feb-2020)** - - [#26](https://github.com/raydac/java-binary-block-parser/issues/26) fixed bug in array write with MSB0 - -- **2.0.0 (20-nov-2019)** - - __removed DslBinCustom annotation, use @Bin annotation instead__ - - __renamed attributes of @Bin annotation to their correct form__ - - __reworked object mapping system, removed hacks to instantiate classes, now only mapping to objects allowed, support of private fields mapping is removed__ - - __minimal JDK version now 1.8+__ - - __minimal Android API now 3.0+__ - - added support of getters and setters into mapping - - added `Object newInstance(Class)` method support of mapped classes to generate local class member instances - - added generating of `makeFIELD()` method for structure types in Java class converter - - refactoring - -- **1.4.1 (20-aug-2018)** - - fixed incompatibility in tokenizer regex syntax for Android SDK [#23](https://github.com/raydac/java-binary-block-parser/issues/23) - - added DslBinCustom annotation to provide way to mark custom type fields for JBBPDslBuilder - - fixed NPE in JBBPDslBuilder for not-provided outBitNumber attribute in annotated field marked as type BIT or BIT_ARRAY [#20](https://github.com/raydac/java-binary-block-parser/issues/20) - - naming of fields has been made more tolerant, now it is allowed to have field names with names similar to data types - - improved check of field names in JBBPDslBuilder [#21](https://github.com/raydac/java-binary-block-parser/issues/21) - -[Full changelog](https://github.com/raydac/java-binary-block-parser/blob/master/changelog.txt) + +- __3.0.1 (24-dec-2024)__ + - added `MSB0_DIRECT` bit order mode, MSB0 without data + revers [#46](https://github.com/raydac/java-binary-block-parser/issues/46) + - added `JBBPBitInputStream#isDetectedPartlyReadBitField` to check that only part of bit field read during last + operation + - added flag into constructors for JBBPBitInputStream to force return -1 instead of partly accumulated bits data if + end of field + +- __3.0.0 (16-nov-2024)__ + - __Minimum JDK Version: Updated to 11.0.__ + - __Minimum Supported Android: Updated to 12 (API 32).__ + - __API Changes:__ Modifications made to the CompiledBlockVisitor API. + - __New Feature:__ Added `JBBPUtils#findMaxStaticArraySize` for calculating the largest static array size defined in a + JBBP script. + - __Internal API:__ Certain internal APIs have been opened. + - __Codebase Improvements:__ General refactoring performed. + +- __2.1.0 (05-nov-2024)__ + - minor changes in API for `JBBPVarFieldProcessor` and `JBBPCustomFieldTypeProcessor` + - provided way to control size of arrays read as stream + rest [#44](https://github.com/raydac/java-binary-block-parser/issues/44) + - provided way to control size of arrays which size calculated through + expressions [#45](https://github.com/raydac/java-binary-block-parser/issues/45) + - improved tests + +[Full changelog](https://github.com/raydac/java-binary-block-parser/blob/master/changelog.txt) # Maven dependency + The Framework has been published in the Maven Central and can be easily added as a dependency + ``` com.igormaznitsa jbbp - 2.0.1 + 3.0.1 ``` -the precompiled library jar, javadoc and sources also can be downloaded directly from [the Maven central.](https://search.maven.org/artifact/com.igormaznitsa/jbbp/2.0.1/jar) + +the precompiled library jar, javadoc and sources also can be downloaded directly +from [the Maven central.](https://search.maven.org/artifact/com.igormaznitsa/jbbp/3.0.1/jar) # Hello world -The library is very easy in use because in many cases only two its classes are needed - com.igormaznitsa.jbbp.JBBPParser (for data parsing) and com.igormaznitsa.jbbp.io.JBBPOut (for binary block writing). Both these classes work over low-level IO classes - com.igormaznitsa.jbbp.io.JBBPBitInputStream and com.igormaznitsa.jbbp.io.JBBPBitOutputStream, those bit stream classes are the core of the library. -The easiet use case shows parsing of whole byte array to bits. +The library is very easy in use because in many cases only two its classes are needed - +com.igormaznitsa.jbbp.JBBPParser (for data parsing) and com.igormaznitsa.jbbp.io.JBBPOut (for binary block writing). +Both these classes work over low-level IO classes - com.igormaznitsa.jbbp.io.JBBPBitInputStream and +com.igormaznitsa.jbbp.io.JBBPBitOutputStream, those bit stream classes are the core of the library. + +The easiet use case shows parsing of whole byte array to bits. + ```Java - byte [] parsedBits = JBBPParser.prepare("bit:1 [_];").parse(new byte[]{1,2,3,4,5}). - findFieldForType(JBBPFieldArrayBit.class).getArray(); + byte[]parsedBits=JBBPParser.prepare("bit:1 [_];").parse(new byte[]{1,2,3,4,5}). + findFieldForType(JBBPFieldArrayBit.class).getArray(); ``` -On start it was the only functionality but then I found that it is no so comfort way to get result, so that added some mapping of parsed result to pre-instantiated object. It works slower, because uses a lot of Java reflection but much easy in some cases. + +On start it was the only functionality but then I found that it is no so comfort way to get result, so that added some +mapping of parsed result to pre-instantiated object. It works slower, because uses a lot of Java reflection but much +easy in some cases. + ```Java -class Parsed {@Bin(type = BinType.BIT_ARRAY)byte[] parsed;} -Parsed parsedBits = JBBPParser.prepare("bit:1 [_] parsed;").parse(new byte[]{1,2,3,4,5}).mapTo(new Parsed()); +class Parsed { + @Bin(type = BinType.BIT_ARRAY) + byte[] parsed; +} + Parsed parsedBits = JBBPParser.prepare("bit:1 [_] parsed;").parse(new byte[] {1, 2, 3, 4, 5}).mapTo(new Parsed()); ``` # Relative speed of different approaches in parsing -Mainly I developed the library to help in my development of ZX-Spectrum emulator where I needed to work with data snapshots containing data on bit level. It didn't need much productivity in work. But since 1.3.0 version I added way to generate Java classes from JBBP scripts, such classes work in about five times faster than dynamic parsing and mapping approaches. + +Mainly I developed the library to help in my development of ZX-Spectrum emulator where I needed to work with data +snapshots containing data on bit level. It didn't need much productivity in work. But since 1.3.0 version I added way to +generate Java classes from JBBP scripts, such classes work in about five times faster than dynamic parsing and mapping +approaches. ![JMH results](https://github.com/raydac/java-binary-block-parser/blob/master/docs/jmh_results.png) Chart below compares speed of three provided ways to parse data with JBBP: -* __Dynamic__ - the basic parsing through interpretation of prepared JBBP DSL script. It is no so fast, but provide way to generate parsers on fly from text description. -* __Dynamic + map to class__ - parsing through interpretation of parsed JBBP script and mapping of parsed data to pre-instantiated class instance. It provides compfortable way to work with data and get result but uses a lot of Java reflection features and so fast. -* __Static class__ - the fastest way of JBBP use, some JBBP script is translated into Java class. There is no any interpretation or reflection operators so that it is very fast. [You can take a look at auxiliary class which I use in tests](https://github.com/raydac/java-binary-block-parser/blob/master/jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJavaConverterTest.java). +* __Dynamic__ - the basic parsing through interpretation of prepared JBBP DSL script. It is no so fast, but provide way + to generate parsers on fly from text description. +* __Dynamic + map to class__ - parsing through interpretation of parsed JBBP script and mapping of parsed data to + pre-instantiated class instance. It provides compfortable way to work with data and get result but uses a lot of Java + reflection features and so fast. +* __Static class__ - the fastest way of JBBP use, some JBBP script is translated into Java class. There is no any + interpretation or reflection operators so that it is very + fast. [You can take a look at auxiliary class which I use in tests](https://github.com/raydac/java-binary-block-parser/blob/master/jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJavaConverterTest.java) + . # Generate sources from JBBP scripts -Since 1.3.0 version, the library provides Java source generator for JBBP scripts, __(keep in mind that generated sources anyway depends on JBBP library and it is needed for their work)__. -For instance such snippet can be used to generate Java classes from a JBBP script. It also can generate multiple classes. + +Since 1.3.0 version, the library provides Java source generator for JBBP scripts, __(keep in mind that generated sources +anyway depends on JBBP library and it is needed for their work)__. For instance such snippet can be used to generate +Java classes from a JBBP script. It also can generate multiple classes. + ```Java - JBBPParser parser = JBBPParser.prepare("byte a; byte b; byte c;"); - List generated = parser.convertToSrc(TargetSources.JAVA,"com.test.jbbp.gen.SomeClazz"); - for(ResultSrcItem i : generated) { - for(Map.Entry j :i.getResult().entrySet()) { - System.out.println("Class file name "+j.getKey()); - System.out.println("Class file content "+j.getValue()); - } + JBBPParser parser=JBBPParser.prepare("byte a; byte b; byte c;"); + List generated=parser.convertToSrc(TargetSources.JAVA,"com.test.jbbp.gen.SomeClazz"); + for(ResultSrcItem i:generated){ + for(Map.Entry j:i.getResult().entrySet()) { + System.out.println("Class file name "+j.getKey()); + System.out.println("Class file content "+j.getValue()); + } } ``` -also there are developed plug-ins for both Maven and Gradle to generate sources from JBBP scripts during source generate phase. + +also there are developed plug-ins for both Maven and Gradle to generate sources from JBBP scripts during source generate +phase. in Maven it can be used through snippet: + ```xml - - com.igormaznitsa - jbbp-maven-plugin - 2.0.1 - - - gen-jbbp-src - - generate - - - + + + com.igormaznitsa + jbbp-maven-plugin + 3.0.1 + + + gen-jbbp-src + + generate + + + ``` -By default the maven plug-in looks for files with `jbbp` extension in `src/jbbp` folder of the project (it can be changed through plug-in configuration) and produces resulting java classes into `target/generated-sources/jbbp` folder. [For instance, I use such approach in my ZX-Poly emulator](https://github.com/raydac/zxpoly/tree/master/zxpoly-emul/src/jbbp). + +By default the maven plug-in looks for files with `jbbp` extension in `src/jbbp` folder of the project (it can be +changed through plug-in configuration) and produces resulting java classes into `target/generated-sources/jbbp` +folder. [For instance, I use such approach in my ZX-Poly emulator](https://github.com/raydac/zxpoly/tree/master/zxpoly-emul/src/jbbp) +. # More complex example with features added as of 1.1.0 -Example below shows how to parse a byte stream written in non-standard MSB0 order (Java has LSB0 bit order) into bit fields, then print its values and pack fields back: + +Example below shows how to parse a byte stream written in non-standard MSB0 order (Java has LSB0 bit order) into bit +fields, then print its values and pack fields back: + ```Java class Flags { - @Bin(order = 1, name = "f1", type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_1, comment = "It's flag one") byte flag1; - @Bin(order = 2, name = "f2", type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_2, comment = "It's second flag") byte flag2; - @Bin(order = 3, name = "f3", type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_1, comment = "It's 3th flag") byte flag3; - @Bin(order = 4, name = "f4", type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_4, comment = "It's 4th flag") byte flag4; - } - - final int data = 0b10101010; + @Bin(order = 1, name = "f1", type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_1, comment = "It's flag one") + byte flag1; + @Bin(order = 2, name = "f2", type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_2, comment = "It's second flag") + byte flag2; + @Bin(order = 3, name = "f3", type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_1, comment = "It's 3th flag") + byte flag3; + @Bin(order = 4, name = "f4", type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_4, comment = "It's 4th flag") + byte flag4; +} + + final int data = 0b10101010; Flags parsed = JBBPParser.prepare("bit:1 f1; bit:2 f2; bit:1 f3; bit:4 f4;", JBBPBitOrder.MSB0).parse(new byte[]{(byte)data}).mapTo(new Flags()); - assertEquals(1,parsed.flag1); - assertEquals(2,parsed.flag2); - assertEquals(0,parsed.flag3); - assertEquals(5,parsed.flag4); + assertEquals(1, parsed.flag1); + assertEquals(2, parsed.flag2); + assertEquals(0, parsed.flag3); + assertEquals(5, parsed.flag4); System.out.println(new JBBPTextWriter().Bin(parsed).Close().toString()); assertEquals(data, JBBPOut.BeginBin(JBBPBitOrder.MSB0).Bin(parsed).End().toByteArray()[0] & 0xFF); ``` + The Example will print in console the text below + ``` ;-------------------------------------------------------------------------------- ; START : Flags @@ -135,32 +190,51 @@ The Example will print in console the text below ; END : Flags ;-------------------------------------------------------------------------------- ``` + # Fields -Each field can have case insensitive name which must not contain '.' (because dot is reserved for links to structure field values) and '#'(because it is also reserved for internal library use). -A field name must not be started with either number or chars '$' and '_'. *Keep in mind that field names are case insensitive!* + +Each field can have case insensitive name which must not contain '.' (because dot is reserved for links to structure +field values) and '#'(because it is also reserved for internal library use). A field name must not be started with +either number or chars '$' and '_'. *Keep in mind that field names are case insensitive!* + ``` int someNamedField; byte field1; byte field2; byte field3; ``` + ![JBBP field format, types and examples](https://github.com/raydac/java-binary-block-parser/blob/master/docs/jbbp_fields.png) ## Primitive types + JBBP supports full set of Java numeric primitives with some extra types like ubyte and bit. ![JBBP field format, types and examples](https://github.com/raydac/java-binary-block-parser/blob/master/docs/jbbp_primitives.png) + ## Complex types -JBBP provides support both arrays and structures. __In expressions you can use links only to field values which already read!__ + +JBBP provides support both arrays and structures. __In expressions you can use links only to field values which already +read!__ ![JBBP field format, types and examples](https://github.com/raydac/java-binary-block-parser/blob/master/docs/jbbp_complex_types.png) ## Custom types -It is possible to define processors for custom data types. For instance you can take a look at [case processing three byte unsigned integer types](https://github.com/raydac/java-binary-block-parser/blob/master/jbbp/src/test/java/com/igormaznitsa/jbbp/it/CustomThreeByteIntegerTypeTest.java). + +It is possible to define processors for custom data types. For instance you can take a look +at [case processing three byte unsigned integer types](https://github.com/raydac/java-binary-block-parser/blob/master/jbbp/src/test/java/com/igormaznitsa/jbbp/it/CustomThreeByteIntegerTypeTest.java) +. ### Support of float, double and String types -Since 1.4.0 in JBBP was added support of Java float, double and String values. Because they have specific format, they are named as `doublej`, `floatj` and `stringj`. + +Since 1.4.0 in JBBP was added support of Java float, double and String values. Because they have specific format, they +are named as `doublej`, `floatj` and `stringj`. ## Variable fields -If you have some data which internal structure is undefined and variable then you can use the `var` type to mark such field and provide custom processor to read data of such value. Processor should implement interface [JBBPVarFieldProcessor](https://github.com/raydac/java-binary-block-parser/blob/master/src/main/java/com/igormaznitsa/jbbp/JBBPVarFieldProcessor.java) instance. + +If you have some data which internal structure is undefined and variable then you can use the `var` type to mark such +field and provide custom processor to read data of such value. Processor should implement +interface [JBBPVarFieldProcessor](https://github.com/raydac/java-binary-block-parser/blob/master/src/main/java/com/igormaznitsa/jbbp/JBBPVarFieldProcessor.java) +instance. + ``` final JBBPParser parser = JBBPParser.prepare("short k; var; int;"); final JBBPIntCounter counter = new JBBPIntCounter(); @@ -177,24 +251,35 @@ If you have some data which internal structure is undefined and variable then yo } }, null); ``` -*NB! Some programmers trying to use only parser for complex data, it is a mistake. In the case it is much better to have several easy parsers working with the same [JBBPBitInputStream](https://github.com/raydac/java-binary-block-parser/blob/master/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitInputStream.java) instance, it allows to keep decision points on Java level and make solution easier.* + +*NB! Some programmers trying to use only parser for complex data, it is a mistake. In the case it is much better to have +several easy parsers working with the +same [JBBPBitInputStream](https://github.com/raydac/java-binary-block-parser/blob/master/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitInputStream.java) +instance, it allows to keep decision points on Java level and make solution easier.* ## Special types + Special types makes some actions to skip data in input stream ![JBBP field format, types and examples](https://github.com/raydac/java-binary-block-parser/blob/master/docs/jbbp_special_fields.png) ## Byte order + Multi-byte types can be read with different byte order. ![JBBP field format, types and examples](https://github.com/raydac/java-binary-block-parser/blob/master/docs/jbbp_byteorder.png) # Expressions -Expressions are used for calculation of length of arrays and allow brackets and integer operators which work similar to Java operators: + +Expressions are used for calculation of length of arrays and allow brackets and integer operators which work similar to +Java operators: + - Arithmetic operators: +,-,%,*,/,% - Bit operators: &,|,^,~ - Shift operators: <<,>>,>>> - Brackets: (, ) -Inside expression you can use integer numbers and named field values through their names (if you use fields from the same structure) or paths. Keep in your mind that you can't use array fields or fields placed inside structure arrays. +Inside expression you can use integer numbers and named field values through their names (if you use fields from the +same structure) or paths. Keep in your mind that you can't use array fields or fields placed inside structure arrays. + ``` int field1; struct1 { @@ -204,7 +289,10 @@ int field1; ``` # Commentaries -You can use commentaries inside a parser script, the parser supports the only comment format and recognizes as commentaries all text after '//' till the end of line. + +You can use commentaries inside a parser script, the parser supports the only comment format and recognizes as +commentaries all text after '//' till the end of line. + ``` int; // hello commentaries @@ -212,13 +300,23 @@ You can use commentaries inside a parser script, the parser supports the only co ``` # Expression macroses -Inside expression you can use field names and field paths, also you can use the special macros '$$' which represents the current input stream byte counter, all fields started with '$' will be recognized by the parser as special user defined variables and it will be requesting them from special user defined provider. If the array size contains the only '_' symbol then the field or structure will not have defined size and whole stream will be read. + +Inside expression you can use field names and field paths, also you can use the special macros '$$' which represents the +current input stream byte counter, all fields started with '$' will be recognized by the parser as special user defined +variables and it will be requesting them from special user defined provider. If the array size contains the only '_' +symbol then the field or structure will not have defined size and whole stream will be read. # How to get result of parsing -The Result of parsing is an instance of com.igormaznitsa.jbbp.model.JBBPFieldStruct class which represents the root invisible structure for the parsed data and you can use its inside methods to find desired fields for their names, paths or classes. All Fields are successors of com.igormaznitsa.jbbp.model.JBBPAbstractField class. To increase comfort, it is easier to use mapping to classes when the mapper automatically places values to fields of a Java class. + +The Result of parsing is an instance of com.igormaznitsa.jbbp.model.JBBPFieldStruct class which represents the root +invisible structure for the parsed data and you can use its inside methods to find desired fields for their names, paths +or classes. All Fields are successors of com.igormaznitsa.jbbp.model.JBBPAbstractField class. To increase comfort, it is +easier to use mapping to classes when the mapper automatically places values to fields of a Java class. # Example + Example below shows how to parse a PNG file through JBBP parser: + ```Java final InputStream pngStream = getResourceAsInputStream("picture.png"); try { @@ -253,7 +351,9 @@ final InputStream pngStream = getResourceAsInputStream("picture.png"); closeResource(pngStream); } ``` + Also it is possible to map parsed packet to class fields + ```Java final JBBPParser pngParser = JBBPParser.prepare( "long header;" @@ -286,6 +386,7 @@ final JBBPParser pngParser = JBBPParser.prepare( ``` Example shows how to parse TCP frame: + ```Java final JBBPParser tcpParser = JBBPParser.prepare( "skip:34; // skip bytes till the frame\n" @@ -318,17 +419,30 @@ final JBBPParser tcpParser = JBBPParser.prepare( ``` # F.A.Q. + ## Is it possible to use `@Bin` annotations for parsing and not only mapping? -`@Bin` annotations is used only for mapping and data writing, but there is special class [JBBPDslBuilder](/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilder.java) which can convert `@Bin` marked class into JBBP script, for instance: + +`@Bin` annotations is used only for mapping and data writing, but there is special +class [JBBPDslBuilder](/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilder.java) which can convert `@Bin` +marked class into JBBP script, for instance: + ```java JBBPDslBuilder.Begin().AnnotatedClass(SomeBinAnnotatetClass.class).End(true); ``` ## My Binary data format is too complex one to be decoded by a JBBP script -No problems! JBBP parser works over [com.igormaznitsa.jbbp.io.JBBPBitInputStream](/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitInputStream.java) class which can be used directly and allows read bits, bytes, count bytes and align data. For writing there is similar class [JBBPBitOutputStream](https://github.com/raydac/java-binary-block-parser/blob/master/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStream.java). + +No problems! JBBP parser works +over [com.igormaznitsa.jbbp.io.JBBPBitInputStream](/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitInputStream.java) +class which can be used directly and allows read bits, bytes, count bytes and align data. For writing there is similar +class [JBBPBitOutputStream](https://github.com/raydac/java-binary-block-parser/blob/master/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStream.java) +. ## I want to make a binary data block instead of parsing! -Library provides special helper [JBBPOut](/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOut.java). The helper allows to generate binary blocks and provides some kind of DSL + +Library provides special helper [JBBPOut](/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOut.java). The helper allows +to generate binary blocks and provides some kind of DSL + ```Java import static com.igormaznitsa.jbbp.io.JBBPOut.*; ... diff --git a/changelog.txt b/changelog.txt index 14a540e9..143fa08b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,42 @@ +3.0.1 (24-dec-2024) + - added `MSB0_DIRECT` bit order mode, MSB0 without data revers [#46](https://github.com/raydac/java-binary-block-parser/issues/46) + - added `JBBPBitInputStream#isDetectedPartlyReadBitField` to check that only part of bit field read during last operation + - added flag into constructors for JBBPBitInputStream to force return -1 instead of partly accumulated bits data if end of field + +3.0.0 (16-nov-2024) + - Minimum JDK Version: Updated to 11.0. + - Minimum Supported Android: Updated to 12 (API 32). + - API Changes: Modifications made to the CompiledBlockVisitor API. + - New Feature: Added `JBBPUtils#findMaxStaticArraySize` for calculating the largest static array size defined in a JBBP script. + - Internal API: Certain internal APIs have been opened. + - Codebase Improvements: General refactoring performed. + +2.1.0 (05-nov-2024) + - minor changes in API for JBBPVarFieldProcessor and JBBPCustomFieldTypeProcessor + - provided way to control size of arrays read as stream rest [#44](https://github.com/raydac/java-binary-block-parser/issues/44) + - provided way to control size of arrays which size calculated through expressions [#45](https://github.com/raydac/java-binary-block-parser/issues/45) + - improved tests + +2.0.6 (01-jul-2023) + - [#42](https://github.com/raydac/java-binary-block-parser/issues/42) unexpected exception during JBBPDslBuilder.AnnotatedClass method call + - improved tests + +2.0.5 (17-jun-2023) + - [#41](https://github.com/raydac/java-binary-block-parser/issues/41) fix for Gradle plug-in + - improved tests + +2.0.4 (01-aug-2022) + - added unsigned 32 bit integer type __uint__ [#37](https://github.com/raydac/java-binary-block-parser/issues/37) + - provided way to filter fields for mapping operations and write object operations [#36](https://github.com/raydac/java-binary-block-parser/issues/36) + +2.0.3 (03-jan-2021) + - added service methods `JBBPUtils.traceData` to print dump of an input stream into a PrintStream + - improved `JBBPTokenizerException` to show marked error position [#30](https://github.com/raydac/java-binary-block-parser/issues/30) + +2.0.2 (22-aug-2020) + - added `JBBPOut#Bin` variant to override `@Bin` annotation fields in written objects. + - [#28](https://github.com/raydac/java-binary-block-parser/issues/28) added `JBBPOut#BinForceByteOrder` to override byte order defined in `@Bin` annotations of written object. + 2.0.1 - [#26](https://github.com/raydac/java-binary-block-parser/issues/26) fixed bug in array write with MSB0 @@ -38,7 +77,7 @@ - added converter of compiled parser data into Java class sources (1.6+) - added method to read unsigned short values as char [] into JBBPBitInputStream - Class version target has been changed to Java 1.6 - - fixed compatibiity of tests with Java 1.6 + - fixed compatibility of tests with Java 1.6 - Minor refactoring 1.2.0 diff --git a/docs/arthur_sanctuary_banner.png b/docs/arthur_sanctuary_banner.png new file mode 100644 index 00000000..566b7bd5 Binary files /dev/null and b/docs/arthur_sanctuary_banner.png differ diff --git a/docs/jbbp_fields.png b/docs/jbbp_fields.png index 404f36ba..79351c92 100644 Binary files a/docs/jbbp_fields.png and b/docs/jbbp_fields.png differ diff --git a/docs/jbbp_mm.png b/docs/jbbp_mm.png index d5886f54..b4765040 100644 Binary files a/docs/jbbp_mm.png and b/docs/jbbp_mm.png differ diff --git a/docs/jbbp_primitives.png b/docs/jbbp_primitives.png index 70297aaf..32bf5efe 100644 Binary files a/docs/jbbp_primitives.png and b/docs/jbbp_primitives.png differ diff --git a/docs/jmh_results.ods b/docs/jmh_results.ods index 137a1c8d..96dbd502 100644 Binary files a/docs/jmh_results.ods and b/docs/jmh_results.ods differ diff --git a/docs/jmh_results.png b/docs/jmh_results.png index a29ede56..df72ec02 100644 Binary files a/docs/jmh_results.png and b/docs/jmh_results.png differ diff --git a/docs/white_properties.properties b/docs/white_properties.properties new file mode 100644 index 00000000..8144b61c --- /dev/null +++ b/docs/white_properties.properties @@ -0,0 +1,69 @@ +#SciaReto editor settings +#Sat Jun 17 11:11:33 EEST 2023 +MindMapPanelConfig.birdseyeBackground=-1869559553 +MindMapPanelConfig.birdseyeFront=-1879029100 +MindMapPanelConfig.birdseyeMouseButton=BUTTON_2 +MindMapPanelConfig.collapsatorBackgroundColor=-526635 +MindMapPanelConfig.collapsatorBorderColor=-12566464 +MindMapPanelConfig.collapsatorBorderWidth=1.0 +MindMapPanelConfig.collapsatorSize=16 +MindMapPanelConfig.connectorColor=-15592942 +MindMapPanelConfig.connectorWidth=1.5 +MindMapPanelConfig.drawBackground=true +MindMapPanelConfig.dropShadow=true +MindMapPanelConfig.elementBorderColor=-16777216 +MindMapPanelConfig.elementBorderWidth=1.0 +MindMapPanelConfig.firstLevelBackgroundColor=-5128244 +MindMapPanelConfig.firstLevelHorizontalInset=48 +MindMapPanelConfig.firstLevelTextColor=-16777216 +MindMapPanelConfig.firstLevelVerticalInset=32 +MindMapPanelConfig.font.name=Arial +MindMapPanelConfig.font.size=16 +MindMapPanelConfig.font.style=1 +MindMapPanelConfig.gridColor=-12364185 +MindMapPanelConfig.gridStep=32 +MindMapPanelConfig.horizontalBlockGap=5 +MindMapPanelConfig.jumpLinkColor=-15597313 +MindMapPanelConfig.jumpLinkWidth=1.5 +MindMapPanelConfig.otherLevelBackgroundColor=-131587 +MindMapPanelConfig.otherLevelHorizontalInset=32 +MindMapPanelConfig.otherLevelTextColor=-16777216 +MindMapPanelConfig.otherLevelVerticalInset=16 +MindMapPanelConfig.paperColor=-1 +MindMapPanelConfig.paperMargins=20 +MindMapPanelConfig.renderQuality=QUALITY +MindMapPanelConfig.rootBackgroundColor=-16573903 +MindMapPanelConfig.rootTextColor=-1 +MindMapPanelConfig.scale=1.0 +MindMapPanelConfig.scaleModifiers=2 +MindMapPanelConfig.selectLineColor=-14336 +MindMapPanelConfig.selectLineGap=5 +MindMapPanelConfig.selectLineWidth=3.0 +MindMapPanelConfig.shadowColor=805306368 +MindMapPanelConfig.shadowOffset=5.0 +MindMapPanelConfig.showGrid=false +MindMapPanelConfig.smartTextPaste=false +MindMapPanelConfig.textMargins=10 +mapShortCut.addChildAndStartEdit=addChildAndStartEdit*900000000 +mapShortCut.addSiblingAndStartEdit=addSiblingAndStartEdit*A00000000 +mapShortCut.birdsEyeModifiers=birdsEyeModifiers*7FFFFFFF00000000 +mapShortCut.cancelEdit=cancelEdit*1B00000000 +mapShortCut.deleteSelectedTopic=deleteSelectedTopic*7F00000000 +mapShortCut.focusToRootOrStartEdit=focusToRootOrStartEdit*2000000002 +mapShortCut.moveFocusDown=moveFocusDown*2800000000 +mapShortCut.moveFocusDownAddFocused=moveFocusDownAddFocused*2800000001 +mapShortCut.moveFocusLeft=moveFocusLeft*2500000000 +mapShortCut.moveFocusLeftAddFocused=moveFocusLeftAddFocused*2500000001 +mapShortCut.moveFocusRight=moveFocusRight*2700000000 +mapShortCut.moveFocusRightAddFocused=moveFocusRightAddFocused*2700000001 +mapShortCut.moveFocusUp=moveFocusUp*2600000000 +mapShortCut.moveFocusUpAddFocused=moveFocusUpAddFocused*2600000001 +mapShortCut.nextLineInTopicText=nextLineInTopicText*A00000001 +mapShortCut.showPopupMenu=showPopupMenu*200000000A +mapShortCut.topicFold=topicFold*2D00000000 +mapShortCut.topicFoldAll=topicFoldAll*2D00000008 +mapShortCut.topicUnfold=topicUnfold*3D00000000 +mapShortCut.topicUnfoldAll=topicUnfoldAll*3D00000008 +mapShortCut.zoomIn=zoomIn*3D00000002 +mapShortCut.zoomOut=zoomOut*2D00000002 +mapShortCut.zoomReset=zoomReset*3000000002 diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/build.gradle b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/build.gradle new file mode 100644 index 00000000..9d314477 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'java' + id 'com.igormaznitsa.gradle.jbbp' version "${jbbp_plugin_version}" +} + +group = 'com.igormaznitsa.jbbp.gradle.test' +version = '0.0.0-SNAPSHOT' + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + implementation "com.igormaznitsa:jbbp:${jbbp_plugin_version}" + testImplementation platform("org.junit:junit-bom:${junit_version}") + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() +} + +import com.igormaznitsa.jbbp.plugin.common.converters.ParserFlags + +jbbp { + headComment = 'Free license' + addBinAnnotations = true + addGettersSetters = true + customTypes = ['some'] + interfaces = ['java.lang.Runnable'] + customText = 'public void run () {}' + parserFlags = [ParserFlags.SKIP_REMAINING_FIELDS_IF_EOF] +} + +compileJava.dependsOn(jbbpGenerate) \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/pom.xml b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/pom.xml new file mode 100644 index 00000000..09e1c195 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + + + com.igormaznitsa + jbbp-gradle-tests + 0.0.0-SNAPSHOT + + + jbbp-gradle5-plugin-test + pom + + + gradle5 + + + + + + maven-clean-plugin + + + + ${project.basedir}/gradle + false + + + ${project.basedir} + + gradlew + gradlew.bat + + false + + + ${project.basedir}/downloaded + false + + + ${project.basedir}/build + false + + + ${project.basedir}/out + false + + + + + + org.codehaus.mojo + exec-maven-plugin + + + gradle + compile + + ${gradle.executable} + + clean + test + --info + --scan + --no-daemon + -Pjbbp_plugin_version=${jbbp.test.version} + -Pjunit_version=${junit5.version} + + + + exec + + + + + + + + diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/settings.gradle b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/settings.gradle new file mode 100644 index 00000000..a21b7724 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/settings.gradle @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenLocal() + } +} + +rootProject.name = 'jbbp-gradle5-plugin-test' + diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp new file mode 100644 index 00000000..b1f6c18f --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp @@ -0,0 +1,10 @@ +ubyte len; +uint uintField; +uint [1] uintArr; +some1 { + bit:4 [len] someField; + ubyte len; + some2 { + byte [len] field; + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp new file mode 100644 index 00000000..58f5edc9 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp @@ -0,0 +1,8 @@ +ubyte len; +some1 { + bit:4 [len] someField; + ubyte len; + some2 { + byte [len] field; + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp new file mode 100644 index 00000000..39d99c87 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp @@ -0,0 +1,11 @@ +// custom and var fields +byte bytea; +some field1; + readVarArray(Object sourceStruct, + JBBPBitInputStream inStream, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, + int extraValue, + boolean readWholeStream, + int arraySize) + throws IOException { + if (readWholeStream) { + return new JBBPFieldArrayLong(nullableNamedFieldInfo, inStream.readLongArray(-1, byteOrder)); + } else { + return new JBBPFieldArrayLong(nullableNamedFieldInfo, + inStream.readLongArray(arraySize, byteOrder)); + } + } + + @Override + public void run() { + } + + @Override + public void writeVarField(Object sourceStruct, JBBPAbstractField value, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) + throws IOException { + outStream.writeLong(((JBBPFieldLong) value).getAsLong(), byteOrder); + } + + @Override + public void writeVarArray(Object sourceStruct, + JBBPAbstractArrayField array, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, + int arraySizeToWrite) throws IOException { + final JBBPFieldArrayLong a = (JBBPFieldArrayLong) array; + if (arraySizeToWrite < 0) { + for (final long l : a.getArray()) { + outStream.writeLong(l, byteOrder); + } + } else { + final long[] larr = a.getArray(); + for (int i = 0; i < arraySizeToWrite; i++) { + outStream.writeLong(larr[i], byteOrder); + } + } + } + +} diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/main/java/org/example/Main.java b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/main/java/org/example/Main.java new file mode 100644 index 00000000..407f157b --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/main/java/org/example/Main.java @@ -0,0 +1,7 @@ +package org.example; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/test/java/org/example/MainTest.java b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/test/java/org/example/MainTest.java new file mode 100644 index 00000000..f98a9f30 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/test/java/org/example/MainTest.java @@ -0,0 +1,124 @@ +package org.example; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.igormaznitsa.jbbp.JBBPParser; +import com.igormaznitsa.jbbp.io.JBBPBitInputStream; +import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; +import com.igormaznitsa.mvn.tst.VarCustomImpl; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Random; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +import com.igormaznitsa.mvn.test.jbbp.*; + +public class MainTest { + + @Test + void testReadWrite_Annotations_Static() throws IOException { + final byte[] testData = new byte[] { + 4, + (byte)0xFF, (byte)0x1A, (byte)0x1B, (byte)0x1C, + (byte)0xFF, (byte)0x2A, (byte)0x2B, (byte)0x2C, + (byte) 0x12, (byte) 0x34, 3, 5, 6, 7 + }; + + final GenAnnotations result = + new GenAnnotations().read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + assertEquals(4, result.getLEN()); + assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); + + final String script = "ubyte len;" + + " uint uintField;" + + " uint [1] uintArr;" + + "some1 {" + + " bit:4 [len] someField;" + + " ubyte len;" + + " some2 {" + + " byte [len] field;" + + " }" + + "}"; + + final GenAnnotations instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotations()); + + assertEquals(result.getUINTFIELD(), instance.getUINTFIELD()); + assertArrayEquals(result.getUINTARR(), instance.getUINTARR()); + assertEquals(result.getLEN(), instance.getLEN()); + assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); + assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); + } + + @Test + void testReadWrite_Annotations_NonStatic() throws IOException { + final byte[] testData = new byte[] {4, (byte) 0x12, (byte) 0x34, 3, 5, 6, 7}; + + final GenAnnotationsNonStatic result = new GenAnnotationsNonStatic() + .read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + assertEquals(4, result.getLEN()); + assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); + + final String script = "ubyte len;" + + "some1 {" + + " bit:4 [len] someField;" + + " ubyte len;" + + " some2 {" + + " byte [len] field;" + + " }" + + "}"; + + final GenAnnotationsNonStatic instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotationsNonStatic()); + assertEquals(result.getLEN(), instance.getLEN()); + assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); + assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); + } + + private static final Random RND = new Random(12345); + + @Test + public void testReadWrite_VarCustom() throws Exception { + final VarCustomImpl impl = new VarCustomImpl(); + + final byte[] etalonArray = new byte[319044]; + RND.nextBytes(etalonArray); + etalonArray[0] = 1; + + impl.read(new JBBPBitInputStream(new ByteArrayInputStream(etalonArray))); + + assertEquals(1, impl.getBYTEA()); + + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + final JBBPBitOutputStream bios = new JBBPBitOutputStream(bos); + + impl.write(bios); + bios.close(); + + assertArrayEquals(etalonArray, bos.toByteArray()); + } + + @Test + public void testRead_DefaultBitOrder() throws IOException { + final WholeStreamByteArray struct = new WholeStreamByteArray().read(new JBBPBitInputStream( + new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, struct.getARRAY()); + } + + @Test + public void testWrite_DefaultBitOrder() throws IOException { + final WholeStreamByteArray struct = new WholeStreamByteArray(); + struct.setARRAY(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final JBBPBitOutputStream bitOut = new JBBPBitOutputStream(out); + struct.write(bitOut); + bitOut.close(); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, out.toByteArray()); + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/build.gradle b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/build.gradle new file mode 100644 index 00000000..9d314477 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'java' + id 'com.igormaznitsa.gradle.jbbp' version "${jbbp_plugin_version}" +} + +group = 'com.igormaznitsa.jbbp.gradle.test' +version = '0.0.0-SNAPSHOT' + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + implementation "com.igormaznitsa:jbbp:${jbbp_plugin_version}" + testImplementation platform("org.junit:junit-bom:${junit_version}") + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() +} + +import com.igormaznitsa.jbbp.plugin.common.converters.ParserFlags + +jbbp { + headComment = 'Free license' + addBinAnnotations = true + addGettersSetters = true + customTypes = ['some'] + interfaces = ['java.lang.Runnable'] + customText = 'public void run () {}' + parserFlags = [ParserFlags.SKIP_REMAINING_FIELDS_IF_EOF] +} + +compileJava.dependsOn(jbbpGenerate) \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/pom.xml b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/pom.xml new file mode 100644 index 00000000..9f3903b1 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + + + com.igormaznitsa + jbbp-gradle-tests + 0.0.0-SNAPSHOT + + + jbbp-gradle6-plugin-test + pom + + + gradle6 + + + + + + maven-clean-plugin + + + + ${project.basedir}/gradle + false + + + ${project.basedir} + + gradlew + gradlew.bat + + false + + + ${project.basedir}/downloaded + false + + + ${project.basedir}/build + false + + + ${project.basedir}/out + false + + + + + + org.codehaus.mojo + exec-maven-plugin + + + gradle + compile + + ${gradle.executable} + + clean + test + --info + --scan + --no-daemon + -Pjbbp_plugin_version=${jbbp.test.version} + -Pjunit_version=${junit5.version} + + + + exec + + + + + + + + diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/settings.gradle b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/settings.gradle new file mode 100644 index 00000000..713e1502 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/settings.gradle @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenLocal() + } +} + +rootProject.name = 'jbbp-gradle6-plugin-test' + diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp new file mode 100644 index 00000000..b1f6c18f --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp @@ -0,0 +1,10 @@ +ubyte len; +uint uintField; +uint [1] uintArr; +some1 { + bit:4 [len] someField; + ubyte len; + some2 { + byte [len] field; + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp new file mode 100644 index 00000000..58f5edc9 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp @@ -0,0 +1,8 @@ +ubyte len; +some1 { + bit:4 [len] someField; + ubyte len; + some2 { + byte [len] field; + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp new file mode 100644 index 00000000..39d99c87 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp @@ -0,0 +1,11 @@ +// custom and var fields +byte bytea; +some field1; + readVarArray(Object sourceStruct, + JBBPBitInputStream inStream, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, + int extraValue, + boolean readWholeStream, + int arraySize) + throws IOException { + if (readWholeStream) { + return new JBBPFieldArrayLong(nullableNamedFieldInfo, inStream.readLongArray(-1, byteOrder)); + } else { + return new JBBPFieldArrayLong(nullableNamedFieldInfo, + inStream.readLongArray(arraySize, byteOrder)); + } + } + + @Override + public void run() { + } + + @Override + public void writeVarField(Object sourceStruct, JBBPAbstractField value, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) + throws IOException { + outStream.writeLong(((JBBPFieldLong) value).getAsLong(), byteOrder); + } + + @Override + public void writeVarArray(Object sourceStruct, + JBBPAbstractArrayField array, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, + int arraySizeToWrite) throws IOException { + final JBBPFieldArrayLong a = (JBBPFieldArrayLong) array; + if (arraySizeToWrite < 0) { + for (final long l : a.getArray()) { + outStream.writeLong(l, byteOrder); + } + } else { + final long[] larr = a.getArray(); + for (int i = 0; i < arraySizeToWrite; i++) { + outStream.writeLong(larr[i], byteOrder); + } + } + } + +} diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/main/java/org/example/Main.java b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/main/java/org/example/Main.java new file mode 100644 index 00000000..407f157b --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/main/java/org/example/Main.java @@ -0,0 +1,7 @@ +package org.example; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/test/java/org/example/MainTest.java b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/test/java/org/example/MainTest.java new file mode 100644 index 00000000..f98a9f30 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle6-plugin-test/src/test/java/org/example/MainTest.java @@ -0,0 +1,124 @@ +package org.example; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.igormaznitsa.jbbp.JBBPParser; +import com.igormaznitsa.jbbp.io.JBBPBitInputStream; +import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; +import com.igormaznitsa.mvn.tst.VarCustomImpl; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Random; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +import com.igormaznitsa.mvn.test.jbbp.*; + +public class MainTest { + + @Test + void testReadWrite_Annotations_Static() throws IOException { + final byte[] testData = new byte[] { + 4, + (byte)0xFF, (byte)0x1A, (byte)0x1B, (byte)0x1C, + (byte)0xFF, (byte)0x2A, (byte)0x2B, (byte)0x2C, + (byte) 0x12, (byte) 0x34, 3, 5, 6, 7 + }; + + final GenAnnotations result = + new GenAnnotations().read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + assertEquals(4, result.getLEN()); + assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); + + final String script = "ubyte len;" + + " uint uintField;" + + " uint [1] uintArr;" + + "some1 {" + + " bit:4 [len] someField;" + + " ubyte len;" + + " some2 {" + + " byte [len] field;" + + " }" + + "}"; + + final GenAnnotations instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotations()); + + assertEquals(result.getUINTFIELD(), instance.getUINTFIELD()); + assertArrayEquals(result.getUINTARR(), instance.getUINTARR()); + assertEquals(result.getLEN(), instance.getLEN()); + assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); + assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); + } + + @Test + void testReadWrite_Annotations_NonStatic() throws IOException { + final byte[] testData = new byte[] {4, (byte) 0x12, (byte) 0x34, 3, 5, 6, 7}; + + final GenAnnotationsNonStatic result = new GenAnnotationsNonStatic() + .read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + assertEquals(4, result.getLEN()); + assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); + + final String script = "ubyte len;" + + "some1 {" + + " bit:4 [len] someField;" + + " ubyte len;" + + " some2 {" + + " byte [len] field;" + + " }" + + "}"; + + final GenAnnotationsNonStatic instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotationsNonStatic()); + assertEquals(result.getLEN(), instance.getLEN()); + assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); + assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); + } + + private static final Random RND = new Random(12345); + + @Test + public void testReadWrite_VarCustom() throws Exception { + final VarCustomImpl impl = new VarCustomImpl(); + + final byte[] etalonArray = new byte[319044]; + RND.nextBytes(etalonArray); + etalonArray[0] = 1; + + impl.read(new JBBPBitInputStream(new ByteArrayInputStream(etalonArray))); + + assertEquals(1, impl.getBYTEA()); + + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + final JBBPBitOutputStream bios = new JBBPBitOutputStream(bos); + + impl.write(bios); + bios.close(); + + assertArrayEquals(etalonArray, bos.toByteArray()); + } + + @Test + public void testRead_DefaultBitOrder() throws IOException { + final WholeStreamByteArray struct = new WholeStreamByteArray().read(new JBBPBitInputStream( + new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, struct.getARRAY()); + } + + @Test + public void testWrite_DefaultBitOrder() throws IOException { + final WholeStreamByteArray struct = new WholeStreamByteArray(); + struct.setARRAY(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final JBBPBitOutputStream bitOut = new JBBPBitOutputStream(out); + struct.write(bitOut); + bitOut.close(); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, out.toByteArray()); + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/build.gradle b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/build.gradle new file mode 100644 index 00000000..9d314477 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'java' + id 'com.igormaznitsa.gradle.jbbp' version "${jbbp_plugin_version}" +} + +group = 'com.igormaznitsa.jbbp.gradle.test' +version = '0.0.0-SNAPSHOT' + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + implementation "com.igormaznitsa:jbbp:${jbbp_plugin_version}" + testImplementation platform("org.junit:junit-bom:${junit_version}") + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() +} + +import com.igormaznitsa.jbbp.plugin.common.converters.ParserFlags + +jbbp { + headComment = 'Free license' + addBinAnnotations = true + addGettersSetters = true + customTypes = ['some'] + interfaces = ['java.lang.Runnable'] + customText = 'public void run () {}' + parserFlags = [ParserFlags.SKIP_REMAINING_FIELDS_IF_EOF] +} + +compileJava.dependsOn(jbbpGenerate) \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/pom.xml b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/pom.xml new file mode 100644 index 00000000..397b970d --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + + + com.igormaznitsa + jbbp-gradle-tests + 0.0.0-SNAPSHOT + + + jbbp-gradle7-plugin-test + pom + + + gradle7 + + + + + + maven-clean-plugin + + + + ${project.basedir}/gradle + false + + + ${project.basedir} + + gradlew + gradlew.bat + + false + + + ${project.basedir}/downloaded + false + + + ${project.basedir}/build + false + + + ${project.basedir}/out + false + + + + + + org.codehaus.mojo + exec-maven-plugin + + + gradle + compile + + ${gradle.executable} + + clean + test + --info + --scan + --no-daemon + -Pjbbp_plugin_version=${jbbp.test.version} + -Pjunit_version=${junit5.version} + + + + exec + + + + + + + + diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/settings.gradle b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/settings.gradle new file mode 100644 index 00000000..944d2e3c --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/settings.gradle @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenLocal() + } +} + +rootProject.name = 'jbbp-gradle7-plugin-test' + diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp new file mode 100644 index 00000000..b1f6c18f --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp @@ -0,0 +1,10 @@ +ubyte len; +uint uintField; +uint [1] uintArr; +some1 { + bit:4 [len] someField; + ubyte len; + some2 { + byte [len] field; + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp new file mode 100644 index 00000000..58f5edc9 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp @@ -0,0 +1,8 @@ +ubyte len; +some1 { + bit:4 [len] someField; + ubyte len; + some2 { + byte [len] field; + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp new file mode 100644 index 00000000..39d99c87 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp @@ -0,0 +1,11 @@ +// custom and var fields +byte bytea; +some field1; + readVarArray(Object sourceStruct, + JBBPBitInputStream inStream, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, + int extraValue, + boolean readWholeStream, + int arraySize) + throws IOException { + if (readWholeStream) { + return new JBBPFieldArrayLong(nullableNamedFieldInfo, inStream.readLongArray(-1, byteOrder)); + } else { + return new JBBPFieldArrayLong(nullableNamedFieldInfo, + inStream.readLongArray(arraySize, byteOrder)); + } + } + + @Override + public void run() { + } + + @Override + public void writeVarField(Object sourceStruct, JBBPAbstractField value, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) + throws IOException { + outStream.writeLong(((JBBPFieldLong) value).getAsLong(), byteOrder); + } + + @Override + public void writeVarArray(Object sourceStruct, + JBBPAbstractArrayField array, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, + int arraySizeToWrite) throws IOException { + final JBBPFieldArrayLong a = (JBBPFieldArrayLong) array; + if (arraySizeToWrite < 0) { + for (final long l : a.getArray()) { + outStream.writeLong(l, byteOrder); + } + } else { + final long[] larr = a.getArray(); + for (int i = 0; i < arraySizeToWrite; i++) { + outStream.writeLong(larr[i], byteOrder); + } + } + } + +} diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/main/java/org/example/Main.java b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/main/java/org/example/Main.java new file mode 100644 index 00000000..407f157b --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/main/java/org/example/Main.java @@ -0,0 +1,7 @@ +package org.example; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/test/java/org/example/MainTest.java b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/test/java/org/example/MainTest.java new file mode 100644 index 00000000..f98a9f30 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle7-plugin-test/src/test/java/org/example/MainTest.java @@ -0,0 +1,124 @@ +package org.example; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.igormaznitsa.jbbp.JBBPParser; +import com.igormaznitsa.jbbp.io.JBBPBitInputStream; +import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; +import com.igormaznitsa.mvn.tst.VarCustomImpl; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Random; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +import com.igormaznitsa.mvn.test.jbbp.*; + +public class MainTest { + + @Test + void testReadWrite_Annotations_Static() throws IOException { + final byte[] testData = new byte[] { + 4, + (byte)0xFF, (byte)0x1A, (byte)0x1B, (byte)0x1C, + (byte)0xFF, (byte)0x2A, (byte)0x2B, (byte)0x2C, + (byte) 0x12, (byte) 0x34, 3, 5, 6, 7 + }; + + final GenAnnotations result = + new GenAnnotations().read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + assertEquals(4, result.getLEN()); + assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); + + final String script = "ubyte len;" + + " uint uintField;" + + " uint [1] uintArr;" + + "some1 {" + + " bit:4 [len] someField;" + + " ubyte len;" + + " some2 {" + + " byte [len] field;" + + " }" + + "}"; + + final GenAnnotations instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotations()); + + assertEquals(result.getUINTFIELD(), instance.getUINTFIELD()); + assertArrayEquals(result.getUINTARR(), instance.getUINTARR()); + assertEquals(result.getLEN(), instance.getLEN()); + assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); + assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); + } + + @Test + void testReadWrite_Annotations_NonStatic() throws IOException { + final byte[] testData = new byte[] {4, (byte) 0x12, (byte) 0x34, 3, 5, 6, 7}; + + final GenAnnotationsNonStatic result = new GenAnnotationsNonStatic() + .read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + assertEquals(4, result.getLEN()); + assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); + + final String script = "ubyte len;" + + "some1 {" + + " bit:4 [len] someField;" + + " ubyte len;" + + " some2 {" + + " byte [len] field;" + + " }" + + "}"; + + final GenAnnotationsNonStatic instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotationsNonStatic()); + assertEquals(result.getLEN(), instance.getLEN()); + assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); + assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); + } + + private static final Random RND = new Random(12345); + + @Test + public void testReadWrite_VarCustom() throws Exception { + final VarCustomImpl impl = new VarCustomImpl(); + + final byte[] etalonArray = new byte[319044]; + RND.nextBytes(etalonArray); + etalonArray[0] = 1; + + impl.read(new JBBPBitInputStream(new ByteArrayInputStream(etalonArray))); + + assertEquals(1, impl.getBYTEA()); + + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + final JBBPBitOutputStream bios = new JBBPBitOutputStream(bos); + + impl.write(bios); + bios.close(); + + assertArrayEquals(etalonArray, bos.toByteArray()); + } + + @Test + public void testRead_DefaultBitOrder() throws IOException { + final WholeStreamByteArray struct = new WholeStreamByteArray().read(new JBBPBitInputStream( + new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, struct.getARRAY()); + } + + @Test + public void testWrite_DefaultBitOrder() throws IOException { + final WholeStreamByteArray struct = new WholeStreamByteArray(); + struct.setARRAY(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final JBBPBitOutputStream bitOut = new JBBPBitOutputStream(out); + struct.write(bitOut); + bitOut.close(); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, out.toByteArray()); + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/build.gradle b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/build.gradle new file mode 100644 index 00000000..9d314477 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'java' + id 'com.igormaznitsa.gradle.jbbp' version "${jbbp_plugin_version}" +} + +group = 'com.igormaznitsa.jbbp.gradle.test' +version = '0.0.0-SNAPSHOT' + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + implementation "com.igormaznitsa:jbbp:${jbbp_plugin_version}" + testImplementation platform("org.junit:junit-bom:${junit_version}") + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() +} + +import com.igormaznitsa.jbbp.plugin.common.converters.ParserFlags + +jbbp { + headComment = 'Free license' + addBinAnnotations = true + addGettersSetters = true + customTypes = ['some'] + interfaces = ['java.lang.Runnable'] + customText = 'public void run () {}' + parserFlags = [ParserFlags.SKIP_REMAINING_FIELDS_IF_EOF] +} + +compileJava.dependsOn(jbbpGenerate) \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/pom.xml b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/pom.xml new file mode 100644 index 00000000..b7765735 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + + + com.igormaznitsa + jbbp-gradle-tests + 0.0.0-SNAPSHOT + + + jbbp-gradle8-plugin-test + pom + + + gradle8 + + + + + + maven-clean-plugin + + + + ${project.basedir}/gradle + false + + + ${project.basedir} + + gradlew + gradlew.bat + + false + + + ${project.basedir}/downloaded + false + + + ${project.basedir}/build + false + + + ${project.basedir}/out + false + + + + + + org.codehaus.mojo + exec-maven-plugin + + + gradle + compile + + ${gradle.executable} + + clean + test + --info + --scan + --no-daemon + -Pjbbp_plugin_version=${jbbp.test.version} + -Pjunit_version=${junit5.version} + + + + exec + + + + + + + + diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/settings.gradle b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/settings.gradle new file mode 100644 index 00000000..2422dece --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/settings.gradle @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenLocal() + } +} + +rootProject.name = 'jbbp-gradle8-plugin-test' + diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp new file mode 100644 index 00000000..b1f6c18f --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp @@ -0,0 +1,10 @@ +ubyte len; +uint uintField; +uint [1] uintArr; +some1 { + bit:4 [len] someField; + ubyte len; + some2 { + byte [len] field; + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp new file mode 100644 index 00000000..58f5edc9 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp @@ -0,0 +1,8 @@ +ubyte len; +some1 { + bit:4 [len] someField; + ubyte len; + some2 { + byte [len] field; + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp new file mode 100644 index 00000000..39d99c87 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp @@ -0,0 +1,11 @@ +// custom and var fields +byte bytea; +some field1; + readVarArray(Object sourceStruct, + JBBPBitInputStream inStream, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, + int extraValue, + boolean readWholeStream, + int arraySize) + throws IOException { + if (readWholeStream) { + return new JBBPFieldArrayLong(nullableNamedFieldInfo, inStream.readLongArray(-1, byteOrder)); + } else { + return new JBBPFieldArrayLong(nullableNamedFieldInfo, + inStream.readLongArray(arraySize, byteOrder)); + } + } + + @Override + public void run() { + } + + @Override + public void writeVarField(Object sourceStruct, JBBPAbstractField value, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) + throws IOException { + outStream.writeLong(((JBBPFieldLong) value).getAsLong(), byteOrder); + } + + @Override + public void writeVarArray(Object sourceStruct, + JBBPAbstractArrayField array, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, + int arraySizeToWrite) throws IOException { + final JBBPFieldArrayLong a = (JBBPFieldArrayLong) array; + if (arraySizeToWrite < 0) { + for (final long l : a.getArray()) { + outStream.writeLong(l, byteOrder); + } + } else { + final long[] larr = a.getArray(); + for (int i = 0; i < arraySizeToWrite; i++) { + outStream.writeLong(larr[i], byteOrder); + } + } + } + +} diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/main/java/org/example/Main.java b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/main/java/org/example/Main.java new file mode 100644 index 00000000..407f157b --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/main/java/org/example/Main.java @@ -0,0 +1,7 @@ +package org.example; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/test/java/org/example/MainTest.java b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/test/java/org/example/MainTest.java new file mode 100644 index 00000000..f98a9f30 --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle8-plugin-test/src/test/java/org/example/MainTest.java @@ -0,0 +1,124 @@ +package org.example; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.igormaznitsa.jbbp.JBBPParser; +import com.igormaznitsa.jbbp.io.JBBPBitInputStream; +import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; +import com.igormaznitsa.mvn.tst.VarCustomImpl; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Random; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +import com.igormaznitsa.mvn.test.jbbp.*; + +public class MainTest { + + @Test + void testReadWrite_Annotations_Static() throws IOException { + final byte[] testData = new byte[] { + 4, + (byte)0xFF, (byte)0x1A, (byte)0x1B, (byte)0x1C, + (byte)0xFF, (byte)0x2A, (byte)0x2B, (byte)0x2C, + (byte) 0x12, (byte) 0x34, 3, 5, 6, 7 + }; + + final GenAnnotations result = + new GenAnnotations().read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + assertEquals(4, result.getLEN()); + assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); + + final String script = "ubyte len;" + + " uint uintField;" + + " uint [1] uintArr;" + + "some1 {" + + " bit:4 [len] someField;" + + " ubyte len;" + + " some2 {" + + " byte [len] field;" + + " }" + + "}"; + + final GenAnnotations instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotations()); + + assertEquals(result.getUINTFIELD(), instance.getUINTFIELD()); + assertArrayEquals(result.getUINTARR(), instance.getUINTARR()); + assertEquals(result.getLEN(), instance.getLEN()); + assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); + assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); + } + + @Test + void testReadWrite_Annotations_NonStatic() throws IOException { + final byte[] testData = new byte[] {4, (byte) 0x12, (byte) 0x34, 3, 5, 6, 7}; + + final GenAnnotationsNonStatic result = new GenAnnotationsNonStatic() + .read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + assertEquals(4, result.getLEN()); + assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); + + final String script = "ubyte len;" + + "some1 {" + + " bit:4 [len] someField;" + + " ubyte len;" + + " some2 {" + + " byte [len] field;" + + " }" + + "}"; + + final GenAnnotationsNonStatic instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotationsNonStatic()); + assertEquals(result.getLEN(), instance.getLEN()); + assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); + assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); + } + + private static final Random RND = new Random(12345); + + @Test + public void testReadWrite_VarCustom() throws Exception { + final VarCustomImpl impl = new VarCustomImpl(); + + final byte[] etalonArray = new byte[319044]; + RND.nextBytes(etalonArray); + etalonArray[0] = 1; + + impl.read(new JBBPBitInputStream(new ByteArrayInputStream(etalonArray))); + + assertEquals(1, impl.getBYTEA()); + + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + final JBBPBitOutputStream bios = new JBBPBitOutputStream(bos); + + impl.write(bios); + bios.close(); + + assertArrayEquals(etalonArray, bos.toByteArray()); + } + + @Test + public void testRead_DefaultBitOrder() throws IOException { + final WholeStreamByteArray struct = new WholeStreamByteArray().read(new JBBPBitInputStream( + new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, struct.getARRAY()); + } + + @Test + public void testWrite_DefaultBitOrder() throws IOException { + final WholeStreamByteArray struct = new WholeStreamByteArray(); + struct.setARRAY(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final JBBPBitOutputStream bitOut = new JBBPBitOutputStream(out); + struct.write(bitOut); + bitOut.close(); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, out.toByteArray()); + } +} \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/pom.xml b/jbbp-plugins/jbbp-gradle-tests/pom.xml new file mode 100644 index 00000000..f4e5c5cf --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + + + com.igormaznitsa + jbbp-main-plugin-pom + 3.0.2-SNAPSHOT + + + jbbp-gradle-tests + 0.0.0-SNAPSHOT + pom + + + ${jbbp.version} + + + + jbbp-gradle5-plugin-test + jbbp-gradle6-plugin-test + jbbp-gradle7-plugin-test + jbbp-gradle8-plugin-test + + + diff --git a/jbbp-plugins/jbbp-gradle/build.gradle b/jbbp-plugins/jbbp-gradle/build.gradle index 561aeb4b..5e9ef93d 100644 --- a/jbbp-plugins/jbbp-gradle/build.gradle +++ b/jbbp-plugins/jbbp-gradle/build.gradle @@ -1,35 +1,36 @@ -def getProp(name, dflt) { - if (project.hasProperty(name)) { - return project.getProperty(name) +def getProp(name) { + String found = project.findProperty(name) + if (found == null) { + GradleException('Property not found: ' + name) } else { - logger.warn('Can not find property "' + name + '" is not found') - return dflt + return project.getProperty(name) } } -def jbbpVersion = getProp('jbbp_plugin_version', '2.0.1') -def metaLibVersion = getProp('meta_lib_version', '1.1.2') +def jbbpVersion = getProp('jbbp_plugin_version') +def metaLibVersion = getProp('meta_lib_version') +def commonsIoVersion = getProp('commons_io_version') +def junitVersion = getProp('junit_version') group = 'com.igormaznitsa' version = jbbpVersion apply plugin: 'groovy' -apply plugin: 'maven' +apply plugin: 'maven-publish' apply plugin: "com.gradle.plugin-publish" -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +sourceCompatibility = 11 +targetCompatibility = 11 dependencies { - compile gradleApi() - compile localGroovy() + implementation gradleApi() + implementation localGroovy() - compile "commons-io:commons-io:2.5" - compile "com.igormaznitsa:jbbp:" + jbbpVersion - compile "com.igormaznitsa:meta-annotations:" + metaLibVersion - compile "com.igormaznitsa:meta-utils:" + metaLibVersion + implementation "commons-io:commons-io:" + commonsIoVersion + implementation "com.igormaznitsa:meta-annotations:" + metaLibVersion + implementation "com.igormaznitsa:meta-utils:" + metaLibVersion - testCompile 'junit:junit:4.12' + testImplementation "junit:junit:" + junitVersion } repositories { @@ -44,29 +45,48 @@ buildscript { } } dependencies { - classpath "com.gradle.publish:plugin-publish-plugin:0.9.7" + classpath "com.gradle.publish:plugin-publish-plugin:1.1.0" } } +tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:deprecation" +} + +task sourcesJar(type: Jar) { + duplicatesStrategy = 'include' + archiveClassifier = 'sources' + from sourceSets.main.allSource +} + sourceSets { main { java { + srcDirs '../../jbbp/src/main/java' srcDirs 'src/main/java' srcDirs '../jbbp-plugin-common/src/main/java' } } } -pluginBundle { +gradlePlugin { website = 'https://github.com/raydac/java-binary-block-parser' vcsUrl = 'https://github.com/raydac/java-binary-block-parser' - description = 'JBBP script translator!' - tags = ['jbbp', 'converter'] - plugins { - JBBPPlugin { + jbbpPlugin { id = 'com.igormaznitsa.gradle.jbbp' displayName = 'JBBP Sources Generator plugin' + implementationClass = 'com.igormaznitsa.jbbp.plugin.gradle.JBBPPlugin' + description = 'The plug-in processes JBBP scripts and generate Java classes from them' + tags = ['jbbp', 'converter'] + } + } +} + +publishing { + publications { + maven(MavenPublication) { + from components.java } } } \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle/pom.xml b/jbbp-plugins/jbbp-gradle/pom.xml index 33cf6a55..76bc97ea 100644 --- a/jbbp-plugins/jbbp-gradle/pom.xml +++ b/jbbp-plugins/jbbp-gradle/pom.xml @@ -6,7 +6,7 @@ com.igormaznitsa jbbp-main-plugin-pom - 2.0.1 + 3.0.2-SNAPSHOT jbbp-gradle-plugin @@ -22,9 +22,8 @@ - 1.8 - 1.8 - install + gradle8 + publishToMavenLocal @@ -93,29 +92,29 @@ - org.fortasoft - gradle-maven-plugin - 1.0.8 - - - org.gradle - gradle-tooling-api - 5.2.1 - - - - - 5.4 - - clean - ${gradleGoal} - - + org.codehaus.mojo + exec-maven-plugin + gradle compile + + ${gradle.executable} + + clean + build + ${gradleGoal} + --info + --scan + --no-daemon + -Pjbbp_plugin_version=${project.version} + -Pmeta_lib_version=${meta.version} + -Pcommons_io_version=${commonsio.version} + -Pjunit_version=${junit4.version} + + - invoke + exec diff --git a/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/AbstractJBBPTask.java b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/AbstractJBBPTask.java index 13ae07d9..3dbb749f 100644 --- a/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/AbstractJBBPTask.java +++ b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/AbstractJBBPTask.java @@ -1,6 +1,12 @@ package com.igormaznitsa.jbbp.plugin.gradle; import com.igormaznitsa.meta.common.utils.GetUtils; +import java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.apache.commons.io.FileUtils; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; @@ -8,13 +14,6 @@ import org.gradle.api.file.FileVisitor; import org.gradle.api.tasks.TaskAction; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.File; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - public abstract class AbstractJBBPTask extends DefaultTask { public AbstractJBBPTask() { @@ -22,13 +21,16 @@ public AbstractJBBPTask() { } @Nullable - public static String getTextOrFileContent(@Nonnull final JBBPExtension extension, @Nullable final String text, @Nullable final File file) { + public static String getTextOrFileContent(@Nonnull final JBBPExtension extension, + @Nullable final String text, + @Nullable final File file) { String result = null; if (text != null) { result = text; } else if (file != null) { try { - result = FileUtils.readFileToString(file, GetUtils.ensureNonNull(extension.inEncoding, "UTF-8")); + result = + FileUtils.readFileToString(file, GetUtils.ensureNonNull(extension.inEncoding, "UTF-8")); } catch (IOException ex) { throw new GradleException("Can't read file " + file, ex); } diff --git a/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPCleanTask.java b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPCleanTask.java index c451a395..229b8de6 100644 --- a/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPCleanTask.java +++ b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPCleanTask.java @@ -1,11 +1,10 @@ package com.igormaznitsa.jbbp.plugin.gradle; import com.igormaznitsa.jbbp.plugin.common.converters.JBBPScriptTranslator; -import org.gradle.api.GradleException; - -import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; +import javax.annotation.Nonnull; +import org.gradle.api.GradleException; /** * Task allows to delete generated files. diff --git a/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPGenerateTask.java b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPGenerateTask.java index e71ec128..9c021429 100644 --- a/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPGenerateTask.java +++ b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPGenerateTask.java @@ -2,10 +2,10 @@ import static com.igormaznitsa.jbbp.utils.JBBPUtils.ARRAY_STRING_EMPTY; - import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.model.JBBPAbstractField; @@ -27,7 +27,6 @@ import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.SourceSet; /** @@ -41,9 +40,12 @@ public class JBBPGenerateTask extends AbstractJBBPTask { * Flag to register the output folder in Java source folders at the end of process. */ @Input - @Optional protected boolean addSource = true; + public boolean isAddSource() { + return this.addSource; + } + @Override protected void doTaskAction(@Nonnull final JBBPExtension ext) { final Target target = GetUtils.ensureNonNull(ext.target, Target.JAVA); @@ -54,7 +56,8 @@ protected void doTaskAction(@Nonnull final JBBPExtension ext) { final String trimmed = s.trim(); final String normalized = trimmed.toLowerCase(Locale.ENGLISH); if (!normalized.equals(trimmed)) { - getLogger().warn(String.format("Custom type name '%s' in JBBP normal form is '%s' ", trimmed, normalized)); + getLogger().warn(String + .format("Custom type name '%s' in JBBP normal form is '%s' ", trimmed, normalized)); } normalizedCustomTypeNames.add(normalized); } @@ -71,7 +74,9 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(@Nonnull final JBBPFieldTypeParameterContainer fieldType, @Nullable final String fieldName, final int extraData, final boolean isArray) { + public boolean isAllowed(@Nonnull final JBBPFieldTypeParameterContainer fieldType, + @Nullable final String fieldName, final int extraData, + final boolean isArray) { final boolean result = normalizedCustomTypeNames.contains(fieldType.getTypeName()); if (!result) { getLogger().warn("Detected not allowed custom type name : " + fieldType.getTypeName()); @@ -81,7 +86,16 @@ public boolean isAllowed(@Nonnull final JBBPFieldTypeParameterContainer fieldTyp @Override @Nonnull - public JBBPAbstractField readCustomFieldType(@Nonnull final JBBPBitInputStream in, @Nonnull final JBBPBitOrder bitOrder, final int parserFlags, @Nonnull final JBBPFieldTypeParameterContainer customTypeFieldInfo, @Nullable final JBBPNamedFieldInfo fieldName, final int extraData, final boolean readWholeStream, final int arrayLength) throws IOException { + public JBBPAbstractField readCustomFieldType(@Nonnull final JBBPBitInputStream in, + @Nonnull final JBBPBitOrder bitOrder, + final int parserFlags, @Nonnull + final JBBPFieldTypeParameterContainer customTypeFieldInfo, + @Nullable final JBBPNamedFieldInfo fieldName, + final int extraData, + final boolean readWholeStream, + final int arrayLength, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { throw new Error("Must not be called"); } }; @@ -117,19 +131,25 @@ public JBBPAbstractField readCustomFieldType(@Nonnull final JBBPBitInputStream i final Set files = target.getTranslator().translate(parameters, false); getLogger().debug("Converted " + aScript + " into " + files); for (final File f : files) { - getLogger().info(String.format("JBBP script '%s' has been converted into '%s'", aScript.getName(), f.getName())); + getLogger().info(String + .format("JBBP script '%s' has been converted into '%s'", aScript.getName(), + f.getName())); } } catch (IOException ex) { - throw new GradleException("Error during JBBP script translation : " + aScript.getAbsolutePath(), ex); + throw new GradleException( + "Error during JBBP script translation : " + aScript.getAbsolutePath(), ex); } } if (this.addSource) { - getLogger().debug("Registering path to java sources : " + Assertions.assertNotNull("Output must not be null", ext.output)); + getLogger().debug("Registering path to java sources : " + + Assertions.assertNotNull("Output must not be null", ext.output)); if (getProject().getPlugins().hasPlugin(JavaPlugin.class)) { - final JavaPluginConvention javaPluginConvention = getProject().getConvention().getPlugin(JavaPluginConvention.class); - final SourceSet main = javaPluginConvention.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); + final JavaPluginConvention javaPluginConvention = + getProject().getConvention().getPlugin(JavaPluginConvention.class); + final SourceSet main = + javaPluginConvention.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); main.getJava().srcDir(ext.output); getLogger().info("Source folder has been added into Java task : " + ext.output); } else { diff --git a/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPPlugin.java b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPPlugin.java index 44e97439..41c08ba5 100644 --- a/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPPlugin.java +++ b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPPlugin.java @@ -1,16 +1,20 @@ package com.igormaznitsa.jbbp.plugin.gradle; +import javax.annotation.Nonnull; import org.gradle.api.Plugin; import org.gradle.api.Project; -import javax.annotation.Nonnull; - public class JBBPPlugin implements Plugin { @Override public void apply(@Nonnull final Project project) { - project.getExtensions().create(JBBPExtension.EXT_NAME, JBBPExtension.class, project); - project.getTasks().create("jbbpGenerate", JBBPGenerateTask.class); - project.getTasks().create("jbbpClean", JBBPCleanTask.class); + JBBPExtension extension = project.getExtensions() + .create(JBBPExtension.class, JBBPExtension.EXT_NAME, JBBPExtension.class, project); + project.getTasks().register("jbbpGenerate", JBBPGenerateTask.class, task -> { + task.setDescription("Generate JBBP stuff."); + }); + project.getTasks().register("jbbpClean", JBBPCleanTask.class, task -> { + task.setDescription("Clean all JBBP stuff."); + }); } } \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle/src/main/resources/META-INF/gradle-plugins/com.igormaznitsa.gradle.jbbp.properties b/jbbp-plugins/jbbp-gradle/src/main/resources/META-INF/gradle-plugins/com.igormaznitsa.gradle.jbbp.properties deleted file mode 100644 index 282c28f3..00000000 --- a/jbbp-plugins/jbbp-gradle/src/main/resources/META-INF/gradle-plugins/com.igormaznitsa.gradle.jbbp.properties +++ /dev/null @@ -1 +0,0 @@ -implementation-class=com.igormaznitsa.jbbp.plugin.gradle.JBBPPlugin \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle/src/test/groovy/com/igormaznitsa/jbbp/plugin/gradle/JBBPPluginTest.groovy b/jbbp-plugins/jbbp-gradle/src/test/groovy/com/igormaznitsa/jbbp/plugin/gradle/JBBPPluginTest.groovy index 02a42fbe..714ed009 100644 --- a/jbbp-plugins/jbbp-gradle/src/test/groovy/com/igormaznitsa/jbbp/plugin/gradle/JBBPPluginTest.groovy +++ b/jbbp-plugins/jbbp-gradle/src/test/groovy/com/igormaznitsa/jbbp/plugin/gradle/JBBPPluginTest.groovy @@ -2,17 +2,18 @@ import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.junit.Test -import static org.junit.Assert.assertTrue +import static org.junit.Assert.assertNotNull class JBBPPluginTest { @Test void demo_plugin_should_add_task_to_project() { Project project = ProjectBuilder.builder().build() - project.getPlugins().apply 'jbbp' + project.tasks.create("jbbpGenerate") + project.tasks.create("jbbpClean") - assertTrue(project.tasks.jbbpGenerate instanceof JBBPGenerateTask) - assertTrue(project.tasks.jbbpClean instanceof JBBPCleanTask) + assertNotNull(project.tasks.getByName("jbbpGenerate")) + assertNotNull(project.tasks.getByName("jbbpClean")) } } \ No newline at end of file diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java index 69b08c68..1234feb7 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java @@ -27,42 +27,69 @@ import com.igormaznitsa.jbbp.model.JBBPFieldLong; import com.igormaznitsa.jbbp.model.JBBPFieldShort; import com.igormaznitsa.mvn.test.jbbp.VarCustom; - import java.io.IOException; public class VarCustomImpl extends VarCustom { @Override - public JBBPAbstractField readCustomFieldType(Object sourceStruct, JBBPBitInputStream inStream, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException { - return new JBBPFieldShort(nullableNamedFieldInfo, (short) inStream.readUnsignedShort(typeParameterContainer.getByteOrder())); + public JBBPAbstractField readCustomFieldType(Object sourceStruct, JBBPBitInputStream inStream, + JBBPFieldTypeParameterContainer typeParameterContainer, + JBBPNamedFieldInfo nullableNamedFieldInfo, + int extraValue, boolean readWholeStream, + int arraySize) throws IOException { + return new JBBPFieldShort(nullableNamedFieldInfo, + (short) inStream.readUnsignedShort(typeParameterContainer.getByteOrder())); } @Override - public void writeCustomFieldType(Object sourceStruct, JBBPBitOutputStream outStream, JBBPAbstractField fieldValue, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean wholeArray, int arraySize) throws IOException { - outStream.writeShort(((JBBPFieldShort) fieldValue).getAsInt(), typeParameterContainer.getByteOrder()); + public void writeCustomFieldType(Object sourceStruct, JBBPBitOutputStream outStream, + JBBPAbstractField fieldValue, + JBBPFieldTypeParameterContainer typeParameterContainer, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, + boolean wholeArray, int arraySize) throws IOException { + outStream.writeShort(((JBBPFieldShort) fieldValue).getAsInt(), + typeParameterContainer.getByteOrder()); } @Override - public JBBPAbstractField readVarField(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException { + public JBBPAbstractField readVarField(Object sourceStruct, JBBPBitInputStream inStream, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) + throws IOException { return new JBBPFieldLong(nullableNamedFieldInfo, inStream.readLong(byteOrder)); } @Override - public JBBPAbstractArrayField readVarArray(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException { + public JBBPAbstractArrayField readVarArray(Object sourceStruct, + JBBPBitInputStream inStream, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, + int extraValue, + boolean readWholeStream, + int arraySize) + throws IOException { if (readWholeStream) { return new JBBPFieldArrayLong(nullableNamedFieldInfo, inStream.readLongArray(-1, byteOrder)); } else { - return new JBBPFieldArrayLong(nullableNamedFieldInfo, inStream.readLongArray(arraySize, byteOrder)); + return new JBBPFieldArrayLong(nullableNamedFieldInfo, + inStream.readLongArray(arraySize, byteOrder)); } } @Override - public void writeVarField(Object sourceStruct, JBBPAbstractField value, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException { + public void writeVarField(Object sourceStruct, JBBPAbstractField value, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) + throws IOException { outStream.writeLong(((JBBPFieldLong) value).getAsLong(), byteOrder); } @Override - public void writeVarArray(Object sourceStruct, JBBPAbstractArrayField array, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, int arraySizeToWrite) throws IOException { + public void writeVarArray(Object sourceStruct, + JBBPAbstractArrayField array, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, + int arraySizeToWrite) throws IOException { final JBBPFieldArrayLong a = (JBBPFieldArrayLong) array; if (arraySizeToWrite < 0) { for (final long l : a.getArray()) { diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java index 58d9134e..85347e24 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java @@ -16,16 +16,16 @@ package com.igormaznitsa.mvn.test.jbbp; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + + import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; import com.igormaznitsa.mvn.tst.VarCustomImpl; -import org.junit.jupiter.api.Test; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.Random; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import org.junit.jupiter.api.Test; public class VarCustomTest { diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsNonStaticTest.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsNonStaticTest.java index 8d99671e..ed031763 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsNonStaticTest.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsNonStaticTest.java @@ -32,7 +32,8 @@ class GenAnnotationsNonStaticTest { void testReadWrite() throws IOException { final byte[] testData = new byte[] {4, (byte) 0x12, (byte) 0x34, 3, 5, 6, 7}; - final GenAnnotationsNonStatic result = new GenAnnotationsNonStatic().read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + final GenAnnotationsNonStatic result = new GenAnnotationsNonStatic() + .read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); assertEquals(4, result.getLEN()); assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); @@ -45,10 +46,12 @@ void testReadWrite() throws IOException { + " }" + "}"; - final GenAnnotationsNonStatic instance = JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotationsNonStatic()); + final GenAnnotationsNonStatic instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotationsNonStatic()); assertEquals(result.getLEN(), instance.getLEN()); assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); - assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), instance.getSOME1().getSOME2().getFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); } } diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp index 58f5edc9..b1f6c18f 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotations.jbbp @@ -1,4 +1,6 @@ ubyte len; +uint uintField; +uint [1] uintArr; some1 { bit:4 [len] someField; ubyte len; diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsTest.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsTest.java index 350e0b64..f137c3a1 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsTest.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsTest.java @@ -30,13 +30,20 @@ class GenAnnotationsTest { @Test void testReadWrite() throws IOException { - final byte[] testData = new byte[] {4, (byte) 0x12, (byte) 0x34, 3, 5, 6, 7}; + final byte[] testData = new byte[] { + 4, + (byte)0xFF, (byte)0x1A, (byte)0x1B, (byte)0x1C, + (byte)0xFF, (byte)0x2A, (byte)0x2B, (byte)0x2C, + (byte) 0x12, (byte) 0x34, 3, 5, 6, 7}; - final GenAnnotations result = new GenAnnotations().read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); + final GenAnnotations result = + new GenAnnotations().read(new JBBPBitInputStream(new ByteArrayInputStream(testData))); assertEquals(4, result.getLEN()); assertEquals(3, result.getSOME1().getSOME2().getFIELD().length); final String script = "ubyte len;" + + " uint uintField;" + + " uint [1] uintArr;" + "some1 {" + " bit:4 [len] someField;" + " ubyte len;" @@ -45,10 +52,14 @@ void testReadWrite() throws IOException { + " }" + "}"; - final GenAnnotations instance = JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotations()); + final GenAnnotations instance = + JBBPParser.prepare(script).parse(testData).mapTo(new GenAnnotations()); + assertEquals(result.getUINTFIELD(), instance.getUINTFIELD()); + assertArrayEquals(result.getUINTARR(), instance.getUINTARR()); assertEquals(result.getLEN(), instance.getLEN()); assertEquals(result.getSOME1().getLEN(), instance.getSOME1().getLEN()); assertArrayEquals(result.getSOME1().getSOMEFIELD(), instance.getSOME1().getSOMEFIELD()); - assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), instance.getSOME1().getSOME2().getFIELD()); + assertArrayEquals(result.getSOME1().getSOME2().getFIELD(), + instance.getSOME1().getSOME2().getFIELD()); } } diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java index ac1430f0..b7c6a973 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java @@ -32,26 +32,47 @@ public class VarCustomImpl extends VarCustom { @Override - public JBBPAbstractField readCustomFieldType(Object sourceStruct, JBBPBitInputStream inStream, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException { - return new JBBPFieldShort(nullableNamedFieldInfo, (short) inStream.readUnsignedShort(typeParameterContainer.getByteOrder())); + public JBBPAbstractField readCustomFieldType(Object sourceStruct, JBBPBitInputStream inStream, + JBBPFieldTypeParameterContainer typeParameterContainer, + JBBPNamedFieldInfo nullableNamedFieldInfo, + int extraValue, boolean readWholeStream, + int arraySize) throws IOException { + return new JBBPFieldShort(nullableNamedFieldInfo, + (short) inStream.readUnsignedShort(typeParameterContainer.getByteOrder())); } @Override - public void writeCustomFieldType(Object sourceStruct, JBBPBitOutputStream outStream, JBBPAbstractField fieldValue, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean wholeArray, int arraySize) throws IOException { - outStream.writeShort(((JBBPFieldShort) fieldValue).getAsInt(), typeParameterContainer.getByteOrder()); + public void writeCustomFieldType(Object sourceStruct, JBBPBitOutputStream outStream, + JBBPAbstractField fieldValue, + JBBPFieldTypeParameterContainer typeParameterContainer, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, + boolean wholeArray, int arraySize) throws IOException { + outStream.writeShort(((JBBPFieldShort) fieldValue).getAsInt(), + typeParameterContainer.getByteOrder()); } @Override - public JBBPAbstractField readVarField(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException { + public JBBPAbstractField readVarField(Object sourceStruct, JBBPBitInputStream inStream, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) + throws IOException { return new JBBPFieldLong(nullableNamedFieldInfo, inStream.readLong(byteOrder)); } @Override - public JBBPAbstractArrayField readVarArray(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException { + public JBBPAbstractArrayField readVarArray(Object sourceStruct, + JBBPBitInputStream inStream, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, + int extraValue, + boolean readWholeStream, + int arraySize) + throws IOException { if (readWholeStream) { return new JBBPFieldArrayLong(nullableNamedFieldInfo, inStream.readLongArray(-1, byteOrder)); } else { - return new JBBPFieldArrayLong(nullableNamedFieldInfo, inStream.readLongArray(arraySize, byteOrder)); + return new JBBPFieldArrayLong(nullableNamedFieldInfo, + inStream.readLongArray(arraySize, byteOrder)); } } @@ -60,12 +81,19 @@ public void run() { } @Override - public void writeVarField(Object sourceStruct, JBBPAbstractField value, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException { + public void writeVarField(Object sourceStruct, JBBPAbstractField value, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) + throws IOException { outStream.writeLong(((JBBPFieldLong) value).getAsLong(), byteOrder); } @Override - public void writeVarArray(Object sourceStruct, JBBPAbstractArrayField array, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, int arraySizeToWrite) throws IOException { + public void writeVarArray(Object sourceStruct, + JBBPAbstractArrayField array, + JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, + int arraySizeToWrite) throws IOException { final JBBPFieldArrayLong a = (JBBPFieldArrayLong) array; if (arraySizeToWrite < 0) { for (final long l : a.getArray()) { diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-primitives/src/test/java/com/igormaznitsa/mvn/test/jbbp/WholeStreamByteArrayTest.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-primitives/src/test/java/com/igormaznitsa/mvn/test/jbbp/WholeStreamByteArrayTest.java index 8f69face..3c9a76fc 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-primitives/src/test/java/com/igormaznitsa/mvn/test/jbbp/WholeStreamByteArrayTest.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-primitives/src/test/java/com/igormaznitsa/mvn/test/jbbp/WholeStreamByteArrayTest.java @@ -16,22 +16,23 @@ package com.igormaznitsa.mvn.test.jbbp; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + + import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; -import org.junit.jupiter.api.Test; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import org.junit.jupiter.api.Test; public class WholeStreamByteArrayTest { @Test public void testRead_DefaultBitOrder() throws IOException { - final WholeStreamByteArray struct = new WholeStreamByteArray().read(new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))); + final WholeStreamByteArray struct = new WholeStreamByteArray().read(new JBBPBitInputStream( + new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))); assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, struct.array); } diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/pom.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/pom.xml index a31fd33c..709f4ec2 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/pom.xml +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-maven-plugin-pom - 2.0.1 + 3.0.2-SNAPSHOT jbbp-maven-plugin-tests @@ -31,7 +31,6 @@ org.apache.maven.shared maven-verifier - 1.6 test diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/pom.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/pom.xml index 2f4436d0..f73897be 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/pom.xml +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-maven-plugin-pom - 2.0.1 + 3.0.2-SNAPSHOT jbbp-maven-plugin @@ -14,11 +14,6 @@ JBBP Maven plugin Generator of sources from JBBP scripts - - 1.8 - 1.8 - - publish @@ -85,6 +80,33 @@ + + net.nicoulaj.maven.plugins + checksum-maven-plugin + + + verify + + files + + + + + ${project.build.directory} + + *.jar + *.pom + + + + + SHA-1 + MD5 + + + + + @@ -168,7 +190,7 @@ com.igormaznitsa uber-pom - 1.0.1 + 1.0.3
parent
@@ -185,31 +207,10 @@
- - org.codehaus.mojo - animal-sniffer-maven-plugin - 1.17 - - - org.codehaus.mojo.signature - java16-sun - 1.10 - - - - - animal-sniffer - test - - check - - - - org.apache.maven.plugins maven-plugin-plugin - 3.5 + 3.8.1 true jbbp diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/assemble/bundle.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/assemble/bundle.xml index 1d3c7e7f..008c1efd 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/assemble/bundle.xml +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/assemble/bundle.xml @@ -7,17 +7,21 @@ false - jar + tar.gz ${project.build.directory} - / + /com/igormaznitsa/${project.artifactId}/${project.version} - *.jar.asc *.jar + *.jar.asc + *.jar.sha1 + *.jar.md5 *.pom *.pom.asc + *.pom.sha1 + *.pom.md5 original*.* diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/assemble/distribution.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/assemble/distribution.xml deleted file mode 100644 index 22c183dc..00000000 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/assemble/distribution.xml +++ /dev/null @@ -1,46 +0,0 @@ - - distr - - false - false - - - tar.gz - - - - ${project.basedir} - /project - - target/ - texts/ - nbactions.xml - catalog.xml - **/.* - - - - /lib - ${project.basedir}/target - - ${project.build.finalName}.jar - - - - /lib - ${project.basedir} - - pom.xml - - - - / - ${basedir}/texts - - *.* - - - - \ No newline at end of file diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/AbstractJBBPMojo.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/AbstractJBBPMojo.java index 85650ad3..66d95075 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/AbstractJBBPMojo.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/AbstractJBBPMojo.java @@ -3,6 +3,11 @@ import com.igormaznitsa.jbbp.plugin.common.converters.Target; import com.igormaznitsa.meta.annotation.MustNotContainNull; import com.igormaznitsa.meta.common.utils.Assertions; +import java.io.File; +import java.util.HashSet; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -13,12 +18,6 @@ import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner; import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.File; -import java.util.HashSet; -import java.util.Set; - public abstract class AbstractJBBPMojo extends AbstractMojo { /** * Provides an explicit list of all the JBBP scripts that should be included @@ -170,7 +169,8 @@ protected void registerSourceRoot(@Nonnull final File outputDir) { @Nonnull public Set findSources(@Nonnull final File targetDirectory) throws MojoExecutionException { try { - final SourceInclusionScanner scanner = new SimpleSourceInclusionScanner(this.includes, this.excludes); + final SourceInclusionScanner scanner = + new SimpleSourceInclusionScanner(this.includes, this.excludes); scanner.addSourceMapping(new SuffixMapping("JBBP", "jbbp")); return scanner.getIncludedSources(this.source, targetDirectory); } catch (InclusionScanException ex) { diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPCleanMojo.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPCleanMojo.java index bbfa3b67..3bfc7a9d 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPCleanMojo.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPCleanMojo.java @@ -2,6 +2,9 @@ import com.igormaznitsa.jbbp.plugin.common.converters.JBBPScriptTranslator; import com.igormaznitsa.jbbp.plugin.common.converters.Target; +import java.io.File; +import java.io.IOException; +import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -9,10 +12,6 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -import java.io.File; -import java.io.IOException; -import java.util.Set; - /** * The Mojo looks for all java files generated for JBBP scripts and delete them. * @@ -67,12 +66,15 @@ public void executeMojo() throws MojoExecutionException, MojoFailureException { if (f.isFile()) { if (f.delete()) { counter++; - logInfo("Deleted file '" + f.getAbsolutePath() + "' for script '" + aScript + "'", true); + logInfo("Deleted file '" + f.getAbsolutePath() + "' for script '" + aScript + "'", + true); } else { - getLog().error("Can't delete file '" + f.getAbsolutePath() + "' for script '" + aScript + "'"); + getLog().error( + "Can't delete file '" + f.getAbsolutePath() + "' for script '" + aScript + "'"); } } else { - getLog().debug("File '" + f.getAbsolutePath() + "' generated for script '" + aScript + "' is not found"); + getLog().debug("File '" + f.getAbsolutePath() + "' generated for script '" + aScript + + "' is not found"); } } } diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojo.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojo.java index 6171a8c5..ac17f190 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojo.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/main/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojo.java @@ -19,10 +19,10 @@ import static com.igormaznitsa.jbbp.plugin.common.utils.CommonUtils.ensureEncodingName; import static com.igormaznitsa.jbbp.utils.JBBPUtils.ARRAY_STRING_EMPTY; - import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.mapper.Bin; @@ -202,14 +202,14 @@ public String getSuperClass() { return this.superClass; } - public void setDoAbstract(final boolean value) { - this.doAbstract = value; - } - public boolean isDoAbstract() { return this.doAbstract; } + public void setDoAbstract(final boolean value) { + this.doAbstract = value; + } + @Nonnull public Map getMapStructToInterfaces() { return this.mapStructToInterfaces; @@ -280,14 +280,14 @@ public void setDisableGenerateFields(final boolean value) { this.disableGenerateFields = value; } - public void setDoInnerClassesNonStatic(final boolean value) { - this.doInnerClassesNonStatic = value; - } - public boolean isDoInnerClassesNonStatic() { return this.doInnerClassesNonStatic; } + public void setDoInnerClassesNonStatic(final boolean value) { + this.doInnerClassesNonStatic = value; + } + @Nullable private String makeCapText(@Nonnull final String inEncoding) throws IOException { String result = null; @@ -343,7 +343,8 @@ protected void executeMojo() throws MojoExecutionException, MojoFailureException final String trimmed = s.trim(); final String normalized = trimmed.toLowerCase(Locale.ENGLISH); if (!normalized.equals(trimmed)) { - getLog().warn(String.format("Custom type name '%s' in JBBP normal form is '%s' ", trimmed, normalized)); + getLog().warn(String + .format("Custom type name '%s' in JBBP normal form is '%s' ", trimmed, normalized)); } normalizedCustomTypeNames.add(normalized); } @@ -360,7 +361,9 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(@Nonnull final JBBPFieldTypeParameterContainer fieldType, @Nullable final String fieldName, final int extraData, final boolean isArray) { + public boolean isAllowed(@Nonnull final JBBPFieldTypeParameterContainer fieldType, + @Nullable final String fieldName, final int extraData, + final boolean isArray) { final boolean result = normalizedCustomTypeNames.contains(fieldType.getTypeName()); if (!result) { getLog().warn("Detected not allowed custom type name : " + fieldType.getTypeName()); @@ -370,7 +373,17 @@ public boolean isAllowed(@Nonnull final JBBPFieldTypeParameterContainer fieldTyp @Override @Nonnull - public JBBPAbstractField readCustomFieldType(@Nonnull final JBBPBitInputStream in, @Nonnull final JBBPBitOrder bitOrder, final int parserFlags, @Nonnull final JBBPFieldTypeParameterContainer customTypeFieldInfo, @Nullable final JBBPNamedFieldInfo fieldName, final int extraData, final boolean readWholeStream, final int arrayLength) throws IOException { + public JBBPAbstractField readCustomFieldType(@Nonnull final JBBPBitInputStream in, + @Nonnull final JBBPBitOrder bitOrder, + final int parserFlags, @Nonnull + final JBBPFieldTypeParameterContainer customTypeFieldInfo, + @Nullable final JBBPNamedFieldInfo fieldName, + final int extraData, + final boolean readWholeStream, + final int arrayLength, + @Nonnull + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { throw new Error("Must not be called"); } }; @@ -407,20 +420,24 @@ public JBBPAbstractField readCustomFieldType(@Nonnull final JBBPBitInputStream i final Set files = theTarget.getTranslator().translate(parameters, false); getLog().debug("Converted " + aScript + " into " + files); for (final File f : files) { - logInfo(String.format("JBBP script '%s' has been converted into '%s'", aScript.getName(), f.getName()), false); + logInfo(String + .format("JBBP script '%s' has been converted into '%s'", aScript.getName(), + f.getName()), false); } } catch (IOException ex) { - throw new MojoExecutionException("Error during JBBP script translation : " + aScript.getAbsolutePath(), ex); + throw new MojoExecutionException( + "Error during JBBP script translation : " + aScript.getAbsolutePath(), ex); } } if (this.isAddToSourceFolders()) { - getLog().info("Add folder to compile source root: "+ this.getOutput().getAbsolutePath()); + getLog().info("Add folder to compile source root: " + this.getOutput().getAbsolutePath()); this.project.addCompileSourceRoot(this.getOutput().getAbsolutePath()); } if (this.isAddToTestSourceFolders()) { - getLog().info("Add folder to test compile source root: "+ this.getOutput().getAbsolutePath()); + getLog() + .info("Add folder to test compile source root: " + this.getOutput().getAbsolutePath()); this.project.addTestCompileSourceRoot(this.getOutput().getAbsolutePath()); } } diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverterTest.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverterTest.java index bc8aba43..430d4962 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverterTest.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverterTest.java @@ -32,9 +32,12 @@ void testTranslateParameters() { assertTrue(parameters.setDoInternalClassesNonStatic(true).isDoInternalClassesNonStatic()); assertFalse(parameters.setDoInternalClassesNonStatic(false).isDoInternalClassesNonStatic()); - assertEquals(new File("some_test"), parameters.setOutputDir(new File("some_test")).getOutputDir()); - assertEquals(new File("some_test.script"), parameters.setScriptFile(new File("some_test.script")).getScriptFile()); - assertEquals("some.test.package", parameters.setPackageName("some.test.package").getPackageName()); + assertEquals(new File("some_test"), + parameters.setOutputDir(new File("some_test")).getOutputDir()); + assertEquals(new File("some_test.script"), + parameters.setScriptFile(new File("some_test.script")).getScriptFile()); + assertEquals("some.test.package", + parameters.setPackageName("some.test.package").getPackageName()); assertEquals("bit a;", parameters.setScriptText("bit a;").getScriptText()); assertEquals("SomeSuperClass", parameters.setSuperClass("SomeSuperClass").getSuperClass()); assertEquals(1234, parameters.setParserFlags(1234).getParserFlags()); diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojoTest.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojoTest.java index 35cb965c..8127b70a 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojoTest.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/java/com/igormaznitsa/jbbp/plugin/mvn/JBBPGenerateMojoTest.java @@ -98,9 +98,12 @@ public void testConfig() throws Exception { assertTrue(mojo.isAddToTestSourceFolders()); assertTrue(mojo.getAddGettersSetters()); assertArrayEquals(new String[] {"abc", "def"}, set2array(mojo.getCustomTypes())); - assertArrayEquals(new String[] {"com.igormaznitsa.InterfaceA", "com.igormaznitsa.InterfaceB"}, set2array(mojo.getInterfaces())); - assertArrayEquals(new String[] {"path1/**/*.jbbp", "path2/**/*.jbbp"}, set2array(mojo.getIncludes())); - assertArrayEquals(new String[] {"path3/**/*.jbbp", "path4/**/*.jbbp"}, set2array(mojo.getExcludes())); + assertArrayEquals(new String[] {"com.igormaznitsa.InterfaceA", "com.igormaznitsa.InterfaceB"}, + set2array(mojo.getInterfaces())); + assertArrayEquals(new String[] {"path1/**/*.jbbp", "path2/**/*.jbbp"}, + set2array(mojo.getIncludes())); + assertArrayEquals(new String[] {"path3/**/*.jbbp", "path4/**/*.jbbp"}, + set2array(mojo.getExcludes())); assertTrue(mojo.isDoInnerClassesNonStatic()); assertTrue(mojo.isDisableGenerateFields()); diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/resources/com/igormaznitsa/jbbp/plugin/mvn/mojoConfig.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/resources/com/igormaznitsa/jbbp/plugin/mvn/mojoConfig.xml index 1f2ee6b0..cf77af0d 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/resources/com/igormaznitsa/jbbp/plugin/mvn/mojoConfig.xml +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/resources/com/igormaznitsa/jbbp/plugin/mvn/mojoConfig.xml @@ -14,7 +14,7 @@ com.igormaznitsa jbbp-maven-plugin - 2.0.1 + 2.0.4-SNAPSHOT generate diff --git a/jbbp-plugins/jbbp-maven/pom.xml b/jbbp-plugins/jbbp-maven/pom.xml index 53ee3bcb..1da1b5aa 100644 --- a/jbbp-plugins/jbbp-maven/pom.xml +++ b/jbbp-plugins/jbbp-maven/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-main-plugin-pom - 2.0.1 + 3.0.2-SNAPSHOT jbbp-maven-plugin-pom diff --git a/jbbp-plugins/jbbp-plugin-common/pom.xml b/jbbp-plugins/jbbp-plugin-common/pom.xml index 5157cb73..c320c4b8 100644 --- a/jbbp-plugins/jbbp-plugin-common/pom.xml +++ b/jbbp-plugins/jbbp-plugin-common/pom.xml @@ -6,7 +6,7 @@ com.igormaznitsa jbbp-main-plugin-pom - 2.0.1 + 3.0.2-SNAPSHOT jbbp-plugin-common diff --git a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JBBPScriptTranslator.java b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JBBPScriptTranslator.java index 94a46b4a..ba7f365c 100644 --- a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JBBPScriptTranslator.java +++ b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JBBPScriptTranslator.java @@ -47,24 +47,27 @@ public final class Parameters { */ @Nonnull private final Map subClassSuperclasses = new HashMap(); - + /** + * Set of interface names to be implemented by the main class. + */ + @Nonnull + private final Set classImplements = new HashSet(); + /** + * Processor for custom types. + */ + @Nullable + JBBPCustomFieldTypeProcessor customFieldTypeProcessor = null; /** * Flag to not make generated subclasses as static ones. * * @since 1.4.0 */ private boolean doInternalClassesNonStatic; - /** - * Set of interface names to be implemented by the main class. - */ - @Nonnull - private final Set classImplements = new HashSet(); /** * Super class for main class. */ @Nullable private String superClass = null; - /** * Destination file name. * @@ -72,12 +75,6 @@ public final class Parameters { */ @Nullable private String destFileName = null; - - /** - * Processor for custom types. - */ - @Nullable - JBBPCustomFieldTypeProcessor customFieldTypeProcessor = null; /** * Disable generate class fields. * @@ -161,12 +158,6 @@ public Parameters setPackageName(@Nullable final String value) { return this; } - @Nonnull - public Parameters setSuperClass(@Nullable final String value) { - this.superClass = value; - return this; - } - public boolean isAddGettersSetters() { return this.addGettersSetters; } @@ -215,14 +206,22 @@ public Map getSubClassInterfaces() { return Collections.unmodifiableMap(this.subClassInterfaces); } + @Nonnull + public Parameters setSubClassInterfaces(@Nonnull final Map value) { + this.subClassInterfaces.clear(); + this.subClassInterfaces.putAll(value); + return this; + } + @Nonnull public Map getSubClassSuperclasses() { return Collections.unmodifiableMap(this.subClassSuperclasses); } @Nonnull - public Parameters setDoInternalClassesNonStatic(final boolean flag) { - this.doInternalClassesNonStatic = flag; + public Parameters setSubClassSuperclasses(@Nonnull final Map value) { + this.subClassSuperclasses.clear(); + this.subClassSuperclasses.putAll(value); return this; } @@ -230,6 +229,12 @@ public boolean isDoInternalClassesNonStatic() { return this.doInternalClassesNonStatic; } + @Nonnull + public Parameters setDoInternalClassesNonStatic(final boolean flag) { + this.doInternalClassesNonStatic = flag; + return this; + } + public boolean isAddNewInstanceMethods() { return this.addNewInstanceMethods; } @@ -250,20 +255,6 @@ public Parameters setAddBinAnnotations(final boolean flag) { return this; } - @Nonnull - public Parameters setSubClassSuperclasses(@Nonnull final Map value) { - this.subClassSuperclasses.clear(); - this.subClassSuperclasses.putAll(value); - return this; - } - - @Nonnull - public Parameters setSubClassInterfaces(@Nonnull final Map value) { - this.subClassInterfaces.clear(); - this.subClassInterfaces.putAll(value); - return this; - } - public int getParserFlags() { return this.parserFlags; } @@ -367,7 +358,8 @@ public JBBPCustomFieldTypeProcessor getCustomFieldTypeProcessor() { } @Nonnull - public Parameters setCustomFieldTypeProcessor(@Nullable final JBBPCustomFieldTypeProcessor customProcessor) { + public Parameters setCustomFieldTypeProcessor( + @Nullable final JBBPCustomFieldTypeProcessor customProcessor) { this.customFieldTypeProcessor = customProcessor; return this; } @@ -384,5 +376,11 @@ public Parameters assertAllOk() { public String getSuperClass() { return this.superClass; } + + @Nonnull + public Parameters setSuperClass(@Nullable final String value) { + this.superClass = value; + return this; + } } } diff --git a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverter.java b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverter.java index 4ccb8005..28595c4a 100644 --- a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverter.java +++ b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverter.java @@ -20,26 +20,35 @@ public class JavaConverter implements JBBPScriptTranslator { @Override @Nonnull - public Set translate(@Nonnull final Parameters parameters, final boolean dryRun) throws IOException { + public Set translate(@Nonnull final Parameters parameters, final boolean dryRun) + throws IOException { final String text; final String rawFileName; if (parameters.getScriptFile() == null) { - rawFileName = parameters.getDestFileName() == null ? "JbbpNoName" : parameters.getDestFileName(); - text = Assertions.assertNotNull("Script file is null, expected script text", parameters.getScriptText()); + rawFileName = + parameters.getDestFileName() == null ? "JbbpNoName" : parameters.getDestFileName(); + text = Assertions + .assertNotNull("Script file is null, expected script text", parameters.getScriptText()); } else { final File scriptToProcess = parameters.getScriptFile(); rawFileName = FilenameUtils.getBaseName(scriptToProcess.getName()); text = FileUtils.readFileToString(scriptToProcess, parameters.getEncodingIn()); } final String className = CommonUtils.extractClassName(rawFileName); - final String packageName = parameters.getPackageName() == null ? CommonUtils.extractPackageName(rawFileName) : parameters.getPackageName(); + final String packageName = + parameters.getPackageName() == null ? CommonUtils.extractPackageName(rawFileName) : + parameters.getPackageName(); - final Set resultFiles = Collections.singleton(CommonUtils.scriptFileToJavaFile(parameters.getOutputDir(), parameters.getPackageName(), parameters.getScriptFile())); + final Set resultFiles = Collections.singleton(CommonUtils + .scriptFileToJavaFile(parameters.getOutputDir(), parameters.getPackageName(), + parameters.getScriptFile())); if (!dryRun) { final File resultJavaFile = resultFiles.iterator().next(); - final JBBPParser parser = JBBPParser.prepare(text, JBBPBitOrder.LSB0, parameters.customFieldTypeProcessor, parameters.getParserFlags()); + final JBBPParser parser = JBBPParser + .prepare(text, JBBPBitOrder.LSB0, parameters.customFieldTypeProcessor, + parameters.getParserFlags()); final String[] implementsSorted = parameters.getClassImplements().toArray(ARRAY_STRING_EMPTY); Arrays.sort(implementsSorted); diff --git a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/ParserFlags.java b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/ParserFlags.java index 852afa2e..65f65acd 100644 --- a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/ParserFlags.java +++ b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/ParserFlags.java @@ -1,9 +1,8 @@ package com.igormaznitsa.jbbp.plugin.common.converters; import com.igormaznitsa.jbbp.JBBPParser; - -import javax.annotation.Nullable; import java.util.Set; +import javax.annotation.Nullable; /** * Allowed parser flags. diff --git a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/utils/CommonUtils.java b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/utils/CommonUtils.java index 9986cf6c..e4354afb 100644 --- a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/utils/CommonUtils.java +++ b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/utils/CommonUtils.java @@ -16,13 +16,12 @@ package com.igormaznitsa.jbbp.plugin.common.utils; -import org.apache.commons.io.FilenameUtils; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.File; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.apache.commons.io.FilenameUtils; /** * Misc auxiliary methods. @@ -44,7 +43,8 @@ private CommonUtils() { public static String ensureEncodingName(@Nullable final String charsetName) { final Charset defaultCharset = Charset.defaultCharset(); try { - return (charsetName == null) ? defaultCharset.name() : Charset.forName(charsetName.trim()).name(); + return (charsetName == null) ? defaultCharset.name() : + Charset.forName(charsetName.trim()).name(); } catch (IllegalCharsetNameException ex) { throw new IllegalArgumentException("Can't recognize charset for name '" + charsetName + '\''); } @@ -89,10 +89,13 @@ public static String extractPackageName(@Nonnull final String fileNameWithoutExt * @return java source file for the script file */ @Nonnull - public static File scriptFileToJavaFile(@Nullable final File targetDir, @Nullable final String classPackage, @Nonnull final File scriptFile) { + public static File scriptFileToJavaFile(@Nullable final File targetDir, + @Nullable final String classPackage, + @Nonnull final File scriptFile) { final String rawFileName = FilenameUtils.getBaseName(scriptFile.getName()); final String className = CommonUtils.extractClassName(rawFileName); - final String packageName = classPackage == null ? CommonUtils.extractPackageName(rawFileName) : classPackage; + final String packageName = + classPackage == null ? CommonUtils.extractPackageName(rawFileName) : classPackage; String fullClassName = packageName.isEmpty() ? className : packageName + '.' + className; fullClassName = fullClassName.replace('.', File.separatorChar) + ".java"; diff --git a/jbbp-plugins/jbbp-plugin-common/src/test/java/com/igormaznitsa/jbbp/plugin/common/utils/CommonUtilsTest.java b/jbbp-plugins/jbbp-plugin-common/src/test/java/com/igormaznitsa/jbbp/plugin/common/utils/CommonUtilsTest.java index fedb1916..d53ae44b 100644 --- a/jbbp-plugins/jbbp-plugin-common/src/test/java/com/igormaznitsa/jbbp/plugin/common/utils/CommonUtilsTest.java +++ b/jbbp-plugins/jbbp-plugin-common/src/test/java/com/igormaznitsa/jbbp/plugin/common/utils/CommonUtilsTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.assertEquals; public class CommonUtilsTest { diff --git a/jbbp-plugins/pom.xml b/jbbp-plugins/pom.xml index 867b0a49..f1cc9863 100644 --- a/jbbp-plugins/pom.xml +++ b/jbbp-plugins/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-main-pom - 2.0.1 + 3.0.2-SNAPSHOT jbbp-main-plugin-pom @@ -31,10 +31,18 @@ commons-io commons-io - 2.6 + + + gradle-tests + + jbbp-gradle-tests + + + + @@ -42,10 +50,8 @@ meta-checker ${meta.version} - 6 true true - risky diff --git a/jbbp/pom.xml b/jbbp/pom.xml index a7f40c8e..9f031e0f 100644 --- a/jbbp/pom.xml +++ b/jbbp/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-main-pom - 2.0.1 + 3.0.2-SNAPSHOT jbbp @@ -37,25 +37,22 @@ org.apache.commons commons-lang3 - 3.9 + 3.18.0 test net.minidev json-smart - 2.3 test commons-io commons-io - 2.6 test commons-codec commons-codec - 1.13 test @@ -118,7 +115,7 @@ test - java + java8 -classpath @@ -158,6 +155,7 @@ org.apache.maven.plugins maven-javadoc-plugin + false true protected UTF-8 @@ -170,7 +168,7 @@ jar - 1.8 + 8 @@ -188,6 +186,33 @@ + + net.nicoulaj.maven.plugins + checksum-maven-plugin + + + verify + + files + + + + + ${project.build.directory} + + *.jar + *.pom + + + + + SHA-1 + MD5 + + + + + @@ -230,30 +255,16 @@ animal-sniffer-maven-plugin - ensure-java-1.8-class-library - test - - check - - - - org.codehaus.mojo.signature - java18 - 1.0 - - - - - ensure-android-3.0_r2-class-library + ensure-android-api-32-class-library test check - net.sf.androidscents.signature - android-api-level-11 - 3.0_r2 + com.toasttab.android + gummy-bears-api-32 + 0.10.0 sun.misc.Unsafe diff --git a/jbbp/src/assemble/bundle.xml b/jbbp/src/assemble/bundle.xml index 227e64af..008c1efd 100644 --- a/jbbp/src/assemble/bundle.xml +++ b/jbbp/src/assemble/bundle.xml @@ -1,19 +1,3 @@ - - @@ -23,19 +7,24 @@ false - jar + tar.gz ${project.build.directory} - ${file.separator} + /com/igormaznitsa/${project.artifactId}/${project.version} - *.jar.asc *.jar + *.jar.asc + *.jar.sha1 + *.jar.md5 *.pom *.pom.asc + *.pom.sha1 + *.pom.md5 + original*.* *.zip diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessor.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessor.java index 25fb3452..c0453dae 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessor.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessor.java @@ -18,10 +18,11 @@ import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.exceptions.JBBPReachedArraySizeLimitException; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.model.JBBPAbstractField; - import java.io.IOException; /** @@ -46,7 +47,8 @@ public interface JBBPCustomFieldTypeProcessor { * @param isArray flag shows that the field describes an array * @return true if such configuration allowed, false otherwise */ - boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, int extraData, boolean isArray); + boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, int extraData, + boolean isArray); /** * Read custom field from stream and return the data as a JBBP field. @@ -59,8 +61,20 @@ public interface JBBPCustomFieldTypeProcessor { * @param extraData extra numeric value for the field, followed by ':', if not presented then 0 * @param readWholeStream if true then the field is array which should contain parse data for whole stream till the end * @param arrayLength -1 if it is not array else length of the array to be read. + * @param arraySizeLimiter limiter to check number of elements during whole stream array read, must not be null * @return parsed data as JBBP field, must not be null - * @throws IOException it can be thrown for transport errors + * @throws IOException it can be thrown for transport errors + * @throws JBBPReachedArraySizeLimitException thrown if reached limit for a whole stream array + * @since 2.1.0 + * @see JBBPArraySizeLimiter#isBreakReadWholeStream(int, JBBPArraySizeLimiter) + * @see JBBPArraySizeLimiter#NO_LIMIT_FOR_ARRAY_SIZE */ - JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, int parserFlags, JBBPFieldTypeParameterContainer customTypeFieldInfo, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException; + JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, + int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) throws IOException; + } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPExternalValueProvider.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPExternalValueProvider.java index 1271bb40..360e37fe 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPExternalValueProvider.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPExternalValueProvider.java @@ -32,5 +32,6 @@ public interface JBBPExternalValueProvider { * @param compiledBlock the compiled block for the script to provide extra information * @return the size of an array */ - int provideArraySize(final String fieldName, final JBBPNamedNumericFieldMap numericFieldMap, final JBBPCompiledBlock compiledBlock); + int provideArraySize(final String fieldName, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPCompiledBlock compiledBlock); } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPNamedNumericFieldMap.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPNamedNumericFieldMap.java index cfde2d4b..0dac9595 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPNamedNumericFieldMap.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPNamedNumericFieldMap.java @@ -26,7 +26,6 @@ import com.igormaznitsa.jbbp.model.JBBPNumericField; import com.igormaznitsa.jbbp.model.finder.JBBPFieldFinder; import com.igormaznitsa.jbbp.utils.JBBPUtils; - import java.util.LinkedHashMap; import java.util.Map; @@ -168,14 +167,16 @@ public T findFieldForType(final Class fieldType } @Override - public T findFieldForNameAndType(final String fieldName, final Class fieldType) { + public T findFieldForNameAndType(final String fieldName, + final Class fieldType) { final String normalizedName = JBBPUtils.normalizeFieldNameOrPath(fieldName); JBBPUtils.assertNotNull(fieldType, "Field type must not be null"); T result = null; for (final Map.Entry f : fieldMap.entrySet()) { - if (normalizedName.equals(f.getKey().getFieldName()) && fieldType.isAssignableFrom(f.getValue().getClass())) { + if (normalizedName.equals(f.getKey().getFieldName()) && + fieldType.isAssignableFrom(f.getValue().getClass())) { result = fieldType.cast(f.getValue()); break; } @@ -184,14 +185,16 @@ public T findFieldForNameAndType(final String fiel } @Override - public T findFieldForPathAndType(final String fieldPath, final Class fieldType) { + public T findFieldForPathAndType(final String fieldPath, + final Class fieldType) { final String normalizedPath = JBBPUtils.normalizeFieldNameOrPath(fieldPath); JBBPUtils.assertNotNull(fieldType, "Field type must not be null"); T result = null; for (final Map.Entry f : fieldMap.entrySet()) { - if (normalizedPath.equals(f.getKey().getFieldPath()) && fieldType.isAssignableFrom(f.getValue().getClass())) { + if (normalizedPath.equals(f.getKey().getFieldPath()) && + fieldType.isAssignableFrom(f.getValue().getClass())) { result = fieldType.cast(f.getValue()); break; } @@ -293,10 +296,13 @@ public int size() { * @return integer value for the field * @throws JBBPException if there is not any external value provider */ - public int getExternalFieldValue(final String externalFieldName, final JBBPCompiledBlock compiledBlock, final JBBPIntegerValueEvaluator evaluator) { + public int getExternalFieldValue(final String externalFieldName, + final JBBPCompiledBlock compiledBlock, + final JBBPIntegerValueEvaluator evaluator) { final String normalizedName = JBBPUtils.normalizeFieldNameOrPath(externalFieldName); if (this.externalValueProvider == null) { - throw new JBBPEvalException("Request for '" + externalFieldName + "' but there is not any value provider", evaluator); + throw new JBBPEvalException( + "Request for '" + externalFieldName + "' but there is not any value provider", evaluator); } else { return this.externalValueProvider.provideArraySize(normalizedName, this, compiledBlock); } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParser.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParser.java index 4550802a..da3c2ce9 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParser.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParser.java @@ -16,9 +16,9 @@ package com.igormaznitsa.jbbp; +import static com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE; import static com.igormaznitsa.jbbp.utils.JBBPUtils.ARRAY_FIELD_EMPTY; - import com.igormaznitsa.jbbp.compiler.JBBPCompiledBlock; import com.igormaznitsa.jbbp.compiler.JBBPCompiler; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; @@ -26,6 +26,8 @@ import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; import com.igormaznitsa.jbbp.compiler.varlen.JBBPIntegerValueEvaluator; import com.igormaznitsa.jbbp.exceptions.JBBPParsingException; +import com.igormaznitsa.jbbp.exceptions.JBBPReachedArraySizeLimitException; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitNumber; import com.igormaznitsa.jbbp.io.JBBPBitOrder; @@ -43,6 +45,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldArrayString; import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUByte; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayUInt; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUShort; import com.igormaznitsa.jbbp.model.JBBPFieldBit; import com.igormaznitsa.jbbp.model.JBBPFieldBoolean; @@ -55,6 +58,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldString; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; import com.igormaznitsa.jbbp.model.JBBPFieldUByte; +import com.igormaznitsa.jbbp.model.JBBPFieldUInt; import com.igormaznitsa.jbbp.model.JBBPFieldUShort; import com.igormaznitsa.jbbp.model.JBBPNumericField; import com.igormaznitsa.jbbp.utils.JBBPIntCounter; @@ -76,7 +80,7 @@ * * @since 1.0 */ -@SuppressWarnings( {"WeakerAccess"}) +@SuppressWarnings({"WeakerAccess"}) public final class JBBPParser { /** @@ -89,6 +93,15 @@ public final class JBBPParser { * @since 1.4.0 */ public static final int FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO = 2; + + /** + * Default expression array size controller. It is doing nothing. + * + * @since 2.1.0 + */ + public static final JBBPParserExpressionArraySizeController + DEFAULT_EXPRESSION_ARRAY_SIZE_CONTROLLER = + (parser, expressionEvaluator, fieldName, arraySize) -> arraySize; /** * Empty structure array */ @@ -109,22 +122,29 @@ public final class JBBPParser { * Custom field type processor for the parser, it can be null. */ private final JBBPCustomFieldTypeProcessor customFieldTypeProcessor; + /** + * Controller to get and change values calculated by expressions as size for array fields. + * + * @since 2.1.0 + */ + private JBBPParserExpressionArraySizeController expressionArraySizeController = + DEFAULT_EXPRESSION_ARRAY_SIZE_CONTROLLER; /** * The Variable contains the last parsing counter value. */ private long finalStreamByteCounter; - /** * Constructor. * * @param source the source script to parse binary blocks and streams, must * not be null - * @param bitOrder the bit order for bit reading operations, must not be null + * @param bitOrder the bit order for a bit reading operations, must not be null * @param customFieldTypeProcessor custom field type processor for the parser instance, it can be null * @param flags special flags for parsing process * @see #FLAG_SKIP_REMAINING_FIELDS_IF_EOF */ - private JBBPParser(final String source, final JBBPBitOrder bitOrder, final JBBPCustomFieldTypeProcessor customFieldTypeProcessor, final int flags) { + private JBBPParser(final String source, final JBBPBitOrder bitOrder, + final JBBPCustomFieldTypeProcessor customFieldTypeProcessor, final int flags) { JBBPUtils.assertNotNull(source, "Script is null"); JBBPUtils.assertNotNull(bitOrder, "Bit order is null"); this.customFieldTypeProcessor = customFieldTypeProcessor; @@ -145,7 +165,9 @@ private JBBPParser(final String source, final JBBPBitOrder bitOrder, final JBBPC */ private static void assertArrayLength(final int length, final JBBPNamedFieldInfo name) { if (length < 0) { - throw new JBBPParsingException("Detected negative calculated array length for field '" + (name == null ? "" : name.getFieldPath()) + "\' [" + JBBPUtils.int2msg(length) + ']'); + throw new JBBPParsingException("Detected negative calculated array length for field '" + + (name == null ? "" : name.getFieldPath()) + "' [" + JBBPUtils.int2msg(length) + + ']'); } } @@ -163,7 +185,7 @@ public static JBBPParser prepare(final String script, final JBBPBitOrder bitOrde } /** - * Prepare a parser for a script with defined bit order and special flags. + * Prepare a parser for a script with defined a bit order and special flags. * * @param script a text script contains field order and types reference, it * must not be null @@ -175,12 +197,13 @@ public static JBBPParser prepare(final String script, final JBBPBitOrder bitOrde * @see #FLAG_SKIP_REMAINING_FIELDS_IF_EOF * @since 1.1 */ - public static JBBPParser prepare(final String script, final JBBPBitOrder bitOrder, final int flags) { + public static JBBPParser prepare(final String script, final JBBPBitOrder bitOrder, + final int flags) { return new JBBPParser(script, bitOrder, null, flags); } /** - * Prepare a parser for a script with defined bit order and special flags. + * Prepare a parser for a script with defined a bit order and special flags. * * @param script a text script contains field order and types reference, it * must not be null @@ -193,7 +216,9 @@ public static JBBPParser prepare(final String script, final JBBPBitOrder bitOrde * @see #FLAG_SKIP_REMAINING_FIELDS_IF_EOF * @since 1.1.1 */ - public static JBBPParser prepare(final String script, final JBBPBitOrder bitOrder, final JBBPCustomFieldTypeProcessor customFieldTypeProcessor, final int flags) { + public static JBBPParser prepare(final String script, final JBBPBitOrder bitOrder, + final JBBPCustomFieldTypeProcessor customFieldTypeProcessor, + final int flags) { return new JBBPParser(script, bitOrder, customFieldTypeProcessor, flags); } @@ -218,7 +243,8 @@ public static JBBPParser prepare(final String script) { * @see JBBPBitOrder#LSB0 * @since 1.2.0 */ - public static JBBPParser prepare(final String script, final JBBPCustomFieldTypeProcessor customFieldTypeProcessor) { + public static JBBPParser prepare(final String script, + final JBBPCustomFieldTypeProcessor customFieldTypeProcessor) { return JBBPParser.prepare(script, JBBPBitOrder.LSB0, customFieldTypeProcessor, 0); } @@ -237,33 +263,72 @@ public static JBBPParser prepare(final String script, final int flags) { return JBBPParser.prepare(script, JBBPBitOrder.LSB0, flags); } + /** + * Get current registered instance of controller to check array size calculated by expression. + * + * @return current instance of array size observer, can't be null + * @since 2.1.0 + */ + public JBBPParserExpressionArraySizeController getExpressionArraySizeController() { + return this.expressionArraySizeController; + } + + /** + * Set current registered instance of controller to check array size calculated by expression. + * + * @param arraySizeController instance of array size observer, must not be null. + * @return instance of the parser. + * @throws NullPointerException if argument is null + * @see #DEFAULT_EXPRESSION_ARRAY_SIZE_CONTROLLER + * @since 2.1.0 + */ + public JBBPParser setExpressionArraySizeController( + final JBBPParserExpressionArraySizeController arraySizeController) { + if (arraySizeController == null) { + throw new NullPointerException("Controller value must not be null"); + } + this.expressionArraySizeController = arraySizeController; + return this; + } + /** * Inside method to parse a structure. * * @param inStream the input stream, must not be null * @param positionAtCompiledBlock the current position in the compiled script * block - * @param varFieldProcessor a processor to process var fields, it can be null + * @param varFieldProcessor a processor to process var fields, it can be null, * but it will thrown NPE if a var field is met * @param namedNumericFieldMap the named numeric field map * @param positionAtNamedFieldList the current position at the named field * list * @param positionAtVarLengthProcessors the current position at the variable * array length processor list + * @param arraySizeLimiter limiter for only whole stream arrays, must not be null * @param skipStructureFields the flag shows that content of fields must be * skipped because the structure is skipped * @return list of read fields for the structure - * @throws IOException it will be thrown for transport errors + * @throws IOException it will be thrown for transport errors + * @throws JBBPReachedArraySizeLimitException thrown if reached limit for a whole stream array */ - private List parseStruct(final JBBPBitInputStream inStream, final JBBPIntCounter positionAtCompiledBlock, final JBBPVarFieldProcessor varFieldProcessor, final JBBPNamedNumericFieldMap namedNumericFieldMap, final JBBPIntCounter positionAtNamedFieldList, final JBBPIntCounter positionAtVarLengthProcessors, final boolean skipStructureFields) throws IOException { + private List parseStruct(final JBBPBitInputStream inStream, + final JBBPIntCounter positionAtCompiledBlock, + final JBBPVarFieldProcessor varFieldProcessor, + final JBBPNamedNumericFieldMap namedNumericFieldMap, + final JBBPIntCounter positionAtNamedFieldList, + final JBBPIntCounter positionAtVarLengthProcessors, + final JBBPArraySizeLimiter arraySizeLimiter, + final boolean skipStructureFields) + throws IOException { final List structureFields = skipStructureFields ? null : new ArrayList<>(); final byte[] compiled = this.compiledBlock.getCompiledData(); boolean endStructureNotMet = true; while (endStructureNotMet && positionAtCompiledBlock.get() < compiled.length) { - if (!inStream.hasAvailableData() && (flags & FLAG_SKIP_REMAINING_FIELDS_IF_EOF) != 0) { - // Break reading because the ignore flag for EOF has been set + if (inStream.isDetectedArrayLimit() || + (!inStream.hasAvailableData() && (flags & FLAG_SKIP_REMAINING_FIELDS_IF_EOF) != 0)) { + // Break reading because the ignore flag for EOF has been set or reached limit for whole stream array read break; } @@ -274,17 +339,24 @@ private List parseStruct(final JBBPBitInputStream inStream, f final int code = (ec << 8) | c; final boolean fieldTypeDiff = (ec & JBBPCompiler.EXT_FLAG_EXTRA_DIFF_TYPE) != 0; - final JBBPNamedFieldInfo name = (code & JBBPCompiler.FLAG_NAMED) == 0 ? null : compiledBlock.getNamedFields()[positionAtNamedFieldList.getAndIncrement()]; - final JBBPByteOrder byteOrder = (code & JBBPCompiler.FLAG_LITTLE_ENDIAN) == 0 ? JBBPByteOrder.BIG_ENDIAN : JBBPByteOrder.LITTLE_ENDIAN; + final JBBPNamedFieldInfo name = (code & JBBPCompiler.FLAG_NAMED) == 0 ? null : + compiledBlock.getNamedFields()[positionAtNamedFieldList.getAndIncrement()]; + final JBBPByteOrder byteOrder = + (code & JBBPCompiler.FLAG_LITTLE_ENDIAN) == 0 ? JBBPByteOrder.BIG_ENDIAN : + JBBPByteOrder.LITTLE_ENDIAN; final boolean resultNotIgnored = !skipStructureFields; final int extraFieldNumExprResult; if (extraFieldNumAsExpr) { - final JBBPIntegerValueEvaluator evaluator = this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors.getAndIncrement()]; + final JBBPIntegerValueEvaluator evaluator = + this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors + .getAndIncrement()]; int resultOfExpression; if (resultNotIgnored) { - resultOfExpression = evaluator.eval(inStream, positionAtCompiledBlock.get(), this.compiledBlock, namedNumericFieldMap); + resultOfExpression = evaluator + .eval(inStream, positionAtCompiledBlock.get(), this.compiledBlock, + namedNumericFieldMap); if ((this.flags & FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO) != 0) { resultOfExpression = Math.max(resultOfExpression, 0); } @@ -299,7 +371,8 @@ private List parseStruct(final JBBPBitInputStream inStream, f final boolean wholeStreamArray; final int arrayLength; final int packedArraySizeOffset; - switch (code & (JBBPCompiler.FLAG_ARRAY | (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8))) { + switch (code & + (JBBPCompiler.FLAG_ARRAY | (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8))) { case JBBPCompiler.FLAG_ARRAY: { final int pos = positionAtCompiledBlock.get(); arrayLength = JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); @@ -314,13 +387,20 @@ private List parseStruct(final JBBPBitInputStream inStream, f } break; case JBBPCompiler.FLAG_ARRAY | (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8): { - final JBBPIntegerValueEvaluator evaluator = this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors.getAndIncrement()]; + final JBBPIntegerValueEvaluator evaluator = + this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors + .getAndIncrement()]; int resultOfExpression; if (resultNotIgnored) { - resultOfExpression = evaluator.eval(inStream, positionAtCompiledBlock.get(), this.compiledBlock, namedNumericFieldMap); + resultOfExpression = evaluator + .eval(inStream, positionAtCompiledBlock.get(), this.compiledBlock, + namedNumericFieldMap); if ((this.flags & FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO) != 0) { resultOfExpression = Math.max(resultOfExpression, 0); } + resultOfExpression = + this.expressionArraySizeController.onCalculatedArraySize(this, evaluator, name, + resultOfExpression); } else { resultOfExpression = 0; } @@ -349,14 +429,16 @@ private List parseStruct(final JBBPBitInputStream inStream, f } break; case JBBPCompiler.CODE_ALIGN: { - final int alignValue = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); + final int alignValue = extraFieldNumAsExpr ? extraFieldNumExprResult : + JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); if (resultNotIgnored) { inStream.align(alignValue); } } break; case JBBPCompiler.CODE_SKIP: { - final int skipByteNumber = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); + final int skipByteNumber = extraFieldNumAsExpr ? extraFieldNumExprResult : + JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); if (resultNotIgnored) { if (fieldTypeDiff) { singleAtomicField = new JBBPFieldInt(name, skipByteNumber); @@ -364,7 +446,9 @@ private List parseStruct(final JBBPBitInputStream inStream, f if (skipByteNumber > 0) { final long skippedBytes = inStream.skip(skipByteNumber); if (skippedBytes != skipByteNumber) { - throw new EOFException("Can't skip " + skipByteNumber + " byte(s), skipped only " + skippedBytes + " byte(s)"); + throw new EOFException( + "Can't skip " + skipByteNumber + " byte(s), skipped only " + skippedBytes + + " byte(s)"); } } } @@ -372,35 +456,52 @@ private List parseStruct(final JBBPBitInputStream inStream, f } break; case JBBPCompiler.CODE_BIT: { - final int numberOfBits = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); + final int numberOfBits = extraFieldNumAsExpr ? extraFieldNumExprResult : + JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); if (resultNotIgnored) { final JBBPBitNumber bitNumber = JBBPBitNumber.decode(numberOfBits); if (arrayLength < 0) { final int read = inStream.readBitField(bitNumber); singleAtomicField = new JBBPFieldBit(name, read & 0xFF, bitNumber); } else { - structureFields.add(new JBBPFieldArrayBit(name, inStream.readBitsArray(wholeStreamArray ? -1 : arrayLength, bitNumber), bitNumber)); + structureFields.add(new JBBPFieldArrayBit(name, + inStream.readBitsArray(wholeStreamArray ? -1 : arrayLength, bitNumber, + arraySizeLimiter), + bitNumber)); } } } break; case JBBPCompiler.CODE_VAR: { - final int extraField = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); + final int extraField = extraFieldNumAsExpr ? extraFieldNumExprResult : + JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); if (resultNotIgnored) { if (arrayLength < 0) { - singleAtomicField = varFieldProcessor.readVarField(inStream, name, extraField, byteOrder, namedNumericFieldMap); - JBBPUtils.assertNotNull(singleAtomicField, "A Var processor must not return null as a result of a field reading"); + singleAtomicField = varFieldProcessor + .readVarField(inStream, name, extraField, byteOrder, namedNumericFieldMap); + JBBPUtils.assertNotNull(singleAtomicField, + "A Var processor must not return null as a result of a field reading"); if (singleAtomicField instanceof JBBPAbstractArrayField) { - throw new JBBPParsingException("A Var field processor has returned an array value instead of a field value [" + name + ':' + extraField + ']'); + throw new JBBPParsingException( + "A Var field processor has returned an array value instead of a field value [" + + name + ':' + extraField + ']'); } if (singleAtomicField.getNameInfo() != name) { - throw new JBBPParsingException("Detected wrong name for a read field , must be " + name + " but detected " + singleAtomicField.getNameInfo() + ']'); + throw new JBBPParsingException( + "Detected wrong name for a read field , must be " + name + " but detected " + + singleAtomicField.getNameInfo() + ']'); } } else { - final JBBPAbstractArrayField array = varFieldProcessor.readVarArray(inStream, wholeStreamArray ? -1 : arrayLength, name, extraField, byteOrder, namedNumericFieldMap); - JBBPUtils.assertNotNull(array, "A Var processor must not return null as a result of an array field reading [" + name + ':' + extraField + ']'); + final JBBPAbstractArrayField array = varFieldProcessor + .readVarArray(inStream, wholeStreamArray ? -1 : arrayLength, name, extraField, + byteOrder, namedNumericFieldMap, arraySizeLimiter); + JBBPUtils.assertNotNull(array, + "A Var processor must not return null as a result of an array field reading [" + + name + ':' + extraField + ']'); if (array.getNameInfo() != name) { - throw new JBBPParsingException("Detected wrong name for a read field array, must be " + name + " but detected " + array.getNameInfo() + ']'); + throw new JBBPParsingException( + "Detected wrong name for a read field array, must be " + name + + " but detected " + array.getNameInfo() + ']'); } structureFields.add(array); } @@ -408,10 +509,15 @@ private List parseStruct(final JBBPBitInputStream inStream, f } break; case JBBPCompiler.CODE_CUSTOMTYPE: { - final int extraData = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); + final int extraData = extraFieldNumAsExpr ? extraFieldNumExprResult : + JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); if (resultNotIgnored) { - final JBBPFieldTypeParameterContainer fieldTypeInfo = this.compiledBlock.getCustomTypeFields()[JBBPUtils.unpackInt(compiled, positionAtCompiledBlock)]; - final JBBPAbstractField field = this.customFieldTypeProcessor.readCustomFieldType(inStream, this.bitOrder, this.flags, fieldTypeInfo, name, extraData, wholeStreamArray, arrayLength); + final JBBPFieldTypeParameterContainer fieldTypeInfo = + this.compiledBlock.getCustomTypeFields()[JBBPUtils + .unpackInt(compiled, positionAtCompiledBlock)]; + final JBBPAbstractField field = this.customFieldTypeProcessor + .readCustomFieldType(inStream, this.bitOrder, this.flags, fieldTypeInfo, name, + extraData, wholeStreamArray, arrayLength, arraySizeLimiter); JBBPUtils.assertNotNull(field, "Must not return null as read result"); if (arrayLength < 0) { @@ -425,9 +531,17 @@ private List parseStruct(final JBBPBitInputStream inStream, f case JBBPCompiler.CODE_BYTE: { if (resultNotIgnored) { if (arrayLength < 0) { - singleAtomicField = new JBBPFieldByte(name, (byte) inStream.readByte()); + singleAtomicField = fieldTypeDiff ? + new JBBPFieldUInt(name, inStream.readInt(byteOrder) & 0xFFFFFFFFL) : + new JBBPFieldByte(name, (byte) inStream.readByte()); } else { - structureFields.add(new JBBPFieldArrayByte(name, inStream.readByteArray(wholeStreamArray ? -1 : arrayLength, byteOrder))); + structureFields.add(fieldTypeDiff ? + new JBBPFieldArrayUInt(name, + inStream.readIntArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter)) : + new JBBPFieldArrayByte(name, + inStream.readByteArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter))); } } } @@ -437,7 +551,9 @@ private List parseStruct(final JBBPBitInputStream inStream, f if (arrayLength < 0) { singleAtomicField = new JBBPFieldUByte(name, (byte) inStream.readByte()); } else { - structureFields.add(new JBBPFieldArrayUByte(name, inStream.readByteArray(wholeStreamArray ? -1 : arrayLength, byteOrder))); + structureFields.add(new JBBPFieldArrayUByte(name, + inStream.readByteArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter))); } } } @@ -445,11 +561,17 @@ private List parseStruct(final JBBPBitInputStream inStream, f case JBBPCompiler.CODE_BOOL: { if (resultNotIgnored) { if (arrayLength < 0) { - singleAtomicField = fieldTypeDiff ? new JBBPFieldString(name, inStream.readString(byteOrder)) : new JBBPFieldBoolean(name, inStream.readBoolean()); + singleAtomicField = + fieldTypeDiff ? new JBBPFieldString(name, inStream.readString(byteOrder)) : + new JBBPFieldBoolean(name, inStream.readBoolean()); } else { structureFields.add(fieldTypeDiff ? - new JBBPFieldArrayString(name, inStream.readStringArray(wholeStreamArray ? -1 : arrayLength, byteOrder)) : - new JBBPFieldArrayBoolean(name, inStream.readBoolArray(wholeStreamArray ? -1 : arrayLength)) + new JBBPFieldArrayString(name, + inStream.readStringArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter)) : + new JBBPFieldArrayBoolean(name, + inStream.readBoolArray(wholeStreamArray ? -1 : arrayLength, + arraySizeLimiter)) ); } } @@ -458,11 +580,17 @@ private List parseStruct(final JBBPBitInputStream inStream, f case JBBPCompiler.CODE_INT: { if (resultNotIgnored) { if (arrayLength < 0) { - singleAtomicField = fieldTypeDiff ? new JBBPFieldFloat(name, inStream.readFloat(byteOrder)) : new JBBPFieldInt(name, inStream.readInt(byteOrder)); + singleAtomicField = + fieldTypeDiff ? new JBBPFieldFloat(name, inStream.readFloat(byteOrder)) : + new JBBPFieldInt(name, inStream.readInt(byteOrder)); } else { structureFields.add(fieldTypeDiff ? - new JBBPFieldArrayFloat(name, inStream.readFloatArray(wholeStreamArray ? -1 : arrayLength, byteOrder)) : - new JBBPFieldArrayInt(name, inStream.readIntArray(wholeStreamArray ? -1 : arrayLength, byteOrder)) + new JBBPFieldArrayFloat(name, + inStream.readFloatArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter)) : + new JBBPFieldArrayInt(name, + inStream.readIntArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter)) ); } } @@ -471,11 +599,17 @@ private List parseStruct(final JBBPBitInputStream inStream, f case JBBPCompiler.CODE_LONG: { if (resultNotIgnored) { if (arrayLength < 0) { - singleAtomicField = fieldTypeDiff ? new JBBPFieldDouble(name, inStream.readDouble(byteOrder)) : new JBBPFieldLong(name, inStream.readLong(byteOrder)); + singleAtomicField = + fieldTypeDiff ? new JBBPFieldDouble(name, inStream.readDouble(byteOrder)) : + new JBBPFieldLong(name, inStream.readLong(byteOrder)); } else { structureFields.add(fieldTypeDiff ? - new JBBPFieldArrayDouble(name, inStream.readDoubleArray(wholeStreamArray ? -1 : arrayLength, byteOrder)) : - new JBBPFieldArrayLong(name, inStream.readLongArray(wholeStreamArray ? -1 : arrayLength, byteOrder)) + new JBBPFieldArrayDouble(name, + inStream.readDoubleArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter)) : + new JBBPFieldArrayLong(name, + inStream.readLongArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter)) ); } } @@ -487,7 +621,9 @@ private List parseStruct(final JBBPBitInputStream inStream, f final int value = inStream.readUnsignedShort(byteOrder); singleAtomicField = new JBBPFieldShort(name, (short) value); } else { - structureFields.add(new JBBPFieldArrayShort(name, inStream.readShortArray(wholeStreamArray ? -1 : arrayLength, byteOrder))); + structureFields.add(new JBBPFieldArrayShort(name, + inStream.readShortArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter))); } } } @@ -498,18 +634,24 @@ private List parseStruct(final JBBPBitInputStream inStream, f final int value = inStream.readUnsignedShort(byteOrder); singleAtomicField = new JBBPFieldUShort(name, (short) value); } else { - structureFields.add(new JBBPFieldArrayUShort(name, inStream.readShortArray(wholeStreamArray ? -1 : arrayLength, byteOrder))); + structureFields.add(new JBBPFieldArrayUShort(name, + inStream.readShortArray(wholeStreamArray ? -1 : arrayLength, byteOrder, + arraySizeLimiter))); } } } break; case JBBPCompiler.CODE_STRUCT_START: { if (arrayLength < 0) { - final List structFields = parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, skipStructureFields); + final List structFields = + parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, + namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, + arraySizeLimiter, skipStructureFields); // skip offset JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); if (resultNotIgnored) { - structureFields.add(new JBBPFieldStruct(name, structFields.toArray(ARRAY_FIELD_EMPTY))); + structureFields + .add(new JBBPFieldStruct(name, structFields.toArray(ARRAY_FIELD_EMPTY))); } } else { final int nameFieldCurrent = positionAtNamedFieldList.get(); @@ -524,9 +666,18 @@ private List parseStruct(final JBBPBitInputStream inStream, f positionAtNamedFieldList.set(nameFieldCurrent); positionAtVarLengthProcessors.set(varLenProcCurrent); - final List fieldsForStruct = parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, skipStructureFields); + final List fieldsForStruct = + parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, + namedNumericFieldMap, positionAtNamedFieldList, + positionAtVarLengthProcessors, arraySizeLimiter, skipStructureFields); list.add(new JBBPFieldStruct(name, fieldsForStruct)); + if (JBBPArraySizeLimiter.isBreakReadWholeStream(list.size(), + arraySizeLimiter)) { + inStream.setDetectedArrayLimit(true); + break; + } + final int structStart = JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); if (inStream.hasAvailableData()) { @@ -540,14 +691,20 @@ private List parseStruct(final JBBPBitInputStream inStream, f if (arrayLength == 0) { // skip the structure result = EMPTY_STRUCT_ARRAY; - parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, true); + parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, + namedNumericFieldMap, positionAtNamedFieldList, + positionAtVarLengthProcessors, arraySizeLimiter, true); JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); } else { result = new JBBPFieldStruct[arrayLength]; for (int i = 0; i < arrayLength; i++) { - final List fieldsForStruct = parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, skipStructureFields); - final int structBodyStart = JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); + final List fieldsForStruct = + parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, + namedNumericFieldMap, positionAtNamedFieldList, + positionAtVarLengthProcessors, arraySizeLimiter, skipStructureFields); + final int structBodyStart = + JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); result[i] = new JBBPFieldStruct(name, fieldsForStruct); @@ -555,7 +712,8 @@ private List parseStruct(final JBBPBitInputStream inStream, f // not the last positionAtNamedFieldList.set(nameFieldCurrent); positionAtVarLengthProcessors.set(varLenProcCurrent); - positionAtCompiledBlock.set(structBodyStart + packedArraySizeOffset + (wideCode ? 2 : 1)); + positionAtCompiledBlock + .set(structBodyStart + packedArraySizeOffset + (wideCode ? 2 : 1)); } } } @@ -565,7 +723,9 @@ private List parseStruct(final JBBPBitInputStream inStream, f structureFields.add(new JBBPFieldArrayStruct(name, result)); } } else { - parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, skipStructureFields); + parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, + namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, + arraySizeLimiter, skipStructureFields); JBBPUtils.unpackInt(compiled, positionAtCompiledBlock); } } @@ -583,13 +743,15 @@ private List parseStruct(final JBBPBitInputStream inStream, f if (name == null) { throw ex; } else { - throw new JBBPParsingException("Can't parse field '" + name.getFieldPath() + "' for IOException", ex); + throw new JBBPParsingException( + "Can't parse field '" + name.getFieldPath() + "' for IOException", ex); } } if (singleAtomicField != null) { structureFields.add(singleAtomicField); - if (namedNumericFieldMap != null && singleAtomicField instanceof JBBPNumericField && name != null) { + if (namedNumericFieldMap != null && singleAtomicField instanceof JBBPNumericField && + name != null) { namedNumericFieldMap.putField((JBBPNumericField) singleAtomicField); } } @@ -622,8 +784,43 @@ public JBBPFieldStruct parse(final InputStream in) throws IOException { * @return the parsed content as the root structure * @throws IOException it will be thrown for transport errors */ - public JBBPFieldStruct parse(final InputStream in, final JBBPVarFieldProcessor varFieldProcessor, final JBBPExternalValueProvider externalValueProvider) throws IOException { - final JBBPBitInputStream bitInStream = in instanceof JBBPBitInputStream ? (JBBPBitInputStream) in : new JBBPBitInputStream(in, bitOrder); + public JBBPFieldStruct parse( + final InputStream in, + final JBBPVarFieldProcessor varFieldProcessor, + final JBBPExternalValueProvider externalValueProvider + ) throws IOException { + return this.parse( + in, + varFieldProcessor, + externalValueProvider, + NO_LIMIT_FOR_ARRAY_SIZE + ); + } + + /** + * Parse am input stream with defined external value provider. + * + * @param in an input stream which content will be parsed, it must not be null + * @param varFieldProcessor a var field processor, it may be null if there is + * not any var field in a script, otherwise NPE will be thrown during parsing + * @param externalValueProvider an external value provider, it can be null but + * only if the script doesn't have fields desired the provider + * @param arraySizeLimiter limiter to read whole stream arrays, must not be null + * @return the parsed content as the root structure + * @throws IOException it will be thrown for transport errors + * @throws JBBPReachedArraySizeLimitException thrown if reached limit for a whole stream array + * @see JBBPArraySizeLimiter#NO_LIMIT_FOR_ARRAY_SIZE + * @since 2.1.0 + */ + public JBBPFieldStruct parse( + final InputStream in, + final JBBPVarFieldProcessor varFieldProcessor, + final JBBPExternalValueProvider externalValueProvider, + final JBBPArraySizeLimiter arraySizeLimiter + ) throws IOException { + final JBBPBitInputStream bitInStream = + in instanceof JBBPBitInputStream ? (JBBPBitInputStream) in : + new JBBPBitInputStream(in, bitOrder); this.finalStreamByteCounter = bitInStream.getCounter(); final JBBPNamedNumericFieldMap fieldMap; @@ -634,10 +831,13 @@ public JBBPFieldStruct parse(final InputStream in, final JBBPVarFieldProcessor v } if (this.compiledBlock.hasVarFields()) { - JBBPUtils.assertNotNull(varFieldProcessor, "The Script contains VAR fields, a var field processor must be provided"); + JBBPUtils.assertNotNull(varFieldProcessor, + "The Script contains VAR fields, a var field processor must be provided"); } try { - return new JBBPFieldStruct(new JBBPNamedFieldInfo("", "", -1), parseStruct(bitInStream, new JBBPIntCounter(), varFieldProcessor, fieldMap, new JBBPIntCounter(), new JBBPIntCounter(), false)); + return new JBBPFieldStruct(new JBBPNamedFieldInfo("", "", -1), + parseStruct(bitInStream, new JBBPIntCounter(), varFieldProcessor, fieldMap, + new JBBPIntCounter(), new JBBPIntCounter(), arraySizeLimiter, false)); } finally { this.finalStreamByteCounter = bitInStream.getCounter(); } @@ -678,7 +878,9 @@ public JBBPFieldStruct parse(final byte[] array) throws IOException { * @return the parsed content as the root structure * @throws IOException it will be thrown for transport errors */ - public JBBPFieldStruct parse(final byte[] array, final JBBPVarFieldProcessor varFieldProcessor, final JBBPExternalValueProvider externalValueProvider) throws IOException { + public JBBPFieldStruct parse(final byte[] array, final JBBPVarFieldProcessor varFieldProcessor, + final JBBPExternalValueProvider externalValueProvider) + throws IOException { JBBPUtils.assertNotNull(array, "Array must not be null"); return this.parse(new ByteArrayInputStream(array), varFieldProcessor, externalValueProvider); } @@ -737,8 +939,11 @@ public List convertToSrc(final TargetSources target, final String className = name.substring(nameStart + 1); } - final String resultSources = JBBPToJavaConverter.makeBuilder(this).setMainClassPackage(packageName).setMainClassName(className).build().convert(); - final Map resultMap = Collections.singletonMap(name.replace('.', '/') + ".java", resultSources); + final String resultSources = + JBBPToJavaConverter.makeBuilder(this).setMainClassPackage(packageName) + .setMainClassName(className).build().convert(); + final Map resultMap = + Collections.singletonMap(name.replace('.', '/') + ".java", resultSources); return Collections.singletonList(new ResultSrcItem() { @Override diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParserExpressionArraySizeController.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParserExpressionArraySizeController.java new file mode 100644 index 00000000..9d56f5f9 --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParserExpressionArraySizeController.java @@ -0,0 +1,26 @@ +package com.igormaznitsa.jbbp; + +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.compiler.varlen.JBBPIntegerValueEvaluator; + +/** + * Controller to get value for every array field which size calculated by expression. + * + * @see JBBPParser#setExpressionArraySizeController(JBBPParserExpressionArraySizeController) + * @see JBBPParser#getExpressionArraySizeController() + * @since 2.1.0 + */ +@FunctionalInterface +public interface JBBPParserExpressionArraySizeController { + /** + * Called for every calculation of an array size by expression. + * + * @param parser source parser, must not be null + * @param expressionEvaluator expression evaluator used for calculation, must not be null + * @param fieldInfo target field info, must not be null + * @param calculatedArraySize calculated array size + * @return array size which can be same as provided size or changed + */ + int onCalculatedArraySize(JBBPParser parser, JBBPIntegerValueEvaluator expressionEvaluator, + JBBPNamedFieldInfo fieldInfo, int calculatedArraySize); +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPVarFieldProcessor.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPVarFieldProcessor.java index ec7aebf4..445ded67 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPVarFieldProcessor.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPVarFieldProcessor.java @@ -17,11 +17,12 @@ package com.igormaznitsa.jbbp; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.exceptions.JBBPReachedArraySizeLimitException; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPByteOrder; import com.igormaznitsa.jbbp.model.JBBPAbstractArrayField; import com.igormaznitsa.jbbp.model.JBBPAbstractField; - import java.io.IOException; /** @@ -39,10 +40,22 @@ public interface JBBPVarFieldProcessor { * @param extraValue the extra value for the field, by default it is 0, it is the integer value after ':' char in the field type * @param byteOrder the byte order for the field, it must not be null * @param numericFieldMap the numeric field map for the session, it must not be null, it can be used for access to already read values of another numeric fields. + * @param arraySizeLimiter limiter to check number of elements during whole stream array read, must not be null * @return a field array without nulls as values, it must not return null - * @throws IOException it can be thrown for transport errors or another process exceptions + * @throws IOException it can be thrown for transport errors or another process exceptions + * @throws JBBPReachedArraySizeLimitException thrown if reached limit for whole stream array + * @since 2.1.0 + * @see JBBPArraySizeLimiter#isBreakReadWholeStream(int, JBBPArraySizeLimiter) + * @see JBBPArraySizeLimiter#NO_LIMIT_FOR_ARRAY_SIZE */ - JBBPAbstractArrayField readVarArray(JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException; + JBBPAbstractArrayField readVarArray(JBBPBitInputStream inStream, + int arraySize, + JBBPNamedFieldInfo fieldName, + int extraValue, + JBBPByteOrder byteOrder, + JBBPNamedNumericFieldMap numericFieldMap, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException; /** * Read a field from a stream. The Method must read a field from a stream and return it with the provided name field info. @@ -59,5 +72,7 @@ public interface JBBPVarFieldProcessor { * @return a read field object, it must not return null * @throws IOException it should be thrown for transport errors */ - JBBPAbstractField readVarField(JBBPBitInputStream inStream, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException; + JBBPAbstractField readVarField(JBBPBitInputStream inStream, JBBPNamedFieldInfo fieldName, + int extraValue, JBBPByteOrder byteOrder, + JBBPNamedNumericFieldMap numericFieldMap) throws IOException; } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompiledBlock.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompiledBlock.java index 7a92cdd7..7a9aab5c 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompiledBlock.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompiledBlock.java @@ -21,7 +21,6 @@ import com.igormaznitsa.jbbp.exceptions.JBBPException; import com.igormaznitsa.jbbp.exceptions.JBBPIllegalArgumentException; import com.igormaznitsa.jbbp.utils.JBBPUtils; - import java.util.ArrayList; import java.util.List; @@ -34,8 +33,10 @@ public final class JBBPCompiledBlock { private static final JBBPNamedFieldInfo[] ARRAY_FIELDINFO_EMPTY = new JBBPNamedFieldInfo[0]; - private static final JBBPIntegerValueEvaluator[] ARRAY_INTEVALUATOR_EMPTY = new JBBPIntegerValueEvaluator[0]; - private static final JBBPFieldTypeParameterContainer[] ARRAY_FIELDTYPE_EMPTY = new JBBPFieldTypeParameterContainer[0]; + private static final JBBPIntegerValueEvaluator[] ARRAY_INTEVALUATOR_EMPTY = + new JBBPIntegerValueEvaluator[0]; + private static final JBBPFieldTypeParameterContainer[] ARRAY_FIELDTYPE_EMPTY = + new JBBPFieldTypeParameterContainer[0]; /** * The Array of named field info items. @@ -74,7 +75,10 @@ public final class JBBPCompiledBlock { * @param compiledData compiled data block * @param hasVarFields the flag shows that te block contains var fields */ - private JBBPCompiledBlock(final String source, final JBBPNamedFieldInfo[] namedFields, final JBBPIntegerValueEvaluator[] arraySizeEvaluators, final byte[] compiledData, final boolean hasVarFields, final JBBPFieldTypeParameterContainer[] customTypeFields) { + private JBBPCompiledBlock(final String source, final JBBPNamedFieldInfo[] namedFields, + final JBBPIntegerValueEvaluator[] arraySizeEvaluators, + final byte[] compiledData, final boolean hasVarFields, + final JBBPFieldTypeParameterContainer[] customTypeFields) { this.source = source; this.namedFieldData = namedFields; this.hasVarFields = hasVarFields; @@ -215,7 +219,10 @@ public JBBPCompiledBlock build() { JBBPUtils.assertNotNull(source, "Source is not defined"); JBBPUtils.assertNotNull(compiledData, "Compiled data is not defined"); - return new JBBPCompiledBlock(this.source, this.namedFields.toArray(ARRAY_FIELDINFO_EMPTY), this.varLenProcessors.isEmpty() ? null : this.varLenProcessors.toArray(ARRAY_INTEVALUATOR_EMPTY), this.compiledData, this.hasVarFields, this.customTypeFields.toArray(ARRAY_FIELDTYPE_EMPTY)); + return new JBBPCompiledBlock(this.source, this.namedFields.toArray(ARRAY_FIELDINFO_EMPTY), + this.varLenProcessors.isEmpty() ? null : + this.varLenProcessors.toArray(ARRAY_INTEVALUATOR_EMPTY), this.compiledData, + this.hasVarFields, this.customTypeFields.toArray(ARRAY_FIELDTYPE_EMPTY)); } /** diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompiler.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompiler.java index 8c0891d0..94979261 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompiler.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompiler.java @@ -28,8 +28,8 @@ import com.igormaznitsa.jbbp.model.JBBPFieldDouble; import com.igormaznitsa.jbbp.model.JBBPFieldFloat; import com.igormaznitsa.jbbp.model.JBBPFieldString; +import com.igormaznitsa.jbbp.model.JBBPFieldUInt; import com.igormaznitsa.jbbp.utils.JBBPUtils; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -114,12 +114,12 @@ public final class JBBPCompiler { */ public static final int FLAG_NAMED = 0x10; /** - * The Byte-Code Flag shows that the field is an array but it must be omitted + * The Byte-Code Flag shows that the field is an array, but it must be omitted * for unlimited field arrays. */ public static final int FLAG_ARRAY = 0x20; /** - * The Byte-Code Flag shows that a multi-byte field must be decoded as + * The Byte-Code Flag shows that a multibyte field must be decoded as * Little-endian one. */ public static final int FLAG_LITTLE_ENDIAN = 0x40; @@ -157,7 +157,8 @@ public static JBBPCompiledBlock compile(final String script) throws IOException private static void assertTokenNotArray(final String fieldType, final JBBPToken token) { if (token.getArraySizeAsString() != null) { final String fieldName = token.getFieldName() == null ? "" : token.getFieldName(); - throw new JBBPCompilationException('\'' + fieldType + "' can't be array (" + fieldName + ')', token); + throw new JBBPCompilationException('\'' + fieldType + "' can't be array (" + fieldName + ')', + token); } } @@ -169,19 +170,14 @@ private static void assertTokenNamed(final String fieldType, final JBBPToken tok private static void assertTokenNotNamed(final String fieldType, final JBBPToken token) { if (token.getFieldName() != null) { - throw new JBBPCompilationException('\'' + fieldType + "' must not be named (" + token.getFieldName() + ')', token); + throw new JBBPCompilationException( + '\'' + fieldType + "' must not be named (" + token.getFieldName() + ')', token); } } private static void assertTokenHasExtraData(final String fieldType, final JBBPToken token) { if (token.getFieldTypeParameters().getExtraData() == null) { - throw new JBBPCompilationException('\'' + fieldType + "\' doesn't have extra value", token); - } - } - - private static void assertTokenDoesntHaveExtraData(final String fieldType, final JBBPToken token) { - if (token.getFieldTypeParameters().getExtraData() != null) { - throw new JBBPCompilationException('\'' + fieldType + "\' has extra value", token); + throw new JBBPCompilationException('\'' + fieldType + "' doesn't have extra value", token); } } @@ -196,7 +192,9 @@ private static void assertTokenDoesntHaveExtraData(final String fieldType, final * @throws JBBPException it will be thrown for any logical or work exception * for the parser and compiler */ - public static JBBPCompiledBlock compile(final String script, final JBBPCustomFieldTypeProcessor customTypeFieldProcessor) throws IOException { + public static JBBPCompiledBlock compile(final String script, + final JBBPCustomFieldTypeProcessor customTypeFieldProcessor) + throws IOException { JBBPUtils.assertNotNull(script, "Script must not be null"); final JBBPCompiledBlock.Builder builder = JBBPCompiledBlock.prepare().setSource(script); @@ -238,7 +236,8 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie int extraFieldNumberAsInt = -1; int customTypeFieldIndex = -1; - final boolean extraFieldNumericDataAsExpression = ((code >>> 8) & EXT_FLAG_EXTRA_AS_EXPRESSION) != 0; + final boolean extraFieldNumericDataAsExpression = + ((code >>> 8) & EXT_FLAG_EXTRA_AS_EXPRESSION) != 0; final boolean fieldTypeDiff = ((code >>> 8) & EXT_FLAG_EXTRA_DIFF_TYPE) != 0; switch (code & 0xF) { @@ -252,7 +251,9 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie case CODE_LONG: { if ((code & 0x0F) == CODE_CUSTOMTYPE) { if (extraFieldNumericDataAsExpression) { - varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance().make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, out.toByteArray())); + varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance() + .make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, + out.toByteArray())); } else { final String extraDataAsStr = token.getFieldTypeParameters().getExtraData(); if (extraDataAsStr == null) { @@ -261,12 +262,15 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie try { extraFieldNumberAsInt = Integer.parseInt(extraDataAsStr); } catch (NumberFormatException ex) { - throw new JBBPCompilationException("Can't parse extra data, must be numeric", token); + throw new JBBPCompilationException("Can't parse extra data, must be numeric", + token); } } writeExtraFieldNumberInCompiled = true; } - if (customTypeFieldProcessor.isAllowed(token.getFieldTypeParameters(), token.getFieldName(), extraFieldNumberAsInt, token.isArray())) { + if (customTypeFieldProcessor + .isAllowed(token.getFieldTypeParameters(), token.getFieldName(), + extraFieldNumberAsInt, token.isArray())) { customTypeFieldIndex = customTypeFields.size(); customTypeFields.add(token.getFieldTypeParameters()); } else { @@ -285,7 +289,9 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie assertTokenNotNamed("skip", token); } if (extraFieldNumericDataAsExpression) { - varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance().make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, out.toByteArray())); + varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance() + .make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, + out.toByteArray())); } else { final String extraNumberAsStr = token.getFieldTypeParameters().getExtraData(); writeExtraFieldNumberInCompiled = true; @@ -309,7 +315,9 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie assertTokenNotNamed("align", token); if (extraFieldNumericDataAsExpression) { - varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance().make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, out.toByteArray())); + varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance() + .make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, + out.toByteArray())); } else { final String extraNumberAsStr = token.getFieldTypeParameters().getExtraData(); writeExtraFieldNumberInCompiled = true; @@ -323,7 +331,8 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie extraFieldNumberAsInt = -1; } if (extraFieldNumberAsInt <= 0) { - throw new JBBPCompilationException("'align' size must be greater than zero [" + token.getFieldTypeParameters().getExtraData() + ']', token); + throw new JBBPCompilationException("'align' size must be greater than zero [" + + token.getFieldTypeParameters().getExtraData() + ']', token); } } } @@ -331,7 +340,9 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie break; case CODE_BIT: { if (extraFieldNumericDataAsExpression) { - varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance().make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, out.toByteArray())); + varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance() + .make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, + out.toByteArray())); } else { final String extraFieldNumAsStr = token.getFieldTypeParameters().getExtraData(); writeExtraFieldNumberInCompiled = true; @@ -345,7 +356,9 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie extraFieldNumberAsInt = -1; } if (extraFieldNumberAsInt < 1 || extraFieldNumberAsInt > 8) { - throw new JBBPCompilationException("Bit-width must be 1..8 [" + token.getFieldTypeParameters().getExtraData() + ']', token); + throw new JBBPCompilationException( + "Bit-width must be 1..8 [" + token.getFieldTypeParameters().getExtraData() + + ']', token); } } } @@ -354,7 +367,9 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie case CODE_VAR: { hasVarFields = true; if (extraFieldNumericDataAsExpression) { - varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance().make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, out.toByteArray())); + varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance() + .make(token.getFieldTypeParameters().getExtraDataExpression(), namedFields, + out.toByteArray())); } else { final String extraFieldNumStr = token.getFieldTypeParameters().getExtraData(); writeExtraFieldNumberInCompiled = true; @@ -364,7 +379,9 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie try { extraFieldNumberAsInt = Integer.parseInt(extraFieldNumStr); } catch (NumberFormatException ex) { - throw new JBBPCompilationException("Can't parse the extra value of a VAR field, must be integer [" + token.getFieldTypeParameters().getExtraData() + ']', token); + throw new JBBPCompilationException( + "Can't parse the extra value of a VAR field, must be integer [" + + token.getFieldTypeParameters().getExtraData() + ']', token); } } } @@ -373,22 +390,30 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie case CODE_RESET_COUNTER: { assertTokenNotArray("Reset counter", token); assertTokenNotNamed("Reset counter", token); - assertTokenDoesntHaveExtraData("Reset counter", token); + assertTokenHasNotExtraData("Reset counter", token); } break; case CODE_STRUCT_START: { - final boolean arrayReadTillEnd = (code & FLAG_ARRAY) != 0 && (extraCode & EXT_FLAG_EXPRESSION_OR_WHOLESTREAM) != 0 && "_".equals(token.getArraySizeAsString()); - structureStack.add(new StructStackItem(namedFields.size() + ((code & JBBPCompiler.FLAG_NAMED) == 0 ? 0 : 1), startFieldOffset, arrayReadTillEnd, code, token)); + final boolean arrayReadTillEnd = + (code & FLAG_ARRAY) != 0 && (extraCode & EXT_FLAG_EXPRESSION_OR_WHOLESTREAM) != 0 && + "_".equals(token.getArraySizeAsString()); + structureStack.add(new StructStackItem( + namedFields.size() + ((code & JBBPCompiler.FLAG_NAMED) == 0 ? 0 : 1), + startFieldOffset, arrayReadTillEnd, code, token)); } break; case CODE_STRUCT_END: { if (structureStack.isEmpty()) { - throw new JBBPCompilationException("Detected structure close tag without opening one", token); + throw new JBBPCompilationException("Detected structure close tag without opening one", + token); } else { if (fieldUnrestrictedArrayOffset >= 0) { final StructStackItem startOfStruct = structureStack.get(structureStack.size() - 1); - if (startOfStruct.arrayToReadTillEndOfStream && fieldUnrestrictedArrayOffset != startOfStruct.startStructureOffset) { - throw new JBBPCompilationException("Detected unlimited array of structures but there is already presented one", token); + if (startOfStruct.arrayToReadTillEndOfStream && + fieldUnrestrictedArrayOffset != startOfStruct.startStructureOffset) { + throw new JBBPCompilationException( + "Detected unlimited array of structures but there is already presented one", + token); } } @@ -398,28 +423,33 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie } break; default: - throw new Error("Detected unsupported compiled code, notify the developer please [" + code + ']'); + throw new Error( + "Detected unsupported compiled code, notify the developer please [" + code + ']'); } if ((code & FLAG_ARRAY) == 0) { - if (structureStack.isEmpty() && (code & 0x0F) != CODE_STRUCT_END && fieldUnrestrictedArrayOffset >= 0) { - throw new JBBPCompilationException("Detected field defined after unlimited array", token); + if (structureStack.isEmpty() && (code & 0x0F) != CODE_STRUCT_END && + fieldUnrestrictedArrayOffset >= 0) { + throw new JBBPCompilationException("Detected field defined after unlimited array", token); } } else { if ((extraCode & EXT_FLAG_EXPRESSION_OR_WHOLESTREAM) != 0) { if ("_".equals(token.getArraySizeAsString())) { if (fieldUnrestrictedArrayOffset >= 0) { - throw new JBBPCompilationException("Detected two or more unlimited arrays [" + script + ']', token); + throw new JBBPCompilationException( + "Detected two or more unlimited arrays [" + script + ']', token); } else { fieldUnrestrictedArrayOffset = startFieldOffset; } } else { - varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance().make(token.getArraySizeAsString(), namedFields, out.toByteArray())); + varLengthEvaluators.add(JBBPEvaluatorFactory.getInstance() + .make(token.getArraySizeAsString(), namedFields, out.toByteArray())); } } else { final int fixedArraySize = token.getArraySizeAsInt(); if (fixedArraySize <= 0) { - throw new JBBPCompilationException("Detected an array with negative or zero fixed length", token); + throw new JBBPCompilationException( + "Detected an array with negative or zero fixed length", token); } offset += writePackedInt(out, fixedArraySize); } @@ -436,31 +466,37 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie if ((code & FLAG_NAMED) != 0) { final String normalizedName = JBBPUtils.normalizeFieldNameOrPath(token.getFieldName()); assertName(normalizedName, token); - registerNamedField(normalizedName, structureStack.isEmpty() ? 0 : structureStack.get(structureStack.size() - 1).namedFieldCounter, startFieldOffset, namedFields, token); + registerNamedField(normalizedName, structureStack.isEmpty() ? 0 : + structureStack.get(structureStack.size() - 1).namedFieldCounter, startFieldOffset, + namedFields, token); } else { if (currentClosedStructure != null && (currentClosedStructure.code & FLAG_NAMED) != 0) { // it is structure, process field names - final String normalizedName = JBBPUtils.normalizeFieldNameOrPath(currentClosedStructure.token.getFieldName()); + final String normalizedName = + JBBPUtils.normalizeFieldNameOrPath(currentClosedStructure.token.getFieldName()); for (int i = namedFields.size() - 1; i >= 0; i--) { final JBBPNamedFieldInfo f = namedFields.get(i); if (f.getFieldOffsetInCompiledBlock() <= currentClosedStructure.startStructureOffset) { break; } final String newFullName = normalizedName + '.' + f.getFieldPath(); - namedFields.set(i, new JBBPNamedFieldInfo(newFullName, f.getFieldName(), f.getFieldOffsetInCompiledBlock())); + namedFields.set(i, new JBBPNamedFieldInfo(newFullName, f.getFieldName(), + f.getFieldOffsetInCompiledBlock())); } } } } if (!structureStack.isEmpty()) { - throw new JBBPCompilationException("Detected non-closed " + structureStack.size() + " structure(s)"); + throw new JBBPCompilationException( + "Detected non-closed " + structureStack.size() + " structure(s)"); } final byte[] compiledBlock = out.toByteArray(); if (fieldUnrestrictedArrayOffset >= 0) { - compiledBlock[fieldUnrestrictedArrayOffset] = (byte) (compiledBlock[fieldUnrestrictedArrayOffset] & ~FLAG_ARRAY); + compiledBlock[fieldUnrestrictedArrayOffset] = + (byte) (compiledBlock[fieldUnrestrictedArrayOffset] & ~FLAG_ARRAY); } return builder @@ -472,6 +508,13 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie .build(); } + private static void assertTokenHasNotExtraData(final String fieldType, + final JBBPToken token) { + if (token.getFieldTypeParameters().getExtraData() != null) { + throw new JBBPCompilationException('\'' + fieldType + "' has extra value", token); + } + } + /** * The Method checks a value for negative. * @@ -481,7 +524,9 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie */ private static void assertNonNegativeValue(final int value, final JBBPToken token) { if (value < 0) { - throw new JBBPCompilationException("Detected unsupported negative value for a field must have only zero or a positive one", token); + throw new JBBPCompilationException( + "Detected unsupported negative value for a field must have only zero or a positive one", + token); } } @@ -494,7 +539,8 @@ private static void assertNonNegativeValue(final int value, final JBBPToken toke */ private static void assertName(final String name, final JBBPToken token) { if (name.indexOf('.') >= 0) { - throw new JBBPCompilationException("Detected disallowed char '.' in name [" + name + ']', token); + throw new JBBPCompilationException("Detected disallowed char '.' in name [" + name + ']', + token); } } @@ -508,11 +554,15 @@ private static void assertName(final String name, final JBBPToken token) { * @throws JBBPCompilationException if there is already a registered field for * the path */ - private static void registerNamedField(final String normalizedName, final int structureBorder, final int offset, final List namedFields, final JBBPToken token) { + private static void registerNamedField(final String normalizedName, final int structureBorder, + final int offset, + final List namedFields, + final JBBPToken token) { for (int i = namedFields.size() - 1; i >= structureBorder; i--) { final JBBPNamedFieldInfo info = namedFields.get(i); if (info.getFieldPath().equals(normalizedName)) { - throw new JBBPCompilationException("Duplicated named field detected [" + normalizedName + ']', token); + throw new JBBPCompilationException( + "Duplicated named field detected [" + normalizedName + ']', token); } } namedFields.add(new JBBPNamedFieldInfo(normalizedName, normalizedName, offset)); @@ -540,7 +590,8 @@ private static int writePackedInt(final OutputStream out, final int value) throw * it can be null * @return the prepared byte code for the token */ - private static int prepareCodeForToken(final JBBPToken token, final JBBPCustomFieldTypeProcessor customTypeFieldProcessor) { + private static int prepareCodeForToken(final JBBPToken token, + final JBBPCustomFieldTypeProcessor customTypeFieldProcessor) { int result = -1; switch (token.getType()) { case ATOM: { @@ -550,9 +601,11 @@ private static int prepareCodeForToken(final JBBPToken token, final JBBPCustomFi final boolean hasExpressionAsExtraNumber = descriptor.hasExpressionAsExtraData(); - result |= token.getArraySizeAsString() == null ? 0 : (token.isVarArrayLength() ? FLAG_ARRAY | FLAG_WIDE | (EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8) : FLAG_ARRAY); + result |= token.getArraySizeAsString() == null ? 0 : (token.isVarArrayLength() ? + FLAG_ARRAY | FLAG_WIDE | (EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8) : FLAG_ARRAY); result |= hasExpressionAsExtraNumber ? FLAG_WIDE | (EXT_FLAG_EXTRA_AS_EXPRESSION << 8) : 0; - result |= token.getFieldTypeParameters().isSpecialField() ? FLAG_WIDE | (EXT_FLAG_EXTRA_DIFF_TYPE << 8) : 0; + result |= token.getFieldTypeParameters().isSpecialField() ? + FLAG_WIDE | (EXT_FLAG_EXTRA_DIFF_TYPE << 8) : 0; result |= token.getFieldName() == null ? 0 : FLAG_NAMED; final String name = descriptor.getTypeName().toLowerCase(Locale.ENGLISH); @@ -578,6 +631,7 @@ private static int prepareCodeForToken(final JBBPToken token, final JBBPCustomFi result |= CODE_UBYTE; break; case "byte": + case JBBPFieldUInt.TYPE_NAME: result |= CODE_BYTE; break; case "ushort": @@ -609,7 +663,8 @@ private static int prepareCodeForToken(final JBBPToken token, final JBBPCustomFi } } if (unsupportedType) { - throw new JBBPCompilationException("Unsupported type [" + descriptor.getTypeName() + ']', token); + throw new JBBPCompilationException( + "Unsupported type [" + descriptor.getTypeName() + ']', token); } break; } @@ -620,7 +675,8 @@ private static int prepareCodeForToken(final JBBPToken token, final JBBPCustomFi } break; case STRUCT_START: { - result = token.getArraySizeAsString() == null ? 0 : (token.isVarArrayLength() ? FLAG_ARRAY | FLAG_WIDE | (EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8) : FLAG_ARRAY); + result = token.getArraySizeAsString() == null ? 0 : (token.isVarArrayLength() ? + FLAG_ARRAY | FLAG_WIDE | (EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8) : FLAG_ARRAY); result |= token.getFieldName() == null ? 0 : FLAG_NAMED; result |= CODE_STRUCT_START; } @@ -659,7 +715,7 @@ private static final class StructStackItem { private final int namedFieldCounter; /** - * Flag shows that the structure is array which shoukd be read till end of stream + * Flag shows that the structure is array which should be read till end of stream */ private final boolean arrayToReadTillEndOfStream; @@ -670,11 +726,13 @@ private static final class StructStackItem { * start * @param startStructureOffset the offset of the start structure byte-code * instruction - * @param arrayToReadTillEnd if true then it is array to read till end + * @param arrayToReadTillEnd if true then it is an array to read till end * @param code the start byte code * @param token the token */ - private StructStackItem(final int namedFieldCounter, final int startStructureOffset, final boolean arrayToReadTillEnd, final int code, final JBBPToken token) { + private StructStackItem(final int namedFieldCounter, final int startStructureOffset, + final boolean arrayToReadTillEnd, final int code, + final JBBPToken token) { this.namedFieldCounter = namedFieldCounter; this.arrayToReadTillEndOfStream = arrayToReadTillEnd; this.startStructureOffset = startStructureOffset; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompilerUtils.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompilerUtils.java index 6194a67e..5bfe4be5 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompilerUtils.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPCompilerUtils.java @@ -16,13 +16,12 @@ package com.igormaznitsa.jbbp.compiler; +import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.FLAG_ARRAY; + import com.igormaznitsa.jbbp.exceptions.JBBPCompilationException; import com.igormaznitsa.jbbp.utils.JBBPUtils; - import java.util.List; -import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.FLAG_ARRAY; - /** * Class contains specific common auxiliary methods for parser and compiler classes. * @@ -39,7 +38,8 @@ private JBBPCompilerUtils() { * @param namedFields a list contains named field info items. * @return the index of a field for the path if found one, -1 otherwise */ - public static int findIndexForFieldPath(final String fieldPath, final List namedFields) { + public static int findIndexForFieldPath(final String fieldPath, + final List namedFields) { final String normalized = JBBPUtils.normalizeFieldNameOrPath(fieldPath); int result = -1; for (int i = namedFields.size() - 1; i >= 0; i--) { @@ -59,7 +59,8 @@ public static int findIndexForFieldPath(final String fieldPath, final List namedFields) { + public static JBBPNamedFieldInfo findForFieldPath(final String fieldPath, + final List namedFields) { final String normalized = JBBPUtils.normalizeFieldNameOrPath(fieldPath); JBBPNamedFieldInfo result = null; for (int i = namedFields.size() - 1; i >= 0; i--) { @@ -73,30 +74,36 @@ public static JBBPNamedFieldInfo findForFieldPath(final String fieldPath, final } /** - * Check a field in a compiled list defined by its named field info, that the field is not an array and it is not inside a structure array. + * Check a field in a compiled list defined by it's named field info, that the field is not an array and it is not inside a structure array. * * @param fieldToCheck a named field info to be checked, must not be null * @param namedFieldList a named field info list, must not be null. * @param compiledScript a compiled script body */ - public static void assertFieldIsNotArrayOrInArray(final JBBPNamedFieldInfo fieldToCheck, final List namedFieldList, final byte[] compiledScript) { + public static void assertFieldIsNotArrayOrInArray(final JBBPNamedFieldInfo fieldToCheck, + final List namedFieldList, + final byte[] compiledScript) { // check that the field is not array if ((compiledScript[fieldToCheck.getFieldOffsetInCompiledBlock()] & FLAG_ARRAY) != 0) { - throw new JBBPCompilationException("An Array field can't be used as array size [" + fieldToCheck.getFieldPath() + ']'); + throw new JBBPCompilationException( + "An Array field can't be used as array size [" + fieldToCheck.getFieldPath() + ']'); } if (fieldToCheck.getFieldPath().indexOf('.') >= 0) { // the field in structure, check that the structure is not an array or not in an array - final String[] splittedFieldPath = JBBPUtils.splitString(fieldToCheck.getFieldPath(), '.'); + final String[] splitFieldPath = JBBPUtils.splitString(fieldToCheck.getFieldPath(), '.'); final StringBuilder fieldPath = new StringBuilder(); // process till the field name because we have already checked the field - for (int i = 0; i < splittedFieldPath.length - 1; i++) { + for (int i = 0; i < splitFieldPath.length - 1; i++) { if (fieldPath.length() != 0) { fieldPath.append('.'); } - fieldPath.append(splittedFieldPath[i]); - final JBBPNamedFieldInfo structureEnd = JBBPCompilerUtils.findForFieldPath(fieldPath.toString(), namedFieldList); + fieldPath.append(splitFieldPath[i]); + final JBBPNamedFieldInfo structureEnd = + JBBPCompilerUtils.findForFieldPath(fieldPath.toString(), namedFieldList); if ((compiledScript[structureEnd.getFieldOffsetInCompiledBlock()] & FLAG_ARRAY) != 0) { - throw new JBBPCompilationException("Field from structure array can't be use as array size [" + fieldToCheck.getFieldPath() + ';' + structureEnd.getFieldPath() + ']'); + throw new JBBPCompilationException( + "Field from structure array can't be use as array size [" + + fieldToCheck.getFieldPath() + ';' + structureEnd.getFieldPath() + ']'); } } } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPNamedFieldInfo.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPNamedFieldInfo.java index 4b1d4bed..59bb84f8 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPNamedFieldInfo.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/JBBPNamedFieldInfo.java @@ -17,12 +17,11 @@ package com.igormaznitsa.jbbp.compiler; import com.igormaznitsa.jbbp.utils.JBBPUtils; - import java.io.Serializable; /** * The Class describes a named field info item. Such objects are presented - * inside of compiled blocks only for fields which have names. + * inside compiled blocks only for fields which have names. * * @since 1.0 */ @@ -49,7 +48,8 @@ public final class JBBPNamedFieldInfo implements Serializable { * @param fieldName the field name * @param offsetInCompiledBlock the offset in the compiled block for the field */ - public JBBPNamedFieldInfo(final String fieldPath, final String fieldName, final int offsetInCompiledBlock) { + public JBBPNamedFieldInfo(final String fieldPath, final String fieldName, + final int offsetInCompiledBlock) { this.fieldPath = JBBPUtils.normalizeFieldNameOrPath(fieldPath); this.fieldName = JBBPUtils.normalizeFieldNameOrPath(fieldName); this.offsetInCompiledBlock = offsetInCompiledBlock; @@ -95,7 +95,8 @@ public boolean equals(final Object obj) { if (obj instanceof JBBPNamedFieldInfo) { final JBBPNamedFieldInfo that = (JBBPNamedFieldInfo) obj; - result = this.fieldPath.equals(that.fieldPath) && this.offsetInCompiledBlock == that.offsetInCompiledBlock; + result = this.fieldPath.equals(that.fieldPath) && + this.offsetInCompiledBlock == that.offsetInCompiledBlock; } return result; } @@ -107,7 +108,8 @@ public int hashCode() { @Override public String toString() { - return this.getClass().getSimpleName() + "[fieldPath=" + this.fieldPath + ", fieldName=" + this.fieldName + ", offsetInCompiledBlock=" + this.offsetInCompiledBlock + ']'; + return this.getClass().getSimpleName() + "[fieldPath=" + this.fieldPath + ", fieldName=" + + this.fieldName + ", offsetInCompiledBlock=" + this.offsetInCompiledBlock + ']'; } } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/CompiledBlockVisitor.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/CompiledBlockVisitor.java index c3734bf1..5ab3512b 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/CompiledBlockVisitor.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/CompiledBlockVisitor.java @@ -88,12 +88,16 @@ public final CompiledBlockVisitor visit() { final boolean extraFieldNumAsExpr = (ec & JBBPCompiler.EXT_FLAG_EXTRA_AS_EXPRESSION) != 0; final int code = (ec << 8) | c; - final JBBPNamedFieldInfo name = (code & JBBPCompiler.FLAG_NAMED) == 0 ? null : this.compiledBlock.getNamedFields()[positionAtNamedFieldList++]; - final JBBPByteOrder byteOrder = (code & JBBPCompiler.FLAG_LITTLE_ENDIAN) == 0 ? JBBPByteOrder.BIG_ENDIAN : JBBPByteOrder.LITTLE_ENDIAN; + final JBBPNamedFieldInfo name = (code & JBBPCompiler.FLAG_NAMED) == 0 ? null : + this.compiledBlock.getNamedFields()[positionAtNamedFieldList++]; + final JBBPByteOrder byteOrder = + (code & JBBPCompiler.FLAG_LITTLE_ENDIAN) == 0 ? JBBPByteOrder.BIG_ENDIAN : + JBBPByteOrder.LITTLE_ENDIAN; final JBBPIntegerValueEvaluator extraFieldValueEvaluator; if (extraFieldNumAsExpr) { - extraFieldValueEvaluator = this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors++]; + extraFieldValueEvaluator = + this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors++]; } else { extraFieldValueEvaluator = null; } @@ -102,9 +106,11 @@ public final CompiledBlockVisitor visit() { boolean readWholeStream = false; - switch (code & (JBBPCompiler.FLAG_ARRAY | (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8))) { + switch (code & + (JBBPCompiler.FLAG_ARRAY | (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8))) { case JBBPCompiler.FLAG_ARRAY: { - arraySizeEvaluator = new IntConstValueEvaluator(JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); + arraySizeEvaluator = new IntConstValueEvaluator( + JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); } break; case (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8): { @@ -113,7 +119,8 @@ public final CompiledBlockVisitor visit() { } break; case JBBPCompiler.FLAG_ARRAY | (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8): { - arraySizeEvaluator = this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors++]; + arraySizeEvaluator = + this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors++]; } break; default: { @@ -132,7 +139,9 @@ public final CompiledBlockVisitor visit() { break; case JBBPCompiler.CODE_SKIP: case JBBPCompiler.CODE_ALIGN: { - final JBBPIntegerValueEvaluator evaluator = extraFieldNumAsExpr ? extraFieldValueEvaluator : new IntConstValueEvaluator(JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); + final JBBPIntegerValueEvaluator evaluator = + extraFieldNumAsExpr ? extraFieldValueEvaluator : new IntConstValueEvaluator( + JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); if (altFileType) { if (theCode == JBBPCompiler.CODE_SKIP) { visitValField(theOffset, byteOrder, name, evaluator); @@ -146,8 +155,11 @@ public final CompiledBlockVisitor visit() { break; case JBBPCompiler.CODE_BIT: { - final JBBPIntegerValueEvaluator numberOfBits = extraFieldNumAsExpr ? extraFieldValueEvaluator : new IntConstValueEvaluator(JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); - visitBitField(theOffset, byteOrder, name, numberOfBits, arraySizeEvaluator); + final JBBPIntegerValueEvaluator numberOfBits = + extraFieldNumAsExpr ? extraFieldValueEvaluator : new IntConstValueEvaluator( + JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); + visitBitField(theOffset, byteOrder, name, readWholeStream, numberOfBits, + arraySizeEvaluator); } break; @@ -158,12 +170,13 @@ public final CompiledBlockVisitor visit() { case JBBPCompiler.CODE_USHORT: case JBBPCompiler.CODE_INT: case JBBPCompiler.CODE_LONG: { - visitPrimitiveField(theOffset, theCode, name, byteOrder, readWholeStream, altFileType, arraySizeEvaluator); + visitPrimitiveField(theOffset, theCode, name, byteOrder, readWholeStream, altFileType, + arraySizeEvaluator); } break; case JBBPCompiler.CODE_STRUCT_START: { - visitStructureStart(theOffset, byteOrder, name, arraySizeEvaluator); + visitStructureStart(theOffset, byteOrder, readWholeStream, name, arraySizeEvaluator); } break; @@ -174,15 +187,23 @@ public final CompiledBlockVisitor visit() { break; case JBBPCompiler.CODE_VAR: { - final JBBPIntegerValueEvaluator extraDataValueEvaluator = extraFieldNumAsExpr ? extraFieldValueEvaluator : new IntConstValueEvaluator(JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); - visitVarField(theOffset, name, byteOrder, readWholeStream, arraySizeEvaluator, extraDataValueEvaluator); + final JBBPIntegerValueEvaluator extraDataValueEvaluator = + extraFieldNumAsExpr ? extraFieldValueEvaluator : new IntConstValueEvaluator( + JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); + visitVarField(theOffset, name, byteOrder, readWholeStream, arraySizeEvaluator, + extraDataValueEvaluator); } break; case JBBPCompiler.CODE_CUSTOMTYPE: { - final JBBPIntegerValueEvaluator extraDataValueEvaluator = extraFieldNumAsExpr ? extraFieldValueEvaluator : new IntConstValueEvaluator(JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); - final JBBPFieldTypeParameterContainer fieldTypeInfo = this.compiledBlock.getCustomTypeFields()[JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)]; - visitCustomField(theOffset, fieldTypeInfo, name, byteOrder, readWholeStream, arraySizeEvaluator, extraDataValueEvaluator); + final JBBPIntegerValueEvaluator extraDataValueEvaluator = + extraFieldNumAsExpr ? extraFieldValueEvaluator : new IntConstValueEvaluator( + JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); + final JBBPFieldTypeParameterContainer fieldTypeInfo = + this.compiledBlock.getCustomTypeFields()[JBBPUtils + .unpackInt(compiledData, positionAtCompiledBlock)]; + visitCustomField(theOffset, fieldTypeInfo, name, byteOrder, readWholeStream, + arraySizeEvaluator, extraDataValueEvaluator); } break; default: @@ -205,19 +226,23 @@ public final CompiledBlockVisitor visit() { * @see JBBPCompiler#CODE_ALIGN * @see JBBPCompiler#CODE_SKIP */ - public void visitActionItem(int offsetInCompiledBlock, int actionType, JBBPIntegerValueEvaluator nullableArgument) { + public void visitActionItem(int offsetInCompiledBlock, int actionType, + JBBPIntegerValueEvaluator nullableArgument) { } /** - * Visit field contains virtual field with VAL type. + * Visit field contains virtual field defined through VAL type. * * @param offsetInCompiledBlock offset in the compiled block - * @param byteOrder byteOrder + * @param byteOrder byteOrder * @param nameFieldInfo name of the field, must not be null * @param expression expression to calculate value * @since 1.4.0 */ - public void visitValField(int offsetInCompiledBlock, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nameFieldInfo, JBBPIntegerValueEvaluator expression) { + public void visitValField(int offsetInCompiledBlock, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nameFieldInfo, + JBBPIntegerValueEvaluator expression) { } /** @@ -227,7 +252,7 @@ public void visitValField(int offsetInCompiledBlock, JBBPByteOrder byteOrder, JB * @param primitiveType the primitive type * @param nullableNameFieldInfo field info, null if the field is anonymous one * @param byteOrder byte order for the field, must not be null - * @param readWholeStreamAsArray if true then it is array with unknown size till the stream end + * @param readWholeStreamAsArray if true then it is an array with unknown size till the stream end * @param altFieldType flag shows that field type is alternative one, INT should be recognized as FLOAT and LONG as DOUBLE and BOOL as STRING * @param nullableArraySize array size if the field is array, null if the field is not array or variable length array * @see JBBPCompiler#CODE_BYTE @@ -239,37 +264,106 @@ public void visitValField(int offsetInCompiledBlock, JBBPByteOrder byteOrder, JB * @see JBBPCompiler#CODE_LONG * @see JBBPCompiler#CODE_SKIP */ - public void visitPrimitiveField(int offsetInCompiledBlock, int primitiveType, JBBPNamedFieldInfo nullableNameFieldInfo, JBBPByteOrder byteOrder, boolean readWholeStreamAsArray, boolean altFieldType, JBBPIntegerValueEvaluator nullableArraySize) { + public void visitPrimitiveField(int offsetInCompiledBlock, + int primitiveType, + JBBPNamedFieldInfo nullableNameFieldInfo, + JBBPByteOrder byteOrder, + boolean readWholeStreamAsArray, + boolean altFieldType, + JBBPIntegerValueEvaluator nullableArraySize) { } /** * Visit a variable field (which is defined with var data type) * - * @param offsetInCompiledBlock offset in the compiled block - * @param nullableNameFieldInfo field info, null if the field is anonymous one - * @param byteOrder byte order for the field, must not be null - * @param readWholeStreamIntoArray true if whole stream should be read as array of var type, false otherwise - * @param nullableArraySize if not null then evaluator of array size to be read from stream - * @param extraDataValueEvaluator if not null then extra data evaluator for the var field + * @param offsetInCompiledBlock offset in the compiled block + * @param nullableNameFieldInfo field info, null if the field is anonymous one + * @param byteOrder byte order for the field, must not be null + * @param readWholeStream true if whole stream should be read as array of var type, false otherwise + * @param nullableArraySize if not null then evaluator of array size to be read from stream + * @param extraDataValue if not null then extra data evaluator for the var field */ - public void visitVarField(int offsetInCompiledBlock, JBBPNamedFieldInfo nullableNameFieldInfo, JBBPByteOrder byteOrder, boolean readWholeStreamIntoArray, JBBPIntegerValueEvaluator nullableArraySize, JBBPIntegerValueEvaluator extraDataValueEvaluator) { + public void visitVarField(int offsetInCompiledBlock, + JBBPNamedFieldInfo nullableNameFieldInfo, + JBBPByteOrder byteOrder, + boolean readWholeStream, + JBBPIntegerValueEvaluator nullableArraySize, + JBBPIntegerValueEvaluator extraDataValue) { } - public void visitCustomField(int offsetInCompiledBlock, JBBPFieldTypeParameterContainer notNullFieldType, JBBPNamedFieldInfo nullableNameFieldInfo, JBBPByteOrder byteOrder, boolean readWholeStream, JBBPIntegerValueEvaluator nullableArraySizeEvaluator, JBBPIntegerValueEvaluator extraDataValueEvaluator) { + /** + * Visit a custom type field. + * + * @param offsetInCompiledBlock offset in the compiled block + * @param notNullFieldType field type info, must not be null + * @param nullableNameFieldInfo field info, null if the field is anonymous one + * @param byteOrder byte order for the field, must not be null + * @param readWholeStream true if whole stream should be read as array of var type, false otherwise + * @param nullableArraySize if not null then evaluator of array size to be read from stream + * @param extraDataValue if not null then extra data evaluator for the var field + */ + public void visitCustomField(int offsetInCompiledBlock, + JBBPFieldTypeParameterContainer notNullFieldType, + JBBPNamedFieldInfo nullableNameFieldInfo, + JBBPByteOrder byteOrder, + boolean readWholeStream, + JBBPIntegerValueEvaluator nullableArraySize, + JBBPIntegerValueEvaluator extraDataValue) { } - public void visitBitField(int offsetInCompiledBlock, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNameFieldInfo, JBBPIntegerValueEvaluator notNullFieldSize, JBBPIntegerValueEvaluator nullableArraySize) { + /** + * Visit a custom type field. + * + * @param offsetInCompiledBlock offset in the compiled block + * @param byteOrder byte order for the field, must not be null + * @param nullableNameFieldInfo field info, null if the field is anonymous one + * @param readWholeStream true if whole stream should be read as array of var type, false otherwise + * @param notNullFieldSize evaluator to calculate size of the field, must not be null + * @param nullableArraySize if not null then evaluator of array size to be read from stream + */ + public void visitBitField(int offsetInCompiledBlock, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNameFieldInfo, + boolean readWholeStream, + JBBPIntegerValueEvaluator notNullFieldSize, + JBBPIntegerValueEvaluator nullableArraySize) { } - public void visitStructureStart(int offsetInCompiledBlock, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNameFieldInfo, JBBPIntegerValueEvaluator nullableArraySize) { + /** + * Visit a structure field. + * + * @param offsetInCompiledBlock offset in the compiled block + * @param byteOrder byte order for the field, must not be null + * @param readWholeStream true if whole stream should be read as array of var type, false otherwise + * @param nullableNameFieldInfo field info, null if the field is anonymous one + * @param nullableArraySize if not null then evaluator of array size to be read from stream + */ + public void visitStructureStart(int offsetInCompiledBlock, + JBBPByteOrder byteOrder, + boolean readWholeStream, + JBBPNamedFieldInfo nullableNameFieldInfo, + JBBPIntegerValueEvaluator nullableArraySize) { } - public void visitStructureEnd(int offsetInCompiledBlock, JBBPNamedFieldInfo nullableNameFieldInfo) { + /** + * End visit of a structure + * + * @param offsetInCompiledBlock offset in the compiled block + * @param nullableNameFieldInfo field info, null if the field is anonymous one + */ + public void visitStructureEnd(int offsetInCompiledBlock, + JBBPNamedFieldInfo nullableNameFieldInfo) { } + /** + * Called before visit of each item. + */ public void visitStart() { } + /** + * Called after visit each item. + */ public void visitEnd() { } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/ExpressionEvaluatorVisitor.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/ExpressionEvaluatorVisitor.java index 8d7059e0..365bee08 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/ExpressionEvaluatorVisitor.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/ExpressionEvaluatorVisitor.java @@ -47,7 +47,8 @@ public interface ExpressionEvaluatorVisitor { * @param nullableExternalFieldName name of external field, it will be null for regular field * @return the visitor instance, must not be null */ - ExpressionEvaluatorVisitor visitField(JBBPNamedFieldInfo nullableNameFieldInfo, String nullableExternalFieldName); + ExpressionEvaluatorVisitor visitField(JBBPNamedFieldInfo nullableNameFieldInfo, + String nullableExternalFieldName); /** * Visit operator diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/IntConstValueEvaluator.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/IntConstValueEvaluator.java index 36c3868f..2a140524 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/IntConstValueEvaluator.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/IntConstValueEvaluator.java @@ -26,7 +26,7 @@ * * @since 1.3.0 */ -final class IntConstValueEvaluator implements JBBPIntegerValueEvaluator { +public final class IntConstValueEvaluator implements JBBPIntegerValueEvaluator { private static final long serialVersionUID = 4640385518512384490L; @@ -40,12 +40,20 @@ final class IntConstValueEvaluator implements JBBPIntegerValueEvaluator { } @Override - public int eval(final JBBPBitInputStream inStream, final int currentCompiledBlockOffset, final JBBPCompiledBlock block, final JBBPNamedNumericFieldMap fieldMap) { + public int eval(final JBBPBitInputStream inStream, + final int currentCompiledBlockOffset, + final JBBPCompiledBlock block, + final JBBPNamedNumericFieldMap fieldMap + ) { return this.value; } @Override - public void visitItems(JBBPCompiledBlock block, int currentCompiledBlockOffset, ExpressionEvaluatorVisitor visitor) { + public void visitItems( + JBBPCompiledBlock block, + int currentCompiledBlockOffset, + ExpressionEvaluatorVisitor visitor + ) { visitor.visitStart(); visitor.visitConstant(this.value); visitor.visitEnd(); diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverter.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverter.java index 51a96c6f..7b7cb043 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverter.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverter.java @@ -27,7 +27,6 @@ import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_UBYTE; import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_USHORT; - import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; @@ -56,7 +55,7 @@ * @since 1.3.0 */ @SuppressWarnings("SpellCheckingInspection") -public final class JBBPToJavaConverter extends CompiledBlockVisitor { +public class JBBPToJavaConverter extends CompiledBlockVisitor { private static final int FLAG_DETECTED_CUSTOM_FIELDS = 1; private static final int FLAG_DETECTED_EXTERNAL_FIELDS = 2; @@ -64,68 +63,6 @@ public final class JBBPToJavaConverter extends CompiledBlockVisitor { private static final int FLAG_ADD_ASSERT_NOT_NEGATIVE_EXPR = 8; private static final Set RESERVED_JAVA_KEYWORDS; - - static { - final Set reserved = new HashSet<>(); - - reserved.add("abstract"); - reserved.add("assert"); - reserved.add("boolean"); - reserved.add("break"); - reserved.add("byte"); - reserved.add("case"); - reserved.add("catch"); - reserved.add("char"); - reserved.add("class"); - reserved.add("continue"); - reserved.add("default"); - reserved.add("do"); - reserved.add("double"); - reserved.add("else"); - reserved.add("enum"); - reserved.add("extends"); - reserved.add("final"); - reserved.add("finally"); - reserved.add("float"); - reserved.add("for"); - reserved.add("if"); - reserved.add("implements"); - reserved.add("import"); - reserved.add("instanceof"); - reserved.add("int"); - reserved.add("interface"); - reserved.add("long"); - reserved.add("native"); - reserved.add("new"); - reserved.add("package"); - reserved.add("private"); - reserved.add("protected"); - reserved.add("public"); - reserved.add("return"); - reserved.add("short"); - reserved.add("static"); - reserved.add("strictfp"); - reserved.add("super"); - reserved.add("switch"); - reserved.add("synchronized"); - reserved.add("this"); - reserved.add("throw"); - reserved.add("throws"); - reserved.add("transient"); - reserved.add("try"); - reserved.add("void"); - reserved.add("volatile"); - reserved.add("while"); - reserved.add("true"); - reserved.add("null"); - reserved.add("false"); - reserved.add("var"); - reserved.add("const"); - reserved.add("goto"); - - RESERVED_JAVA_KEYWORDS = Collections.unmodifiableSet(reserved); - } - /** * Name of the field to be used as link to the root structure instance in * child structures. @@ -143,6 +80,19 @@ public final class JBBPToJavaConverter extends CompiledBlockVisitor { * Name of the output stream argument. */ private static final String NAME_OUTPUT_STREAM = "Out"; + + static { + + RESERVED_JAVA_KEYWORDS = + Set.of("abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", + "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", + "float", "for", "if", "implements", "import", "instanceof", "int", "interface", "long", + "native", "new", "package", "private", "protected", "public", "return", "short", + "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", + "transient", "try", "void", "volatile", "while", "true", "null", "false", "var", + "const", "goto"); + } + /** * Detected flags. */ @@ -218,7 +168,8 @@ private void registerNamedField(final JBBPNamedFieldInfo fieldInfo, final FieldT if (this.foundNamedFields.containsKey(fieldInfo)) { throw new Error("Detected duplication of named field : " + fieldInfo); } - this.foundNamedFields.put(fieldInfo, new NamedFieldInfo(fieldInfo, this.getCurrentStruct(), fieldType)); + this.foundNamedFields + .put(fieldInfo, new NamedFieldInfo(fieldInfo, this.getCurrentStruct(), fieldType)); } } @@ -258,7 +209,7 @@ public void visitEnd() { buffer.printCommentMultiLinesWithIndent(this.builder.headComment); } - if (this.builder.mainClassPackage != null && this.builder.mainClassPackage.length() != 0) { + if (this.builder.mainClassPackage != null && !this.builder.mainClassPackage.isEmpty()) { buffer.print("package ").print(this.builder.mainClassPackage).println(";"); } @@ -279,61 +230,82 @@ public void visitEnd() { buffer.println(); this.specialSection.println(); - this.specialSection.printJavaDocLinesWithIndent("The Constant contains parser flags\n@see JBBPParser#FLAG_SKIP_REMAINING_FIELDS_IF_EOF\n@see JBBPParser#FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO"); - this.specialSection.indent().printf("protected static final int %s = %d;", NAME_PARSER_FLAGS, this.parserFlags); + this.specialSection.printJavaDocLinesWithIndent( + "The Constant contains parser flags\n@see JBBPParser#FLAG_SKIP_REMAINING_FIELDS_IF_EOF\n@see JBBPParser#FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO"); + this.specialSection.indent() + .printf("protected static final int %s = %d;", NAME_PARSER_FLAGS, this.parserFlags); final int detected = this.flagSet.get(); if ((detected & FLAG_DETECTED_CUSTOM_FIELDS) != 0) { - this.specialMethods.printJavaDocLinesWithIndent("Reading of custom fields\n@param sourceStruct source structure holding the field, must not be null\n@param inStream the input stream, must not be null\n@param typeParameterContainer info about field type, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, default value 0\n@param readWholeStream flag to read the stream as array till the stream end if true\n@param arraySize if array then it is zero or great\n@exception IOException if data can't be read\n@return read value as abstract field, must not be null"); - this.specialMethods.println("public abstract JBBPAbstractField readCustomFieldType(Object sourceStruct, JBBPBitInputStream inStream, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException;"); + this.specialMethods.printJavaDocLinesWithIndent( + "Reading of custom fields\n@param sourceStruct source structure holding the field, must not be null\n@param inStream the input stream, must not be null\n@param typeParameterContainer info about field type, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, default value 0\n@param readWholeStream flag to read the stream as array till the stream end if true\n@param arraySize if array then it is zero or great\n@exception IOException if data can't be read\n@return read value as abstract field, must not be null"); + this.specialMethods.println( + "public abstract JBBPAbstractField readCustomFieldType(Object sourceStruct, JBBPBitInputStream inStream, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException;"); this.specialMethods.println(); - this.specialMethods.printJavaDocLinesWithIndent("Writing custom fields\n@param sourceStruct source structure holding the field, must not be null\n@param outStream the output stream, must not be null\n@param fieldValue value to be written\n@param typeParameterContainer info about field type, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, default value is 0\n@param wholeArray true if to write whole array\n@param arraySize if array then it is zero or great\n@exception IOException if data can't be written"); - this.specialMethods.println("public abstract void writeCustomFieldType(Object sourceStruct, JBBPBitOutputStream outStream, JBBPAbstractField fieldValue, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean wholeArray, int arraySize) throws IOException;"); + this.specialMethods.printJavaDocLinesWithIndent( + "Writing custom fields\n@param sourceStruct source structure holding the field, must not be null\n@param outStream the output stream, must not be null\n@param fieldValue value to be written\n@param typeParameterContainer info about field type, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, default value is 0\n@param wholeArray true if to write whole array\n@param arraySize if array then it is zero or great\n@exception IOException if data can't be written"); + this.specialMethods.println( + "public abstract void writeCustomFieldType(Object sourceStruct, JBBPBitOutputStream outStream, JBBPAbstractField fieldValue, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean wholeArray, int arraySize) throws IOException;"); } if ((detected & FLAG_DETECTED_EXTERNAL_FIELDS) != 0) { if (!this.specialMethods.isEmpty()) { this.specialMethods.println(); } - this.specialMethods.printJavaDocLinesWithIndent("Method is called from expressions to provide value\n@param sourceStruct source structure holding the field, must not be null\n@param valueName name of value to be provided, must not be null\n@return integer value for the named parameter"); - this.specialMethods.println("public abstract int getNamedValue(Object sourceStruct, String valueName);"); + this.specialMethods.printJavaDocLinesWithIndent( + "Method is called from expressions to provide value\n@param sourceStruct source structure holding the field, must not be null\n@param valueName name of value to be provided, must not be null\n@return integer value for the named parameter"); + this.specialMethods + .println("public abstract int getNamedValue(Object sourceStruct, String valueName);"); } if ((detected & FLAG_DETECTED_VAR_FIELDS) != 0) { if (!this.specialMethods.isEmpty()) { this.specialMethods.println(); } - this.specialMethods.printJavaDocLinesWithIndent("Read variable field\n@param sourceStruct source structure holding the field, must not be null\n@param inStream the input stream, must not be null\n@param byteOrder\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, -1 if not defined\n@return\n@exception IOException"); - this.specialMethods.println("public abstract JBBPAbstractField readVarField(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException;"); + this.specialMethods.printJavaDocLinesWithIndent( + "Read variable field\n@param sourceStruct source structure holding the field, must not be null\n@param inStream the input stream, must not be null\n@param byteOrder\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, -1 if not defined\n@return\n@exception IOException"); + this.specialMethods.println( + "public abstract JBBPAbstractField readVarField(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException;"); this.specialMethods.println(); - this.specialMethods.printJavaDocLinesWithIndent("Read variable array field\n@param sourceStruct source structure holding the field, must not be null\n@param inStream the input stream, must not be null\n@param byteOrder byte order to be used for reading, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, -1 if not defined\n@param readWholeStream if true then whole stream should be read\n@param arraySize size of array to read (if whole stream flag is false)\n@return array object contains read data, must not be null\n@exception IOException if error during data reading"); - this.specialMethods.println("public abstract JBBPAbstractArrayField readVarArray(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException;"); + this.specialMethods.printJavaDocLinesWithIndent( + "Read variable array field\n@param sourceStruct source structure holding the field, must not be null\n@param inStream the input stream, must not be null\n@param byteOrder byte order to be used for reading, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, -1 if not defined\n@param readWholeStream if true then whole stream should be read\n@param arraySize size of array to read (if whole stream flag is false)\n@return array object contains read data, must not be null\n@exception IOException if error during data reading"); + this.specialMethods.println( + "public abstract JBBPAbstractArrayField readVarArray(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException;"); this.specialMethods.println(); - this.specialMethods.printJavaDocLinesWithIndent("Read variable field\n@param sourceStruct source structure holding the field, must not be null\n@param value field value, must not be null\n@param outStream the output stream, must not be null,\n@param byteOrder byte order to be used for reading, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, -1 if not defined\n@exception IOException it is thrown if any transport error during operation"); - this.specialMethods.println("public abstract void writeVarField(Object sourceStruct, JBBPAbstractField value, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException;"); + this.specialMethods.printJavaDocLinesWithIndent( + "Read variable field\n@param sourceStruct source structure holding the field, must not be null\n@param value field value, must not be null\n@param outStream the output stream, must not be null,\n@param byteOrder byte order to be used for reading, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, -1 if not defined\n@exception IOException it is thrown if any transport error during operation"); + this.specialMethods.println( + "public abstract void writeVarField(Object sourceStruct, JBBPAbstractField value, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException;"); this.specialMethods.println(); - this.specialMethods.printJavaDocLinesWithIndent("Write variable array\n@param sourceStruct source structure holding the field, must not be null\n@param array array value to be written, must not be null\n@param outStream the output stream, must not be null\n@param byteOrder byte order to be used for reading, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, -1 if not defined\n@param arraySizeToWrite\n@exception IOException it is thrown if any transport error during operation"); - this.specialMethods.println("public abstract void writeVarArray(Object sourceStruct, JBBPAbstractArrayField array, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, int arraySizeToWrite) throws IOException;"); + this.specialMethods.printJavaDocLinesWithIndent( + "Write variable array\n@param sourceStruct source structure holding the field, must not be null\n@param array array value to be written, must not be null\n@param outStream the output stream, must not be null\n@param byteOrder byte order to be used for reading, must not be null\n@param nullableNamedFieldInfo info abut field name, it can be null\n@param extraValue value from extra field part, -1 if not defined\n@param arraySizeToWrite\n@exception IOException it is thrown if any transport error during operation"); + this.specialMethods.println( + "public abstract void writeVarArray(Object sourceStruct, JBBPAbstractArrayField array, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, int arraySizeToWrite) throws IOException;"); } if ((detected & FLAG_ADD_ASSERT_NOT_NEGATIVE_EXPR) != 0) { if (!this.specialMethods.isEmpty()) { this.specialMethods.println(); } - this.specialMethods.println("private static int assrtExprNotNeg(final int value) { if (value<0) throw new IllegalArgumentException(\"Negative value in expression\"); return value; }"); + this.specialMethods.println( + "private static int assrtExprNotNeg(final int value) { if (value<0) throw new IllegalArgumentException(\"Negative value in expression\"); return value; }"); } final String specialMethodsText = this.specialMethods.toString(); - final boolean hasAbstractMethods = (this.flagSet.get() & (FLAG_DETECTED_CUSTOM_FIELDS | FLAG_DETECTED_VAR_FIELDS | FLAG_DETECTED_EXTERNAL_FIELDS)) != 0 || this.builder.doMainClassAbstract; + final boolean hasAbstractMethods = (this.flagSet.get() & + (FLAG_DETECTED_CUSTOM_FIELDS | FLAG_DETECTED_VAR_FIELDS | FLAG_DETECTED_EXTERNAL_FIELDS)) != + 0 || this.builder.doMainClassAbstract; - buffer.printJavaDocLinesWithIndent("Generated from JBBP script by internal JBBP Class Source Generator"); + buffer.printJavaDocLinesWithIndent( + "Generated from JBBP script by internal JBBP Class Source Generator"); final Struct rootStruct = this.structStack.get(0); if (this.builder.addNewInstanceMethods) { - rootStruct.misc.println(String.format("public Object %s(Class aClass) {", JBBPMapper.MAKE_CLASS_INSTANCE_METHOD_NAME)); + rootStruct.misc.println(String.format("public Object %s(Class aClass) {", + JBBPMapper.MAKE_CLASS_INSTANCE_METHOD_NAME)); rootStruct.misc.incIndent(); for (final Struct c : rootStruct.children) { @@ -356,7 +328,7 @@ public void visitEnd() { this.builder.mapSubClassesInterfaces, this.builder.mapSubClassesSuperclasses, this.specialSection.toString(), - specialMethodsText.length() == 0 ? null : specialMethodsText, + specialMethodsText.isEmpty() ? null : specialMethodsText, this.builder.mainClassCustomText, true ); @@ -365,12 +337,22 @@ public void visitEnd() { } @Override - public void visitStructureStart(final int offsetInCompiledBlock, final JBBPByteOrder byteOrder, final JBBPNamedFieldInfo nullableNameFieldInfo, final JBBPIntegerValueEvaluator nullableArraySize) { - final String structName = (nullableNameFieldInfo == null ? makeAnonymousStructName() : prepFldName(nullableNameFieldInfo.getFieldName())).toLowerCase(Locale.ENGLISH); + public void visitStructureStart(final int offsetInCompiledBlock, + final JBBPByteOrder byteOrder, + final boolean readWholeStream, + final JBBPNamedFieldInfo nullableNameFieldInfo, + final JBBPIntegerValueEvaluator nullableArraySize) { + final String structName = (nullableNameFieldInfo == null ? makeAnonymousStructName() : + prepFldName(nullableNameFieldInfo.getFieldName())).toLowerCase(Locale.ENGLISH); final String structBaseTypeName = structName.toUpperCase(Locale.ENGLISH); - final String arraySizeIn = nullableArraySize == null ? null : evaluatorToString(NAME_INPUT_STREAM, offsetInCompiledBlock, nullableArraySize, this.flagSet, true); - final String arraySizeOut = nullableArraySize == null ? null : evaluatorToString(NAME_OUTPUT_STREAM, offsetInCompiledBlock, nullableArraySize, this.flagSet, true); - final Struct newStruct = new Struct(this.getCurrentStruct(), structBaseTypeName, "public" + (builder.internalClassesNotStatic ? "" : " static")); + final String arraySizeIn = nullableArraySize == null ? null : + evaluatorToString(NAME_INPUT_STREAM, offsetInCompiledBlock, nullableArraySize, this.flagSet, + true); + final String arraySizeOut = nullableArraySize == null ? null : + evaluatorToString(NAME_OUTPUT_STREAM, offsetInCompiledBlock, nullableArraySize, + this.flagSet, true); + final Struct newStruct = new Struct(this.getCurrentStruct(), structBaseTypeName, + "public" + (builder.internalClassesNotStatic ? "" : " static")); final String fieldModifier = makeModifier(nullableNameFieldInfo); @@ -388,43 +370,60 @@ public void visitStructureStart(final int offsetInCompiledBlock, final JBBPByteO if (nullableArraySize == null) { structType = structBaseTypeName; if (this.builder.generateFields) { - printField(nullableNameFieldInfo, byteOrder, false, offsetInCompiledBlock, getCurrentStruct().getFields().indent(), null, fieldModifier, structType, structName); + printField(nullableNameFieldInfo, byteOrder, false, offsetInCompiledBlock, + getCurrentStruct().getFields().indent(), null, fieldModifier, structType, structName); } processSkipRemainingFlag(); processSkipRemainingFlagForWriting("this." + structName); this.getCurrentStruct().getReadFunc().indent() - .printf("if ( this.%1$s == null) { this.%1$s = new %2$s(%3$s);}", structName, structType, pathToRootObject) - .printf(" %s.read(%s);%n", toType.length() == 0 ? "this." + structName : '(' + toType + "this." + structName + ')', NAME_INPUT_STREAM); - this.getCurrentStruct().getWriteFunc().indent().print(toType.length() == 0 ? structName : '(' + toType + structName + ')').println(".write(Out);"); + .printf("if ( this.%1$s == null) { this.%1$s = new %2$s(%3$s);}", structName, structType, + pathToRootObject) + .printf(" %s.read(%s);%n", toType.isEmpty() ? "this." + structName : + '(' + toType + "this." + structName + ')', NAME_INPUT_STREAM); + this.getCurrentStruct().getWriteFunc().indent() + .print(toType.isEmpty() ? structName : '(' + toType + structName + ')') + .println(".write(Out);"); } else { structType = structBaseTypeName + " []"; if (this.builder.generateFields) { - printField(nullableNameFieldInfo, byteOrder, true, offsetInCompiledBlock, getCurrentStruct().getFields().indent(), null, fieldModifier, structType, structName); + printField(nullableNameFieldInfo, byteOrder, true, offsetInCompiledBlock, + getCurrentStruct().getFields().indent(), null, fieldModifier, structType, structName); } processSkipRemainingFlag(); processSkipRemainingFlagForWriting("this." + structName); - if ("-1".equals(arraySizeIn)) { + if (readWholeStream) { this.getCurrentStruct().getReadFunc().indent() - .printf("List<%3$s> __%1$s_tmplst__ = new ArrayList<%3$s>(); while (%5$s.hasAvailableData()){ __%1$s_tmplst__.add(new %3$s(%4$s).read(%5$s));} this.%1$s = __%1$s_tmplst__.toArray(new %3$s[__%1$s_tmplst__.size()]);__%1$s_tmplst__ = null;%n", + .printf( + "List<%3$s> __%1$s_tmplst__ = new ArrayList<%3$s>(); while (%5$s.hasAvailableData()){ __%1$s_tmplst__.add(new %3$s(%4$s).read(%5$s));} this.%1$s = __%1$s_tmplst__.toArray(new %3$s[__%1$s_tmplst__.size()]);__%1$s_tmplst__ = null;%n", structName, arraySizeIn, structBaseTypeName, pathToRootObject, NAME_INPUT_STREAM); - this.getCurrentStruct().getWriteFunc().indent().printf("for (int I=0;I mapClassName * @return the builder instance, must not be null * @since 1.4.0 */ - public Builder setMapSubClassesSuperclasses(final Map mapClassNameToSuperclasses) { + public Builder setMapSubClassesSuperclasses( + final Map mapClassNameToSuperclasses) { assertNonLocked(); this.mapSubClassesSuperclasses.clear(); if (mapClassNameToSuperclasses != null) { @@ -1529,7 +1689,7 @@ public Builder setHeadComment(final String text) { /** * Disable generate fields, useful if some super class extended and its * fields should be used instead of generated ones. If disable then all code - * will be generated but without class fields. By default field generate is + * will be generated but without class fields. By default, field generate is * enabled. * * @return the builder instance, must not be null @@ -1541,7 +1701,7 @@ public Builder disableGenerateFields() { } /** - * Build converter with provided parameters. NB! It locks builder parameters + * Build converter with provided parameters. NB! It locks builder parameters, * and they can't be changed in future. * * @return a converter instance. @@ -1569,7 +1729,8 @@ private static class Struct { private final String path; private Struct(final Struct parent, final String className, final String classModifiers) { - this.path = parent == null ? "" : parent.path + (parent.path.length() == 0 ? "" : ".") + className.toLowerCase(Locale.ENGLISH); + this.path = parent == null ? "" : parent.path + (parent.path.isEmpty() ? "" : ".") + + className.toLowerCase(Locale.ENGLISH); this.classModifiers = classModifiers; this.className = className; this.parent = parent; @@ -1615,7 +1776,8 @@ void write( final String specialMethods, final String customText, final boolean useSuperclassForReadWrite) { - final String interfaceForGetSet = mapStructInterfaces == null ? null : mapStructInterfaces.get(this.getPath()); + final String interfaceForGetSet = + mapStructInterfaces == null ? null : mapStructInterfaces.get(this.getPath()); buffer.indent().printf( "%s%sclass %s%s%s {%n", @@ -1623,7 +1785,10 @@ void write( extraModifier == null ? " " : ' ' + extraModifier + ' ', this.className, superClass != null ? " extends " + superClass + ' ' : "", - interfaceForGetSet == null ? implementedInterfaces != null && !implementedInterfaces.isEmpty() ? " implements " + interfaces2str(implementedInterfaces) + ' ' : "" : " implements " + interfaceForGetSet + interfaceForGetSet == null ? + implementedInterfaces != null && !implementedInterfaces.isEmpty() ? + " implements " + interfaces2str(implementedInterfaces) + ' ' : "" : + " implements " + interfaceForGetSet ); buffer.incIndent(); @@ -1632,13 +1797,15 @@ void write( } for (final Struct c : this.children) { - c.write(buffer, null, mapStructSuperclasses.get(c.getPath()), null, mapStructInterfaces, mapStructSuperclasses, null, null, null, false); + c.write(buffer, null, mapStructSuperclasses.get(c.getPath()), null, mapStructInterfaces, + mapStructSuperclasses, null, null, null, false); } buffer.println(); buffer.printLinesWithIndent(this.fields.toString()); if (this.parent != null) { - buffer.indent().println("private final " + findRoot().className + ' ' + NAME_ROOT_STRUCT + ';'); + buffer.indent() + .println("private final " + findRoot().className + ' ' + NAME_ROOT_STRUCT + ';'); } buffer.println(); @@ -1656,7 +1823,8 @@ void write( buffer.println(); - buffer.indent().printf("public %s read(final JBBPBitInputStream In) throws IOException {%n", useSuperclassForReadWrite && superClass != null ? superClass : this.className); + buffer.indent().printf("public %s read(final JBBPBitInputStream In) throws IOException {%n", + useSuperclassForReadWrite && superClass != null ? superClass : this.className); buffer.incIndent(); buffer.printLinesWithIndent(this.readFunc.toString()); buffer.indent().println("return this;"); @@ -1665,7 +1833,9 @@ void write( buffer.println(); - buffer.indent().printf("public %s write(final JBBPBitOutputStream Out) throws IOException {%n", useSuperclassForReadWrite && superClass != null ? superClass : this.className); + buffer.indent() + .printf("public %s write(final JBBPBitOutputStream Out) throws IOException {%n", + useSuperclassForReadWrite && superClass != null ? superClass : this.className); buffer.incIndent(); buffer.printLinesWithIndent(this.writeFunc.toString()); buffer.indent().println("return this;"); @@ -1690,7 +1860,7 @@ void write( buffer.println(); } - if (customText != null && customText.length() != 0) { + if (customText != null && !customText.isEmpty()) { buffer.printCommentLinesWithIndent("------ Custom section START"); buffer.printLinesWithIndent(customText); buffer.printCommentLinesWithIndent("------ Custom section END"); diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPFieldTypeParameterContainer.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPFieldTypeParameterContainer.java index d74ebb38..ac9b0c1a 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPFieldTypeParameterContainer.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPFieldTypeParameterContainer.java @@ -20,7 +20,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldDouble; import com.igormaznitsa.jbbp.model.JBBPFieldFloat; import com.igormaznitsa.jbbp.model.JBBPFieldString; - +import com.igormaznitsa.jbbp.model.JBBPFieldUInt; import java.io.Serializable; /** @@ -52,7 +52,8 @@ public final class JBBPFieldTypeParameterContainer implements Serializable { * @param typeName the type of the field, can be null * @param extraData the extra data placed after ':' char, can be null */ - public JBBPFieldTypeParameterContainer(final JBBPByteOrder byteOrder, final String typeName, final String extraData) { + public JBBPFieldTypeParameterContainer(final JBBPByteOrder byteOrder, final String typeName, + final String extraData) { this.byteOrder = byteOrder; this.typeName = typeName; this.extraData = extraData; @@ -108,16 +109,21 @@ public boolean hasExpressionAsExtraData() { } /** - * Check that the type is a special one ('floatj', 'doublej', 'stringj' or 'value'). + * Check that the type is a special one ('floatj', 'doublej', 'stringj', 'uint' or 'value'). * * @return true if the type is a special one * @see JBBPFieldFloat#TYPE_NAME * @see JBBPFieldDouble#TYPE_NAME * @see JBBPFieldString#TYPE_NAME + * @see JBBPFieldUInt#TYPE_NAME * @since 1.4.0 */ public boolean isSpecialField() { - return this.typeName.equals(JBBPFieldFloat.TYPE_NAME) || this.typeName.equals(JBBPFieldDouble.TYPE_NAME) || this.typeName.equals(JBBPFieldString.TYPE_NAME) || this.typeName.equals("val"); + return this.typeName.equals(JBBPFieldFloat.TYPE_NAME) + || this.typeName.equals(JBBPFieldDouble.TYPE_NAME) + || this.typeName.equals(JBBPFieldString.TYPE_NAME) + || this.typeName.equals(JBBPFieldUInt.TYPE_NAME) + || this.typeName.equals("val"); } @Override diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPToken.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPToken.java index 60b61ba3..7f248fb7 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPToken.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPToken.java @@ -17,7 +17,6 @@ package com.igormaznitsa.jbbp.compiler.tokenizer; import com.igormaznitsa.jbbp.utils.JBBPUtils; - import java.io.Serializable; /** @@ -59,7 +58,9 @@ public final class JBBPToken implements Serializable { * @param arrayLength the string value of array size, it can be null * @param fieldName the field name, it can be null */ - JBBPToken(final JBBPTokenType type, final int position, final JBBPFieldTypeParameterContainer fieldTypeParameters, final String arrayLength, final String fieldName) { + JBBPToken(final JBBPTokenType type, final int position, + final JBBPFieldTypeParameterContainer fieldTypeParameters, final String arrayLength, + final String fieldName) { JBBPUtils.assertNotNull(type, "Type must not be null"); this.type = type; this.position = position; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPTokenizer.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPTokenizer.java index 126f9944..caefbbd0 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPTokenizer.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPTokenizer.java @@ -22,8 +22,8 @@ import com.igormaznitsa.jbbp.model.JBBPFieldDouble; import com.igormaznitsa.jbbp.model.JBBPFieldFloat; import com.igormaznitsa.jbbp.model.JBBPFieldString; +import com.igormaznitsa.jbbp.model.JBBPFieldUInt; import com.igormaznitsa.jbbp.utils.JBBPUtils; - import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; @@ -44,11 +44,14 @@ public final class JBBPTokenizer implements Iterable, IteratorWARNING! DO NOT UNESCAPE '}' AND '{' CHARS BECAUSE IT MAKES INCOMPATIBILITY WITH ANDROID! */ - private static final Pattern PATTERN = Pattern.compile("\\s*//.*$|\\s*(\\})|\\s*([^\\s;\\[\\]\\}\\{]+)?\\s*(?:\\[\\s*([^\\[\\]\\{\\};]+)\\s*\\])?\\s*([^\\d\\s;\\[\\]\\}\\{/][^\\s;\\[\\]\\}\\{/]*)?\\s*([\\{;])", Pattern.MULTILINE); + private static final Pattern PATTERN = Pattern.compile( + "\\s*//.*$|\\s*(\\})|\\s*([^\\s;\\[\\]\\}\\{]+)?\\s*(?:\\[\\s*([^\\[\\]\\{\\};]+)\\s*\\])?\\s*([^\\d\\s;\\[\\]\\}\\{/][^\\s;\\[\\]\\}\\{/]*)?\\s*([\\{;])", + Pattern.MULTILINE); /** * The Pattern to break field type to parameters. */ - private static final Pattern FIELD_TYPE_BREAK_PATTERN = Pattern.compile("^([<>])?([\\w][\\w$]*)(?::((?:[-]?\\d+)|(?:\\(.+\\))))?$"); + private static final Pattern FIELD_TYPE_BREAK_PATTERN = + Pattern.compile("^([<>])?([\\w][\\w$]*)(?::((?:[-]?\\d+)|(?:\\(.+\\))))?$"); /** * Inside table to keep disabled names for fields. */ @@ -59,6 +62,7 @@ public final class JBBPTokenizer implements Iterable, Iterator".equals(groupTypeByteOrder)) { + byteOrder = JBBPByteOrder.BIG_ENDIAN; + } else if ("<".equals(groupTypeByteOrder)) { + byteOrder = JBBPByteOrder.LITTLE_ENDIAN; + } else { + throw new Error( + "Illegal byte order char, unexpected error, contact developer please [" + + fieldType + ']'); + } + } else { + byteOrder = JBBPByteOrder.BIG_ENDIAN; + } + return byteOrder; + } + /** * Inside method to read the next token from the string and place it into * inside storage. @@ -145,9 +168,13 @@ private void readNextItem() { final String groupName = this.matcher.group(4); final String groupEnder = this.matcher.group(5); - final String skipString = this.processingString.substring(Math.max(this.lastCharSubstringFound, 0), matcher.start()).trim(); - if (skipString.length() != 0 && !skipString.startsWith("//")) { - this.detectedException = new JBBPTokenizerException(skipString, Math.max(this.lastCharSubstringFound, 0)); + final String skipString = + this.processingString.substring(Math.max(this.lastCharSubstringFound, 0), matcher.start()) + .trim(); + if (!skipString.isEmpty() && !skipString.startsWith("//")) { + this.detectedException = + new JBBPTokenizerException(skipString, this.processingString, + Math.max(this.lastCharSubstringFound, 0)); } else { JBBPTokenType type = JBBPTokenType.ATOM; @@ -157,15 +184,22 @@ private void readNextItem() { // { type = JBBPTokenType.STRUCT_START; if (groupName != null) { - final int position = matcher.start() + groupWholeFound.length() - groupWholeFoundTrimmed.length(); - this.detectedException = new JBBPTokenizerException("Wrong structure format, it must have only name (and may be array definition)", position); + final int position = + matcher.start() + groupWholeFound.length() - groupWholeFoundTrimmed.length(); + this.detectedException = new JBBPTokenizerException( + "Wrong structure format, it must have only name (and may be array definition)", + this.processingString, + position); return; } } else if (groupCloseStruct != null) { type = JBBPTokenType.STRUCT_END; } else if (groupTypeOrName == null) { - final int position = matcher.start() + groupWholeFound.length() - groupWholeFoundTrimmed.length(); - this.detectedException = new JBBPTokenizerException("Detected atomic field definition without type", position); + final int position = + matcher.start() + groupWholeFound.length() - groupWholeFoundTrimmed.length(); + this.detectedException = + new JBBPTokenizerException("Detected atomic field definition without type", + this.processingString, position); return; } @@ -206,24 +240,17 @@ private void readNextItem() { wrongFormat = false; - JBBPByteOrder byteOrder; - if (groupTypeByteOrder != null) { - if (">".equals(groupTypeByteOrder)) { - byteOrder = JBBPByteOrder.BIG_ENDIAN; - } else if ("<".equals(groupTypeByteOrder)) { - byteOrder = JBBPByteOrder.LITTLE_ENDIAN; - } else { - throw new Error("Illegal byte order char, unexpected error, contact developer please [" + fieldType + ']'); - } - } else { - byteOrder = JBBPByteOrder.BIG_ENDIAN; - } - - parsedType = new JBBPFieldTypeParameterContainer(byteOrder, groupTypeName, groupTypeExtraField); + JBBPByteOrder byteOrder = getJbbpByteOrder(groupTypeByteOrder, fieldType); + + parsedType = + new JBBPFieldTypeParameterContainer(byteOrder, groupTypeName, groupTypeExtraField); } if (wrongFormat) { - this.detectedException = new JBBPTokenizerException("Wrong format of type definition [" + fieldType + ']', position); + this.detectedException = + new JBBPTokenizerException("Wrong format of type definition [" + fieldType + ']', + this.processingString, + position); return; } } @@ -233,11 +260,15 @@ private void readNextItem() { } } else { if (this.lastCharSubstringFound < 0) { - this.detectedException = new JBBPTokenizerException("Wrong format of whole string", 0); + this.detectedException = + new JBBPTokenizerException("Wrong format of whole string", this.processingString, 0); } else { final String restOfString = this.processingString.substring(this.lastCharSubstringFound); - if (restOfString.trim().length() != 0) { - throw new JBBPTokenizerException("Can't recognize a part of script [" + restOfString + ']', this.lastCharSubstringFound); + if (!restOfString.trim().isEmpty()) { + throw new JBBPTokenizerException( + "Can't recognize a part of script [" + restOfString + ']', + this.processingString, + this.lastCharSubstringFound); } } this.nextItem = null; @@ -256,22 +287,25 @@ private JBBPTokenizerException checkFieldName(final String name, final int posit if (name != null) { final String normalized = JBBPUtils.normalizeFieldNameOrPath(name); if (normalized.indexOf('.') >= 0) { - return new JBBPTokenizerException("Field name must not contain '.' char", position); + return new JBBPTokenizerException("Field name must not contain '.' char", + this.processingString, position); } - if (normalized.length() > 0) { + if (!normalized.isEmpty()) { if (normalized.equals("_") || normalized.equals("$$") || normalized.startsWith("$") || Character.isDigit(normalized.charAt(0)) ) { - return new JBBPTokenizerException("'" + name + "' can't be field name", position); + return new JBBPTokenizerException("'" + name + "' can't be field name", + this.processingString, position); } for (int i = 1; i < normalized.length(); i++) { final char chr = normalized.charAt(i); if (chr != '_' && !Character.isLetterOrDigit(chr)) { - return new JBBPTokenizerException("Char '" + chr + "' not allowed in name", position); + return new JBBPTokenizerException("Char '" + chr + "' not allowed in name", + this.processingString, position); } } } @@ -279,7 +313,6 @@ private JBBPTokenizerException checkFieldName(final String name, final int posit return null; } - @SuppressWarnings("NullableProblems") @Override public Iterator iterator() { return this; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPEvaluatorFactory.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPEvaluatorFactory.java index 2d78d932..2cafd9b1 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPEvaluatorFactory.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPEvaluatorFactory.java @@ -18,7 +18,6 @@ import com.igormaznitsa.jbbp.compiler.JBBPCompilerUtils; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; - import java.util.List; /** @@ -53,7 +52,9 @@ public static JBBPEvaluatorFactory getInstance() { * @see JBBPExpressionEvaluator * @see JBBPOnlyFieldEvaluator */ - public JBBPIntegerValueEvaluator make(final String expression, final List namedFields, final byte[] compiledScript) { + public JBBPIntegerValueEvaluator make(final String expression, + final List namedFields, + final byte[] compiledScript) { final JBBPIntegerValueEvaluator result; if (JBBPExpressionEvaluator.hasExpressionOperators(expression)) { @@ -75,7 +76,8 @@ public JBBPIntegerValueEvaluator make(final String expression, final List>", ">>>"}; + private static final String[] SYMBOLS = + new String[] {"(", "", "", "", "~", "-", "+", "+", "-", "*", "/", "%", "|", "^", "&", "<<", + ">>", ">>>"}; /** * Array of first chars of operators to recognize a string as possible expression. */ - private static final char[] OPERATOR_FIRST_CHARS = new char[] {'(', '+', '-', '*', '/', '%', '|', '&', '^', '~', ')', '>', '<'}; + private static final char[] OPERATOR_FIRST_CHARS = + new char[] {'(', '+', '-', '*', '/', '%', '|', '&', '^', '~', ')', '>', '<'}; /** * The Pattern to parse an expression. */ - private static final Pattern PATTERN = Pattern.compile("([0-9]+)|([()])|(<<|>>>|>>|[%*+\\-/&|^~])|([\\S][^<>\\s+%*\\-/()&|^~]*)"); + private static final Pattern PATTERN = + Pattern.compile("([0-9]+)|([()])|(<<|>>>|>>|[%*+\\-/&|^~])|([\\S][^<>\\s+%*\\-/()&|^~]*)"); /** * The Array contains byte code of compiled expression. */ @@ -162,7 +167,9 @@ public final class JBBPExpressionEvaluator implements JBBPIntegerValueEvaluator * @param compiledData the current compiled data block of JBBP parent script for the expression, must not be null * @throws JBBPCompilationException if any problem in compilation */ - public JBBPExpressionEvaluator(final String expression, final List namedFields, final byte[] compiledData) { + public JBBPExpressionEvaluator(final String expression, + final List namedFields, + final byte[] compiledData) { this.expressionSource = expression; final Matcher matcher = PATTERN.matcher(expression); @@ -185,9 +192,10 @@ public JBBPExpressionEvaluator(final String expression, final List= 0) { // check for skipped substring - final String substr = expression.substring(lastFound, matcher.start()); - if (substr.trim().length() != 0) { - throw new JBBPCompilationException("Can't recognize part of expression '" + substr + "' [" + expression + ']'); + final String subString = expression.substring(lastFound, matcher.start()); + if (!subString.trim().isEmpty()) { + throw new JBBPCompilationException( + "Can't recognize part of expression '" + subString + "' [" + expression + ']'); } } @@ -215,7 +223,8 @@ public JBBPExpressionEvaluator(final String expression, final List= 0) { - switch (unaryOperatorCode) { - case CODE_UNARYPLUS: - case CODE_ADD: { - // do nothing - } - break; - case CODE_UNARYMINUS: - case CODE_MINUS: { - parsed = -parsed; - } - break; - case CODE_NOT: { - parsed = ~parsed; - } - break; - default: { - throw new Error("Unsupported unary operator [" + SYMBOLS[unaryOperatorCode] + ']'); - } - } - } + int parsed = getParsed(number, unaryOperatorCode); unaryOperatorCode = -1; compiledScript.write(CODE_CONST); @@ -383,14 +372,18 @@ public JBBPExpressionEvaluator(final String expression, final List 0) { - throw new JBBPCompilationException("Unary operator without argument '" + SYMBOLS[unaryOperatorCode] + "' [" + this.expressionSource + ']'); + throw new JBBPCompilationException( + "Unary operator without argument '" + SYMBOLS[unaryOperatorCode] + "' [" + + this.expressionSource + ']'); } if (counterOperators == 0) { @@ -404,26 +397,56 @@ public JBBPExpressionEvaluator(final String expression, final List= 0) { + switch (unaryOperatorCode) { + case CODE_UNARYPLUS: + case CODE_ADD: { + // do nothing + } + break; + case CODE_UNARYMINUS: + case CODE_MINUS: { + parsed = -parsed; + } + break; + case CODE_NOT: { + parsed = ~parsed; + } + break; + default: { + throw new Error("Unsupported unary operator [" + SYMBOLS[unaryOperatorCode] + ']'); + } + } + } + return parsed; + } + /** * Encode code of an operator to code of similar unary operator. * * @param code a code of operator. - * @return code of an unary similar operator if it exists, the same code otherwise + * @return code of a unary similar operator if it exists, the same code otherwise */ private static int codeToUnary(final int code) { final int result; @@ -514,7 +537,8 @@ public static boolean hasExpressionOperators(final String str) { */ private void assertUnaryOperator(final String operator) { if (!("+".equals(operator) || "-".equals(operator) || "~".equals(operator))) { - throw new JBBPCompilationException("Wrong unary operator '" + operator + "' [" + this.expressionSource + ']'); + throw new JBBPCompilationException( + "Wrong unary operator '" + operator + "' [" + this.expressionSource + ']'); } } @@ -547,7 +571,8 @@ private int calculateMaxStackDepth() { case CODE_MINUS: case CODE_XOR: { if (stackPosition < 2) { - throw new JBBPEvalException("Operator '" + code2operator(code) + "' needs two operands", this); + throw new JBBPEvalException("Operator '" + code2operator(code) + "' needs two operands", + this); } // decrease for one position stackPosition--; @@ -558,7 +583,8 @@ private int calculateMaxStackDepth() { case CODE_NOT: { // stack not changed if (stackPosition < 1) { - throw new JBBPEvalException("Operator '" + code2operator(code) + "' needs operand", this); + throw new JBBPEvalException("Operator '" + code2operator(code) + "' needs operand", + this); } } break; @@ -568,7 +594,9 @@ private int calculateMaxStackDepth() { } if (stackPosition != 1) { - throw new JBBPEvalException("Wrong expression [" + this.expressionSource + "] (" + stackPosition + ':' + stackMaxPosition + ')', this); + throw new JBBPEvalException( + "Wrong expression [" + this.expressionSource + "] (" + stackPosition + ':' + + stackMaxPosition + ')', this); } return stackMaxPosition; } @@ -594,7 +622,9 @@ public int getMaxStackDepth() { * @throws JBBPEvalException if there is any problem during processing */ @Override - public int eval(final JBBPBitInputStream inStream, final int currentCompiledBlockOffset, final JBBPCompiledBlock compiledBlockData, final JBBPNamedNumericFieldMap fieldMap) { + public int eval(final JBBPBitInputStream inStream, final int currentCompiledBlockOffset, + final JBBPCompiledBlock compiledBlockData, + final JBBPNamedNumericFieldMap fieldMap) { final int[] stack = new int[this.maxStackDepth]; int stackDepth = 0; @@ -610,12 +640,15 @@ public int eval(final JBBPBitInputStream inStream, final int currentCompiledBloc final int value; if (code == CODE_EXTVAR) { - value = "$".equals(this.externalValueNames[index]) ? (int) inStream.getCounter() : fieldMap.getExternalFieldValue(this.externalValueNames[index], compiledBlockData, this); + value = "$".equals(this.externalValueNames[index]) ? (int) inStream.getCounter() : + fieldMap + .getExternalFieldValue(this.externalValueNames[index], compiledBlockData, this); } else { final JBBPNamedFieldInfo namedField = compiledBlockData.getNamedFields()[index]; final JBBPNumericField numericField = fieldMap.get(namedField); if (numericField == null) { - throw new java.lang.ArithmeticException("Can't find field '" + namedField.getFieldName() + "' among numeric fields"); + throw new java.lang.ArithmeticException( + "Can't find field '" + namedField.getFieldName() + "' among numeric fields"); } else { value = fieldMap.get(namedField).getAsInt(); } @@ -703,7 +736,8 @@ public int eval(final JBBPBitInputStream inStream, final int currentCompiledBloc } @Override - public void visitItems(final JBBPCompiledBlock block, final int currentCompiledBlockOffset, final ExpressionEvaluatorVisitor visitor) { + public void visitItems(final JBBPCompiledBlock block, final int currentCompiledBlockOffset, + final ExpressionEvaluatorVisitor visitor) { visitor.visitStart(); final JBBPIntCounter counter = new JBBPIntCounter(); diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPIntegerValueEvaluator.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPIntegerValueEvaluator.java index 3cc3be25..7a697bad 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPIntegerValueEvaluator.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPIntegerValueEvaluator.java @@ -20,7 +20,6 @@ import com.igormaznitsa.jbbp.compiler.JBBPCompiledBlock; import com.igormaznitsa.jbbp.compiler.conversion.ExpressionEvaluatorVisitor; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; - import java.io.Serializable; /** @@ -38,7 +37,8 @@ public interface JBBPIntegerValueEvaluator extends Serializable { * @param fieldMap a named numeric field map * @return calculated value as integer */ - int eval(JBBPBitInputStream inStream, int currentCompiledBlockOffset, JBBPCompiledBlock block, JBBPNamedNumericFieldMap fieldMap); + int eval(JBBPBitInputStream inStream, int currentCompiledBlockOffset, JBBPCompiledBlock block, + JBBPNamedNumericFieldMap fieldMap); /** * Visit all expression items @@ -48,5 +48,6 @@ public interface JBBPIntegerValueEvaluator extends Serializable { * @param visitor the visitor to visit items, must not be null * @since 1.3.0 */ - void visitItems(JBBPCompiledBlock block, int currentCompiledBlockOffset, ExpressionEvaluatorVisitor visitor); + void visitItems(JBBPCompiledBlock block, int currentCompiledBlockOffset, + ExpressionEvaluatorVisitor visitor); } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPOnlyFieldEvaluator.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPOnlyFieldEvaluator.java index efd3b494..519c6c22 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPOnlyFieldEvaluator.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPOnlyFieldEvaluator.java @@ -53,13 +53,15 @@ public JBBPOnlyFieldEvaluator(final String externalFieldName, final int namedFie } @Override - public int eval(final JBBPBitInputStream inStream, final int currentCompiledBlockOffset, final JBBPCompiledBlock block, final JBBPNamedNumericFieldMap fieldMap) { + public int eval(final JBBPBitInputStream inStream, final int currentCompiledBlockOffset, + final JBBPCompiledBlock block, final JBBPNamedNumericFieldMap fieldMap) { final int result; if (this.externalFieldName == null) { final JBBPNamedFieldInfo namedField = block.getNamedFields()[this.namedFieldIndex]; final JBBPNumericField numericField = fieldMap.get(namedField); if (numericField == null) { - throw new java.lang.ArithmeticException("Can't find field '" + namedField.getFieldName() + "' among numeric fields"); + throw new java.lang.ArithmeticException( + "Can't find field '" + namedField.getFieldName() + "' among numeric fields"); } else { result = numericField.getAsInt(); } @@ -73,11 +75,13 @@ public int eval(final JBBPBitInputStream inStream, final int currentCompiledBloc @Override public String toString() { - return this.externalFieldName == null ? "NamedFieldIndex=" + this.namedFieldIndex : this.externalFieldName; + return this.externalFieldName == null ? "NamedFieldIndex=" + this.namedFieldIndex : + this.externalFieldName; } @Override - public void visitItems(final JBBPCompiledBlock block, final int currentCompiledBlockOffset, final ExpressionEvaluatorVisitor visitor) { + public void visitItems(final JBBPCompiledBlock block, final int currentCompiledBlockOffset, + final ExpressionEvaluatorVisitor visitor) { visitor.visitStart(); if (this.externalFieldName == null) { diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPEvalException.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPEvalException.java index ce403cf0..cd287baa 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPEvalException.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPEvalException.java @@ -48,7 +48,8 @@ public JBBPEvalException(final String message, final JBBPIntegerValueEvaluator e * @param evaluator a cause evaluator, can be null * @param cause a cause exception, can be null */ - public JBBPEvalException(final String message, final JBBPIntegerValueEvaluator evaluator, Throwable cause) { + public JBBPEvalException(final String message, final JBBPIntegerValueEvaluator evaluator, + Throwable cause) { super(message, cause); this.evaluator = evaluator; } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPFinderException.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPFinderException.java index 21047a15..090af415 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPFinderException.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPFinderException.java @@ -32,7 +32,7 @@ public class JBBPFinderException extends JBBPException { private final String nameOrPath; /** - * The Field type of a field to be searched. It may contain null. + * The Field type of field to be searched. It may contain null. */ private final Class fieldType; @@ -43,7 +43,8 @@ public class JBBPFinderException extends JBBPException { * @param nameOrPath the name of the path for used for search process, it can be null * @param fieldType the field type used for the search process, it can be null */ - public JBBPFinderException(final String message, final String nameOrPath, final Class fieldType) { + public JBBPFinderException(final String message, final String nameOrPath, + final Class fieldType) { super(message); this.nameOrPath = nameOrPath; this.fieldType = fieldType; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPMapperException.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPMapperException.java index ab57c0dd..7de1f65a 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPMapperException.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPMapperException.java @@ -17,7 +17,6 @@ package com.igormaznitsa.jbbp.exceptions; import com.igormaznitsa.jbbp.model.JBBPAbstractField; - import java.lang.reflect.Field; /** @@ -51,7 +50,9 @@ public class JBBPMapperException extends JBBPException { * @param mappingClassField the class field which mapping is wrong * @param cause the root cause for the exception, it can be null */ - public JBBPMapperException(final String message, final JBBPAbstractField field, final Class mappingClass, final Field mappingClassField, final Throwable cause) { + public JBBPMapperException(final String message, final JBBPAbstractField field, + final Class mappingClass, final Field mappingClassField, + final Throwable cause) { super(message, cause); this.field = field; this.mappingClassField = mappingClassField; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPNumericFieldValueConversionException.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPNumericFieldValueConversionException.java new file mode 100644 index 00000000..0490d86d --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPNumericFieldValueConversionException.java @@ -0,0 +1,67 @@ +package com.igormaznitsa.jbbp.exceptions; + +import com.igormaznitsa.jbbp.model.JBBPNumericField; + +/** + * Exception to indicate error during value conversion process. + * + * @since 2.0.4 + */ +public class JBBPNumericFieldValueConversionException extends JBBPException { + + private final JBBPNumericField source; + + /** + * Get source field. + * + * @return source field for exception, can be null + */ + public JBBPNumericField getSource() { + return this.source; + } + + /** + * Constructor to provide source field and message. + * + * @param source source field. can be null + * @param message message, can be null + */ + public JBBPNumericFieldValueConversionException(final JBBPNumericField source, + final String message) { + this(source, message, null); + } + + /** + * Constructor to provide source field, message and cause error. + * + * @param source source field. can be null + * @param message message, can be null + * @param cause cause error, can be null + */ + public JBBPNumericFieldValueConversionException(final JBBPNumericField source, + final String message, final Throwable cause) { + super(message, cause); + this.source = source; + } + + @Override + public String toString() { + final StringBuilder result = new StringBuilder(getClass().getName()); + final String message = this.getLocalizedMessage(); + final JBBPNumericField source = this.getSource(); + + result.append('('); + result + .append("message=").append(message).append(',') + .append("source=").append(source); + + final Throwable cause = this.getCause(); + if (cause != null) { + result.append(",cause=").append(cause.getClass().getName()); + } + + result.append(')'); + + return result.toString(); + } +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPReachedArraySizeLimitException.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPReachedArraySizeLimitException.java new file mode 100644 index 00000000..b4c0ecfd --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPReachedArraySizeLimitException.java @@ -0,0 +1,38 @@ +package com.igormaznitsa.jbbp.exceptions; + +/** + * Exception thrown if reached limit of items for whole stream array. + * + * @since 2.1.0 + */ +public class JBBPReachedArraySizeLimitException extends JBBPIOException { + + private final int readSize; + private final int limitSize; + + public JBBPReachedArraySizeLimitException( + final String message, + final int readSize, + final int limitSize + ) { + super(message); + this.readSize = readSize; + this.limitSize = limitSize; + } + + public int getReadSize() { + return this.readSize; + } + + public int getLimitSize() { + return this.limitSize; + } + + @Override + public String toString() { + return JBBPReachedArraySizeLimitException.class.getSimpleName() + '{' + + "readSize=" + this.readSize + + ", limitSize=" + this.limitSize + + '}'; + } +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPTokenizerException.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPTokenizerException.java index 74a5c0bf..2ba1996d 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPTokenizerException.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPTokenizerException.java @@ -17,29 +17,106 @@ package com.igormaznitsa.jbbp.exceptions; /** - * The Exception can be thrown during parsing sources for tokens and allows to figure out the position of the problematic token. + * The Exception can be thrown during parsing sources for tokens and allows to figure + * out the position of the problematic token. * * @since 1.0 */ public class JBBPTokenizerException extends JBBPCompilationException { - private static final long serialVersionUID = -1132154077305894146L; + private static final long serialVersionUID = -1132154077305893246L; /** * The Token position. */ private final int position; + private final String errorPart; + /** - * The Constructor. + * Constructor. * * @param message the exception message. + * @param script the script contains error, can be null * @param pos the position of a problematic token inside sources. + * @since 2.0.3 */ - public JBBPTokenizerException(final String message, final int pos) { + public JBBPTokenizerException(final String message, final String script, final int pos) { super(message); + this.errorPart = script == null ? "" : extractErrorPartText(script, pos); this.position = pos; } + /** + * Auxiliary internal method to extract error part from script around specific position. + * + * @param script the error script to be processed, must not be null + * @param errorPosition the error position in the script + * @return error part of the script as string, must not be null + * @since 2.0.3 + */ + private static String extractErrorPartText(final String script, final int errorPosition) { + if (errorPosition >= script.length() || errorPosition < 0) { + return ""; + } + final int maxLengthWing = 16; + final StringBuilder buffer = new StringBuilder(); + buffer.append(script.charAt(errorPosition)); + int errorPositionAtBuffer = 0; + int leftPosition = errorPosition - 1; + int rightPosition = errorPosition + 1; + int leftNonSpaceCounter = 0; + int rightNonSpaceCounter = 0; + for (int i = 0; i < maxLengthWing; i++) { + if (leftPosition >= 0) { + final char chr = script.charAt(leftPosition); + if (Character.isISOControl(chr) + || (i > 2 && leftNonSpaceCounter > 0 && Character.isSpaceChar(chr))) { + leftPosition = -1; + } else { + buffer.insert(0, chr); + leftNonSpaceCounter += Character.isSpaceChar(chr) ? 1 : 0; + errorPositionAtBuffer++; + leftPosition--; + } + } + if (rightPosition >= 0 && rightPosition < script.length()) { + final char chr = script.charAt(rightPosition); + if (Character.isISOControl(chr) + || (i > 2 && rightNonSpaceCounter > 0 && Character.isSpaceChar(chr))) { + rightPosition = -1; + } else { + buffer.append(chr); + rightNonSpaceCounter += Character.isSpaceChar(chr) ? 1 : 0; + rightPosition++; + } + } + } + final String errorMarkerLeft = " ->"; + final String errorMarkerRight = "<- "; + buffer.insert(errorPositionAtBuffer + 1, errorMarkerRight); + buffer.insert(errorPositionAtBuffer, errorMarkerLeft); + errorPositionAtBuffer += errorMarkerLeft.length(); + + if (Character.isISOControl(buffer.charAt(errorPositionAtBuffer))) { + String hex = Integer.toHexString(buffer.charAt(errorPositionAtBuffer)); + hex = "\\u" + "0000".substring(hex.length()) + hex; + + buffer.delete(errorPositionAtBuffer, errorPositionAtBuffer + 1); + buffer.insert(errorPositionAtBuffer, hex); + } + return buffer.toString().trim(); + } + + /** + * Get error part of script where error position marked by !>..<! + * + * @return error part of the script in position, or empty if it was impossible to extract the part + * @since 2.0.3 + */ + public String getErrorPart() { + return this.errorPart; + } + /** * get the position in sources of the problematic token. * @@ -48,4 +125,10 @@ public JBBPTokenizerException(final String message, final int pos) { public int getPosition() { return this.position; } + + @Override + public String toString() { + return this.getLocalizedMessage() + " (pos=" + this.position + ", errorPart=\"" + + this.errorPart + "\")"; + } } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPTooManyFieldsFoundException.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPTooManyFieldsFoundException.java index 5af394d2..0aa276e9 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPTooManyFieldsFoundException.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/exceptions/JBBPTooManyFieldsFoundException.java @@ -39,7 +39,9 @@ public class JBBPTooManyFieldsFoundException extends JBBPFinderException { * @param nameOrPath the name or the path used for search * @param fieldType the field type used for search */ - public JBBPTooManyFieldsFoundException(final int numberOfInstances, final String message, final String nameOrPath, final Class fieldType) { + public JBBPTooManyFieldsFoundException(final int numberOfInstances, final String message, + final String nameOrPath, + final Class fieldType) { super(message, nameOrPath, fieldType); this.numberOfInstances = numberOfInstances; } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/AbstractMappedClassFieldObserver.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/AbstractMappedClassFieldObserver.java index dd47cae7..cf0ca197 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/AbstractMappedClassFieldObserver.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/AbstractMappedClassFieldObserver.java @@ -19,6 +19,7 @@ import com.igormaznitsa.jbbp.exceptions.JBBPException; import com.igormaznitsa.jbbp.exceptions.JBBPIllegalArgumentException; import com.igormaznitsa.jbbp.mapper.Bin; +import com.igormaznitsa.jbbp.mapper.BinFieldFilter; import com.igormaznitsa.jbbp.mapper.BinType; import com.igormaznitsa.jbbp.mapper.JBBPMapper; import com.igormaznitsa.jbbp.mapper.MappedFieldRecord; @@ -26,6 +27,8 @@ import com.igormaznitsa.jbbp.model.JBBPFieldLong; import com.igormaznitsa.jbbp.model.JBBPFieldShort; import com.igormaznitsa.jbbp.model.JBBPFieldString; +import com.igormaznitsa.jbbp.model.JBBPFieldUInt; +import com.igormaznitsa.jbbp.utils.BinAnnotationWrapper; import com.igormaznitsa.jbbp.utils.JBBPUtils; import java.lang.reflect.Array; import java.lang.reflect.Field; @@ -66,7 +69,8 @@ private static Object readFieldValue(final Object obj, final MappedFieldRecord r */ private static void assertFieldArray(final Field field) { if (!field.getType().isArray()) { - throw new IllegalArgumentException("Detected non-array field marked to be written as an array [" + field + ']'); + throw new IllegalArgumentException( + "Detected non-array field marked to be written as an array [" + field + ']'); } } @@ -75,30 +79,87 @@ private static void assertFieldArray(final Field field) { * * @param obj an object which is an instance of a mapped class, must not be null * @param field a field where the object has been found, it can be null for first call + * @param binAnnotationWrapper wrapper to replace Bin annotation values for processing fields, can be null to be ignored * @param customFieldProcessor a processor for custom fields, it can be null * @see Bin + * @since 2.0.2 */ - protected void processObject(final Object obj, Field field, final Object customFieldProcessor) { + protected void processObject( + final Object obj, + final Field field, + final BinAnnotationWrapper binAnnotationWrapper, + final Object customFieldProcessor + ) { + this.processObject(obj, field, binAnnotationWrapper, null, customFieldProcessor); + } + + /** + * Process an object. It works only with classes and fields marked by Bin annotations. It doesn't process classes and fields marked by DslBinCustom annotations. + * + * @param obj an object which is an instance of a mapped class, must not be null + * @param field a field where the object has been found, it can be null for first call + * @param binAnnotationWrapper wrapper to replace Bin annotation values for processing fields, can be null to be ignored + * @param binFieldFilter filter for mapped fields, allows to exclude some of them, can be null + * @param customFieldProcessor a processor for custom fields, it can be null + * @see Bin + * @since 2.0.4 + */ + protected void processObject( + final Object obj, + final Field field, + final BinAnnotationWrapper binAnnotationWrapper, + final BinFieldFilter binFieldFilter, + final Object customFieldProcessor + ) { JBBPUtils.assertNotNull(obj, "Object must not be null"); - final List orderedFields = JBBPMapper.findAffectedFields(obj); + final List orderedFields = JBBPMapper.findAffectedFields(obj, binFieldFilter); final Bin clazzAnno = obj.getClass().getAnnotation(Bin.class); final Bin fieldAnno = field == null ? null : field.getAnnotation(Bin.class); - this.onStructStart(obj, field, clazzAnno == null ? fieldAnno : clazzAnno); + final Bin binAnno = clazzAnno == null ? fieldAnno : clazzAnno; - for (final MappedFieldRecord rec : orderedFields) { - Bin binAnno = rec.binAnnotation; + if (binFieldFilter == null || binFieldFilter.isAllowed(binAnno, field)) { + this.onStructStart(obj, field, binAnno); - if (binAnno.custom() && customFieldProcessor == null) { - throw new JBBPIllegalArgumentException("Class '" + obj.getClass().getName() + "' contains field '" + rec.mappingField.getName() + "\' which is custom one, you must provide JBBPCustomFieldWriter instance to save it."); + for (final MappedFieldRecord rec : orderedFields) { + final Bin annotation = binAnnotationWrapper == null ? rec.binAnnotation : + binAnnotationWrapper.setWrapped(rec.binAnnotation); + + if (binFieldFilter == null || binFieldFilter.isAllowed(annotation, rec.mappingField)) { + if (annotation.custom() && customFieldProcessor == null) { + throw new JBBPIllegalArgumentException( + "Class '" + obj.getClass().getName() + "' contains field '" + + rec.mappingField.getName() + + "' which is custom one, you must provide JBBPCustomFieldWriter instance to save it."); + } + processObjectField(obj, rec, annotation, customFieldProcessor, binFieldFilter); + } } - processObjectField(obj, rec, binAnno, customFieldProcessor); + this.onStructEnd(obj, field, binAnno); } + } - this.onStructEnd(obj, field, clazzAnno == null ? fieldAnno : clazzAnno); + /** + * Inside auxiliary method to process a field of an object. + * + * @param obj the object which field under processing, must not be null + * @param fieldRecord internal record about the field, must not be null + * @param annotation the annotation to be used as data source about the field, + * must not be null + * @param customFieldProcessor an object which will be provided for processing + * of custom fields, must not be null if object contains custom fields + * @since 2.0.4 + */ + protected void processObjectField( + final Object obj, + final MappedFieldRecord fieldRecord, + final Bin annotation, + final Object customFieldProcessor + ) { + this.processObjectField(obj, fieldRecord, annotation, customFieldProcessor, null); } /** @@ -110,13 +171,25 @@ protected void processObject(final Object obj, Field field, final Object customF * must not be null * @param customFieldProcessor an object which will be provided for processing * of custom fields, must not be null if object contains custom fields + * @param binFieldFilter filter allows to exclude some fields from process, can be null + * @since 2.0.4 */ - protected void processObjectField(final Object obj, final MappedFieldRecord fieldRecord, final Bin annotation, final Object customFieldProcessor) { + protected void processObjectField( + final Object obj, + final MappedFieldRecord fieldRecord, + final Bin annotation, + final Object customFieldProcessor, + final BinFieldFilter binFieldFilter + ) { final Field field = fieldRecord.mappingField; + if (annotation.custom()) { - this.onFieldCustom(obj, field, annotation, customFieldProcessor, readFieldValue(obj, fieldRecord)); + this.onFieldCustom(obj, field, annotation, customFieldProcessor, + readFieldValue(obj, fieldRecord)); } else { final Class fieldType = field.getType(); + final BinAnnotationWrapper wrapper = + annotation instanceof BinAnnotationWrapper ? (BinAnnotationWrapper) annotation : null; final BinType type; if (annotation.type() == BinType.UNDEFINED) { @@ -131,7 +204,8 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel case BIT: { final JBBPBitNumber bitNumber = annotation.bitNumber(); if (fieldType == boolean.class) { - this.onFieldBits(obj, field, annotation, bitNumber, ((Boolean) readFieldValue(obj, fieldRecord)) ? 0xFF : 0x00); + this.onFieldBits(obj, field, annotation, bitNumber, + ((Boolean) readFieldValue(obj, fieldRecord)) ? 0xFF : 0x00); } else { byte value = ((Number) readFieldValue(obj, fieldRecord)).byteValue(); if (reverseBits) { @@ -145,7 +219,8 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel if (fieldType == boolean.class) { onFieldBool(obj, field, annotation, (Boolean) readFieldValue(obj, fieldRecord)); } else { - onFieldBool(obj, field, annotation, ((Number) readFieldValue(obj, fieldRecord)).longValue() != 0); + onFieldBool(obj, field, annotation, + ((Number) readFieldValue(obj, fieldRecord)).longValue() != 0); } } break; @@ -181,6 +256,15 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel this.onFieldInt(obj, field, annotation, value); } break; + case UINT: { + long value; + value = ((Number) readFieldValue(obj, fieldRecord)).longValue(); + if (reverseBits) { + value = (int) JBBPFieldUInt.reverseBits(value); + } + this.onFieldUInt(obj, field, annotation, (int) value); + } + break; case FLOAT: { float value; if (float.class == fieldType) { @@ -189,7 +273,8 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel value = ((Number) readFieldValue(obj, fieldRecord)).floatValue(); } if (reverseBits) { - value = Float.intBitsToFloat((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(value))); + value = + Float.intBitsToFloat((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(value))); } this.onFieldFloat(obj, field, annotation, value); } @@ -227,13 +312,14 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel } if (reverseBits) { - value = Double.longBitsToDouble(JBBPFieldLong.reverseBits(Double.doubleToLongBits(value))); + value = + Double.longBitsToDouble(JBBPFieldLong.reverseBits(Double.doubleToLongBits(value))); } this.onFieldDouble(obj, field, annotation, value); } break; case STRUCT: { - processObject(readFieldValue(obj, fieldRecord), field, customFieldProcessor); + processObject(readFieldValue(obj, fieldRecord), field, wrapper, binFieldFilter, customFieldProcessor); } break; default: { @@ -249,7 +335,8 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel if (fieldType.getComponentType() == boolean.class) { for (int i = 0; i < len; i++) { - this.onFieldBits(obj, field, annotation, bitNumber, (Boolean) Array.get(array, i) ? 0xFF : 0x00); + this.onFieldBits(obj, field, annotation, bitNumber, + (Boolean) Array.get(array, i) ? 0xFF : 0x00); } } else { for (int i = 0; i < len; i++) { @@ -358,13 +445,29 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel for (int i = 0; i < len; i++) { float value = Array.getFloat(array, i); if (reverseBits) { - value = Float.intBitsToFloat((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(value))); + value = Float + .intBitsToFloat((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(value))); } this.onFieldFloat(obj, field, annotation, value); } this.onArrayEnd(obj, field, annotation); } break; + case UINT_ARRAY: { + assertFieldArray(field); + final int len = Array.getLength(array); + this.onArrayStart(obj, field, annotation, len); + for (int i = 0; i < len; i++) { + long value = ((Number) Array.get(array, i)).longValue(); + if (reverseBits) { + value = JBBPFieldUInt.reverseBits(value); + } + this.onFieldUInt(obj, field, annotation, (int) value); + } + + this.onArrayEnd(obj, field, annotation); + } + break; case INT_ARRAY: { assertFieldArray(field); final int len = Array.getLength(array); @@ -416,7 +519,8 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel for (int i = 0; i < len; i++) { double value = ((Number) Array.get(array, i)).doubleValue(); if (reverseBits) { - value = Double.longBitsToDouble(JBBPFieldLong.reverseBits(Double.doubleToLongBits(value))); + value = Double + .longBitsToDouble(JBBPFieldLong.reverseBits(Double.doubleToLongBits(value))); } this.onFieldDouble(obj, field, annotation, value); } @@ -428,13 +532,14 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel final int len = Array.getLength(array); this.onArrayStart(obj, field, annotation, len); for (int i = 0; i < len; i++) { - this.processObject(Array.get(array, i), field, customFieldProcessor); + this.processObject(Array.get(array, i), field, wrapper, binFieldFilter, customFieldProcessor); } this.onArrayEnd(obj, field, annotation); } break; default: { - throw new Error("Unexpected situation for field type, contact developer [" + type + ']'); + throw new Error( + "Unexpected situation for field type, contact developer [" + type + ']'); } } } @@ -452,7 +557,8 @@ protected void processObjectField(final Object obj, final MappedFieldRecord fiel * @param customFieldProcessor processor for custom fields, must not be null * @param value the value of the custom field */ - protected void onFieldCustom(final Object obj, final Field field, final Bin annotation, final Object customFieldProcessor, final Object value) { + protected void onFieldCustom(final Object obj, final Field field, final Bin annotation, + final Object customFieldProcessor, final Object value) { } @@ -465,7 +571,8 @@ protected void onFieldCustom(final Object obj, final Field field, final Bin anno * @param bitNumber number of bits for the field, must not be null * @param value the value of the field */ - protected void onFieldBits(final Object obj, final Field field, final Bin annotation, final JBBPBitNumber bitNumber, final int value) { + protected void onFieldBits(final Object obj, final Field field, final Bin annotation, + final JBBPBitNumber bitNumber, final int value) { } @@ -477,7 +584,8 @@ protected void onFieldBits(final Object obj, final Field field, final Bin annota * @param annotation the annotation for field, must not be null * @param value the value of the field */ - protected void onFieldBool(final Object obj, final Field field, final Bin annotation, final boolean value) { + protected void onFieldBool(final Object obj, final Field field, final Bin annotation, + final boolean value) { } @@ -490,7 +598,8 @@ protected void onFieldBool(final Object obj, final Field field, final Bin annota * @param signed flag shows that the field id signed * @param value the value of the field */ - protected void onFieldByte(final Object obj, final Field field, final Bin annotation, final boolean signed, final int value) { + protected void onFieldByte(final Object obj, final Field field, final Bin annotation, + final boolean signed, final int value) { } @@ -503,7 +612,8 @@ protected void onFieldByte(final Object obj, final Field field, final Bin annota * @param signed flag shows that the field id signed * @param value the value of the field */ - protected void onFieldShort(final Object obj, final Field field, final Bin annotation, final boolean signed, final int value) { + protected void onFieldShort(final Object obj, final Field field, final Bin annotation, + final boolean signed, final int value) { } @@ -515,7 +625,22 @@ protected void onFieldShort(final Object obj, final Field field, final Bin annot * @param annotation the annotation for field, must not be null * @param value the value of the field */ - protected void onFieldInt(final Object obj, final Field field, final Bin annotation, final int value) { + protected void onFieldInt(final Object obj, final Field field, final Bin annotation, + final int value) { + + } + + /** + * Notification about unsigned integer field. + * + * @param obj the object instance, must not be null + * @param field the field, must not be null + * @param annotation the annotation for field, must not be null + * @param value the value of the field + * @since 2.0.4 + */ + protected void onFieldUInt(final Object obj, final Field field, final Bin annotation, + final int value) { } @@ -528,7 +653,8 @@ protected void onFieldInt(final Object obj, final Field field, final Bin annotat * @param value the value of the field * @since 1.4.0 */ - protected void onFieldFloat(final Object obj, final Field field, final Bin annotation, final float value) { + protected void onFieldFloat(final Object obj, final Field field, final Bin annotation, + final float value) { } @@ -541,7 +667,8 @@ protected void onFieldFloat(final Object obj, final Field field, final Bin annot * @param value the value of the field * @since 1.4.0 */ - protected void onFieldString(final Object obj, final Field field, final Bin annotation, final String value) { + protected void onFieldString(final Object obj, final Field field, final Bin annotation, + final String value) { } @@ -554,7 +681,8 @@ protected void onFieldString(final Object obj, final Field field, final Bin anno * @param value the value of the field * @since 1.4.0 */ - protected void onFieldDouble(final Object obj, final Field field, final Bin annotation, final double value) { + protected void onFieldDouble(final Object obj, final Field field, final Bin annotation, + final double value) { } @@ -566,7 +694,8 @@ protected void onFieldDouble(final Object obj, final Field field, final Bin anno * @param annotation the annotation for field, must not be null * @param value the value of the field */ - protected void onFieldLong(final Object obj, final Field field, final Bin annotation, final long value) { + protected void onFieldLong(final Object obj, final Field field, final Bin annotation, + final long value) { } @@ -600,7 +729,8 @@ protected void onStructEnd(final Object obj, final Field field, final Bin annota * @param annotation the annotation for field, must not be null * @param length the length of the array */ - protected void onArrayStart(final Object obj, final Field field, final Bin annotation, final int length) { + protected void onArrayStart(final Object obj, final Field field, final Bin annotation, + final int length) { } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPArraySizeLimiter.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPArraySizeLimiter.java new file mode 100644 index 00000000..de7f094d --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPArraySizeLimiter.java @@ -0,0 +1,52 @@ +package com.igormaznitsa.jbbp.io; + +import com.igormaznitsa.jbbp.exceptions.JBBPReachedArraySizeLimitException; + +/** + * Interface describing an object which provides limit to read array items. + * + * @since 2.1.0 + */ +@FunctionalInterface +public interface JBBPArraySizeLimiter { + /** + * Read arrays without limits. + */ + JBBPArraySizeLimiter NO_LIMIT_FOR_ARRAY_SIZE = () -> 0; + + /** + * Check number of read items for whole stream array and return flag if read should be stopped or throw exception if required. + * + * @param readItems number of currently read array items + * @param limiter limiter provides number of allowed items, must not be null + * @return true if read must be stopped immediately, false otherwise + * @throws JBBPReachedArraySizeLimitException it will be thrown if reach of limit is not allowed + */ + static boolean isBreakReadWholeStream( + final int readItems, + final JBBPArraySizeLimiter limiter + ) { + final int limit = limiter.getArrayItemsLimit(); + if (limit == 0) { + return false; + } + if (limit > 0) { + if (readItems > limit) { + throw new JBBPReachedArraySizeLimitException( + "Detected too big array during stream rest read: " + readItems, readItems, + Math.abs(limit)); + } else { + return false; + } + } else { + return readItems >= Math.abs(limit); + } + } + + /** + * Get allowed size of array to read. + * + * @return 0 means no limit, positive value means allowed number of items with exception throwing if read more items, negative value means number of read values and stop read if exceeded. + */ + int getArrayItemsLimit(); +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitInputStream.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitInputStream.java index 796a8231..2bb56cf3 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitInputStream.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitInputStream.java @@ -16,9 +16,11 @@ package com.igormaznitsa.jbbp.io; +import static com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter.isBreakReadWholeStream; + +import com.igormaznitsa.jbbp.exceptions.JBBPReachedArraySizeLimitException; import com.igormaznitsa.jbbp.utils.JBBPSystemProperty; import com.igormaznitsa.jbbp.utils.JBBPUtils; - import java.io.EOFException; import java.io.FilterInputStream; import java.io.IOException; @@ -36,18 +38,24 @@ public class JBBPBitInputStream extends FilterInputStream implements JBBPCountab /** * The Initial an Array buffer size for whole stream read. */ - protected static final int INITIAL_ARRAY_BUFFER_SIZE = JBBPSystemProperty.PROPERTY_INPUT_INITIAL_ARRAY_BUFFER_SIZE.getAsInteger(32); + protected static final int INITIAL_ARRAY_BUFFER_SIZE = + JBBPSystemProperty.PROPERTY_INPUT_INITIAL_ARRAY_BUFFER_SIZE.getAsInteger(32); + /** + * Allow return accumulated read data if end of stream and not full required bit field read. + * + * @since 3.0.1 + */ + private final boolean enablePartialBitsOnEOF; /** - * Flag shows that bit operations must be processed for MSB0 (most significant - * bit 0) mode. + * Contains bit mode for bit operations. */ - private final boolean msb0; + private final JBBPBitOrder bitOrderMode; /** - * The Inside bit buffer, + * Internal bit buffer, */ private int bitBuffer; /** - * The Inside counter of bits in the bit buffer. + * Internal counter of bits in the bit buffer. */ private int bitsInBuffer; /** @@ -55,39 +63,124 @@ public class JBBPBitInputStream extends FilterInputStream implements JBBPCountab */ private long byteCounter; /** - * Inside temp variable to keep the bit buffer temporarily. + * Internal temp variable to keep the bit buffer temporarily. */ private int markedBitBuffer; /** - * Inside temp variable to keep the bit buffer counter temporarily. + * Internal temp variable to keep the bit buffer counter temporarily. */ private int markedBitsInBuffer; /** - * Inside temp variable to keep the byte counter temporarily. + * Internal temp variable to keep the byte counter temporarily. */ private long markedByteCounter; + /** + * Internal flag shows that read stopped for whole stream array read limit reach. + * + * @since 2.1.0 + */ + private boolean detectedArrayLimit; /** - * A Constructor, the LSB0 bit order will be used by default. + * Flag shows that during last read some bit field was not fully read. * - * @param in an input stream to be filtered. + * @see JBBPBitInputStream#isEnablePartialBitsOnEOF() + * @since 3.0.1 */ - public JBBPBitInputStream(final InputStream in) { - this(in, JBBPBitOrder.LSB0); - } + private boolean detectedPartlyReadBitField; /** * A Constructor. + * By default, if missing part of bit field in the end of stream then current accumulated data will be returned. * * @param in an input stream to be filtered. * @param order a bit order mode for the filter. * @see JBBPBitOrder#LSB0 * @see JBBPBitOrder#MSB0 + * @see JBBPBitOrder#MSB0_DIRECT */ public JBBPBitInputStream(final InputStream in, final JBBPBitOrder order) { + this(in, order, true); + } + + /** + * A Constructor, the LSB0 bit order will be used by default. + * By default, if missing part of bit field in the end of stream then current accumulated data will be returned. + * + * @param in an input stream to be filtered. + */ + public JBBPBitInputStream(final InputStream in) { + this(in, JBBPBitOrder.LSB0); + } + + /** + * A Constructor, the LSB0 bit order will be used by default. + * + * @param in an input stream to be filtered. + * @param enablePartialBitsOnEOF if true then already accumulated partly read bit field data returned in case EOF, -1 otherwise. + * @since 3.0.1 + */ + public JBBPBitInputStream(final InputStream in, final boolean enablePartialBitsOnEOF) { + this(in, JBBPBitOrder.LSB0, enablePartialBitsOnEOF); + } + + /** + * Create wrapping bit input stream. + * + * @param in the base input stream, must not be null + * @param order a bitness order mode for the filter. + * @param enablePartialBitsOnEOF if true then partly read bit data is returned in end of stream, -1 returned otherwise even if there is partly read bits data. + * @since 3.0.1 + */ + public JBBPBitInputStream(final InputStream in, final JBBPBitOrder order, + final boolean enablePartialBitsOnEOF) { super(in); this.bitsInBuffer = 0; - this.msb0 = order == JBBPBitOrder.MSB0; + this.bitOrderMode = order; + this.enablePartialBitsOnEOF = enablePartialBitsOnEOF; + } + + /** + * Shows that during last read some bit field was not fully read. + * + * @see JBBPBitInputStream#isEnablePartialBitsOnEOF() + * @since 3.0.1 + */ + public boolean isDetectedPartlyReadBitField() { + return this.detectedPartlyReadBitField; + } + + /** + * Get flag shows behavior if end of file but presented bit data in buffer. + * If true then partly read bit data is returned in end of stream, -1 returned otherwise even if there is partly read bits data. + * + * @return boolean flag for the behavior, true if allowed + * @since 3.0.1 + */ + public boolean isEnablePartialBitsOnEOF() { + return this.enablePartialBitsOnEOF; + } + + /** + * Flag shows that read of array was stopped for array limiter restrictions. + * + * @return true if array limiter restrictions detected, false otherwise + * @see JBBPArraySizeLimiter + * @since 2.1.0 + */ + public boolean isDetectedArrayLimit() { + return this.detectedArrayLimit; + } + + /** + * Set value for array limit detected flag. It is important to set the flag for correct processing of parsing. + * + * @param value true or false. + * @see com.igormaznitsa.jbbp.JBBPParser + * @since 2.1.0 + */ + public void setDetectedArrayLimit(final boolean value) { + this.detectedArrayLimit = value; } /** @@ -99,6 +192,24 @@ public JBBPBitInputStream(final InputStream in, final JBBPBitOrder order) { * @throws IOException it will be thrown for transport error */ public boolean[] readBoolArray(final int items) throws IOException { + return this.readBoolArray(items, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read array of boolean values. + * + * @param items number of items to be read, if less than zero then read whole + * stream till the end + * @param arraySizeLimiter limiter provides number of allowed array items, must not be null + * @return read values as boolean array + * @throws IOException it will be thrown for transport error + * @throws JBBPReachedArraySizeLimitException if reached limit of read + * @since 2.1.0 + */ + public boolean[] readBoolArray(final int items, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + this.setDetectedArrayLimit(false); int pos = 0; byte[] buffer; if (items < 0) { @@ -111,10 +222,19 @@ public boolean[] readBoolArray(final int items) throws IOException { } pos += read; + if (isBreakReadWholeStream(pos, arraySizeLimiter)) { + this.setDetectedArrayLimit(true); + final int limit = arraySizeLimiter.getArrayItemsLimit(); + if (limit < 0) { + pos = Math.min(pos, Math.abs(limit)); + } + break; + } + if (buffer.length == pos) { - final byte[] newbuffer = new byte[buffer.length << 1]; - System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); - buffer = newbuffer; + final byte[] newBuffer = new byte[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; } } } else { @@ -138,49 +258,70 @@ public boolean[] readBoolArray(final int items) throws IOException { return result; } - private byte[] _readArray(final int items, final JBBPBitNumber bitNumber) throws IOException { - final boolean readByteArray = bitNumber == null; + @Override + public int read(final byte[] array, final int offset, final int length) throws IOException { + return this.read(array, offset, length, this.enablePartialBitsOnEOF); + } - int pos = 0; - if (items < 0) { - byte[] buffer = new byte[INITIAL_ARRAY_BUFFER_SIZE]; - // till end - while (true) { - final int next = readByteArray ? read() : readBits(bitNumber); - if (next < 0) { + /** + * Reads up to {@code len} bytes of data from this input stream + * into an array of bytes. If {@code len} is not zero, the method + * blocks until some input is available; otherwise, no + * bytes are read and {@code 0} is returned. + * + * @param array target array + * @param offset offset in the target array + * @param length the length of data portion to be read + * @param enablePartialBitsOnEOF if true then already accumulated partly read bit field data returned in case EOF, -1 otherwise. + * @return number of read bytes from the wrapped input stream + * @throws IOException thrown if any transport error + * @since 3.0.1 + */ + public int read(final byte[] array, final int offset, final int length, + final boolean enablePartialBitsOnEOF) throws IOException { + this.detectedPartlyReadBitField = false; + if (this.bitsInBuffer == 0) { + int readBytes = 0; + int tempOffset = offset; + int tempLength = length; + while (tempLength > 0) { + int read = this.in.read(array, tempOffset, tempLength); + if (read < 0) { + readBytes = readBytes == 0 ? read : readBytes; break; } - if (buffer.length == pos) { - final byte[] newbuffer = new byte[buffer.length << 1]; - System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); - buffer = newbuffer; - } - buffer[pos++] = (byte) next; + tempLength -= read; + tempOffset += read; + readBytes += read; + this.byteCounter += read; } - if (buffer.length == pos) { - return buffer; + + if (this.bitOrderMode == JBBPBitOrder.MSB0) { + int index = offset; + int number = readBytes; + while (number > 0) { + array[index] = JBBPUtils.reverseBitsInByte(array[index]); + index++; + number--; + } } - final byte[] result = new byte[pos]; - System.arraycopy(buffer, 0, result, 0, pos); - return result; + + return readBytes; } else { - // number - final byte[] buffer = new byte[items]; - if (readByteArray) { - final int read = this.read(buffer, 0, items); - if (read != items) { - throw new EOFException("Have read only " + read + " byte(s) instead of " + items + " byte(s)"); - } - } else { - for (int i = 0; i < items; i++) { - final int next = readBits(bitNumber); - if (next < 0) { - throw new EOFException("Have read only " + i + " bit portions instead of " + items); - } - buffer[i] = (byte) next; + int count = length; + int i = offset; + boolean partlyReadBits = false; + while (count > 0) { + final int nextByte = this.readBits(JBBPBitNumber.BITS_8, enablePartialBitsOnEOF); + partlyReadBits |= this.detectedPartlyReadBitField; + if (nextByte < 0) { + break; } + count--; + array[i++] = (byte) nextByte; } - return buffer; + this.detectedPartlyReadBitField = partlyReadBits; + return length - count; } } @@ -195,7 +336,26 @@ private byte[] _readArray(final int items, final JBBPBitNumber bitNumber) throws * operation */ public byte[] readBitsArray(final int items, final JBBPBitNumber bitNumber) throws IOException { - return _readArray(items, bitNumber); + return this.readBitsArray(items, bitNumber, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read array of bit sequence. + * + * @param items number of items to be read, if less than zero then read whole + * @param bitNumber bit number for each bit sequence item, must be 1..8 + * stream till the end + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return array of read bit items as a byte array + * @throws JBBPReachedArraySizeLimitException if reached limit of read + * @throws IOException it will be thrown for any transport problem during the + * operation + * @since 2.1.0 + */ + public byte[] readBitsArray(final int items, final JBBPBitNumber bitNumber, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + return internalReadArray(items, bitNumber, arraySizeLimiter); } /** @@ -208,7 +368,23 @@ public byte[] readBitsArray(final int items, final JBBPBitNumber bitNumber) thro * operation */ public byte[] readByteArray(final int items) throws IOException { - return _readArray(items, null); + return this.readBitsArray(items, null, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read number of bytes for the stream. + * + * @param items number of items to be read, if less than zero then read whole + * stream till the end + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return read byte items as a byte array + * @throws IOException it will be thrown for any transport problem during the + * operation + * @since 2.1.0 + */ + public byte[] readByteArray(final int items, final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + return internalReadArray(items, null, arraySizeLimiter); } /** @@ -224,263 +400,440 @@ public byte[] readByteArray(final int items) throws IOException { * @since 1.3.0 */ public byte[] readByteArray(final int items, final JBBPByteOrder byteOrder) throws IOException { - final byte[] result = _readArray(items, null); - if (byteOrder == JBBPByteOrder.LITTLE_ENDIAN) { - JBBPUtils.reverseArray(result); - } - return result; + return this.readByteArray(items, byteOrder, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); } /** - * Read number of short items from the input stream. + * Read number of bytes for the stream. Invert their order if byte order is LITTLE_ENDIAN * - * @param items number of items to be read from the input stream, if less than - * zero then all stream till the end will be read - * @param byteOrder the order of bytes to be used to decode short values - * @return read items as a short array - * @throws IOException it will be thrown for any transport problem during the - * operation - * @see JBBPByteOrder#BIG_ENDIAN + * @param items number of items to be read, if less than zero then read whole + * stream till the end + * @param byteOrder desired order of bytes + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return read byte items as a byte array, if byte order is LITTLE_ENDIAN then the result array will be reversed one + * @throws IOException it will be thrown for any transport problem during the + * operation + * @throws JBBPReachedArraySizeLimitException if reached limit of array read * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.1.0 */ - public short[] readShortArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + public byte[] readByteArray( + final int items, + final JBBPByteOrder byteOrder, + final JBBPArraySizeLimiter arraySizeLimiter + ) throws IOException { + final byte[] result = internalReadArray(items, null, arraySizeLimiter); + if (byteOrder == JBBPByteOrder.LITTLE_ENDIAN) { + JBBPUtils.reverseArray(result); + } + return result; + } + + @Override + public void mark(final int readLimit) { + in.mark(readLimit); + this.markedBitBuffer = this.bitBuffer; + this.markedByteCounter = this.byteCounter; + this.markedBitsInBuffer = this.bitsInBuffer; + } + + private byte[] internalReadArray( + final int items, + final JBBPBitNumber bitNumber, + final JBBPArraySizeLimiter streamLimiter + ) throws IOException { + this.detectedPartlyReadBitField = false; + final boolean readByteArray = bitNumber == null; + this.setDetectedArrayLimit(false); int pos = 0; if (items < 0) { - short[] buffer = new short[INITIAL_ARRAY_BUFFER_SIZE]; + byte[] buffer = new byte[INITIAL_ARRAY_BUFFER_SIZE]; // till end - while (hasAvailableData()) { - final int next = readUnsignedShort(byteOrder); + while (true) { + final int next = + readByteArray ? read() : this.readBits(bitNumber, this.enablePartialBitsOnEOF); + if (next < 0) { + break; + } if (buffer.length == pos) { - final short[] newbuffer = new short[buffer.length << 1]; - System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); - buffer = newbuffer; + final byte[] newBuffer = new byte[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + buffer[pos++] = (byte) next; + if (isBreakReadWholeStream(pos, streamLimiter)) { + this.setDetectedArrayLimit(true); + break; } - buffer[pos++] = (short) next; } if (buffer.length == pos) { return buffer; } - final short[] result = new short[pos]; + final byte[] result = new byte[pos]; System.arraycopy(buffer, 0, result, 0, pos); return result; } else { // number - final short[] buffer = new short[items]; - for (int i = 0; i < items; i++) { - buffer[i] = (short) readUnsignedShort(byteOrder); + final byte[] buffer = new byte[items]; + if (readByteArray) { + final int read = this.read(buffer, 0, items); + if (read != items) { + throw new EOFException( + "Have read only " + read + " byte(s) instead of " + items + " byte(s)"); + } + } else { + for (int i = 0; i < items; i++) { + final int next = this.readBits(bitNumber, this.enablePartialBitsOnEOF); + if (next < 0) { + throw new EOFException("Have read only " + i + " bit portions instead of " + items); + } + buffer[i] = (byte) next; + } } return buffer; } } /** - * Read number of unsigned short items from the input stream. + * Read number of short items from the input stream. * * @param items number of items to be read from the input stream, if less than * zero then all stream till the end will be read * @param byteOrder the order of bytes to be used to decode short values - * @return read items as a char array + * @return read items as a short array * @throws IOException it will be thrown for any transport problem during the * operation * @see JBBPByteOrder#BIG_ENDIAN * @see JBBPByteOrder#LITTLE_ENDIAN - * @since 1.3 */ - public char[] readUShortArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + public short[] readShortArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + return this.readShortArray(items, byteOrder, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read number of short items from the input stream. + * + * @param items number of items to be read from the input stream, if less than + * zero then all stream till the end will be read + * @param byteOrder the order of bytes to be used to decode short values + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return read items as a short array + * @throws IOException it will be thrown for any transport problem during the + * operation + * @throws JBBPReachedArraySizeLimitException if reached limit of array read + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.1.0 + */ + public short[] readShortArray(final int items, final JBBPByteOrder byteOrder, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + this.setDetectedArrayLimit(false); int pos = 0; if (items < 0) { - char[] buffer = new char[INITIAL_ARRAY_BUFFER_SIZE]; + short[] buffer = new short[INITIAL_ARRAY_BUFFER_SIZE]; // till end while (hasAvailableData()) { final int next = readUnsignedShort(byteOrder); if (buffer.length == pos) { - final char[] newbuffer = new char[buffer.length << 1]; - System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); - buffer = newbuffer; + final short[] newBuffer = new short[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + buffer[pos++] = (short) next; + if (isBreakReadWholeStream(pos, arraySizeLimiter)) { + this.setDetectedArrayLimit(true); + break; } - buffer[pos++] = (char) next; } if (buffer.length == pos) { return buffer; } - final char[] result = new char[pos]; + final short[] result = new short[pos]; System.arraycopy(buffer, 0, result, 0, pos); return result; } else { // number - final char[] buffer = new char[items]; + final short[] buffer = new short[items]; for (int i = 0; i < items; i++) { - buffer[i] = (char) readUnsignedShort(byteOrder); + buffer[i] = (short) readUnsignedShort(byteOrder); } return buffer; } } /** - * Read number of integer items from the input stream. + * Read number of unsigned integer items from the input stream. * * @param items number of items to be read from the input stream, if less than * zero then all stream till the end will be read * @param byteOrder the order of bytes to be used to decode values - * @return read items as an integer array + * @return read items as an unsigned integer array represented through long * @throws IOException it will be thrown for any transport problem during the * operation * @see JBBPByteOrder#BIG_ENDIAN * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.0.4 */ - public int[] readIntArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + public long[] readUIntArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + return this.readUIntArray(items, byteOrder, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read number of unsigned integer items from the input stream. + * + * @param items number of items to be read from the input stream, if less than + * zero then all stream till the end will be read + * @param byteOrder the order of bytes to be used to decode values + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return read items as an unsigned integer array represented through long + * @throws IOException it will be thrown for any transport problem during the + * operation + * @throws JBBPReachedArraySizeLimitException if reached limit of array read + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.1.0 + */ + public long[] readUIntArray( + final int items, + final JBBPByteOrder byteOrder, + final JBBPArraySizeLimiter arraySizeLimiter + ) throws IOException { + this.setDetectedArrayLimit(false); int pos = 0; if (items < 0) { - int[] buffer = new int[INITIAL_ARRAY_BUFFER_SIZE]; + long[] buffer = new long[INITIAL_ARRAY_BUFFER_SIZE]; // till end while (hasAvailableData()) { - final int next = readInt(byteOrder); + final long next = readUInt(byteOrder); if (buffer.length == pos) { - final int[] newbuffer = new int[buffer.length << 1]; - System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); - buffer = newbuffer; + final long[] newBuffer = new long[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; } buffer[pos++] = next; + if (isBreakReadWholeStream(pos, arraySizeLimiter)) { + this.setDetectedArrayLimit(true); + break; + } } if (buffer.length == pos) { return buffer; } - final int[] result = new int[pos]; + final long[] result = new long[pos]; System.arraycopy(buffer, 0, result, 0, pos); return result; } else { // number - final int[] buffer = new int[items]; + final long[] buffer = new long[items]; for (int i = 0; i < items; i++) { - buffer[i] = readInt(byteOrder); + buffer[i] = readUInt(byteOrder); } return buffer; } } /** - * Read number of float items from the input stream. + * Read number of unsigned short items from the input stream. * * @param items number of items to be read from the input stream, if less than * zero then all stream till the end will be read - * @param byteOrder the order of bytes to be used to decode values - * @return read items as float array + * @param byteOrder the order of bytes to be used to decode short values + * @return read items as a char array * @throws IOException it will be thrown for any transport problem during the * operation * @see JBBPByteOrder#BIG_ENDIAN * @see JBBPByteOrder#LITTLE_ENDIAN - * @since 1.4.0 + * @since 1.3 */ - public float[] readFloatArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + public char[] readUShortArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + return this.readUShortArray(items, byteOrder, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read number of unsigned short items from the input stream. + * + * @param items number of items to be read from the input stream, if less than + * zero then all stream till the end will be read + * @param byteOrder the order of bytes to be used to decode short values + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return read items as a char array + * @throws IOException it will be thrown for any transport problem during the + * operation + * @throws JBBPReachedArraySizeLimitException if reached limit of array read + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.1.0 + */ + public char[] readUShortArray(final int items, final JBBPByteOrder byteOrder, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + this.setDetectedArrayLimit(false); int pos = 0; if (items < 0) { - float[] buffer = new float[INITIAL_ARRAY_BUFFER_SIZE]; + char[] buffer = new char[INITIAL_ARRAY_BUFFER_SIZE]; // till end while (hasAvailableData()) { - final float next = readFloat(byteOrder); + final int next = readUnsignedShort(byteOrder); if (buffer.length == pos) { - final float[] newbuffer = new float[buffer.length << 1]; - System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); - buffer = newbuffer; + final char[] newBuffer = new char[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + buffer[pos++] = (char) next; + if (isBreakReadWholeStream(pos, arraySizeLimiter)) { + this.setDetectedArrayLimit(true); + break; } - buffer[pos++] = next; } if (buffer.length == pos) { return buffer; } - final float[] result = new float[pos]; + final char[] result = new char[pos]; System.arraycopy(buffer, 0, result, 0, pos); return result; } else { // number - final float[] buffer = new float[items]; + final char[] buffer = new char[items]; for (int i = 0; i < items; i++) { - buffer[i] = readFloat(byteOrder); + buffer[i] = (char) readUnsignedShort(byteOrder); } return buffer; } } /** - * Read number of long items from the input stream. + * Read number of integer items from the input stream. * * @param items number of items to be read from the input stream, if less than * zero then all stream till the end will be read * @param byteOrder the order of bytes to be used to decode values - * @return read items as a long array + * @return read items as an integer array * @throws IOException it will be thrown for any transport problem during the * operation * @see JBBPByteOrder#BIG_ENDIAN * @see JBBPByteOrder#LITTLE_ENDIAN */ - public long[] readLongArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + public int[] readIntArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + return this.readIntArray(items, byteOrder, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read number of integer items from the input stream. + * + * @param items number of items to be read from the input stream, if less than + * zero then all stream till the end will be read + * @param byteOrder the order of bytes to be used to decode values + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return read items as an integer array + * @throws IOException it will be thrown for any transport problem during the + * operation + * @throws JBBPReachedArraySizeLimitException if reached limit of array read + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + */ + public int[] readIntArray(final int items, final JBBPByteOrder byteOrder, + final JBBPArraySizeLimiter arraySizeLimiter) throws IOException { + this.setDetectedArrayLimit(false); int pos = 0; if (items < 0) { - long[] buffer = new long[INITIAL_ARRAY_BUFFER_SIZE]; + int[] buffer = new int[INITIAL_ARRAY_BUFFER_SIZE]; // till end while (hasAvailableData()) { - final long next = readLong(byteOrder); + final int next = readInt(byteOrder); if (buffer.length == pos) { - final long[] newbuffer = new long[buffer.length << 1]; - System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); - buffer = newbuffer; + final int[] newBuffer = new int[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; } buffer[pos++] = next; + if (isBreakReadWholeStream(pos, arraySizeLimiter)) { + this.setDetectedArrayLimit(true); + break; + } } if (buffer.length == pos) { return buffer; } - final long[] result = new long[pos]; + final int[] result = new int[pos]; System.arraycopy(buffer, 0, result, 0, pos); return result; } else { // number - final long[] buffer = new long[items]; + final int[] buffer = new int[items]; for (int i = 0; i < items; i++) { - buffer[i] = readLong(byteOrder); + buffer[i] = readInt(byteOrder); } return buffer; } } /** - * Read number of double items from the input stream. + * Read number of float items from the input stream. * * @param items number of items to be read from the input stream, if less than * zero then all stream till the end will be read * @param byteOrder the order of bytes to be used to decode values - * @return read items as a double array + * @return read items as float array * @throws IOException it will be thrown for any transport problem during the * operation * @see JBBPByteOrder#BIG_ENDIAN * @see JBBPByteOrder#LITTLE_ENDIAN * @since 1.4.0 */ - public double[] readDoubleArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + public float[] readFloatArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + return this.readFloatArray(items, byteOrder, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read number of float items from the input stream. + * + * @param items number of items to be read from the input stream, if less than + * zero then all stream till the end will be read + * @param byteOrder the order of bytes to be used to decode values + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return read items as float array + * @throws IOException it will be thrown for any transport problem during the + * operation + * @throws JBBPReachedArraySizeLimitException if reached limit of array read + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.1.0 + */ + public float[] readFloatArray( + final int items, + final JBBPByteOrder byteOrder, + final JBBPArraySizeLimiter arraySizeLimiter + ) throws IOException { + this.setDetectedArrayLimit(false); int pos = 0; if (items < 0) { - double[] buffer = new double[INITIAL_ARRAY_BUFFER_SIZE]; + float[] buffer = new float[INITIAL_ARRAY_BUFFER_SIZE]; // till end while (hasAvailableData()) { - final long next = readLong(byteOrder); + final float next = readFloat(byteOrder); if (buffer.length == pos) { - final double[] newbuffer = new double[buffer.length << 1]; - System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); - buffer = newbuffer; + final float[] newBuffer = new float[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + buffer[pos++] = next; + if (isBreakReadWholeStream(pos, arraySizeLimiter)) { + this.setDetectedArrayLimit(true); + break; } - buffer[pos++] = Double.longBitsToDouble(next); } if (buffer.length == pos) { return buffer; } - final double[] result = new double[pos]; + final float[] result = new float[pos]; System.arraycopy(buffer, 0, result, 0, pos); return result; } else { // number - final double[] buffer = new double[items]; + final float[] buffer = new float[items]; for (int i = 0; i < items; i++) { - buffer[i] = readDouble(byteOrder); + buffer[i] = readFloat(byteOrder); } return buffer; } @@ -489,7 +842,7 @@ public double[] readDoubleArray(final int items, final JBBPByteOrder byteOrder) /** * Read a unsigned short value from the stream. * - * @param byteOrder he order of bytes to be used to decode the read value + * @param byteOrder the order of bytes to be used to decode the read value * @return the unsigned short value read from stream * @throws IOException it will be thrown for any transport problem during the * operation @@ -528,6 +881,26 @@ public int readInt(final JBBPByteOrder byteOrder) throws IOException { } } + /** + * Read an unsigned integer value from the stream. + * + * @param byteOrder the order of bytes to be used to decode the read value + * @return the unsigned integer value from the stream + * @throws IOException it will be thrown for any transport problem during the + * operation + * @throws EOFException if the end of the stream has been reached + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.0.4 + */ + public long readUInt(final JBBPByteOrder byteOrder) throws IOException { + if (byteOrder == JBBPByteOrder.BIG_ENDIAN) { + return (((long) readUnsignedShort(byteOrder) << 16) | readUnsignedShort(byteOrder)); + } else { + return readUnsignedShort(byteOrder) | ((long) readUnsignedShort(byteOrder) << 16); + } + } + /** * Read a float value from the stream. * @@ -563,9 +936,11 @@ public float readFloat(final JBBPByteOrder byteOrder) throws IOException { */ public long readLong(final JBBPByteOrder byteOrder) throws IOException { if (byteOrder == JBBPByteOrder.BIG_ENDIAN) { - return (((long) readInt(byteOrder) & 0xFFFFFFFFL) << 32) | ((long) readInt(byteOrder) & 0xFFFFFFFFL); + return (((long) readInt(byteOrder) & 0xFFFFFFFFL) << 32) | + ((long) readInt(byteOrder) & 0xFFFFFFFFL); } else { - return ((long) readInt(byteOrder) & 0xFFFFFFFFL) | (((long) readInt(byteOrder) & 0xFFFFFFFFL) << 32); + return ((long) readInt(byteOrder) & 0xFFFFFFFFL) | + (((long) readInt(byteOrder) & 0xFFFFFFFFL) << 32); } } @@ -584,9 +959,11 @@ public long readLong(final JBBPByteOrder byteOrder) throws IOException { public double readDouble(final JBBPByteOrder byteOrder) throws IOException { final long value; if (byteOrder == JBBPByteOrder.BIG_ENDIAN) { - value = (((long) readInt(byteOrder) & 0xFFFFFFFFL) << 32) | ((long) readInt(byteOrder) & 0xFFFFFFFFL); + value = (((long) readInt(byteOrder) & 0xFFFFFFFFL) << 32) | + ((long) readInt(byteOrder) & 0xFFFFFFFFL); } else { - value = ((long) readInt(byteOrder) & 0xFFFFFFFFL) | (((long) readInt(byteOrder) & 0xFFFFFFFFL) << 32); + value = ((long) readInt(byteOrder) & 0xFFFFFFFFL) | + (((long) readInt(byteOrder) & 0xFFFFFFFFL) << 32); } return Double.longBitsToDouble(value); } @@ -627,10 +1004,11 @@ public int getBufferedBitsNumber() { * @return the bit order parameter * @see JBBPBitOrder#LSB0 * @see JBBPBitOrder#MSB0 + * @see JBBPBitOrder#MSB0_DIRECT */ @Override public JBBPBitOrder getBitOrder() { - return this.msb0 ? JBBPBitOrder.MSB0 : JBBPBitOrder.LSB0; + return this.bitOrderMode; } /** @@ -642,8 +1020,8 @@ public JBBPBitOrder getBitOrder() { * @since 1.3.0 */ public byte readBitField(final JBBPBitNumber numOfBitsToRead) throws IOException { - final int value = this.readBits(numOfBitsToRead); - if (value < 0) { + final int value = this.readBits(numOfBitsToRead, this.enablePartialBitsOnEOF); + if (value < 0 || this.isDetectedPartlyReadBitField()) { throw new EOFException("Can't read bits from stream [" + numOfBitsToRead + ']'); } return (byte) value; @@ -652,7 +1030,7 @@ public byte readBitField(final JBBPBitNumber numOfBitsToRead) throws IOException /** * Read number of bits from the input stream. It reads bits from input stream * since 0 bit and make reversion to return bits in the right order when 0 bit - * is 0 bit. if the stream is completed early than the data read then reading + * is 0 bit. if the stream is completed earlier than the data read then reading * is just stopped and read value returned. The First read bit is placed as * 0th bit. * @@ -662,8 +1040,26 @@ public byte readBitField(final JBBPBitNumber numOfBitsToRead) throws IOException * @throws NullPointerException if number of bits to be read is null */ public int readBits(final JBBPBitNumber numOfBitsToRead) throws IOException { - int result; + return this.readBits(numOfBitsToRead, this.enablePartialBitsOnEOF); + } + /** + * Read number of bits from the input stream. It reads bits from input stream + * since 0 bit and make reversion to return bits in the order according the thread mode. + * Behaviour in case of missing bit data can be tuned by the special argument flag and if it is true then -1 returned otherwise current accumulated bit data returned. + * + * @param numOfBitsToRead the number of bits to be read, must be 1..8 + * @param enablePartialBitsOnEOF if true then already accumulated partly read bit field data returned in case EOF, -1 otherwise. + * @return the read bits as integer, -1 if the end of stream has been reached or if allowed end of stream flag and not all bits read. + * @throws IOException it will be thrown for transport errors to be read + * @throws NullPointerException if number of bits to be read is null + * @since 3.0.1 + */ + public int readBits(final JBBPBitNumber numOfBitsToRead, + final boolean enablePartialBitsOnEOF) + throws IOException { + int result; + this.detectedPartlyReadBitField = false; final int numOfBitsAsNumber = numOfBitsToRead.getBitNumber(); if (this.bitsInBuffer == 0 && numOfBitsAsNumber == 8) { @@ -671,12 +1067,14 @@ public int readBits(final JBBPBitNumber numOfBitsToRead) throws IOException { if (result >= 0) { this.byteCounter++; } - return result; } else { result = 0; if (numOfBitsAsNumber == this.bitsInBuffer) { result = this.bitBuffer; + if (this.bitOrderMode == JBBPBitOrder.MSB0_DIRECT) { + result >>>= this.bitsInBuffer; + } this.bitBuffer = 0; this.bitsInBuffer = 0; this.byteCounter++; @@ -689,35 +1087,75 @@ public int readBits(final JBBPBitNumber numOfBitsToRead) throws IOException { final boolean doIncCounter = theBitBufferCounter != 0; - while (i > 0) { - if (theBitBufferCounter == 0) { - if (doIncCounter) { - this.byteCounter++; - } - final int nextByte = this.readByteFromStream(); - if (nextByte < 0) { - if (i == numOfBitsAsNumber) { - return nextByte; + if (this.bitOrderMode == JBBPBitOrder.MSB0_DIRECT) { + while (i > 0) { + if (theBitBufferCounter == 0) { + if (doIncCounter) { + this.byteCounter++; + } + final int nextByte = this.readByteFromStream(); + if (nextByte < 0) { + if (i == numOfBitsAsNumber) { + return nextByte; + } else { + this.detectedPartlyReadBitField = true; + if (enablePartialBitsOnEOF) { + break; + } else { + this.bitsInBuffer = 0; + return -1; + } + } } else { - break; + theBitBuffer = nextByte; + theBitBufferCounter = 8; } - } else { - theBitBuffer = nextByte; - theBitBufferCounter = 8; } + + result = (result << 1) | ((theBitBuffer >>> 7) & 1); + theBitBuffer = (theBitBuffer << 1) & 0xFF; + theBitBufferCounter--; + i--; } + } else { + while (i > 0) { + if (theBitBufferCounter == 0) { + if (doIncCounter) { + this.byteCounter++; + } + final int nextByte = this.readByteFromStream(); + if (nextByte < 0) { + if (i == numOfBitsAsNumber) { + return nextByte; + } else { + this.detectedPartlyReadBitField = true; + if (enablePartialBitsOnEOF) { + break; + } else { + this.bitsInBuffer = 0; + return -1; + } + } + } else { + theBitBuffer = nextByte; + theBitBufferCounter = 8; + } + } - result = (result << 1) | (theBitBuffer & 1); - theBitBuffer >>= 1; - theBitBufferCounter--; - i--; + result = (result << 1) | (theBitBuffer & 1); + theBitBuffer >>= 1; + theBitBufferCounter--; + i--; + } + result = JBBPUtils.reverseBitsInByte(JBBPBitNumber.decode(numOfBitsAsNumber - i), + (byte) result) & + 0xFF; } this.bitBuffer = theBitBuffer; this.bitsInBuffer = theBitBufferCounter; - - return JBBPUtils.reverseBitsInByte(JBBPBitNumber.decode(numOfBitsAsNumber - i), (byte) result) & 0xFF; } + return result; } /** @@ -749,19 +1187,81 @@ public int readByte() throws IOException { } @Override - public synchronized void reset() throws IOException { + public void reset() throws IOException { in.reset(); this.bitBuffer = this.markedBitBuffer; this.byteCounter = this.markedByteCounter; this.bitsInBuffer = this.markedBitsInBuffer; } - @Override - public synchronized void mark(final int readlimit) { - in.mark(readlimit); - this.markedBitBuffer = this.bitBuffer; - this.markedByteCounter = this.byteCounter; - this.markedBitsInBuffer = this.bitsInBuffer; + /** + * Read number of long items from the input stream. + * + * @param items number of items to be read from the input stream, if less than + * zero then all stream till the end will be read + * @param byteOrder the order of bytes to be used to decode values + * @return read items as a long array + * @throws IOException it will be thrown for any transport problem during the + * operation + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + */ + public long[] readLongArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + return this.readLongArray(items, byteOrder, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read number of long items from the input stream. + * + * @param items number of items to be read from the input stream, if less than + * zero then all stream till the end will be read + * @param byteOrder the order of bytes to be used to decode values + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return read items as a long array + * @throws IOException it will be thrown for any transport problem during the + * operation + * @throws JBBPReachedArraySizeLimitException if reached limit of read + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.1.0 + */ + public long[] readLongArray( + final int items, + final JBBPByteOrder byteOrder, + final JBBPArraySizeLimiter arraySizeLimiter + ) throws IOException { + this.setDetectedArrayLimit(false); + int pos = 0; + if (items < 0) { + long[] buffer = new long[INITIAL_ARRAY_BUFFER_SIZE]; + // till end + while (hasAvailableData()) { + final long next = readLong(byteOrder); + if (buffer.length == pos) { + final long[] newBuffer = new long[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + buffer[pos++] = next; + if (isBreakReadWholeStream(pos, arraySizeLimiter)) { + this.setDetectedArrayLimit(true); + break; + } + } + if (buffer.length == pos) { + return buffer; + } + final long[] result = new long[pos]; + System.arraycopy(buffer, 0, result, 0, pos); + return result; + } else { + // number + final long[] buffer = new long[items]; + for (int i = 0; i < items; i++) { + buffer[i] = readLong(byteOrder); + } + return buffer; + } } /** @@ -812,35 +1312,90 @@ public long skip(final long numOfBytes) throws IOException { } /** - * Inside method to read a byte from stream. + * Internal method to read a byte from wrapped stream. * * @return the read byte or -1 if the end of the stream has been reached * @throws IOException it will be thrown for transport errors */ private int readByteFromStream() throws IOException { + this.detectedPartlyReadBitField = false; int result = this.in.read(); - if (result >= 0 && this.msb0) { + if (result >= 0 && this.bitOrderMode == JBBPBitOrder.MSB0) { result = JBBPUtils.reverseBitsInByte((byte) result) & 0xFF; } return result; } /** - * Read the next stream byte into bit buffer. + * Read number of double items from the input stream. * - * @return the read byte or -1 if the endo of stream has been reached. - * @throws IOException it will be thrown for transport errors + * @param items number of items to be read from the input stream, if less than + * zero then all stream till the end will be read + * @param byteOrder the order of bytes to be used to decode values + * @return read items as a double array + * @throws IOException it will be thrown for any transport problem during the + * operation + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 1.4.0 */ - private int loadNextByteInBuffer() throws IOException { - final int value = this.readByteFromStream(); - if (value < 0) { - return value; - } - - this.bitBuffer = value; - this.bitsInBuffer = 8; + public double[] readDoubleArray(final int items, final JBBPByteOrder byteOrder) + throws IOException { + return this.readDoubleArray(items, byteOrder, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } - return value; + /** + * Read number of double items from the input stream. + * + * @param items number of items to be read from the input stream, if less than + * zero then all stream till the end will be read + * @param byteOrder the order of bytes to be used to decode values + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return read items as a double array + * @throws IOException it will be thrown for any transport problem during the + * operation + * @throws JBBPReachedArraySizeLimitException if reached limit of array read + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.1.0 + */ + public double[] readDoubleArray( + final int items, + final JBBPByteOrder byteOrder, + final JBBPArraySizeLimiter arraySizeLimiter + ) throws IOException { + this.setDetectedArrayLimit(false); + int pos = 0; + if (items < 0) { + double[] buffer = new double[INITIAL_ARRAY_BUFFER_SIZE]; + // till end + while (hasAvailableData()) { + final long next = readLong(byteOrder); + if (buffer.length == pos) { + final double[] newBuffer = new double[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + buffer[pos++] = Double.longBitsToDouble(next); + if (isBreakReadWholeStream(pos, arraySizeLimiter)) { + this.setDetectedArrayLimit(true); + break; + } + } + if (buffer.length == pos) { + return buffer; + } + final double[] result = new double[pos]; + System.arraycopy(buffer, 0, result, 0, pos); + return result; + } else { + // number + final double[] buffer = new double[items]; + for (int i = 0; i < items; i++) { + buffer[i] = readDouble(byteOrder); + } + return buffer; + } } /** @@ -866,49 +1421,22 @@ public boolean hasAvailableData() throws IOException { return this.bitsInBuffer > 0 || loadNextByteInBuffer() >= 0; } - @SuppressWarnings("NullableProblems") - @Override - public int read(final byte[] array, final int offset, final int length) throws IOException { - if (this.bitsInBuffer == 0) { - int readBytes = 0; - int tmpoffset = offset; - int tmplen = length; - while (tmplen > 0) { - int read = this.in.read(array, tmpoffset, tmplen); - if (read < 0) { - readBytes = readBytes == 0 ? read : readBytes; - break; - } - tmplen -= read; - tmpoffset += read; - readBytes += read; - this.byteCounter += read; - } + /** + * Read the next stream byte into bit buffer. + * + * @return the read byte or -1 if the end of stream has been reached. + * @throws IOException it will be thrown for transport errors + */ + private int loadNextByteInBuffer() throws IOException { + final int value = this.readByteFromStream(); + if (value < 0) { + return value; + } - if (this.msb0) { - int index = offset; - int number = readBytes; - while (number > 0) { - array[index] = JBBPUtils.reverseBitsInByte(array[index]); - index++; - number--; - } - } + this.bitBuffer = value; + this.bitsInBuffer = 8; - return readBytes; - } else { - int count = length; - int i = offset; - while (count > 0) { - final int nextByte = this.readBits(JBBPBitNumber.BITS_8); - if (nextByte < 0) { - break; - } - count--; - array[i++] = (byte) nextByte; - } - return length - count; - } + return value; } /** @@ -930,7 +1458,6 @@ public void resetCounter() { this.byteCounter = 0L; } - @SuppressWarnings("NullableProblems") @Override public int read(final byte[] array) throws IOException { return this.read(array, 0, array.length); @@ -1016,9 +1543,8 @@ public String readString(final JBBPByteOrder byteOrder) throws IOException { return result; } - /** - * Read array of srings from stream. + * Read array of strings from stream. * * @param items number of items, or -1 if read whole stream * @param byteOrder order of bytes in structure, must not be null @@ -1027,7 +1553,29 @@ public String readString(final JBBPByteOrder byteOrder) throws IOException { * @see JBBPBitOutputStream#writeStringArray(String[], JBBPByteOrder) * @since 1.4.0 */ - public String[] readStringArray(final int items, final JBBPByteOrder byteOrder) throws IOException { + public String[] readStringArray(final int items, final JBBPByteOrder byteOrder) + throws IOException { + return this.readStringArray(items, byteOrder, JBBPArraySizeLimiter.NO_LIMIT_FOR_ARRAY_SIZE); + } + + /** + * Read array of strings from stream. + * + * @param items number of items, or -1 if read whole stream + * @param byteOrder order of bytes in structure, must not be null + * @param arraySizeLimiter limiter provides number of allowed array items for non-limited array, must not be null + * @return array, it can contain null among values, must not be null + * @throws IOException thrown for transport errors + * @throws JBBPReachedArraySizeLimitException if reached limit of array read + * @see JBBPBitOutputStream#writeStringArray(String[], JBBPByteOrder) + * @since 2.1.0 + */ + public String[] readStringArray( + final int items, + final JBBPByteOrder byteOrder, + final JBBPArraySizeLimiter arraySizeLimiter + ) throws IOException { + this.setDetectedArrayLimit(false); int pos = 0; if (items < 0) { String[] buffer = new String[INITIAL_ARRAY_BUFFER_SIZE]; @@ -1035,11 +1583,15 @@ public String[] readStringArray(final int items, final JBBPByteOrder byteOrder) while (hasAvailableData()) { final String next = readString(byteOrder); if (buffer.length == pos) { - final String[] newbuffer = new String[buffer.length << 1]; - System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); - buffer = newbuffer; + final String[] newBuffer = new String[buffer.length << 1]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; } buffer[pos++] = next; + if (isBreakReadWholeStream(pos, arraySizeLimiter)) { + this.setDetectedArrayLimit(true); + break; + } } if (buffer.length == pos) { return buffer; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOrder.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOrder.java index cc9ca19a..dd72eacd 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOrder.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOrder.java @@ -17,18 +17,26 @@ package com.igormaznitsa.jbbp.io; /** - * Constants for bit order of reading operations. + * Constants for a bit order of reading operations. * * @since 1.0 */ public enum JBBPBitOrder { /** * Most Significant Bit First means that the most significant bit will arrive first, the 7th bit will be read as the first one. + * Read data wille be presented in reverse format for Java because Java is LSB0. */ MSB0, /** * Least Significant Bit First means that the least significant bit will arrive first, the 0th bit will be read as the first one. * It is default order for Java. */ - LSB0 + LSB0, + /** + * Most Significant Bit First means that the most significant bit will arrive first, the 7th bit will be read as the first one. + * In opposite to MSB0 it doesn't make reverse for data during read and write. + * + * @since 3.0.1 + */ + MSB0_DIRECT } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStream.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStream.java index 69a84f2d..dbbe4a35 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStream.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStream.java @@ -16,6 +16,8 @@ package com.igormaznitsa.jbbp.io; +import static java.util.Objects.requireNonNull; + import com.igormaznitsa.jbbp.utils.JBBPUtils; import java.io.FilterOutputStream; import java.io.IOException; @@ -28,16 +30,15 @@ */ public class JBBPBitOutputStream extends FilterOutputStream implements JBBPCountableBitStream { /** - * Flag shows that bit operations must be processed for MSB0 (most significant - * bit 0) mode. + * Contains bit mode for bit operations. */ - private final boolean msb0; + private final JBBPBitOrder bitOrderMode; /** - * Inside bit buffer. + * Internal bit buffer. */ private int bitBuffer; /** - * Number of bits inside the bit buffer. + * Number of bits buffered by the bit buffer. */ private int bitBufferCount; /** @@ -46,7 +47,7 @@ public class JBBPBitOutputStream extends FilterOutputStream implements JBBPCount private long byteCounter; /** - * A Constructor. The Default LSB0 bit mode will be used for bit writing operations. + * A Constructor. The Default LSB0 bit mode will be used for a bit writing operations. * * @param out the output stream to be filtered. */ @@ -57,14 +58,14 @@ public JBBPBitOutputStream(final OutputStream out) { /** * A Constructor. * - * @param out an output stream to be filtered. - * @param order a bit writing mode to used for writing operations. + * @param out an output stream to be filtered. + * @param bitOrderMode a bit writing mode to used for writing operations. * @see JBBPBitOrder#LSB0 * @see JBBPBitOrder#MSB0 */ - public JBBPBitOutputStream(final OutputStream out, final JBBPBitOrder order) { + public JBBPBitOutputStream(final OutputStream out, final JBBPBitOrder bitOrderMode) { super(out); - this.msb0 = order == JBBPBitOrder.MSB0; + this.bitOrderMode = requireNonNull(bitOrderMode, "Bit order mode must not be null"); } /** @@ -76,7 +77,7 @@ public JBBPBitOutputStream(final OutputStream out, final JBBPBitOrder order) { */ @Override public JBBPBitOrder getBitOrder() { - return this.msb0 ? JBBPBitOrder.MSB0 : JBBPBitOrder.LSB0; + return this.bitOrderMode; } /** @@ -118,7 +119,28 @@ public void writeInt(final int value, final JBBPByteOrder byteOrder) throws IOEx } /** - * Write an float value into the output stream. + * Write an unsigned integer value into the output stream. + * + * @param value a value to be written into the output stream. + * @param byteOrder the byte order of the value bytes to be used for writing. + * @throws IOException it will be thrown for transport errors + * @see JBBPByteOrder#BIG_ENDIAN + * @see JBBPByteOrder#LITTLE_ENDIAN + * @since 2.0.4 + */ + public void writeUInt(final long value, final JBBPByteOrder byteOrder) throws IOException { + final int v = (int) value; + if (byteOrder == JBBPByteOrder.BIG_ENDIAN) { + this.writeShort(v >>> 16, byteOrder); + this.writeShort(v, byteOrder); + } else { + this.writeShort(v, byteOrder); + this.writeShort(v >>> 16, byteOrder); + } + } + + /** + * Write a float value into the output stream. * * @param value a value to be written into the output stream. * @param byteOrder the byte order of the value bytes to be used for writing. @@ -189,9 +211,9 @@ public long getCounter() { } /** - * Get the inside bit buffer value. + * Get the internal bit buffer value. * - * @return the inside bit buffer value + * @return the internal bit buffer value */ @Override public int getBitBuffer() { @@ -199,7 +221,7 @@ public int getBitBuffer() { } /** - * Get the number of bits cached in the inside bit buffer. + * Get the number of bits cached in the internal bit buffer. * * @return the number of cached bits in the bit buffer */ @@ -226,10 +248,9 @@ public void flush() throws IOException { this.out.flush(); } - @SuppressWarnings("NullableProblems") @Override public void write(final byte[] b, final int off, final int len) throws IOException { - if (this.msb0 || this.bitBufferCount != 0) { + if (this.bitOrderMode == JBBPBitOrder.MSB0 || this.bitBufferCount != 0) { int i = off; int cnt = len; while (cnt > 0) { @@ -242,7 +263,6 @@ public void write(final byte[] b, final int off, final int len) throws IOExcepti } } - @SuppressWarnings("NullableProblems") @Override public void write(final byte[] b) throws IOException { this.write(b, 0, b.length); @@ -258,29 +278,47 @@ public void write(final byte[] b) throws IOException { */ public void writeBits(final int value, final JBBPBitNumber bitNumber) throws IOException { if (this.bitBufferCount == 0 && bitNumber == JBBPBitNumber.BITS_8) { - write(value); + this.write(value); } else { - final int initialMask; int mask; - initialMask = 1; - mask = initialMask << this.bitBufferCount; - - int accum = value; + int accumulator = value; int i = bitNumber.getBitNumber(); - while (i > 0) { - this.bitBuffer = this.bitBuffer | ((accum & 1) == 0 ? 0 : mask); - accum >>= 1; - - mask = mask << 1; - - i--; - this.bitBufferCount++; - if (this.bitBufferCount == 8) { - this.bitBufferCount = 0; - writeByte(this.bitBuffer); - mask = initialMask; - this.bitBuffer = 0; + if (this.bitOrderMode == JBBPBitOrder.MSB0_DIRECT) { + final int initialMask = 0x80; + mask = initialMask >> this.bitBufferCount; + final int accumulatorMask = 1 << (bitNumber.getBitNumber() - 1); + while (i > 0) { + this.bitBuffer = this.bitBuffer | ((accumulator & accumulatorMask) == 0 ? 0 : mask); + accumulator <<= 1; + mask >>= 1; + + i--; + this.bitBufferCount++; + if (this.bitBufferCount == 8) { + this.bitBufferCount = 0; + writeByte(this.bitBuffer); + mask = initialMask; + this.bitBuffer = 0; + } + } + } else { + final int initialMask = 1; + mask = initialMask << this.bitBufferCount; + while (i > 0) { + this.bitBuffer = this.bitBuffer | ((accumulator & 1) == 0 ? 0 : mask); + + accumulator >>= 1; + mask = mask << 1; + + i--; + this.bitBufferCount++; + if (this.bitBufferCount == 8) { + this.bitBufferCount = 0; + writeByte(this.bitBuffer); + mask = initialMask; + this.bitBuffer = 0; + } } } } @@ -308,13 +346,13 @@ public void align(final long alignByteNumber) throws IOException { } /** - * Inside method to write a byte into wrapped stream. + * Internal method to write a byte into wrapped stream. * * @param value a byte value to be written * @throws IOException it will be thrown for transport problems */ private void writeByte(int value) throws IOException { - if (this.msb0) { + if (this.bitOrderMode == JBBPBitOrder.MSB0) { value = JBBPUtils.reverseBitsInByte((byte) value) & 0xFF; } this.out.write(value); @@ -330,9 +368,9 @@ public void close() throws IOException { @Override public void write(final int value) throws IOException { if (this.bitBufferCount == 0) { - writeByte(value); + this.writeByte(value); } else { - writeBits(value, JBBPBitNumber.BITS_8); + this.writeBits(value, JBBPBitNumber.BITS_8); } } @@ -346,7 +384,8 @@ public void write(final int value) throws IOException { * @see JBBPByteOrder#LITTLE_ENDIAN * @since 1.3.0 */ - public void writeBytes(final byte[] array, final int length, final JBBPByteOrder byteOrder) throws IOException { + public void writeBytes(final byte[] array, final int length, final JBBPByteOrder byteOrder) + throws IOException { if (byteOrder == JBBPByteOrder.LITTLE_ENDIAN) { int i = length < 0 ? array.length - 1 : length - 1; while (i >= 0) { @@ -358,7 +397,7 @@ public void writeBytes(final byte[] array, final int length, final JBBPByteOrder } /** - * Reset the byte counter for the stream. The Inside bit buffer will be reset also. + * Reset the byte counter for the stream. The internal bit buffer will be reset also. */ @Override public void resetCounter() { @@ -380,7 +419,7 @@ public void resetCounter() { public void writeString(final String value, final JBBPByteOrder order) throws IOException { if (value == null) { this.write(0xFF); - } else if (value.length() == 0) { + } else if (value.isEmpty()) { this.write(0); } else { final byte[] array = JBBPUtils.strToUtf8(value); diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPByteOrder.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPByteOrder.java index 7b3da313..2dd4b619 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPByteOrder.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPByteOrder.java @@ -17,7 +17,7 @@ package com.igormaznitsa.jbbp.io; /** - * Constants define byte order for multi-byte values to be read or written into streams. + * Constants define byte order for multibyte values to be read or written into streams. * * @since 1.0 */ diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPCountableBitStream.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPCountableBitStream.java index 4476e922..f2f5fd43 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPCountableBitStream.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPCountableBitStream.java @@ -45,7 +45,7 @@ public interface JBBPCountableBitStream { void resetCounter(); /** - * Get the inside stream bit buffer. + * Get the inside stream a bit buffer. * * @return the value from inside the stream bit buffer */ diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPCustomFieldWriter.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPCustomFieldWriter.java index 45123923..c3764e3e 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPCustomFieldWriter.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPCustomFieldWriter.java @@ -17,7 +17,6 @@ package com.igormaznitsa.jbbp.io; import com.igormaznitsa.jbbp.mapper.Bin; - import java.io.IOException; import java.lang.reflect.Field; @@ -40,5 +39,7 @@ public interface JBBPCustomFieldWriter { * @param value the value found in the field, can be null * @throws IOException it will be thrown if it is impossible to process field data and save them into the stream */ - void writeCustomField(final JBBPOut context, final JBBPBitOutputStream outStream, final Object instanceToSave, final Field instanceCustomField, final Bin fieldAnnotation, final Object value) throws IOException; + void writeCustomField(final JBBPOut context, final JBBPBitOutputStream outStream, + final Object instanceToSave, final Field instanceCustomField, + final Bin fieldAnnotation, final Object value) throws IOException; } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOut.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOut.java index 20ed7b1c..62e1cd5e 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOut.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOut.java @@ -16,10 +16,14 @@ package com.igormaznitsa.jbbp.io; +import static com.igormaznitsa.jbbp.utils.JBBPUtils.assertNotNull; + import com.igormaznitsa.jbbp.exceptions.JBBPIOException; import com.igormaznitsa.jbbp.mapper.Bin; +import com.igormaznitsa.jbbp.mapper.BinFieldFilter; import com.igormaznitsa.jbbp.mapper.JBBPMapper; import com.igormaznitsa.jbbp.model.JBBPFieldShort; +import com.igormaznitsa.jbbp.utils.BinAnnotationWrapper; import com.igormaznitsa.jbbp.utils.JBBPUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -32,7 +36,7 @@ * * @since 1.0 */ -public final class JBBPOut extends AbstractMappedClassFieldObserver { +public class JBBPOut extends AbstractMappedClassFieldObserver { /** * The Default byte outOrder. @@ -60,11 +64,11 @@ public final class JBBPOut extends AbstractMappedClassFieldObserver { */ private boolean processCommands = true; /** - * The Byte outOrder for operations of multi-byte value output. + * The Byte outOrder for operations of multibyte value output. */ private JBBPByteOrder byteOrder; /** - * The Flags shows that the processing has been ended. + * The Flags show that the processing has been ended. */ private boolean ended; @@ -77,15 +81,19 @@ public final class JBBPOut extends AbstractMappedClassFieldObserver { * @throws IllegalArgumentException if defined a bit stream which parameters * incompatible with defined ones */ - private JBBPOut(final OutputStream outStream, final JBBPByteOrder byteOrder, final JBBPBitOrder bitOrder) { - JBBPUtils.assertNotNull(outStream, "Out stream must not be null"); - JBBPUtils.assertNotNull(byteOrder, "Byte order must not be null"); - JBBPUtils.assertNotNull(bitOrder, "Bit order must not be null"); + private JBBPOut(final OutputStream outStream, final JBBPByteOrder byteOrder, + final JBBPBitOrder bitOrder) { + assertNotNull(outStream, "Out stream must not be null"); + assertNotNull(byteOrder, "Byte order must not be null"); + assertNotNull(bitOrder, "Bit order must not be null"); - this.outStream = outStream instanceof JBBPBitOutputStream ? (JBBPBitOutputStream) outStream : new JBBPBitOutputStream(outStream, bitOrder); + this.outStream = outStream instanceof JBBPBitOutputStream ? (JBBPBitOutputStream) outStream : + new JBBPBitOutputStream(outStream, bitOrder); this.bitOrder = this.outStream.getBitOrder(); if (this.bitOrder != bitOrder) { - throw new IllegalArgumentException("Detected JBBPBitOutputStream as argument with already defined different bit order [" + this.bitOrder + ']'); + throw new IllegalArgumentException( + "Detected JBBPBitOutputStream as argument with already defined different bit order [" + + this.bitOrder + ']'); } this.byteOrder = byteOrder; @@ -116,7 +124,8 @@ public static JBBPOut BeginBin(final JBBPByteOrder byteOrder, final JBBPBitOrder * @param bitOrder the bit outOrder for the session * @return the new DSL session generated for the stream with parameters */ - public static JBBPOut BeginBin(final OutputStream out, final JBBPByteOrder byteOrder, final JBBPBitOrder bitOrder) { + public static JBBPOut BeginBin(final OutputStream out, final JBBPByteOrder byteOrder, + final JBBPBitOrder bitOrder) { return new JBBPOut(out, byteOrder, bitOrder); } @@ -140,7 +149,8 @@ public static JBBPOut BeginBin() { * inside byte array stream. */ public static JBBPOut BeginBin(final int initialSize) { - return new JBBPOut(new ByteArrayOutputStream(initialSize), DEFAULT_BYTE_ORDER, DEFAULT_BIT_ORDER); + return new JBBPOut(new ByteArrayOutputStream(initialSize), DEFAULT_BYTE_ORDER, + DEFAULT_BIT_ORDER); } /** @@ -182,7 +192,7 @@ public static JBBPOut BeginBin(final JBBPBitOrder bitOrder) { * @param array an object to be checked for null. */ private static void assertArrayNotNull(final Object array) { - JBBPUtils.assertNotNull(array, "Array must not be null"); + assertNotNull(array, "Array must not be null"); } /** @@ -191,7 +201,7 @@ private static void assertArrayNotNull(final Object array) { * @param str an object to be checked for null. */ private static void assertStringNotNull(final String str) { - JBBPUtils.assertNotNull(str, "String must not be null"); + assertNotNull(str, "String must not be null"); } /** @@ -261,7 +271,7 @@ public JBBPOut Skip(int numberOfBytes) throws IOException { */ public JBBPOut ByteOrder(final JBBPByteOrder value) { assertNotEnded(); - JBBPUtils.assertNotNull(value, "Byte order must not be null"); + assertNotNull(value, "Byte order must not be null"); if (this.processCommands) { this.byteOrder = value; } @@ -300,7 +310,7 @@ public JBBPOut Bit(final byte value) throws IOException { } /** - * Write lowest bits of bytes from an array. + * Write the lowest bits of bytes from an array. * * @param value a byte array, lowest bit of each byte will be saved as a bit * into the output stream, it must not be null @@ -319,7 +329,7 @@ public JBBPOut Bit(final byte[] value) throws IOException { } /** - * Write lowest bits of integers from an array. + * Write the lowest bits of integers from an array. * * @param value an integer array, lowest bit of each integer value will be * saved as a bit into the output stream, it must not be null @@ -341,7 +351,7 @@ public JBBPOut Bit(final int... value) throws IOException { * Write bits represented as boolean flags into the output stream. * * @param value a boolean array which values will be saved into the output - * stream as bits, true is bit on, false is bit off. It must not be null + * stream as bits, true is a bit on, false is bit off. It must not be null * @return the DSL session. * @throws IOException it will be thrown for transport errors */ @@ -378,7 +388,7 @@ private void _writeBits(final JBBPBitNumber numberOfBits, final int value) throw */ public JBBPOut Bits(final JBBPBitNumber numberOfBits, final int value) throws IOException { assertNotEnded(); - JBBPUtils.assertNotNull(numberOfBits, "Number of bits must not be null"); + assertNotNull(numberOfBits, "Number of bits must not be null"); if (this.processCommands) { _writeBits(numberOfBits, value); } @@ -396,7 +406,7 @@ public JBBPOut Bits(final JBBPBitNumber numberOfBits, final int value) throws IO */ public JBBPOut Bits(final JBBPBitNumber numberOfBits, final int... value) throws IOException { assertNotEnded(); - JBBPUtils.assertNotNull(value, "Array must not be null"); + assertNotNull(value, "Array must not be null"); if (this.processCommands) { for (final int v : value) { _writeBits(numberOfBits, v); @@ -416,7 +426,7 @@ public JBBPOut Bits(final JBBPBitNumber numberOfBits, final int... value) throws */ public JBBPOut Bits(final JBBPBitNumber numberOfBits, final byte[] value) throws IOException { assertNotEnded(); - JBBPUtils.assertNotNull(value, "Array must not be null"); + assertNotNull(value, "Array must not be null"); if (this.processCommands) { for (final byte b : value) { _writeBits(numberOfBits, b); @@ -799,6 +809,20 @@ public JBBPOut Int(final int... value) throws IOException { return this; } + @Override + protected void onFieldUInt(final Object obj, final Field field, final Bin annotation, + final int value) { + final JBBPByteOrder old = this.byteOrder; + try { + this.byteOrder = annotation.byteOrder(); + this.UInt(value); + } catch (IOException ex) { + throw new JBBPIOException("Can't write unsigned int value", ex); + } finally { + this.byteOrder = old; + } + } + /** * Write a float value array as integer bits into the stream. * @@ -936,7 +960,7 @@ public JBBPOut Long(final long... value) throws IOException { */ public JBBPOut Var(final JBBPOutVarProcessor processor, final Object... args) throws IOException { assertNotEnded(); - JBBPUtils.assertNotNull(processor, "Var processor must not be null"); + assertNotNull(processor, "Var processor must not be null"); if (this.processCommands) { this.processCommands = processor.processVarOut(this, this.outStream, args); } @@ -995,26 +1019,49 @@ protected void assertNotEnded() { /** * Save fields of an object marked by Bin annotation. Fields will be ordered - * through {@link Bin#order()} field, NB! By default Java doesn't keep field + * through {@link Bin#order()} field, NB! By default, Java doesn't keep field * outOrder. Ordered fields of class will be saved into internal cache for speed * but the cache can be reset through {@link JBBPMapper#clearFieldCache()} + * Warning! it doesn't affect byte order provided in Bin annotations of object. * * @param object an object to be saved into stream, must not be null * @return the context * @throws IOException it will be thrown for any transport error * @see JBBPMapper#clearFieldCache() + * @see #BinForceByteOrder(Object) * @see Bin * @since 1.1 */ public JBBPOut Bin(final Object object) throws IOException { - return this.Bin(object, null); + return this.Bin(object, null, null, null); } /** * Save fields of an object marked by Bin annotation. Fields will be ordered - * through {@link Bin#order()} field, NB! By default Java doesn't keep field + * through {@link Bin#order()} field, NB! By default, Java doesn't keep field * outOrder. Ordered fields of class will be saved into internal cache for speed * but the cache can be reset through {@link JBBPMapper#clearFieldCache()} + * Warning! it doesn't affect byte order provided in Bin annotations of object. + * + * @param object an object to be saved into stream, must not be null + * @param binFieldFilter filter to exclude some fields from process, can be null + * @return the context + * @throws IOException it will be thrown for any transport error + * @see JBBPMapper#clearFieldCache() + * @see #BinForceByteOrder(Object) + * @see Bin + * @since 2.0.4 + */ + public JBBPOut Bin(final Object object, final BinFieldFilter binFieldFilter) throws IOException { + return this.Bin(object, null, null, binFieldFilter); + } + + /** + * Save fields of an object marked by Bin annotation. Fields will be ordered + * through {@link Bin#order()} field, NB! By default, Java doesn't keep field + * outOrder. Ordered fields of class will be saved into internal cache for speed + * but the cache can be reset through {@link JBBPMapper#clearFieldCache()} + * Warning! it doesn't affect byte order provided in Bin annotations of object. * * @param object an object to be saved into stream, must not be null * @param customFieldWriter a custom field writer to be used for saving of @@ -1022,18 +1069,106 @@ public JBBPOut Bin(final Object object) throws IOException { * @return the context * @see JBBPMapper#clearFieldCache() * @see Bin + * @see #BinForceByteOrder(Object, JBBPCustomFieldWriter) * @since 1.1 */ public JBBPOut Bin(final Object object, final JBBPCustomFieldWriter customFieldWriter) { + return this.Bin(object, null, customFieldWriter); + } + + /** + * Save fields of an object marked by Bin annotation. Fields will be ordered + * through {@link Bin#order()} field, NB! By default, Java doesn't keep field + * outOrder. Ordered fields of class will be saved into internal cache for speed + * but the cache can be reset through {@link JBBPMapper#clearFieldCache()} + * Warning! it doesn't affect byte order provided in Bin annotations of object. + * + * @param object an object to be saved into stream, must not be null + * @param customFieldWriter a custom field writer to be used for saving of + * custom fields of the object, it can be null + * @param binFieldFilter filter to exclude fields from process, can be null + * @return the context + * @see JBBPMapper#clearFieldCache() + * @see Bin + * @see #BinForceByteOrder(Object, JBBPCustomFieldWriter) + * @since 2.0.4 + */ + public JBBPOut Bin(final Object object, final JBBPCustomFieldWriter customFieldWriter, final BinFieldFilter binFieldFilter) { + return this.Bin(object, null, customFieldWriter, binFieldFilter); + } + + /** + * Save fields of object but bin annotation wrapper can be provided to replace some annotation field values in all field annotations. + * + * @param object an object to be saved into stream, must not be null + * @param binAnnotationWrapper wrapper for all bin annotations, can be null + * @param customFieldWriter a custom field writer to be used for saving of + * custom fields of the object, it can be null + * @return the context + * @since 2.0.2 + */ + public JBBPOut Bin(final Object object, + final BinAnnotationWrapper binAnnotationWrapper, + final JBBPCustomFieldWriter customFieldWriter) { + return this.Bin(object, binAnnotationWrapper, customFieldWriter, null); + } + + /** + * Save fields of object but bin annotation wrapper can be provided to replace some annotation field values in all field annotations. + * + * @param object an object to be saved into stream, must not be null + * @param binAnnotationWrapper wrapper for all bin annotations, can be null + * @param customFieldWriter a custom field writer to be used for saving of + * custom fields of the object, it can be null + * @param binFieldFilter filter to exclude some fields from process, can be null + * @return the context + * @since 2.0.4 + */ + public JBBPOut Bin(final Object object, + final BinAnnotationWrapper binAnnotationWrapper, + final JBBPCustomFieldWriter customFieldWriter, + final BinFieldFilter binFieldFilter) { if (this.processCommands) { - this.processObject(object, null, customFieldWriter); + this.processObject(object, null, binAnnotationWrapper, binFieldFilter, customFieldWriter); } - return this; } + /** + * Works like {@link #Bin(Object)} but forcing override of all annotation byte order values by the JBBPOut byte order. + * + * @param object an object to be saved into stream, must not be null + * @return the context + * @throws IOException it will be thrown for any transport error + * @see JBBPMapper#clearFieldCache() + * @see Bin + * @see Bin#byteOrder() + * @since 2.0.2 + */ + public JBBPOut BinForceByteOrder(final Object object) throws IOException { + return this.BinForceByteOrder(object, null); + } + + /** + * Works like {@link #Bin(Object, JBBPCustomFieldWriter)} but forcing override of all annotation byte order values by the context byte order. + * + * @param object an object to be saved into stream, must not be null + * @param customFieldWriter a custom field writer to be used for saving of + * custom fields of the object, it can be null + * @return the context + * @see #ByteOrder(JBBPByteOrder) + * @see Bin#byteOrder() + * @since 2.0.2 + */ + public JBBPOut BinForceByteOrder(final Object object, + final JBBPCustomFieldWriter customFieldWriter) { + return this + .Bin(object, new BinAnnotationWrapper().setByteOrder(this.byteOrder), customFieldWriter); + } + @Override - protected void onFieldFloat(final Object obj, final Field field, final Bin annotation, final float value) { + protected void onFieldFloat(final Object obj, final Field field, final Bin annotation, + final float value) { final JBBPByteOrder old = this.byteOrder; try { this.byteOrder = annotation.byteOrder(); @@ -1046,7 +1181,8 @@ protected void onFieldFloat(final Object obj, final Field field, final Bin annot } @Override - protected void onFieldString(final Object obj, final Field field, final Bin annotation, final String value) { + protected void onFieldString(final Object obj, final Field field, final Bin annotation, + final String value) { final JBBPByteOrder old = this.byteOrder; try { this.byteOrder = annotation.byteOrder(); @@ -1059,7 +1195,8 @@ protected void onFieldString(final Object obj, final Field field, final Bin anno } @Override - protected void onFieldDouble(final Object obj, final Field field, final Bin annotation, final double value) { + protected void onFieldDouble(final Object obj, final Field field, final Bin annotation, + final double value) { final JBBPByteOrder old = this.byteOrder; try { this.byteOrder = annotation.byteOrder(); @@ -1072,7 +1209,8 @@ protected void onFieldDouble(final Object obj, final Field field, final Bin anno } @Override - protected void onFieldLong(final Object obj, final Field field, final Bin annotation, final long value) { + protected void onFieldLong(final Object obj, final Field field, final Bin annotation, + final long value) { final JBBPByteOrder old = this.byteOrder; try { this.byteOrder = annotation.byteOrder(); @@ -1085,7 +1223,8 @@ protected void onFieldLong(final Object obj, final Field field, final Bin annota } @Override - protected void onFieldInt(final Object obj, final Field field, final Bin annotation, final int value) { + protected void onFieldInt(final Object obj, final Field field, final Bin annotation, + final int value) { final JBBPByteOrder old = this.byteOrder; try { this.byteOrder = annotation.byteOrder(); @@ -1097,8 +1236,28 @@ protected void onFieldInt(final Object obj, final Field field, final Bin annotat } } + /** + * Write each long value as unsigned integer one into the session stream. + * + * @param value a long value array which values should be written into + * @return the DSl session + * @throws IOException it will be thrown for transport errors + * @since 2.0.4 + */ + public JBBPOut UInt(final long... value) throws IOException { + assertNotEnded(); + assertArrayNotNull(value); + if (this.processCommands) { + for (final long v : value) { + _writeInt((int) v); + } + } + return this; + } + @Override - protected void onFieldShort(final Object obj, final Field field, final Bin annotation, final boolean signed, final int value) { + protected void onFieldShort(final Object obj, final Field field, final Bin annotation, + final boolean signed, final int value) { final JBBPByteOrder old = this.byteOrder; try { this.byteOrder = annotation.byteOrder(); @@ -1111,7 +1270,8 @@ protected void onFieldShort(final Object obj, final Field field, final Bin annot } @Override - protected void onFieldByte(final Object obj, final Field field, final Bin annotation, final boolean signed, final int value) { + protected void onFieldByte(final Object obj, final Field field, final Bin annotation, + final boolean signed, final int value) { try { this.Byte(value); } catch (IOException ex) { @@ -1120,7 +1280,8 @@ protected void onFieldByte(final Object obj, final Field field, final Bin annota } @Override - protected void onFieldBool(final Object obj, final Field field, final Bin annotation, final boolean value) { + protected void onFieldBool(final Object obj, final Field field, final Bin annotation, + final boolean value) { try { this.Bool(value, annotation.bitOrder()); } catch (IOException ex) { @@ -1129,7 +1290,8 @@ protected void onFieldBool(final Object obj, final Field field, final Bin annota } @Override - protected void onFieldBits(final Object obj, final Field field, final Bin annotation, final JBBPBitNumber bitNumber, final int value) { + protected void onFieldBits(final Object obj, final Field field, final Bin annotation, + final JBBPBitNumber bitNumber, final int value) { try { this.Bits(bitNumber, value); } catch (IOException ex) { @@ -1138,7 +1300,8 @@ protected void onFieldBits(final Object obj, final Field field, final Bin annota } @Override - protected void onFieldCustom(final Object obj, final Field field, final Bin annotation, final Object customFieldProcessor, final Object value) { + protected void onFieldCustom(final Object obj, final Field field, final Bin annotation, + final Object customFieldProcessor, final Object value) { try { final JBBPCustomFieldWriter writer = (JBBPCustomFieldWriter) customFieldProcessor; writer.writeCustomField(this, this.outStream, obj, field, annotation, value); diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOutVarProcessor.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOutVarProcessor.java index 973b84fb..b83fbc12 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOutVarProcessor.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOutVarProcessor.java @@ -33,5 +33,6 @@ public interface JBBPOutVarProcessor { * @return true is to continue processing of DSL commands, false skip all commands till the End() * @throws IOException it should be thrown for transport errors */ - boolean processVarOut(JBBPOut context, JBBPBitOutputStream outStream, Object... args) throws IOException; + boolean processVarOut(JBBPOut context, JBBPBitOutputStream outStream, Object... args) + throws IOException; } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/Bin.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/Bin.java index 2988d34a..37a4fb1e 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/Bin.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/Bin.java @@ -30,15 +30,14 @@ /** * The annotation describes a field in a class which can be mapped and loaded - * from parsed a JBBP structure. Also it can be used for whole class but in the + * from parsed a JBBP structure, also it can be used for whole class but in the * case be careful and use default name and path values. The Class is not thread safe. - * * Since 2.0.0 was removed prefix 'out' for fields which contained it. * * @since 1.0 */ @Retention(RetentionPolicy.RUNTIME) -@Target( {ElementType.FIELD, ElementType.TYPE}) +@Target({ElementType.FIELD, ElementType.TYPE}) @Inherited public @interface Bin { diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/BinFieldFilter.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/BinFieldFilter.java new file mode 100644 index 00000000..eb7fb24d --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/BinFieldFilter.java @@ -0,0 +1,38 @@ +/* + * Copyright 2022 Igor Maznitsa. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.igormaznitsa.jbbp.mapper; + +import java.lang.reflect.Field; + +/** + * Filter allows cheeking Bin annotation and fields during mapping or writing operations. + * + * @see com.igormaznitsa.jbbp.io.JBBPOut + * @see JBBPMapper#map + * @see com.igormaznitsa.jbbp.io.JBBPOut#Bin + * @since 2.0.4 + */ +public interface BinFieldFilter { + /** + * Check annotation and field that they allowed. + * + * @param annotation bin annotation, must not be null + * @param field marked field, can be null + * @return true if field allowed, false otherwise + */ + boolean isAllowed(Bin annotation, Field field); +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/BinType.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/BinType.java index 1f3a2a2f..d7f36d29 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/BinType.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/BinType.java @@ -28,6 +28,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldArrayString; import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUByte; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayUInt; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUShort; import com.igormaznitsa.jbbp.model.JBBPFieldBit; import com.igormaznitsa.jbbp.model.JBBPFieldBoolean; @@ -40,6 +41,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldString; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; import com.igormaznitsa.jbbp.model.JBBPFieldUByte; +import com.igormaznitsa.jbbp.model.JBBPFieldUInt; import com.igormaznitsa.jbbp.model.JBBPFieldUShort; /** @@ -83,6 +85,12 @@ public enum BinType { * A Mapping field will be mapped to a parsed integer field. */ INT(JBBPFieldInt.class, false), + /** + * A Mapping field will be mapped to a parsed unsigned integer field. + * + * @since 2.0.4 + */ + UINT(JBBPFieldUInt.class, false), /** * A Mapping field will be mapped to a parsed double field. * @@ -133,6 +141,10 @@ public enum BinType { * A Mapping field will be mapped to a parsed integer array field. */ INT_ARRAY(JBBPFieldArrayInt.class, true), + /** + * A Mapping field will be mapped to a parsed unsigned integer array field. + */ + UINT_ARRAY(JBBPFieldArrayUInt.class, true), /** * A Mapping field will be mapped to a parsed long array field. */ @@ -172,7 +184,7 @@ public enum BinType { /** * The Flag shows that the type describes an array. */ - private final boolean isarray; + private final boolean arrayFlag; /** * The Field class for the value. @@ -181,7 +193,7 @@ public enum BinType { */ BinType(final Class fieldClass, final boolean array) { this.fieldClass = fieldClass; - this.isarray = array; + this.arrayFlag = array; } /** @@ -255,7 +267,7 @@ public static BinType findCompatible(final Class fieldClazz) { * @return true if the type is an array, false otherwise */ public boolean isArray() { - return this.isarray; + return this.arrayFlag; } /** diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapper.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapper.java index 93144865..adb58652 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapper.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapper.java @@ -49,7 +49,8 @@ public final class JBBPMapper { * @since 1.1 */ public static final int FLAG_IGNORE_MISSING_VALUES = 1; - private static final Map, List> CACHED_FIELDS = new ConcurrentHashMap<>(); + private static final Map, List> CACHED_FIELDS = + new ConcurrentHashMap<>(); /** * Create a class instance, map binary data of a structure for its path to its @@ -57,7 +58,7 @@ public final class JBBPMapper { * * @param the mapping class type * @param root a parsed structure to be used as the root, must not be null - * @param structPath the path of a structure inside of the root to be mapped + * @param structPath the path of a structure inside the root to be mapped * to the class, must not be null * @param instance object to be filled by values, must not be null * @param instantiators functions to produce class instance by request, must not be null @@ -66,7 +67,8 @@ public final class JBBPMapper { * @since 2.0.0 */ @SafeVarargs - public static T map(final JBBPFieldStruct root, final String structPath, final T instance, final Function, Object>... instantiators) { + public static T map(final JBBPFieldStruct root, final String structPath, final T instance, + final Function, Object>... instantiators) { return map(root, structPath, instance, null, instantiators); } @@ -76,7 +78,7 @@ public static T map(final JBBPFieldStruct root, final String structPath, fin * * @param the mapping class type * @param root a parsed structure to be used as the root, must not be null - * @param structPath the path of a structure inside of the root to be mapped + * @param structPath the path of a structure inside the root to be mapped * to the class, must not be null * @param instance object to be filled by values, must not be null * @param flags special flags to tune mapping process @@ -88,7 +90,8 @@ public static T map(final JBBPFieldStruct root, final String structPath, fin * @since 2.0.0 */ @SafeVarargs - public static T map(final JBBPFieldStruct root, final String structPath, final T instance, final int flags, final Function, Object>... instantiators) { + public static T map(final JBBPFieldStruct root, final String structPath, final T instance, + final int flags, final Function, Object>... instantiators) { return map(root, structPath, instance, null, flags, instantiators); } @@ -98,7 +101,7 @@ public static T map(final JBBPFieldStruct root, final String structPath, fin * * @param the mapping class type * @param root a parsed structure to be used as the root, must not be null - * @param structPath the path of a structure inside of the root to be mapped + * @param structPath the path of a structure inside the root to be mapped * to the class, must not be null * @param instance instance to be filled by values, must not be null * @param customFieldProcessor a custom field processor to provide custom @@ -111,7 +114,9 @@ public static T map(final JBBPFieldStruct root, final String structPath, fin * @since 2.0.0 */ @SafeVarargs - public static T map(final JBBPFieldStruct root, final String structPath, final T instance, final JBBPMapperCustomFieldProcessor customFieldProcessor, final Function, Object>... instantiators) { + public static T map(final JBBPFieldStruct root, final String structPath, final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final Function, Object>... instantiators) { return map(root, structPath, instance, customFieldProcessor, 0, instantiators); } @@ -121,7 +126,7 @@ public static T map(final JBBPFieldStruct root, final String structPath, fin * * @param the mapping class type * @param root a parsed structure to be used as the root, must not be null - * @param structPath the path of a structure inside of the root to be mapped + * @param structPath the path of a structure inside the root to be mapped * to the class, must not be null * @param instance object to be filled by values, must not be null * @param customFieldProcessor a custom field processor to provide custom @@ -136,11 +141,15 @@ public static T map(final JBBPFieldStruct root, final String structPath, fin * @since 2.0.0 */ @SafeVarargs - public static T map(final JBBPFieldStruct root, final String structPath, final T instance, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags, final Function, Object>... instantiators) { + public static T map(final JBBPFieldStruct root, final String structPath, final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final int flags, final Function, Object>... instantiators) { JBBPUtils.assertNotNull(structPath, "Path must not be null"); final JBBPFieldStruct struct = root.findFieldForPathAndType(structPath, JBBPFieldStruct.class); if (struct == null) { - throw new JBBPMapperException("Can't find a structure field for its path [" + structPath + ']', null, instance.getClass(), null, null); + throw new JBBPMapperException( + "Can't find a structure field for its path [" + structPath + ']', null, + instance.getClass(), null, null); } return map(struct, instance, customFieldProcessor, flags, instantiators); } @@ -161,7 +170,8 @@ public static T map(final JBBPFieldStruct root, final String structPath, fin * @since 2.0.0 */ @SafeVarargs - public static T map(final JBBPFieldStruct root, final T instance, final Function, Object>... instantiators) { + public static T map(final JBBPFieldStruct root, final T instance, + final Function, Object>... instantiators) { return map(root, instance, null, instantiators); } @@ -184,7 +194,8 @@ public static T map(final JBBPFieldStruct root, final T instance, final Func * @since 2.0.0 */ @SafeVarargs - public static T map(final JBBPFieldStruct root, final T instance, final int flags, final Function, Object>... instantiators) { + public static T map(final JBBPFieldStruct root, final T instance, final int flags, + final Function, Object>... instantiators) { return map(root, instance, null, flags, instantiators); } @@ -205,44 +216,59 @@ public static T map(final JBBPFieldStruct root, final T instance, final int * @throws JBBPMapperException for any error */ @SafeVarargs - public static T map(final JBBPFieldStruct rootStructure, final T instance, final JBBPMapperCustomFieldProcessor customFieldProcessor, final Function, Object>... instantiators) { + public static T map(final JBBPFieldStruct rootStructure, final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final Function, Object>... instantiators) { return map(rootStructure, instance, customFieldProcessor, 0, instantiators); } @SafeVarargs @SuppressWarnings("varargs") private static void processFieldOfMappedClass( - final MappedFieldRecord record, - final JBBPFieldStruct rootStructure, - final Object instance, - final JBBPMapperCustomFieldProcessor customFieldProcessor, - final int flags, - final Function, Object>... instantiators + final MappedFieldRecord record, + final JBBPFieldStruct rootStructure, + final Object instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final int flags, + final BinFieldFilter binFieldFilter, + final Function, Object>... instantiators ) { if (record.binAnnotation.custom()) { - JBBPUtils.assertNotNull(customFieldProcessor, "There is a custom mapping field, in the case you must provide a custom mapping field processor"); - final Object value = customFieldProcessor.prepareObjectForMapping(rootStructure, record.binAnnotation, record.mappingField); + JBBPUtils.assertNotNull(customFieldProcessor, + "There is a custom mapping field, in the case you must provide a custom mapping field processor"); + final Object value = customFieldProcessor + .prepareObjectForMapping(rootStructure, record.binAnnotation, record.mappingField); MappedFieldRecord.setFieldValue(instance, record.setter, record.mappingField, null, value); } else { final JBBPAbstractField binField; - if (record.fieldPath.length() == 0) { - binField = record.fieldName.length() == 0 ? rootStructure.findFieldForType(record.fieldType.getFieldClass()) : rootStructure.findFieldForNameAndType(record.fieldName, record.fieldType.getFieldClass()); + if (record.fieldPath.isEmpty()) { + binField = record.fieldName.isEmpty() ? + rootStructure.findFieldForType(record.fieldType.getFieldClass()) : rootStructure + .findFieldForNameAndType(record.fieldName, record.fieldType.getFieldClass()); } else { - binField = rootStructure.findFieldForPathAndType(record.fieldPath, record.fieldType.getFieldClass()); + binField = rootStructure + .findFieldForPathAndType(record.fieldPath, record.fieldType.getFieldClass()); } if (binField == null) { if ((flags & FLAG_IGNORE_MISSING_VALUES) != 0) { return; } - throw new JBBPMapperException("Can't find value for mapping field [" + record.mappingField + ']', null, record.mappingClass, record.mappingField, null); + throw new JBBPMapperException( + "Can't find value for mapping field [" + record.mappingField + ']', null, + record.mappingClass, record.mappingField, null); } - if (record.bitWideField && record.mappedBitNumber != JBBPBitNumber.BITS_8 && ((BitEntity) binField).getBitWidth() != record.mappedBitNumber) { - throw new JBBPMapperException("Can't map mapping field because wrong field bitness [" + record.mappedBitNumber + "!=" + ((BitEntity) binField).getBitWidth().getBitNumber() + ']', null, record.mappingClass, record.mappingField, null); + if (record.bitWideField && record.mappedBitNumber != JBBPBitNumber.BITS_8 && + ((BitEntity) binField).getBitWidth() != record.mappedBitNumber) { + throw new JBBPMapperException( + "Can't map mapping field because wrong field bitness [" + record.mappedBitNumber + + "!=" + ((BitEntity) binField).getBitWidth().getBitNumber() + ']', null, + record.mappingClass, record.mappingField, null); } - record.proc.apply(record, rootStructure, instance, customFieldProcessor, binField, flags, instantiators); + record.proc.apply(record, rootStructure, instance, customFieldProcessor, binField, flags, + binFieldFilter, instantiators); } } @@ -267,19 +293,53 @@ private static void processFieldOfMappedClass( */ @SafeVarargs @SuppressWarnings("varargs") - public static T map(final JBBPFieldStruct rootStructure, final T instance, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags, final Function, Object>... instantiators) { + public static T map(final JBBPFieldStruct rootStructure, final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final int flags, + final Function, Object>... instantiators) { + return map(rootStructure, instance, customFieldProcessor, flags, null, instantiators); + } + + /** + * Map a structure to a class instance. + * + * @param the mapping class type + * @param rootStructure a structure to be mapped, must not be null + * @param instance a class instance to be destination for map + * operations, must not be null + * @param customFieldProcessor a custom field processor to provide custom + * values, it can be null if there is not any mapping field desires the + * processor + * @param flags special flags for mapping process + * @param binFieldFilter filter allows to exclude some fields from process, can be null + * @param instantiators functions to produce class instance by request, must + * not be null + * @return the processed class instance, the same which was the argument for + * the method. + * @throws JBBPMapperException for any error + * @see #FLAG_IGNORE_MISSING_VALUES + * @since 2.0.4 + */ + @SafeVarargs + @SuppressWarnings("varargs") + public static T map(final JBBPFieldStruct rootStructure, final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final int flags, + final BinFieldFilter binFieldFilter, + final Function, Object>... instantiators) { JBBPUtils.assertNotNull(rootStructure, "The Root structure must not be null"); JBBPUtils.assertNotNull(instance, "The Mapping class instance must not be null"); // Don't use forEach() for Android compatibility! - for (final MappedFieldRecord record : findAffectedFields(instance)) { + for (final MappedFieldRecord record : findAffectedFields(instance, binFieldFilter)) { processFieldOfMappedClass( - record, - rootStructure, - instance, - customFieldProcessor, - flags, - instantiators + record, + rootStructure, + instance, + customFieldProcessor, + flags, + binFieldFilter, + instantiators ); } return instance; @@ -304,7 +364,7 @@ public static void clearFieldCache() { CACHED_FIELDS.clear(); } - public static List findAffectedFields(final Object instance) { + public static List findAffectedFields(final Object instance, final BinFieldFilter binFieldFilter) { final Class mappingClass = instance.getClass(); List result = CACHED_FIELDS.get(mappingClass); @@ -319,8 +379,8 @@ public static List findAffectedFields(final Object instance) while (current != null) { final String packageName = current.getPackage().getName(); if (packageName.startsWith("java.") - || packageName.startsWith("javax.") - || packageName.startsWith("android.") + || packageName.startsWith("javax.") + || packageName.startsWith("android.") ) { break; } @@ -334,15 +394,16 @@ public static List findAffectedFields(final Object instance) final Bin fieldAnno = mappingField.getAnnotation(Bin.class); final Bin mappedAnno; - if ((fieldAnno == null && defaultAnno == null) || mappingField.getName().indexOf('$') >= 0) { + if ((fieldAnno == null && defaultAnno == null) || + mappingField.getName().indexOf('$') >= 0) { continue; } mappedAnno = fieldAnno == null ? defaultAnno : fieldAnno; if (fieldAnno == null) { if (Modifier.isTransient(fieldModifiers) - || Modifier.isStatic(fieldModifiers) - || Modifier.isFinal(fieldModifiers)) { + || Modifier.isStatic(fieldModifiers) + || Modifier.isFinal(fieldModifiers)) { continue; } } else { @@ -355,26 +416,33 @@ public static List findAffectedFields(final Object instance) disallowedModifier = null; } if (disallowedModifier != null) { - throw new JBBPMapperException("Detected @Bin marked " + disallowedModifier + " field", null, processingClazz, mappingField, null); + throw new JBBPMapperException("Detected @Bin marked " + disallowedModifier + " field", + null, processingClazz, mappingField, null); } } - final NullableTriple auxMethods = findAuxFieldMethods(processingClazz, mappingField); + final NullableTriple auxMethods = + findAuxFieldMethods(processingClazz, mappingField); final Method fieldGenerator = auxMethods.getA(); final Method fieldGetter = auxMethods.getB(); final Method fieldSetter = auxMethods.getC(); - if (mappingField.getType().isPrimitive() && fieldSetter == null && Modifier.isPrivate(mappingField.getModifiers())) { - throw new JBBPMapperException("Detected private primitive field, mapping requires setter", null, processingClazz, mappingField, null); + if (mappingField.getType().isPrimitive() && fieldSetter == null && + Modifier.isPrivate(mappingField.getModifiers())) { + throw new JBBPMapperException( + "Detected private primitive field, mapping requires setter", null, processingClazz, + mappingField, null); } - if (fieldGetter == null && fieldGenerator == null && !ReflectUtils.isPotentiallyAccessibleField(mappingField)) { + if (fieldGetter == null && fieldGenerator == null && + !ReflectUtils.isPotentiallyAccessibleField(mappingField)) { mappingField = ReflectUtils.makeAccessible(mappingField); } try { - result.add(new MappedFieldRecord(mappingField, fieldGenerator, fieldSetter, fieldGetter, mappingClass, mappedAnno)); + result.add(new MappedFieldRecord(mappingField, fieldGenerator, fieldSetter, fieldGetter, + mappingClass, mappedAnno)); } catch (IllegalStateException ex) { throw new JBBPMapperException(ex.getMessage(), null, mappingClass, mappingField, ex); } @@ -386,10 +454,21 @@ public static List findAffectedFields(final Object instance) CACHED_FIELDS.put(mappingClass, result); } + if (binFieldFilter != null) { + final List filteredRecords = new ArrayList<>(); + for (final MappedFieldRecord r : result) { + if (binFieldFilter.isAllowed(r.binAnnotation, r.mappingField)) { + filteredRecords.add(r); + } + } + result = filteredRecords; + } + return result; } - private static NullableTriple findAuxFieldMethods(final Class klazz, final Field field) { + private static NullableTriple findAuxFieldMethods(final Class klazz, + final Field field) { final String lowerCasedFieldName = field.getName().toLowerCase(Locale.ENGLISH); final String generatorName = "make" + lowerCasedFieldName; final String getterName = "get" + lowerCasedFieldName; @@ -417,7 +496,8 @@ private static NullableTriple findAuxFieldMethods(final } } - if (args.length == 1 && setter == null && lcMethodName.equals(setterName) && field.getType().isAssignableFrom(args[0])) { + if (args.length == 1 && setter == null && lcMethodName.equals(setterName) && + field.getType().isAssignableFrom(args[0])) { setter = m; } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapperCustomFieldProcessor.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapperCustomFieldProcessor.java index 3a5a6d55..a46bca3e 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapperCustomFieldProcessor.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapperCustomFieldProcessor.java @@ -17,7 +17,6 @@ package com.igormaznitsa.jbbp.mapper; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; - import java.lang.reflect.Field; /** @@ -34,5 +33,6 @@ public interface JBBPMapperCustomFieldProcessor { * @param field the mapping field in a mapping class, must not be null * @return an object which will be set to the field in a mapping class instance, it can be null for non-primitive fields */ - Object prepareObjectForMapping(final JBBPFieldStruct parsedBlock, final Bin annotation, final Field field); + Object prepareObjectForMapping(final JBBPFieldStruct parsedBlock, final Bin annotation, + final Field field); } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/MappedFieldRecord.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/MappedFieldRecord.java index bb1131fd..07084e8c 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/MappedFieldRecord.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/MappedFieldRecord.java @@ -2,7 +2,6 @@ import static com.igormaznitsa.jbbp.mapper.JBBPMapper.MAKE_CLASS_INSTANCE_METHOD_NAME; - import com.igormaznitsa.jbbp.exceptions.JBBPMapperException; import com.igormaznitsa.jbbp.io.JBBPBitNumber; import com.igormaznitsa.jbbp.io.JBBPBitOrder; @@ -15,6 +14,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldArrayShort; import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUByte; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayUInt; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUShort; import com.igormaznitsa.jbbp.model.JBBPFieldInt; import com.igormaznitsa.jbbp.model.JBBPFieldLong; @@ -29,128 +29,162 @@ import java.lang.reflect.Modifier; public final class MappedFieldRecord implements Comparable { - private static final Function, Object> STATIC_MAKE_CLASS_INSTANCE_INSTANTIATOR = (Class klazz) -> { - Class currentClass = klazz; - Object result = null; - boolean find; - do { - try { - final Method method = currentClass.getMethod(MAKE_CLASS_INSTANCE_METHOD_NAME, Class.class); - if (Modifier.isStatic(method.getModifiers())) { - result = method.invoke(null, klazz); - } - } catch (IllegalAccessException ex) { - throw new RuntimeException(String.format("Can't get access to static method %s(%ss) in %s", MAKE_CLASS_INSTANCE_METHOD_NAME, klazz, currentClass), ex); - } catch (InvocationTargetException ex) { - throw new RuntimeException(String.format("Can't call static method %s(%s) in %s", MAKE_CLASS_INSTANCE_METHOD_NAME, klazz, currentClass), ex); - } catch (NoSuchMethodException ex) { - // do nothing! - } - if (result == null) { - if (currentClass.isLocalClass()) { - currentClass = currentClass.getEnclosingClass(); - find = currentClass != null; - } else { - find = false; + private static final Function, Object> STATIC_MAKE_CLASS_INSTANCE_INSTANTIATOR = + (Class klazz) -> { + Class currentClass = klazz; + Object result = null; + boolean find; + do { + try { + final Method method = + currentClass.getMethod(MAKE_CLASS_INSTANCE_METHOD_NAME, Class.class); + if (Modifier.isStatic(method.getModifiers())) { + result = method.invoke(null, klazz); + } + } catch (IllegalAccessException ex) { + throw new RuntimeException(String + .format("Can't get access to static method %s(%ss) in %s", + MAKE_CLASS_INSTANCE_METHOD_NAME, klazz, currentClass), ex); + } catch (InvocationTargetException ex) { + throw new RuntimeException(String + .format("Can't call static method %s(%s) in %s", MAKE_CLASS_INSTANCE_METHOD_NAME, + klazz, currentClass), ex); + } catch (NoSuchMethodException ex) { + // do nothing! + } + if (result == null) { + if (currentClass.isLocalClass()) { + currentClass = currentClass.getEnclosingClass(); + find = currentClass != null; + } else { + find = false; + } + } else { + find = false; + } + } while (find); + return result; + }; + private static final Function, Object> DEFAULT_CONSTRUCTOR_INSTANTIATOR = + (Class aClass) -> { + try { + if (!aClass.isLocalClass() || Modifier.isStatic(aClass.getModifiers())) { + return aClass.getConstructor().newInstance(); + } else { + return null; + } + } catch (NoSuchMethodException ex) { + return null; + } catch (InvocationTargetException ex) { + throw new RuntimeException( + String.format("Error during default constructor call, class %s", aClass), ex); + } catch (IllegalAccessException ex) { + throw new RuntimeException( + String.format("Can't get access to default constructor , class %s", aClass), ex); + } catch (InstantiationException ex) { + throw new RuntimeException(String.format("Can't make instance of class %s", aClass), ex); } - } else { - find = false; - } - } while (find); - return result; - }; - private static final Function, Object> DEFAULT_CONSTRUCTOR_INSTANTIATOR = (Class aClass) -> { - try { - if (!aClass.isLocalClass() || Modifier.isStatic(aClass.getModifiers())) { - return aClass.getConstructor().newInstance(); - } else { - return null; - } - } catch (NoSuchMethodException ex) { - return null; - } catch (InvocationTargetException ex) { - throw new RuntimeException(String.format("Error during default constructor call, class %s", aClass), ex); - } catch (IllegalAccessException ex) { - throw new RuntimeException(String.format("Can't get access to default constructor , class %s", aClass), ex); - } catch (InstantiationException ex) { - throw new RuntimeException(String.format("Can't make instance of class %s", aClass), ex); - } - }; - private static final FieldProcessor PROC_ARRAYS = (record, rootStructure, instance, customFieldProcessor, binField, flags, instantiators) -> { + }; + private static final FieldProcessor PROC_ARRAYS = + (record, rootStructure, instance, customFieldProcessor, binField, flags, binFieldFilter, instantiators) -> { - if (binField instanceof JBBPAbstractArrayField) { - if (binField instanceof JBBPFieldArrayStruct) { - // structure - final JBBPFieldArrayStruct structArray = (JBBPFieldArrayStruct) binField; - final Class componentType = record.mappingField.getType().getComponentType(); + if (binField instanceof JBBPAbstractArrayField) { + if (binField instanceof JBBPFieldArrayStruct) { + // structure + final JBBPFieldArrayStruct structArray = (JBBPFieldArrayStruct) binField; + final Class componentType = record.mappingField.getType().getComponentType(); - Object valueArray = getFieldValue(instance, record.getter, record.mappingField); + Object valueArray = getFieldValue(instance, record.getter, record.mappingField); - valueArray = valueArray == null ? Array.newInstance(componentType, structArray.size()) : valueArray; + valueArray = valueArray == null ? Array.newInstance(componentType, structArray.size()) : + valueArray; - if (Array.getLength(valueArray) != structArray.size()) { - throw new JBBPMapperException("Can't map an array field for different expected size [" + Array.getLength(valueArray) + "!=" + structArray.size() + ']', binField, record.mappingClass, record.mappingField, null); - } + if (Array.getLength(valueArray) != structArray.size()) { + throw new JBBPMapperException( + "Can't map an array field for different expected size [" + + Array.getLength(valueArray) + "!=" + structArray.size() + ']', binField, + record.mappingClass, record.mappingField, null); + } - for (int i = 0; i < structArray.size(); i++) { - final Object curInstance = Array.get(valueArray, i); - if (curInstance == null) { - Array.set(valueArray, i, JBBPMapper.map(structArray.getElementAt(i), tryMakeInstance(componentType, binField, instance, record.mappingField, instantiators), customFieldProcessor, instantiators)); + for (int i = 0; i < structArray.size(); i++) { + final Object curInstance = Array.get(valueArray, i); + if (curInstance == null) { + Array.set(valueArray, i, JBBPMapper.map(structArray.getElementAt(i), + tryMakeInstance(componentType, binField, instance, record.mappingField, + instantiators), customFieldProcessor, 0, binFieldFilter, instantiators)); + } else { + Array.set(valueArray, i, + JBBPMapper.map(structArray.getElementAt(i), curInstance, customFieldProcessor, 0, binFieldFilter)); + } + } + setFieldValue(instance, record.setter, record.mappingField, binField, valueArray); } else { - Array.set(valueArray, i, JBBPMapper.map(structArray.getElementAt(i), curInstance, customFieldProcessor)); + // primitive + mapArrayField(instance, record.setter, record.mappingField, + (JBBPAbstractArrayField) binField, + record.binAnnotation.bitOrder() == JBBPBitOrder.MSB0); } + } else { + throw new JBBPMapperException("Can't map a non-array value to an array mapping field", + binField, record.mappingClass, record.mappingField, null); } - setFieldValue(instance, record.setter, record.mappingField, binField, valueArray); - } else { - // primitive - mapArrayField(instance, record.setter, record.mappingField, (JBBPAbstractArrayField) binField, record.binAnnotation.bitOrder() == JBBPBitOrder.MSB0); - } - } else { - throw new JBBPMapperException("Can't map a non-array value to an array mapping field", binField, record.mappingClass, record.mappingField, null); - } - }; - private static final FieldProcessor PROC_NUM = (record, rootStructure, instance, customFieldProcessor, binField, flags, instantiators) -> { - if (binField instanceof JBBPNumericField) { - mapNumericField(instance, record.setter, record.mappingField, (JBBPNumericField) binField, record.binAnnotation.bitOrder() == JBBPBitOrder.MSB0); - } else if (binField instanceof JBBPFieldString) { - if (record.mappingField.getType().isPrimitive()) { - throw new JBBPMapperException("Can't map string to a primitive mapping field", binField, record.mappingClass, record.mappingField, null); - } else { - setFieldValue(instance, record.setter, record.mappingField, binField, ((JBBPFieldString) binField).getAsString()); - } - } else if (binField instanceof JBBPFieldStruct) { - if (record.mappingField.getType().isPrimitive()) { - throw new JBBPMapperException("Can't map structure to a primitive mapping field", binField, record.mappingClass, record.mappingField, null); - } else { - final Object curValue = getFieldValue(instance, record.getter, record.mappingField); - if (curValue == null) { - if (record.instanceMaker == null) { - setFieldValue(instance, record.setter, record.mappingField, binField, JBBPMapper.map((JBBPFieldStruct) binField, tryMakeInstance(record.mappingField.getType(), binField, instance, record.mappingField, instantiators), customFieldProcessor)); + }; + private static final FieldProcessor PROC_NUM = + (record, rootStructure, instance, customFieldProcessor, binField, flags, binFieldFilter, instantiators) -> { + if (binField instanceof JBBPNumericField) { + mapNumericField(instance, record.setter, record.mappingField, (JBBPNumericField) binField, + record.binAnnotation.bitOrder() == JBBPBitOrder.MSB0); + } else if (binField instanceof JBBPFieldString) { + if (record.mappingField.getType().isPrimitive()) { + throw new JBBPMapperException("Can't map string to a primitive mapping field", binField, + record.mappingClass, record.mappingField, null); + } else { + setFieldValue(instance, record.setter, record.mappingField, binField, + ((JBBPFieldString) binField).getAsString()); + } + } else if (binField instanceof JBBPFieldStruct) { + if (record.mappingField.getType().isPrimitive()) { + throw new JBBPMapperException("Can't map structure to a primitive mapping field", + binField, record.mappingClass, record.mappingField, null); } else { - try { - JBBPMapper.map((JBBPFieldStruct) binField, record.instanceMaker.invoke(instance)); - } catch (Exception ex) { - throw new JBBPMapperException("Can't map field which member generatet by instance", binField, record.mappingClass, record.mappingField, ex); + final Object curValue = getFieldValue(instance, record.getter, record.mappingField); + if (curValue == null) { + if (record.instanceMaker == null) { + setFieldValue(instance, record.setter, record.mappingField, binField, JBBPMapper + .map((JBBPFieldStruct) binField, + tryMakeInstance(record.mappingField.getType(), binField, instance, + record.mappingField, instantiators), customFieldProcessor, 0, binFieldFilter)); + } else { + try { + JBBPMapper.map((JBBPFieldStruct) binField, record.instanceMaker.invoke(instance)); + } catch (Exception ex) { + throw new JBBPMapperException( + "Can't map field which member generated by instance", binField, + record.mappingClass, record.mappingField, ex); + } + } + } else { + setFieldValue(instance, record.setter, record.mappingField, binField, + JBBPMapper.map((JBBPFieldStruct) binField, curValue, customFieldProcessor)); } } } else { - setFieldValue(instance, record.setter, record.mappingField, binField, JBBPMapper.map((JBBPFieldStruct) binField, curValue, customFieldProcessor)); - } - } - } else { - boolean processed = false; - if (record.mappingField.getType() == String.class && binField instanceof JBBPAbstractArrayField) { - final String convertedValue = convertFieldValueToString((JBBPAbstractArrayField) binField); - if (convertedValue != null) { - setFieldValue(instance, record.setter, record.mappingField, binField, convertedValue); - processed = true; + boolean processed = false; + if (record.mappingField.getType() == String.class && + binField instanceof JBBPAbstractArrayField) { + final String convertedValue = + convertFieldValueToString((JBBPAbstractArrayField) binField); + if (convertedValue != null) { + setFieldValue(instance, record.setter, record.mappingField, binField, convertedValue); + processed = true; + } + } + if (!processed) { + throw new JBBPMapperException("Can't map a field for its value incompatibility", + binField, record.mappingClass, record.mappingField, null); + } } - } - if (!processed) { - throw new JBBPMapperException("Can't map a field for its value incompatibility", binField, record.mappingClass, record.mappingField, null); - } - } - }; + }; public final Field mappingField; public final Class mappingClass; @@ -182,19 +216,21 @@ public final class MappedFieldRecord implements Comparable { this.mappedBitNumber = binAnnotation.bitNumber(); if (binAnnotation.type() == BinType.UNDEFINED) { - BinType thetype = BinType.findCompatible(mappingField.getType()); - if (thetype == null) { + BinType compatibleBinType = BinType.findCompatible(mappingField.getType()); + if (compatibleBinType == null) { throw new IllegalStateException("Can't find compatible mapped type for field"); - } else if (this.mappedBitNumber.getBitNumber() < 8 && !(thetype == BinType.STRUCT || thetype == BinType.STRUCT_ARRAY)) { - thetype = thetype.isArray() ? BinType.BIT_ARRAY : BinType.BIT; + } else if (this.mappedBitNumber.getBitNumber() < 8 && + !(compatibleBinType == BinType.STRUCT || compatibleBinType == BinType.STRUCT_ARRAY)) { + compatibleBinType = compatibleBinType.isArray() ? BinType.BIT_ARRAY : BinType.BIT; } - this.fieldType = thetype; + this.fieldType = compatibleBinType; } else { this.fieldType = binAnnotation.type(); } this.bitWideField = this.fieldType == BinType.BIT || fieldType == BinType.BIT_ARRAY; - this.fieldName = binAnnotation.name().length() == 0 ? mappingField.getName() : binAnnotation.name(); + this.fieldName = + binAnnotation.name().isEmpty() ? mappingField.getName() : binAnnotation.name(); this.fieldPath = binAnnotation.path(); if (this.mappingField.getType().isArray()) { @@ -215,30 +251,60 @@ public final class MappedFieldRecord implements Comparable { * @param invertBitOrder flag shows that values of an array must be bit * reversed before set */ - private static void mapArrayField(final Object mappingClassInstance, final Method setter, final Field mappingField, final JBBPAbstractArrayField arrayField, final boolean invertBitOrder) { + private static void mapArrayField(final Object mappingClassInstance, final Method setter, + final Field mappingField, + final JBBPAbstractArrayField arrayField, + final boolean invertBitOrder) { try { final Object value; - if (arrayField instanceof JBBPFieldArrayLong && mappingField.getType().getComponentType() == double.class) { - final long[] longarray = (long[]) arrayField.getValueArrayAsObject(invertBitOrder); - final double[] doublearray = new double[longarray.length]; - for (int i = 0; i < longarray.length; i++) { - doublearray[i] = Double.longBitsToDouble(longarray[i]); + if (arrayField instanceof JBBPFieldArrayLong && + mappingField.getType().getComponentType() == double.class) { + final long[] longArray = (long[]) arrayField.getValueArrayAsObject(invertBitOrder); + final double[] doubleArray = new double[longArray.length]; + for (int i = 0; i < longArray.length; i++) { + doubleArray[i] = Double.longBitsToDouble(longArray[i]); + } + value = doubleArray; + } else if (arrayField instanceof JBBPFieldArrayUInt && + mappingField.getType().getComponentType() == double.class) { + final long[] longArray = (long[]) arrayField.getValueArrayAsObject(invertBitOrder); + final double[] doubleArray = new double[longArray.length]; + for (int i = 0; i < longArray.length; i++) { + doubleArray[i] = Double.longBitsToDouble(longArray[i]); + } + value = doubleArray; + } else if (arrayField instanceof JBBPFieldArrayInt && + mappingField.getType().getComponentType() == float.class) { + final int[] intArray = (int[]) arrayField.getValueArrayAsObject(invertBitOrder); + final float[] floatArray = new float[intArray.length]; + for (int i = 0; i < intArray.length; i++) { + floatArray[i] = Float.intBitsToFloat(intArray[i]); + } + value = floatArray; + } else if (arrayField instanceof JBBPFieldArrayUInt && + mappingField.getType().getComponentType() == float.class) { + final long[] longArray = (long[]) arrayField.getValueArrayAsObject(invertBitOrder); + final float[] floatArray = new float[longArray.length]; + for (int i = 0; i < longArray.length; i++) { + floatArray[i] = Float.intBitsToFloat((int) longArray[i]); } - value = doublearray; - } else if (arrayField instanceof JBBPFieldArrayInt && mappingField.getType().getComponentType() == float.class) { - final int[] intarray = (int[]) arrayField.getValueArrayAsObject(invertBitOrder); - final float[] floatarray = new float[intarray.length]; - for (int i = 0; i < intarray.length; i++) { - floatarray[i] = Float.intBitsToFloat(intarray[i]); + value = floatArray; + } else if (arrayField instanceof JBBPFieldArrayUInt && + mappingField.getType().getComponentType() == int.class) { + final long[] longArray = (long[]) arrayField.getValueArrayAsObject(invertBitOrder); + final int[] intArray = new int[longArray.length]; + for (int i = 0; i < longArray.length; i++) { + intArray[i] = (int) longArray[i]; } - value = floatarray; - } else if (arrayField instanceof JBBPFieldArrayUShort && mappingField.getType().getComponentType() == char.class) { - final short[] shortarray = (short[]) arrayField.getValueArrayAsObject(invertBitOrder); - final char[] chararray = new char[shortarray.length]; - for (int i = 0; i < shortarray.length; i++) { - chararray[i] = (char) shortarray[i]; + value = intArray; + } else if (arrayField instanceof JBBPFieldArrayUShort && + mappingField.getType().getComponentType() == char.class) { + final short[] shortArray = (short[]) arrayField.getValueArrayAsObject(invertBitOrder); + final char[] charArray = new char[shortArray.length]; + for (int i = 0; i < shortArray.length; i++) { + charArray[i] = (char) shortArray[i]; } - value = chararray; + value = charArray; } else { value = arrayField.getValueArrayAsObject(invertBitOrder); } @@ -248,11 +314,14 @@ private static void mapArrayField(final Object mappingClassInstance, final Metho setter.invoke(mappingClassInstance, value); } } catch (IllegalAccessException ex) { - throw new JBBPMapperException("Can't get access to a mapping field", arrayField, mappingClassInstance.getClass(), mappingField, ex); + throw new JBBPMapperException("Can't get access to a mapping field", arrayField, + mappingClassInstance.getClass(), mappingField, ex); } catch (IllegalArgumentException ex) { - throw new JBBPMapperException("Can't set argument to a mapping field", arrayField, mappingClassInstance.getClass(), mappingField, ex); + throw new JBBPMapperException("Can't set argument to a mapping field", arrayField, + mappingClassInstance.getClass(), mappingField, ex); } catch (InvocationTargetException ex) { - throw new JBBPMapperException("Can't set argument to field through setter", arrayField, mappingClassInstance.getClass(), mappingField, ex); + throw new JBBPMapperException("Can't set argument to field through setter", arrayField, + mappingClassInstance.getClass(), mappingField, ex); } } @@ -313,11 +382,14 @@ private static String convertFieldValueToString(final JBBPAbstractArrayField * @param invertBitOrder flag shows that the parsed numeric field value must * be reversed in its bit before setting */ - private static void mapNumericField(final Object mappingClassInstance, final Method setter, final Field mappingField, final JBBPNumericField numericField, final boolean invertBitOrder) { + private static void mapNumericField(final Object mappingClassInstance, final Method setter, + final Field mappingField, final JBBPNumericField numericField, + final boolean invertBitOrder) { final Class fieldClass = mappingField.getType(); try { if (fieldClass == byte.class) { - final byte value = (byte) (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsInt()); + final byte value = (byte) (invertBitOrder ? numericField.getAsInvertedBitOrder() : + numericField.getAsInt()); if (setter == null) { mappingField.setByte(mappingClassInstance, value); } else { @@ -330,28 +402,32 @@ private static void mapNumericField(final Object mappingClassInstance, final Met setter.invoke(mappingClassInstance, numericField.getAsBool()); } } else if (fieldClass == char.class) { - final char value = (char) (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsInt()); + final char value = (char) (invertBitOrder ? numericField.getAsInvertedBitOrder() : + numericField.getAsInt()); if (setter == null) { mappingField.setChar(mappingClassInstance, value); } else { setter.invoke(mappingClassInstance, value); } } else if (fieldClass == short.class) { - final short value = (short) (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsInt()); + final short value = (short) (invertBitOrder ? numericField.getAsInvertedBitOrder() : + numericField.getAsInt()); if (setter == null) { mappingField.setShort(mappingClassInstance, value); } else { setter.invoke(mappingClassInstance, value); } } else if (fieldClass == int.class) { - final int value = (int) (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsInt()); + final int value = + (int) (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsInt()); if (setter == null) { mappingField.setInt(mappingClassInstance, value); } else { setter.invoke(mappingClassInstance, value); } } else if (fieldClass == long.class) { - final long value = (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsLong()); + final long value = + (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsLong()); if (setter == null) { mappingField.setLong(mappingClassInstance, value); } else { @@ -360,9 +436,13 @@ private static void mapNumericField(final Object mappingClassInstance, final Met } else if (fieldClass == float.class) { final float value; if (numericField instanceof JBBPFieldInt) { - value = invertBitOrder ? Float.intBitsToFloat((int) numericField.getAsInvertedBitOrder()) : Float.intBitsToFloat(numericField.getAsInt()); + value = + invertBitOrder ? Float.intBitsToFloat((int) numericField.getAsInvertedBitOrder()) : + Float.intBitsToFloat(numericField.getAsInt()); } else { - value = invertBitOrder ? Float.intBitsToFloat((int) numericField.getAsInvertedBitOrder()) : numericField.getAsFloat(); + value = + invertBitOrder ? Float.intBitsToFloat((int) numericField.getAsInvertedBitOrder()) : + numericField.getAsFloat(); } if (setter == null) { mappingField.setFloat(mappingClassInstance, value); @@ -372,9 +452,11 @@ private static void mapNumericField(final Object mappingClassInstance, final Met } else if (fieldClass == double.class) { final double value; if (numericField instanceof JBBPFieldLong) { - value = invertBitOrder ? Double.longBitsToDouble(numericField.getAsInvertedBitOrder()) : Double.longBitsToDouble(numericField.getAsLong()); + value = invertBitOrder ? Double.longBitsToDouble(numericField.getAsInvertedBitOrder()) : + Double.longBitsToDouble(numericField.getAsLong()); } else { - value = invertBitOrder ? Double.longBitsToDouble(numericField.getAsInvertedBitOrder()) : numericField.getAsDouble(); + value = invertBitOrder ? Double.longBitsToDouble(numericField.getAsInvertedBitOrder()) : + numericField.getAsDouble(); } if (setter == null) { mappingField.setDouble(mappingClassInstance, value); @@ -382,14 +464,19 @@ private static void mapNumericField(final Object mappingClassInstance, final Met setter.invoke(mappingClassInstance, value); } } else { - throw new JBBPMapperException("Unsupported mapping class field type to be mapped for binary parsed data", (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, null); + throw new JBBPMapperException( + "Unsupported mapping class field type to be mapped for binary parsed data", + (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, null); } } catch (IllegalAccessException ex) { - throw new JBBPMapperException("Can't get access to a mapping field", (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, ex); + throw new JBBPMapperException("Can't get access to a mapping field", + (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, ex); } catch (IllegalArgumentException ex) { - throw new JBBPMapperException("Can't set argument to a mapping field", (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, ex); + throw new JBBPMapperException("Can't set argument to a mapping field", + (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, ex); } catch (InvocationTargetException ex) { - throw new JBBPMapperException("Can't set argument to a mapping field through setter", (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, ex); + throw new JBBPMapperException("Can't set argument to a mapping field through setter", + (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, ex); } } @@ -402,7 +489,8 @@ private static void mapNumericField(final Object mappingClassInstance, final Met * null * @return the field value for the class instance */ - private static Object getFieldValue(final Object classInstance, final Method getter, final Field classField) { + private static Object getFieldValue(final Object classInstance, final Method getter, + final Field classField) { try { if (getter == null) { return classField.get(classInstance); @@ -410,11 +498,14 @@ private static Object getFieldValue(final Object classInstance, final Method get return getter.invoke(classInstance); } } catch (IllegalArgumentException ex) { - throw new JBBPMapperException("Can't set get value from a mapping field", null, classInstance.getClass(), classField, ex); + throw new JBBPMapperException("Can't set get value from a mapping field", null, + classInstance.getClass(), classField, ex); } catch (IllegalAccessException ex) { - throw new JBBPMapperException("Can't get access to a mapping field", null, classInstance.getClass(), classField, ex); + throw new JBBPMapperException("Can't get access to a mapping field", null, + classInstance.getClass(), classField, ex); } catch (InvocationTargetException ex) { - throw new JBBPMapperException("Can't get field value through getter", null, classInstance.getClass(), classField, ex); + throw new JBBPMapperException("Can't get field value through getter", null, + classInstance.getClass(), classField, ex); } } @@ -429,7 +520,8 @@ private static Object getFieldValue(final Object classInstance, final Method get * @param binField a parsed bin field which value will be set, can be null * @param value a value to be set to the class field */ - static void setFieldValue(final Object classInstance, final Method setter, final Field classField, final JBBPAbstractField binField, final Object value) { + static void setFieldValue(final Object classInstance, final Method setter, final Field classField, + final JBBPAbstractField binField, final Object value) { try { if (setter == null) { classField.set(classInstance, value); @@ -437,21 +529,23 @@ static void setFieldValue(final Object classInstance, final Method setter, final setter.invoke(classInstance, value); } } catch (IllegalArgumentException ex) { - throw new JBBPMapperException("Can't set value to a mapping field", binField, classInstance.getClass(), classField, ex); + throw new JBBPMapperException("Can't set value to a mapping field", binField, + classInstance.getClass(), classField, ex); } catch (IllegalAccessException ex) { - throw new JBBPMapperException("Can't get access to a mapping field", binField, classInstance.getClass(), classField, ex); + throw new JBBPMapperException("Can't get access to a mapping field", binField, + classInstance.getClass(), classField, ex); } catch (InvocationTargetException ex) { - throw new JBBPMapperException("Can't set field value through setter", binField, classInstance.getClass(), classField, ex); + throw new JBBPMapperException("Can't set field value through setter", binField, + classInstance.getClass(), classField, ex); } } - @SuppressWarnings("TryWithIdenticalCatches") private static T tryMakeInstance( - final Class type, - final JBBPAbstractField binField, - final Object mappingObject, - final Field mappingField, - final Function, Object>[] instantiators + final Class type, + final JBBPAbstractField binField, + final Object mappingObject, + final Field mappingField, + final Function, Object>[] instantiators ) { T result = null; for (final Function, Object> instantiator : instantiators) { @@ -464,21 +558,26 @@ private static T tryMakeInstance( if (result == null) { Exception detectedException = null; try { - final Method method = mappingObject.getClass().getMethod(MAKE_CLASS_INSTANCE_METHOD_NAME, Class.class); + final Method method = + mappingObject.getClass().getMethod(MAKE_CLASS_INSTANCE_METHOD_NAME, Class.class); if (!Modifier.isStatic(method.getModifiers())) { - result = type.cast(mappingObject.getClass().getMethod(MAKE_CLASS_INSTANCE_METHOD_NAME, Class.class).invoke(mappingObject, type)); + result = type.cast( + mappingObject.getClass().getMethod(MAKE_CLASS_INSTANCE_METHOD_NAME, Class.class) + .invoke(mappingObject, type)); } } catch (NoSuchMethodException ex) { // do nothing } catch (IllegalAccessException ex) { - // WARNING! Don't replace by multicatch for Android compatibility! + // WARNING! Don't replace by multi-catch for Android compatibility! detectedException = ex; } catch (InvocationTargetException ex) { detectedException = ex; } if (detectedException != null) { - throw new RuntimeException(String.format("Error during %s(%s) call", MAKE_CLASS_INSTANCE_METHOD_NAME, mappingObject.getClass()), detectedException); + throw new RuntimeException(String + .format("Error during %s(%s) call", MAKE_CLASS_INSTANCE_METHOD_NAME, + mappingObject.getClass()), detectedException); } if (result == null) { @@ -489,26 +588,13 @@ private static T tryMakeInstance( } if (result == null) { - throw new JBBPMapperException(String.format("Can't create instance of %s", type), binField, mappingObject.getClass(), mappingField, null); + throw new JBBPMapperException(String.format("Can't create instance of %s", type), binField, + mappingObject.getClass(), mappingField, null); } } return result; } - - interface FieldProcessor { - @SuppressWarnings("unchecked") - void apply( - MappedFieldRecord record, - JBBPFieldStruct rootStructure, - Object instance, - JBBPMapperCustomFieldProcessor customFieldProcessor, - JBBPAbstractField binField, - int flags, - Function, Object>... instantiators - ); - } - @Override public int compareTo(final MappedFieldRecord o) { final int thisOrder = this.binAnnotation.order(); @@ -522,4 +608,18 @@ public int compareTo(final MappedFieldRecord o) { } return result; } + + public interface FieldProcessor { + @SuppressWarnings("unchecked") + void apply( + MappedFieldRecord record, + JBBPFieldStruct rootStructure, + Object instance, + JBBPMapperCustomFieldProcessor customFieldProcessor, + JBBPAbstractField binField, + int flags, + BinFieldFilter binFieldFilter, + Function, Object>... instantiators + ); + } } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/AbstractFieldByteArray.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/AbstractFieldByteArray.java index e268b3c2..19d81373 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/AbstractFieldByteArray.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/AbstractFieldByteArray.java @@ -25,7 +25,8 @@ * @param type of array item. * @since 1.1.1 */ -abstract class AbstractFieldByteArray extends JBBPAbstractArrayField implements JBBPNumericArray { +abstract class AbstractFieldByteArray extends JBBPAbstractArrayField + implements JBBPNumericArray { private static final long serialVersionUID = -884448637983315505L; protected final byte[] array; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPAbstractArrayField.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPAbstractArrayField.java index 29cdd2e1..e8980b84 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPAbstractArrayField.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPAbstractArrayField.java @@ -17,7 +17,6 @@ package com.igormaznitsa.jbbp.model; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; - import java.util.Iterator; import java.util.NoSuchElementException; @@ -27,7 +26,8 @@ * @param type of field which can be contained in the array * @since 1.0 */ -public abstract class JBBPAbstractArrayField extends JBBPAbstractField implements Iterable { +public abstract class JBBPAbstractArrayField extends JBBPAbstractField + implements Iterable { private static final long serialVersionUID = -9007994400543951290L; /** @@ -67,10 +67,9 @@ public JBBPAbstractArrayField(final JBBPNamedFieldInfo name) { * * @return an iterator for the array */ - @SuppressWarnings("NullableProblems") @Override public Iterator iterator() { - return new Iterator() { + return new Iterator<>() { private int index = 0; @Override diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPAbstractField.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPAbstractField.java index 199edcfb..becfee2c 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPAbstractField.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPAbstractField.java @@ -17,7 +17,6 @@ package com.igormaznitsa.jbbp.model; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; - import java.io.Serializable; /** @@ -36,7 +35,7 @@ public abstract class JBBPAbstractField implements Serializable, JBBPNamedField /** * The Variable can hold some payload. It is not used by JBBP and can be used - * without restrictions. By default it is null. The Field is not thread safe. + * without restrictions. By default, it is null. The Field is not thread safe. * * @since 1.2.0 */ diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBit.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBit.java index 26e7af9f..2111feea 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBit.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBit.java @@ -25,7 +25,8 @@ * * @since 1.0 */ -public final class JBBPFieldArrayBit extends JBBPAbstractArrayField implements BitEntity, JBBPNumericArray { +public final class JBBPFieldArrayBit extends JBBPAbstractArrayField + implements BitEntity, JBBPNumericArray { private static final long serialVersionUID = -4589044511663149591L; /** @@ -46,7 +47,8 @@ public final class JBBPFieldArrayBit extends JBBPAbstractArrayField implements JBBPNumericArray { +public final class JBBPFieldArrayBoolean extends JBBPAbstractArrayField + implements JBBPNumericArray { private static final long serialVersionUID = -7896549257985728694L; /** * The Inside value storage. diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayByte.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayByte.java index 48591cf0..cac10922 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayByte.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayByte.java @@ -23,7 +23,8 @@ * * @since 1.0 */ -public final class JBBPFieldArrayByte extends AbstractFieldByteArray implements JBBPNumericArray { +public final class JBBPFieldArrayByte extends AbstractFieldByteArray + implements JBBPNumericArray { private static final long serialVersionUID = -8100947416351943918L; /** diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayDouble.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayDouble.java index bcd5b434..bdb3b9de 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayDouble.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayDouble.java @@ -24,7 +24,8 @@ * * @since 1.4.0 */ -public final class JBBPFieldArrayDouble extends JBBPAbstractArrayField implements JBBPNumericArray { +public final class JBBPFieldArrayDouble extends JBBPAbstractArrayField + implements JBBPNumericArray { private static final long serialVersionUID = -2146959311724853264L; /** * Inside value storage. @@ -89,7 +90,8 @@ public Object getValueArrayAsObject(final boolean reverseBits) { if (reverseBits) { result = this.array.clone(); for (int i = 0; i < result.length; i++) { - result[i] = Double.longBitsToDouble(JBBPFieldLong.reverseBits(Double.doubleToLongBits(result[i]))); + result[i] = + Double.longBitsToDouble(JBBPFieldLong.reverseBits(Double.doubleToLongBits(result[i]))); } } else { result = this.array.clone(); diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayFloat.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayFloat.java index 3da153f9..7d3c0457 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayFloat.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayFloat.java @@ -24,7 +24,8 @@ * * @since 1.4.0 */ -public final class JBBPFieldArrayFloat extends JBBPAbstractArrayField implements JBBPNumericArray { +public final class JBBPFieldArrayFloat extends JBBPAbstractArrayField + implements JBBPNumericArray { private static final long serialVersionUID = 6839868800303265190L; /** * Inside storage. @@ -89,7 +90,8 @@ public Object getValueArrayAsObject(final boolean reverseBits) { if (reverseBits) { result = this.array.clone(); for (int i = 0; i < result.length; i++) { - result[i] = Float.intBitsToFloat((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(result[i]))); + result[i] = + Float.intBitsToFloat((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(result[i]))); } } else { result = this.array.clone(); diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayInt.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayInt.java index 7eb02052..c82dafdc 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayInt.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayInt.java @@ -24,7 +24,8 @@ * * @since 1.0 */ -public final class JBBPFieldArrayInt extends JBBPAbstractArrayField implements JBBPNumericArray { +public final class JBBPFieldArrayInt extends JBBPAbstractArrayField + implements JBBPNumericArray { private static final long serialVersionUID = 6839868800303265190L; /** * Inside storage. diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayLong.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayLong.java index ebcd3eb9..c7df0276 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayLong.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayLong.java @@ -24,7 +24,8 @@ * * @since 1.0 */ -public final class JBBPFieldArrayLong extends JBBPAbstractArrayField implements JBBPNumericArray { +public final class JBBPFieldArrayLong extends JBBPAbstractArrayField + implements JBBPNumericArray { private static final long serialVersionUID = -2146959300724853264L; /** * Inside value storage. diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayShort.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayShort.java index 2f317873..7bcb74e0 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayShort.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayShort.java @@ -24,7 +24,8 @@ * * @since 1.0 */ -public final class JBBPFieldArrayShort extends JBBPAbstractArrayField implements JBBPNumericArray { +public final class JBBPFieldArrayShort extends JBBPAbstractArrayField + implements JBBPNumericArray { private static final long serialVersionUID = 6119269534023759155L; /** * Inside value storage. diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUByte.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUByte.java index fd0469fb..017ef023 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUByte.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUByte.java @@ -19,7 +19,7 @@ import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; /** - * Describes a unsigned byte array. + * Describes an unsigned byte array. * * @since 1.0 */ diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUInt.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUInt.java new file mode 100644 index 00000000..29db7503 --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUInt.java @@ -0,0 +1,112 @@ +/* + * Copyright 2017 Igor Maznitsa. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.igormaznitsa.jbbp.model; + +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.utils.JBBPUtils; + +/** + * Describes a long array. + * + * @since 1.0 + */ +public final class JBBPFieldArrayUInt extends JBBPAbstractArrayField + implements JBBPNumericArray { + private static final long serialVersionUID = -2146953450724853264L; + /** + * Inside value storage. + */ + private final int[] array; + + /** + * The Constructor. + * + * @param name a field name info, it can be null + * @param array a value array, it must not be null + */ + public JBBPFieldArrayUInt(final JBBPNamedFieldInfo name, final int[] array) { + super(name); + JBBPUtils.assertNotNull(array, "Array must not be null"); + this.array = array; + } + + /** + * get the value array + * + * @return the value array as a long array + */ + public long[] getArray() { + long[] result = new long[this.array.length]; + for (int i = 0; i < this.array.length; i++) { + result[i] = (long) this.array[i] & 0xFFFFFFFFL; + } + return result; + } + + /** + * Get internal array of signed integers representing unsigned integers. + * + * @return the internal integer array, must not be null + * @since 2.0.4 + */ + public int[] getInternalArray() { + return this.array; + } + + @Override + public int size() { + return this.array.length; + } + + @Override + public JBBPFieldUInt getElementAt(final int index) { + final JBBPFieldUInt result = + new JBBPFieldUInt(this.fieldNameInfo, (long) this.array[index] & 0xFFFFFFFFL); + result.payload = this.payload; + return result; + } + + @Override + public Object getValueArrayAsObject(final boolean reverseBits) { + final long[] result = new long[this.array.length]; + for (int i = 0; i < result.length; i++) { + result[i] = + (reverseBits ? JBBPFieldInt.reverseBits(this.array[i]) : this.array[i]) & 0xFFFFFFFFL; + } + return result; + } + + @Override + public int getAsInt(final int index) { + return this.array[index]; + } + + @Override + public long getAsLong(final int index) { + return (long) this.array[index] & 0xFFFFFFFFL; + } + + @Override + public boolean getAsBool(final int index) { + return this.array[index] != 0L; + } + + @Override + public String getTypeAsString() { + return "uint " + '[' + this.array.length + ']'; + } +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUShort.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUShort.java index 826016e6..ce841194 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUShort.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUShort.java @@ -20,11 +20,12 @@ import com.igormaznitsa.jbbp.utils.JBBPUtils; /** - * Describes a unsigned short array. + * Describes an unsigned short array. * * @since 1.0 */ -public final class JBBPFieldArrayUShort extends JBBPAbstractArrayField implements JBBPNumericArray { +public final class JBBPFieldArrayUShort extends JBBPAbstractArrayField + implements JBBPNumericArray { private static final long serialVersionUID = -220078798710257343L; /** * Inside value storage. diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldBit.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldBit.java index 326588dc..7b04e17e 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldBit.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldBit.java @@ -44,7 +44,8 @@ public final class JBBPFieldBit extends JBBPAbstractField implements JBBPNumeric * @param value the field value * @param bitNumber number of valuable bits in the value, must not be null */ - public JBBPFieldBit(final JBBPNamedFieldInfo name, final int value, final JBBPBitNumber bitNumber) { + public JBBPFieldBit(final JBBPNamedFieldInfo name, final int value, + final JBBPBitNumber bitNumber) { super(name); JBBPUtils.assertNotNull(bitNumber, "Number of bits must not be null"); this.bitNumber = bitNumber; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldLong.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldLong.java index 06ebe83a..9adc6574 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldLong.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldLong.java @@ -58,7 +58,8 @@ public static long reverseBits(final long value) { final long b6 = JBBPUtils.reverseBitsInByte((byte) (value >> 48)) & 0xFFL; final long b7 = JBBPUtils.reverseBitsInByte((byte) (value >> 56)) & 0xFFL; - return (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; + return (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | + b7; } @Override diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldString.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldString.java index f13055d2..8154f6d0 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldString.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldString.java @@ -25,15 +25,14 @@ */ public final class JBBPFieldString extends JBBPAbstractField { - private static final long serialVersionUID = -2861961302858335702L; public static final String TYPE_NAME = "stringj"; - + private static final long serialVersionUID = -2861961302858335702L; private final String str; /** * A Constructor. * - * @param name a field name info, it can be null + * @param name a field name info, it can be null * @param nullableValue a value, it can be null */ public JBBPFieldString(final JBBPNamedFieldInfo name, final String nullableValue) { @@ -41,14 +40,6 @@ public JBBPFieldString(final JBBPNamedFieldInfo name, final String nullableValue this.str = nullableValue; } - /** - * Get the saved value. - * @return the value as String, it can be null - */ - public String getAsString() { - return this.str; - } - /** * Get the reversed bit representation of the value. * @@ -60,8 +51,8 @@ public static String reverseBits(final String value) { if (value != null) { final char[] chars = value.toCharArray(); - for(int i=0; i T findFieldForType(final Class fieldType } } if (counter > 1) { - throw new JBBPTooManyFieldsFoundException(counter, "Detected more than one field", null, fieldType); + throw new JBBPTooManyFieldsFoundException(counter, "Detected more than one field", null, + fieldType); } return result; } @@ -164,7 +167,8 @@ public T findLastFieldForType(final Class field } @Override - public T findFieldForNameAndType(final String fieldName, final Class fieldType) { + public T findFieldForNameAndType(final String fieldName, + final Class fieldType) { final String normalizedName = JBBPUtils.normalizeFieldNameOrPath(fieldName); T result = null; @@ -209,7 +213,8 @@ public boolean pathExists(final String fieldPath) { } @Override - public T findFieldForPathAndType(final String fieldPath, final Class fieldType) { + public T findFieldForPathAndType(final String fieldPath, + final Class fieldType) { final JBBPAbstractField field = this.findFieldForPath(fieldPath); T result = null; @@ -232,7 +237,8 @@ public T findFieldForPathAndType(final String fiel * @since 2.0.0 */ @SafeVarargs - public final T mapTo(final String path, final T instance, final Function, Object>... instantiators) { + public final T mapTo(final String path, final T instance, + final Function, Object>... instantiators) { return JBBPMapper.map(this, path, instance, instantiators); } @@ -250,7 +256,8 @@ public final T mapTo(final String path, final T instance, final Function T mapTo(final String path, final T instance, final int flags, final Function, Object>... instantiators) { + public final T mapTo(final String path, final T instance, final int flags, + final Function, Object>... instantiators) { return JBBPMapper.map(this, path, instance, flags, instantiators); } @@ -267,7 +274,9 @@ public final T mapTo(final String path, final T instance, final int flags, f * @since 2.0.0 */ @SafeVarargs - public final T mapTo(final String path, final T instance, final JBBPMapperCustomFieldProcessor customFieldProcessor, final Function, Object>... instantiators) { + public final T mapTo(final String path, final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final Function, Object>... instantiators) { return JBBPMapper.map(this, path, instance, customFieldProcessor, instantiators); } @@ -286,7 +295,9 @@ public final T mapTo(final String path, final T instance, final JBBPMapperCu * @since 2.0.0 */ @SafeVarargs - public final T mapTo(final String path, final T instance, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags, final Function, Object>... instantiators) { + public final T mapTo(final String path, final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final int flags, final Function, Object>... instantiators) { return JBBPMapper.map(this, path, instance, customFieldProcessor, flags, instantiators); } @@ -302,7 +313,24 @@ public final T mapTo(final String path, final T instance, final JBBPMapperCu */ @SafeVarargs public final T mapTo(final T objectToMap, final Function, Object>... instantiators) { - return this.mapTo(objectToMap, null, instantiators); + return this.mapTo(objectToMap, (JBBPMapperCustomFieldProcessor) null, instantiators); + } + + /** + * Map the structure fields to object fields. + * + * @param expected result type + * @param objectToMap an object to map fields of the structure, must not be + * null + * @param binFieldFilter filter allows to exclude some fields from process, can be null + * @param instantiators array of functions which can instantiate object of required class, must not be null + * @return the same object from the arguments but with filled fields by values + * of the structure + * @since 2.0.4 + */ + @SafeVarargs + public final T mapTo(final T objectToMap, final BinFieldFilter binFieldFilter, final Function, Object>... instantiators) { + return this.mapTo(objectToMap, null, binFieldFilter, instantiators); } /** @@ -318,10 +346,31 @@ public final T mapTo(final T objectToMap, final Function, Object>.. * @since 2.0.0 */ @SafeVarargs - public final T mapTo(final T instance, final int flags, final Function, Object>... instantiators) { + public final T mapTo(final T instance, final int flags, + final Function, Object>... instantiators) { return this.mapTo(instance, null, flags, instantiators); } + /** + * Map the structure fields to object fields. + * + * @param expected result type + * @param instance object instance to be filled by values, must not be null + * @param flags special flags to tune mapping process + * @param binFieldFilter filter to exclude some fields from process, can be null + * @param instantiators array of functions which can instantiate object of required class, must not be null + * @return the same object from the arguments but with filled fields by values + * of the structure + * @see JBBPMapper#FLAG_IGNORE_MISSING_VALUES + * @since 2.0.4 + */ + @SafeVarargs + public final T mapTo(final T instance, final int flags, + final BinFieldFilter binFieldFilter, + final Function, Object>... instantiators) { + return this.mapTo(instance, null, flags, binFieldFilter, instantiators); + } + /** * Map the structure fields to object fields. * @@ -335,10 +384,39 @@ public final T mapTo(final T instance, final int flags, final Function T mapTo(final T instance, final JBBPMapperCustomFieldProcessor customFieldProcessor, final Function, Object>... instantiators) { + public final T mapTo(final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final Function, Object>... instantiators) { return JBBPMapper.map(this, instance, customFieldProcessor, instantiators); } + /** + * Map the structure fields to object fields. + * + * @param expected result type + * @param instance an object to map fields of the structure, must not be + * null + * @param customFieldProcessor a custom field processor to provide values for + * custom mapping fields, it can be null if there is not any custom field + * @param binFieldFilter filter to exclude some fields, can be null + * @param instantiators array of functions which can instantiate object of required class, must not be null + * @return the same object from the arguments but with filled fields by values + * of the structure + * @since 2.0.4 + */ + @SafeVarargs + public final T mapTo(final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final BinFieldFilter binFieldFilter, + final Function, Object>... instantiators) { + return JBBPMapper.map(this, + instance, + customFieldProcessor, + 0, + binFieldFilter, + instantiators); + } + /** * Map the structure fields to object fields. * @@ -355,10 +433,35 @@ public final T mapTo(final T instance, final JBBPMapperCustomFieldProcessor * @since 1.1 */ @SafeVarargs - public final T mapTo(final T objectToMap, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags, final Function, Object>... instantiators) { + public final T mapTo(final T objectToMap, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final int flags, final Function, Object>... instantiators) { return JBBPMapper.map(this, objectToMap, customFieldProcessor, flags, instantiators); } + /** + * Map the structure fields to object fields. + * + * @param expected result type + * @param objectToMap an object to map fields of the structure, must not be + * null + * @param customFieldProcessor a custom field processor to provide values for + * custom mapping fields, it can be null if there is not any custom field + * @param flags special flags to tune mapping process + * @param binFieldFilter filter to exclude some fields, can be null + * @param instantiators array of functions which can instantiate object of required class, must not be null + * @return the same object from the arguments but with filled fields by values + * of the structure + * @see JBBPMapper#FLAG_IGNORE_MISSING_VALUES + * @since 2.0.4 + */ + @SafeVarargs + public final T mapTo(final T objectToMap, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final int flags, final BinFieldFilter binFieldFilter, final Function, Object>... instantiators) { + return JBBPMapper.map(this, objectToMap, customFieldProcessor, flags, binFieldFilter, instantiators); + } + @Override public String getTypeAsString() { return "{}"; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUByte.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUByte.java index aa8e6756..fc77edf9 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUByte.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUByte.java @@ -20,7 +20,7 @@ import com.igormaznitsa.jbbp.utils.JBBPUtils; /** - * Describes a unsigned byte value field. + * Describes an unsigned byte value field. * * @since 1.0 */ diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUInt.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUInt.java new file mode 100644 index 00000000..f4e2be43 --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUInt.java @@ -0,0 +1,92 @@ +/* + * Copyright 2017 Igor Maznitsa. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.igormaznitsa.jbbp.model; + +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.exceptions.JBBPNumericFieldValueConversionException; +import java.util.Locale; + +/** + * Describes a unsigned integer (32 bit) field. + * + * @since 2.0.4 + */ +public final strictfp class JBBPFieldUInt extends JBBPAbstractField implements JBBPNumericField { + public static final String TYPE_NAME = "uint"; + private static final long serialVersionUID = 354342324375674L; + /** + * Internal field keeps the value. + */ + private final int value; + + /** + * The Constructor. + * + * @param name a field name info, it can be null. + * @param value the field value + */ + public JBBPFieldUInt(final JBBPNamedFieldInfo name, final long value) { + super(name); + this.value = (int) value; + } + + @Override + public int getAsInt() { + if (this.value >= 0) { + return this.value; + } else { + throw new JBBPNumericFieldValueConversionException(this, "UINT 0x" + + (Long.toHexString(this.value & 0xFFFFFFFFL).toUpperCase( + Locale.ENGLISH)) + " can't be represented as INT"); + } + } + + @Override + public double getAsDouble() { + return (double) this.getAsLong(); + } + + @Override + public float getAsFloat() { + return (float) this.getAsLong(); + } + + @Override + public long getAsLong() { + return ((long) this.value & 0xFFFFFFFFL); + } + + @Override + public boolean getAsBool() { + return this.value != 0; + } + + @Override + public long getAsInvertedBitOrder() { + return reverseBits(this.value & 0xFFFFFFFFL); + } + + public static long reverseBits(final long value) { + return JBBPFieldInt.reverseBits((int) value) & 0xFFFFFFFFL; + } + + @Override + public String getTypeAsString() { + return TYPE_NAME; + } + +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUShort.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUShort.java index cd977aa0..abbc2df0 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUShort.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldUShort.java @@ -20,7 +20,7 @@ import com.igormaznitsa.jbbp.utils.JBBPUtils; /** - * Describes a unsigned short value field. + * Describes an unsigned short value field. * * @since 1.0 */ diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPNumericArray.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPNumericArray.java index e9618310..b4e8ffa1 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPNumericArray.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPNumericArray.java @@ -25,6 +25,7 @@ public interface JBBPNumericArray { /** * Get element as integer. + * * @param index index of element in array * @return the element as integer */ @@ -32,6 +33,7 @@ public interface JBBPNumericArray { /** * Get element as long. + * * @param index index of element in array * @return the element as long */ @@ -39,6 +41,7 @@ public interface JBBPNumericArray { /** * Get element as boolean. + * * @param index index of element in array * @return the element as boolean */ diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPNumericField.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPNumericField.java index 41886675..5692ec29 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPNumericField.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPNumericField.java @@ -16,6 +16,8 @@ package com.igormaznitsa.jbbp.model; +import com.igormaznitsa.jbbp.exceptions.JBBPNumericFieldValueConversionException; + /** * The Interface describes a field which content can be represented as a numeric value. * @@ -26,6 +28,7 @@ public interface JBBPNumericField extends JBBPInvertableBitOrder, JBBPNamedField * Get the field value as integer. * * @return the field value as integer + * @throws JBBPNumericFieldValueConversionException can be thrown if impossible to represent saved value as int */ int getAsInt(); @@ -33,6 +36,7 @@ public interface JBBPNumericField extends JBBPInvertableBitOrder, JBBPNamedField * Get the field value as double. * * @return the field value as double + * @throws JBBPNumericFieldValueConversionException can be thrown if impossible to represent saved value as double * @since 1.4.0 */ double getAsDouble(); @@ -41,6 +45,7 @@ public interface JBBPNumericField extends JBBPInvertableBitOrder, JBBPNamedField * Get the field value as float. * * @return the field value as float + * @throws JBBPNumericFieldValueConversionException can be thrown if impossible to represent saved value as float * @since 1.4.0 */ float getAsFloat(); @@ -49,6 +54,7 @@ public interface JBBPNumericField extends JBBPInvertableBitOrder, JBBPNamedField * Get the field value as long * * @return the field value as long + * @throws JBBPNumericFieldValueConversionException can be thrown if impossible to represent saved value as long */ long getAsLong(); @@ -56,6 +62,7 @@ public interface JBBPNumericField extends JBBPInvertableBitOrder, JBBPNamedField * Get the field value as boolean, usually if the value is 0 then false, true otherwise. * * @return the field value as boolean + * @throws JBBPNumericFieldValueConversionException can be thrown if impossible to represent saved value as boolean */ boolean getAsBool(); diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/BinAnnotationWrapper.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/BinAnnotationWrapper.java new file mode 100644 index 00000000..9b7a6d61 --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/BinAnnotationWrapper.java @@ -0,0 +1,176 @@ +package com.igormaznitsa.jbbp.utils; + +import com.igormaznitsa.jbbp.io.JBBPBitNumber; +import com.igormaznitsa.jbbp.io.JBBPBitOrder; +import com.igormaznitsa.jbbp.io.JBBPByteOrder; +import com.igormaznitsa.jbbp.mapper.Bin; +import com.igormaznitsa.jbbp.mapper.BinType; +import java.lang.annotation.Annotation; + +/** + * Auxiliary class to replace Bin annotation field values. + * Not thread safe! + * + * @since 2.0.2 + */ +@SuppressWarnings("ClassExplicitlyAnnotation") +public final class BinAnnotationWrapper implements Bin { + private Bin bin; + private String name; + private String path; + private String customType; + private String arraySizeExpr; + private BinType type; + private JBBPBitOrder bitOrder; + private Boolean custom; + private String paramExpr; + private JBBPBitNumber bitNumber; + private JBBPByteOrder byteOrder; + private Integer order; + private String comment; + + public BinAnnotationWrapper() { + } + + public BinAnnotationWrapper setWrapped(final Bin bin) { + this.bin = bin; + return this; + } + + public BinAnnotationWrapper setName(final String value) { + this.name = value; + return this; + } + + @Override + public String name() { + assert this.bin != null; + return this.name == null ? this.bin.name() : this.name; + } + + public BinAnnotationWrapper setPath(final String value) { + this.path = value; + return this; + } + + @Override + public String path() { + assert this.bin != null; + return this.path == null ? this.bin.path() : this.path; + } + + public BinAnnotationWrapper setCustomType(final String value) { + this.customType = value; + return this; + } + + @Override + public String customType() { + assert this.bin != null; + return this.customType == null ? this.bin.customType() : this.customType; + } + + public BinAnnotationWrapper setArraySizeExpr(final String value) { + this.arraySizeExpr = value; + return this; + } + + @Override + public String arraySizeExpr() { + assert this.bin != null; + return this.arraySizeExpr == null ? this.bin.arraySizeExpr() : this.arraySizeExpr; + } + + public BinAnnotationWrapper setType(final BinType value) { + this.type = value; + return this; + } + + @Override + public BinType type() { + assert this.bin != null; + return this.type == null ? this.bin.type() : this.type; + } + + public BinAnnotationWrapper setBitOrder(final JBBPBitOrder value) { + this.bitOrder = value; + return this; + } + + @Override + public JBBPBitOrder bitOrder() { + assert this.bin != null; + return this.bitOrder == null ? this.bin.bitOrder() : this.bitOrder; + } + + public BinAnnotationWrapper setCustom(final Boolean value) { + this.custom = value; + return this; + } + + @Override + public boolean custom() { + assert this.bin != null; + return this.custom == null ? this.bin.custom() : this.custom; + } + + public BinAnnotationWrapper setParamExpr(final String value) { + this.paramExpr = value; + return this; + } + + @Override + public String paramExpr() { + assert this.bin != null; + return this.paramExpr == null ? this.bin.paramExpr() : this.paramExpr; + } + + public BinAnnotationWrapper setBitNumber(final JBBPBitNumber value) { + this.bitNumber = value; + return this; + } + + @Override + public JBBPBitNumber bitNumber() { + assert this.bin != null; + return this.bitNumber == null ? this.bin.bitNumber() : this.bitNumber; + } + + public BinAnnotationWrapper setByteOrder(final JBBPByteOrder value) { + this.byteOrder = value; + return this; + } + + @Override + public JBBPByteOrder byteOrder() { + assert this.bin != null; + return this.byteOrder == null ? this.bin.byteOrder() : this.byteOrder; + } + + public BinAnnotationWrapper setOrder(final Integer value) { + this.order = value; + return this; + } + + @Override + public int order() { + assert this.bin != null; + return this.order == null ? this.bin.order() : this.order; + } + + public BinAnnotationWrapper setComment(final String value) { + this.comment = value; + return this; + } + + @Override + public String comment() { + assert this.bin != null; + return this.comment == null ? this.bin.comment() : this.comment; + } + + @Override + public Class annotationType() { + return Bin.class; + } +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/Function.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/Function.java index a4a489c6..c77ca8b1 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/Function.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/Function.java @@ -13,14 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.igormaznitsa.jbbp.utils; /** * Auxiliary functional interface. Added to support Android 3. + * * @param the type of the input to the function * @param the type of the result of the function * @since 2.0.0 */ public interface Function { - R apply(T t); + R apply(T t); } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPCustomFieldTypeProcessorAggregator.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPCustomFieldTypeProcessorAggregator.java index f9c4e0cd..e1e9456b 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPCustomFieldTypeProcessorAggregator.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPCustomFieldTypeProcessorAggregator.java @@ -16,19 +16,19 @@ package com.igormaznitsa.jbbp.utils; +import static com.igormaznitsa.jbbp.utils.JBBPUtils.ARRAY_STRING_EMPTY; + import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.model.JBBPAbstractField; - import java.io.IOException; import java.util.HashMap; import java.util.Map; -import static com.igormaznitsa.jbbp.utils.JBBPUtils.ARRAY_STRING_EMPTY; - /** * The Aggregator allows to join several custom field type processors. * @@ -63,12 +63,23 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final String fieldName, final int extraData, final boolean isArray) { - return this.customTypeMap.get(fieldType.getTypeName()).isAllowed(fieldType, fieldName, extraData, isArray); + public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final String fieldName, + final int extraData, final boolean isArray) { + return this.customTypeMap.get(fieldType.getTypeName()) + .isAllowed(fieldType, fieldName, extraData, isArray); } @Override - public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, int parserFlags, JBBPFieldTypeParameterContainer fieldType, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException { - return this.customTypeMap.get(fieldType.getTypeName()).readCustomFieldType(in, bitOrder, parserFlags, fieldType, fieldName, extraData, readWholeStream, arrayLength); + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer fieldType, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + return this.customTypeMap.get(fieldType.getTypeName()) + .readCustomFieldType(in, bitOrder, parserFlags, fieldType, fieldName, extraData, + readWholeStream, arrayLength, arraySizeLimiter); } + } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilder.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilder.java index c4add02b..2d076c07 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilder.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilder.java @@ -52,43 +52,11 @@ public static JBBPDslBuilder Begin() { return new JBBPDslBuilder(); } - protected void addItem(final Item item) { - if (item instanceof ItemComment || item.name == null || item.name.length() == 0) { - this.items.add(item); - } else { - int structCounter = 0; - for (int i = this.items.size() - 1; i >= 0; i--) { - final Item itm = this.items.get(i); - - if (itm instanceof ItemComment) { - continue; - } - - if (itm.type == BinType.STRUCT || itm.type == BinType.STRUCT_ARRAY) { - if (structCounter == 0) { - break; - } - structCounter++; - } else if (itm instanceof ItemStructEnd) { - structCounter--; - } - - if (structCounter == 0) { - final String thatName = itm.name; - if (thatName != null && thatName.length() > 0 && item.name.equalsIgnoreCase(thatName)) { - throw new IllegalArgumentException("Duplicated item name '" + item.name + '\''); - } - } - } - this.items.add(item); - } - } - protected static String assertTextNotNullAndTrimmedNotEmpty(final String text) { if (text == null) { throw new NullPointerException("Must not be null"); } - if (text.trim().length() == 0) { + if (text.trim().isEmpty()) { throw new IllegalArgumentException("Must not be empty: " + text); } return text; @@ -107,7 +75,8 @@ protected static String assertNameIfNotNull(final String name) { } if (!Character.isLetterOrDigit(c) && c != '_') { - throw new IllegalArgumentException("Only letters, digits and underscore allowed: " + name); + throw new IllegalArgumentException( + "Only letters, digits and underscore allowed: " + name); } } } @@ -119,7 +88,7 @@ protected static String assertExpressionChars(final String expression) { throw new NullPointerException("Expression is null"); } - if (expression.trim().length() == 0) { + if (expression.trim().isEmpty()) { throw new IllegalArgumentException("Expression is empty"); } @@ -154,7 +123,8 @@ protected static int assertNotNegativeAndZero(final int value) { return value; } - protected static StringBuilder doTabs(final boolean enable, final StringBuilder buffer, int tabs) { + protected static StringBuilder doTabs(final boolean enable, final StringBuilder buffer, + int tabs) { if (enable) { while (tabs > 0) { buffer.append('\t'); @@ -164,6 +134,38 @@ protected static StringBuilder doTabs(final boolean enable, final StringBuilder return buffer; } + protected void addItem(final Item item) { + if (item instanceof ItemComment || item.name == null || item.name.isEmpty()) { + this.items.add(item); + } else { + int structCounter = 0; + for (int i = this.items.size() - 1; i >= 0; i--) { + final Item itm = this.items.get(i); + + if (itm instanceof ItemComment) { + continue; + } + + if (itm.type == BinType.STRUCT || itm.type == BinType.STRUCT_ARRAY) { + if (structCounter == 0) { + break; + } + structCounter++; + } else if (itm instanceof ItemStructEnd) { + structCounter--; + } + + if (structCounter == 0) { + final String thatName = itm.name; + if (thatName != null && !thatName.isEmpty() && item.name.equalsIgnoreCase(thatName)) { + throw new IllegalArgumentException("Duplicated item name '" + item.name + '\''); + } + } + } + this.items.add(item); + } + } + /** * Get number of items added into internal item list. * @@ -471,7 +473,8 @@ public JBBPDslBuilder VarArray(final String name, final int size, final String p * @param param optional parameter for the field, can be null * @return the builder instance, must not be null */ - public JBBPDslBuilder VarArray(final String name, final String sizeExpression, final String param) { + public JBBPDslBuilder VarArray(final String name, final String sizeExpression, + final String param) { return this.CustomArray("var", name, sizeExpression, param); } @@ -514,7 +517,7 @@ public JBBPDslBuilder CustomArray(final String type, final String name, final St * * @param type custom type, must not be null * @param name name of the array, can be null for anonymous one - * @param size size of he array, if less than zero then read till end of stream. + * @param size size of the array, if less than zero then read till end of stream. * @return the builder instance, must not be null */ public JBBPDslBuilder CustomArray(final String type, final String name, final int size) { @@ -530,7 +533,8 @@ public JBBPDslBuilder CustomArray(final String type, final String name, final in * @param param optional parameter for the field, can be null * @return the builder instance, must not be null */ - public JBBPDslBuilder CustomArray(final String type, final String name, final int size, final String param) { + public JBBPDslBuilder CustomArray(final String type, final String name, final int size, + final String param) { return this.CustomArray(type, name, arraySizeToString(size), param); } @@ -543,7 +547,8 @@ public JBBPDslBuilder CustomArray(final String type, final String name, final in * @param param optional parameter for the field, can be null * @return the builder instance, must not be null */ - public JBBPDslBuilder CustomArray(final String type, final String name, final String sizeExpression, final String param) { + public JBBPDslBuilder CustomArray(final String type, final String name, + final String sizeExpression, final String param) { final ItemCustom item = new ItemCustom(type, name, this.byteOrder); item.array = true; item.bitLenExpression = param == null ? null : assertExpressionChars(param); @@ -719,7 +724,8 @@ public JBBPDslBuilder BitArray(final String bitLenExpression, final String sizeE * @param sizeExpression expression to be used to calculate array size, must not be null * @return the builder instance, must not be null */ - public JBBPDslBuilder BitArray(final String name, final JBBPBitNumber bits, final String sizeExpression) { + public JBBPDslBuilder BitArray(final String name, final JBBPBitNumber bits, + final String sizeExpression) { final Item item = new Item(BinType.BIT_ARRAY, name, this.byteOrder); item.bitNumber = bits; item.sizeExpression = assertExpressionChars(sizeExpression); @@ -735,7 +741,8 @@ public JBBPDslBuilder BitArray(final String name, final JBBPBitNumber bits, fina * @param sizeExpression expression to be used to calculate array size, must not be null * @return the builder instance, must not be null */ - public JBBPDslBuilder BitArray(final String name, final String bitLenExpression, final String sizeExpression) { + public JBBPDslBuilder BitArray(final String name, final String bitLenExpression, + final String sizeExpression) { final Item item = new Item(BinType.BIT_ARRAY, name, this.byteOrder); item.bitLenExpression = assertExpressionChars(bitLenExpression); item.sizeExpression = assertExpressionChars(sizeExpression); @@ -1280,6 +1287,16 @@ public JBBPDslBuilder Double() { return this.Double(null); } + /** + * Add anonymous unsigned int field. + * + * @return the builder instance, must not be null + * @since 2.0.4 + */ + public JBBPDslBuilder UInt() { + return this.UInt(null); + } + /** * Add named double field. * @@ -1292,6 +1309,19 @@ public JBBPDslBuilder Double(final String name) { return this; } + /** + * Add named unsigned int field. + * + * @param name name of the field, can be null for anonymous + * @return the builder instance, must not be null + * @since 2.0.4 + */ + public JBBPDslBuilder UInt(final String name) { + final Item item = new Item(BinType.UINT, name, this.byteOrder); + this.addItem(item); + return this; + } + /** * Add comment, in case that a field followed by the comment, the comment will be placed on the same line as field definition. * @@ -1335,6 +1365,17 @@ public JBBPDslBuilder DoubleArray(final int size) { return this.DoubleArray(null, arraySizeToString(size)); } + /** + * Add anonymous fixed size unsigned int array field. + * + * @param size size of the array, if negative then read till end of stream + * @return the builder instance, must not be null + * @since 2.0.4 + */ + public JBBPDslBuilder UIntArray(final int size) { + return this.UIntArray(null, arraySizeToString(size)); + } + /** * Add named fixed size double array field. * @@ -1346,6 +1387,21 @@ public JBBPDslBuilder DoubleArray(final String name, final int size) { return this.DoubleArray(name, arraySizeToString(size)); } + /** + * Add named unsigned integer array field which size calculated trough expression. + * + * @param name name of the field, can be null for anonymous + * @param sizeExpression expression to be used to calculate array size, must not be null + * @return the builder instance, must not be null + * @since 2.0.4 + */ + public JBBPDslBuilder UIntArray(final String name, final String sizeExpression) { + final Item item = new Item(BinType.UINT_ARRAY, name, this.byteOrder); + item.sizeExpression = assertExpressionChars(sizeExpression); + this.addItem(item); + return this; + } + /** * Add named double array field which size calculated trough expression. * @@ -1360,6 +1416,18 @@ public JBBPDslBuilder DoubleArray(final String name, final String sizeExpression return this; } + /** + * Add named fixed size unsigned int array field. + * + * @param name ame of the field, can be null for anonymous + * @param size size of the array, if negative then read till end of stream + * @return the builder instance, must not be null + * @since 2.0.4 + */ + public JBBPDslBuilder UIntArray(final String name, final int size) { + return this.UIntArray(name, arraySizeToString(size)); + } + /** * Add anonymous string field. * @@ -1466,12 +1534,14 @@ public String End(final boolean format) { for (final Item item : this.items) { switch (item.type) { case STRUCT: { - doTabs(format, buffer, structCounter).append(item.name == null ? "" : item.name).append('{'); + doTabs(format, buffer, structCounter).append(item.name == null ? "" : item.name) + .append('{'); structCounter++; } break; case STRUCT_ARRAY: { - doTabs(format, buffer, structCounter).append(item.name == null ? "" : item.name).append('[').append(item.sizeExpression).append(']').append('{'); + doTabs(format, buffer, structCounter).append(item.name == null ? "" : item.name) + .append('[').append(item.sizeExpression).append(']').append('{'); structCounter++; } break; @@ -1491,22 +1561,28 @@ public String End(final boolean format) { doTabs(format, buffer, structCounter).append('}'); } } else if (item instanceof ItemCustom) { - doTabs(format, buffer, structCounter).append(item.toString()); + doTabs(format, buffer, structCounter).append(item); } else if (item instanceof ItemAlign) { - doTabs(format, buffer, structCounter).append("align").append(item.sizeExpression == null ? "" : ':' + item.makeExpressionForExtraField(item.sizeExpression)).append(';'); + doTabs(format, buffer, structCounter).append("align").append( + item.sizeExpression == null ? "" : + ':' + item.makeExpressionForExtraField(item.sizeExpression)).append(';'); } else if (item instanceof ItemVal) { - doTabs(format, buffer, structCounter).append("val").append(':').append(item.makeExpressionForExtraField(item.sizeExpression)).append(' ').append(item.name).append(';'); + doTabs(format, buffer, structCounter).append("val").append(':') + .append(item.makeExpressionForExtraField(item.sizeExpression)).append(' ') + .append(item.name).append(';'); } else if (item instanceof ItemResetCounter) { doTabs(format, buffer, structCounter).append("reset$$;"); } else if (item instanceof ItemSkip) { - doTabs(format, buffer, structCounter).append("skip").append(item.sizeExpression == null ? "" : ':' + item.makeExpressionForExtraField(item.sizeExpression)).append(';'); + doTabs(format, buffer, structCounter).append("skip").append( + item.sizeExpression == null ? "" : + ':' + item.makeExpressionForExtraField(item.sizeExpression)).append(';'); } else if (item instanceof ItemComment) { final ItemComment comment = (ItemComment) item; final String commentText = comment.getComment().replace("\n", " "); if (comment.isNewLine()) { if (buffer.length() > 0) { final int lastNewLine = buffer.lastIndexOf("\n"); - if (lastNewLine < 0 || buffer.substring(lastNewLine + 1).length() != 0) { + if (lastNewLine < 0 || !buffer.substring(lastNewLine + 1).isEmpty()) { buffer.append('\n'); } } @@ -1532,7 +1608,7 @@ public String End(final boolean format) { } break; default: { - doTabs(format, buffer, structCounter).append(item.toString()); + doTabs(format, buffer, structCounter).append(item); } break; } @@ -1551,39 +1627,40 @@ public String End(final boolean format) { * @return container which contains all found items */ protected BinFieldContainer collectAnnotatedFields(final Class annotatedClass) { - final Bin defautBin = annotatedClass.getAnnotation(Bin.class); + final Bin defaultBin = annotatedClass.getAnnotation(Bin.class); final BinFieldContainer result; - if (defautBin != null) { - result = new BinFieldContainer(annotatedClass, defautBin, true, null); + if (defaultBin != null) { + result = new BinFieldContainer(annotatedClass, defaultBin, true, null); } else { result = new BinFieldContainer(annotatedClass, null); } - final Class superclazz = annotatedClass.getSuperclass(); + final Class superClass = annotatedClass.getSuperclass(); - if (superclazz != null && superclazz != Object.class) { - final BinFieldContainer parentFields = collectAnnotatedFields(superclazz); + if (superClass != null && superClass != Object.class) { + final BinFieldContainer parentFields = collectAnnotatedFields(superClass); if (!parentFields.fields.isEmpty()) { - result.addAllFromContainer(parentFields); + result.addAllFromContainerExcludeEndStruct(parentFields); } } for (final Field f : annotatedClass.getDeclaredFields()) { - if ((f.getModifiers() & (Modifier.NATIVE | Modifier.STATIC | Modifier.FINAL | Modifier.PRIVATE | Modifier.TRANSIENT)) == 0) { + if ((f.getModifiers() & + (Modifier.NATIVE | Modifier.STATIC | Modifier.FINAL | Modifier.PRIVATE | + Modifier.TRANSIENT)) == 0) { final Bin foundFieldBin = f.getAnnotation(Bin.class); - if (foundFieldBin != null || defautBin != null) { - validateAnnotatedField(defautBin, foundFieldBin, f); + if (foundFieldBin != null || defaultBin != null) { + validateAnnotatedField(defaultBin, foundFieldBin, f); - final Class type = f.getType().isArray() ? f.getType().getComponentType() : f.getType(); + final Class type = + f.getType().isArray() ? f.getType().getComponentType() : f.getType(); if (type.isPrimitive() || type == String.class) { if (foundFieldBin != null) { result.addBinField(foundFieldBin, true, f); } else { - if (defautBin != null) { - result.addBinField(defautBin, false, f); - } + result.addBinField(defaultBin, false, f); } } else { final BinFieldContainer container = collectAnnotatedFields(type); @@ -1621,7 +1698,8 @@ private void validateAnnotatedField( && field.getType().isArray() || bin.type().name().endsWith("_ARRAY")) && bin.arraySizeExpr().isEmpty()) { - throw new IllegalArgumentException(field.toString() + ": missing expression in Bin#arraySizeExpression"); + throw new IllegalArgumentException( + field.toString() + ": missing expression in Bin#arraySizeExpression"); } } @@ -1652,7 +1730,8 @@ public JBBPDslBuilder AnnotatedClassFields(final Class annotatedClass) { return addAnnotatedClass(annotatedClass, true); } - protected JBBPDslBuilder addAnnotatedClass(final Class annotatedClass, final boolean onlyFields) { + protected JBBPDslBuilder addAnnotatedClass(final Class annotatedClass, + final boolean onlyFields) { final BinFieldContainer collected = collectAnnotatedFields(annotatedClass); final JBBPByteOrder old = this.byteOrder; @@ -1660,11 +1739,11 @@ protected JBBPDslBuilder addAnnotatedClass(final Class annotatedClass, final class Pair { final BinFieldContainer container; - final Iterator iter; + final Iterator fieldIterator; Pair(final BinFieldContainer container) { this.container = container; - this.iter = container.fields.iterator(); + this.fieldIterator = container.fields.iterator(); } } @@ -1690,20 +1769,20 @@ class Pair { while (!stack.isEmpty()) { final Pair pair = stack.remove(0); - while (pair.iter.hasNext()) { - final BinField field = pair.iter.next(); + while (pair.fieldIterator.hasNext()) { + final BinField field = pair.fieldIterator.next(); if (field instanceof BinFieldContainer) { - final BinFieldContainer conty = (BinFieldContainer) field; - if (conty == BinFieldContainer.END_STRUCT) { + final BinFieldContainer binFieldContainer = (BinFieldContainer) field; + if (binFieldContainer == BinFieldContainer.END_STRUCT) { this.CloseStruct(); } else { if (field.isArrayField()) { - this.StructArray(conty.getName(), conty.bin.arraySizeExpr()); + this.StructArray(binFieldContainer.getName(), binFieldContainer.bin.arraySizeExpr()); } else { - this.Struct(conty.getName()); + this.Struct(binFieldContainer.getName()); } stack.add(0, pair); - stack.add(0, new Pair(conty)); + stack.add(0, new Pair(binFieldContainer)); break; } } else { @@ -1712,9 +1791,11 @@ class Pair { switch (type) { case BIT_ARRAY: { if (field.bin.paramExpr().isEmpty()) { - this.BitArray(field.getName(), pair.container.getBitNumber(field), field.bin.arraySizeExpr()); + this.BitArray(field.getName(), pair.container.getBitNumber(field), + field.bin.arraySizeExpr()); } else { - this.CustomArray("bit", field.getName(), field.bin.arraySizeExpr(), field.bin.paramExpr()); + this.CustomArray("bit", field.getName(), field.bin.arraySizeExpr(), + field.bin.paramExpr()); } } break; @@ -1810,7 +1891,8 @@ class Pair { if (!field.getCustomType().isEmpty()) { this.ByteOrder(pair.container.getByteOrder(field)); if (field.isArrayField() || !field.bin.arraySizeExpr().isEmpty()) { - this.CustomArray(field.bin.customType(), field.getName(), field.bin.arraySizeExpr(), field.bin.paramExpr()); + this.CustomArray(field.bin.customType(), field.getName(), + field.bin.arraySizeExpr(), field.bin.paramExpr()); } else { this.Custom(field.bin.customType(), field.getName(), field.bin.arraySizeExpr()); } @@ -1823,7 +1905,7 @@ class Pair { } } final String comment = field.getComment(); - if (comment.length() != 0) { + if (!comment.isEmpty()) { this.Comment(comment); } } @@ -1854,7 +1936,8 @@ protected static class Item { Item(final BinType type, final String name, final JBBPByteOrder byteOrder) { this.type = type; - this.name = name == null ? null : assertNameIfNotNull(assertTextNotNullAndTrimmedNotEmpty(name)).trim(); + this.name = name == null ? null : + assertNameIfNotNull(assertTextNotNullAndTrimmedNotEmpty(name)).trim(); this.byteOrder = byteOrder; } @@ -1909,7 +1992,7 @@ public String toString() { result.append('[').append(this.sizeExpression).append(']'); } - if (this.name != null && this.name.length() != 0) { + if (this.name != null && !this.name.isEmpty()) { result.append(' ').append(this.name); } @@ -1969,7 +2052,8 @@ BinType findType() { return BinType.STRUCT; } if (this.bin.type() == BinType.UNDEFINED) { - return this.bin.customType().isEmpty() ? BinType.findCompatible(this.field.getType()) : this.bin.type(); + return this.bin.customType().isEmpty() ? BinType.findCompatible(this.field.getType()) : + this.bin.type(); } else { return this.bin.type(); } @@ -1981,7 +2065,7 @@ String getName() { if (this.field != null) { if (this.fieldLocalAnnotation) { if (this.bin != null) { - result = this.bin.name().length() == 0 ? this.field.getName() : this.bin.name(); + result = this.bin.name().isEmpty() ? this.field.getName() : this.bin.name(); } else { throw new Error("Unexpected"); } @@ -2039,18 +2123,18 @@ String getCustomType() { } protected static class BinFieldContainer extends BinField { + static final BinFieldContainer END_STRUCT = new BinFieldContainer(null, null); final List fields = new ArrayList<>(); final Class klazz; - static final BinFieldContainer END_STRUCT = new BinFieldContainer(null, null); - - BinFieldContainer(final Class klazz, final Bin bin, final boolean fieldLocalAnnotation, final Field field) { + BinFieldContainer(final Class klazz, final Bin bin, final boolean fieldLocalAnnotation, + final Field field) { super(bin, fieldLocalAnnotation, field); this.klazz = klazz; } BinFieldContainer(final Class klazz, final Field field) { - super((Bin) null, false, field); + super(null, false, field); this.klazz = klazz; } @@ -2058,8 +2142,12 @@ void sort() { Collections.sort(this.fields); } - void addAllFromContainer(final BinFieldContainer container) { - this.fields.addAll(container.fields); + void addAllFromContainerExcludeEndStruct(final BinFieldContainer container) { + for(final BinField field : container.fields) { + if (field != END_STRUCT) { + this.fields.add(field); + } + } } void addContainer(final BinFieldContainer container) { @@ -2119,7 +2207,8 @@ protected static class ItemAlign extends Item { protected static class ItemVal extends Item { ItemVal(final String name, final String sizeExpression) { super(BinType.UNDEFINED, assertTextNotNullAndTrimmedNotEmpty(name), JBBPByteOrder.BIG_ENDIAN); - this.sizeExpression = assertExpressionChars(assertTextNotNullAndTrimmedNotEmpty(sizeExpression).trim()); + this.sizeExpression = + assertExpressionChars(assertTextNotNullAndTrimmedNotEmpty(sizeExpression).trim()); } } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPSystemProperty.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPSystemProperty.java index 888305a2..7c88362e 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPSystemProperty.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPSystemProperty.java @@ -90,7 +90,8 @@ public int getAsInteger(final int defaultValue) { try { result = Integer.parseInt(value); } catch (NumberFormatException ex) { - throw new Error("Can't get the system property '" + this.propertyName + "' as integer value, may be wrong format [" + value + ']', ex); + throw new Error("Can't get the system property '" + this.propertyName + + "' as integer value, may be wrong format [" + value + ']', ex); } } return result; diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriter.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriter.java index a6f712da..25eaea17 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriter.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriter.java @@ -34,6 +34,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldArrayString; import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUByte; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayUInt; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUShort; import com.igormaznitsa.jbbp.model.JBBPFieldBit; import com.igormaznitsa.jbbp.model.JBBPFieldBoolean; @@ -46,6 +47,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldString; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; import com.igormaznitsa.jbbp.model.JBBPFieldUByte; +import com.igormaznitsa.jbbp.model.JBBPFieldUInt; import com.igormaznitsa.jbbp.model.JBBPFieldUShort; import com.igormaznitsa.jbbp.model.JBBPNumericField; import java.io.FilterWriter; @@ -57,6 +59,7 @@ import java.util.ArrayList; import java.util.Deque; import java.util.List; +import java.util.Objects; /** * the Writer allows to make text describes some bin data, it supports output of @@ -65,6 +68,7 @@ * * @since 1.1 */ +@SuppressWarnings({"resource", "SystemGetProperty"}) public class JBBPTextWriter extends FilterWriter { /** @@ -194,7 +198,7 @@ public class JBBPTextWriter extends FilterWriter { /** * The Current first value at line prefix. */ - private String prefixFirtValueAtLine; + private String prefixFirstValueAtLine; /** * The Current value prefix. @@ -259,7 +263,9 @@ public class JBBPTextWriter extends FilterWriter { * The Default constructor. A StringWriter will be used inside. */ public JBBPTextWriter() { - this(new StringWriter(1024), JBBPByteOrder.BIG_ENDIAN, System.getProperty("line.separator"), DEFAULT_RADIX, DEFAULT_VALUE_PREFIX, DEFAULT_FIRST_VALUE_LINE_PREFIX, DEFAULT_COMMENT_PREFIX, DEFAULT_HR_PREFIX, DEFAULT_VALUE_DELIMITER); + this(new StringWriter(1024), JBBPByteOrder.BIG_ENDIAN, System.getProperty("line.separator"), + DEFAULT_RADIX, DEFAULT_VALUE_PREFIX, DEFAULT_FIRST_VALUE_LINE_PREFIX, + DEFAULT_COMMENT_PREFIX, DEFAULT_HR_PREFIX, DEFAULT_VALUE_DELIMITER); } /** @@ -268,7 +274,9 @@ public JBBPTextWriter() { * @param out a writer to be wrapped, must not be null. */ public JBBPTextWriter(final Writer out) { - this(out, JBBPByteOrder.BIG_ENDIAN, System.getProperty("line.separator"), DEFAULT_RADIX, DEFAULT_VALUE_PREFIX, DEFAULT_FIRST_VALUE_LINE_PREFIX, DEFAULT_COMMENT_PREFIX, DEFAULT_HR_PREFIX, DEFAULT_VALUE_DELIMITER); + this(out, JBBPByteOrder.BIG_ENDIAN, System.getProperty("line.separator"), DEFAULT_RADIX, + DEFAULT_VALUE_PREFIX, DEFAULT_FIRST_VALUE_LINE_PREFIX, DEFAULT_COMMENT_PREFIX, + DEFAULT_HR_PREFIX, DEFAULT_VALUE_DELIMITER); } /** @@ -278,7 +286,9 @@ public JBBPTextWriter(final Writer out) { * @param byteOrder a byte order to be used, it must not be null. */ public JBBPTextWriter(final Writer out, final JBBPByteOrder byteOrder) { - this(out, byteOrder, System.getProperty("line.separator"), DEFAULT_RADIX, DEFAULT_VALUE_PREFIX, DEFAULT_FIRST_VALUE_LINE_PREFIX, DEFAULT_COMMENT_PREFIX, DEFAULT_HR_PREFIX, DEFAULT_VALUE_DELIMITER); + this(out, byteOrder, System.getProperty("line.separator"), DEFAULT_RADIX, DEFAULT_VALUE_PREFIX, + DEFAULT_FIRST_VALUE_LINE_PREFIX, DEFAULT_COMMENT_PREFIX, DEFAULT_HR_PREFIX, + DEFAULT_VALUE_DELIMITER); } /** @@ -330,18 +340,15 @@ public JBBPTextWriter( */ public static JBBPTextWriter makeStrWriter() { final String lineSeparator = System.setProperty("line.separator", "\n"); - return new JBBPTextWriter(new StringWriter(), JBBPByteOrder.BIG_ENDIAN, lineSeparator, 16, "0x", ".", ";", "~", ","); + return new JBBPTextWriter(new StringWriter(), JBBPByteOrder.BIG_ENDIAN, lineSeparator, 16, "0x", + ".", ";", "~", ","); } protected static String makeFieldComment(final JBBPAbstractField field) { final String path = field.getFieldPath(); final StringBuilder result = new StringBuilder(128); result.append(field.getTypeAsString()).append(' '); - if (path == null) { - result.append(""); - } else { - result.append(path); - } + result.append(Objects.requireNonNullElse(path, "")); return result.toString(); } @@ -404,7 +411,7 @@ private void ensureValueMode() throws IOException { e.onBeforeFirstValue(this); } writeIndent(); - this.write(this.prefixFirtValueAtLine); + this.write(this.prefixFirstValueAtLine); } break; case MODE_COMMENTS: { @@ -414,7 +421,7 @@ private void ensureValueMode() throws IOException { for (final Extra e : extras) { e.onBeforeFirstValue(this); } - this.write(this.prefixFirtValueAtLine); + this.write(this.prefixFirstValueAtLine); } break; case MODE_VALUES: @@ -425,7 +432,7 @@ private void ensureValueMode() throws IOException { } /** - * Write current indent to line as bunch of spaces. + * Write current indent to line as a bunch of spaces. * * @throws IOException it will be thrown for transport errors */ @@ -492,17 +499,17 @@ private void ensureNewLineMode() throws IOException { * @throws IOException it will be thrown for transport errors */ private void printValueString(final String value) throws IOException { - if (this.valuesLineCounter > 0 && this.valueSeparator.length() > 0) { + if (this.valuesLineCounter > 0 && !this.valueSeparator.isEmpty()) { this.write(this.valueSeparator); } - if (this.prefixValue.length() > 0) { + if (!this.prefixValue.isEmpty()) { this.write(this.prefixValue); } this.write(value); - if (this.postfixValue.length() > 0) { + if (!this.postfixValue.isEmpty()) { this.write(this.postfixValue); } this.valuesLineCounter++; @@ -578,11 +585,9 @@ public JBBPTextWriter Byte(final int value) throws IOException { } } - if (convertedByExtras == null) { - printValueString(JBBPUtils.ensureMinTextLength(JBBPUtils.ulong2str(value & 0xFF, this.radix, CHAR_BUFFER), this.maxCharsRadixForByte, '0', 0)); - } else { - printValueString(convertedByExtras); - } + printValueString(Objects.requireNonNullElseGet(convertedByExtras, () -> JBBPUtils + .ensureMinTextLength(JBBPUtils.ulong2str(value & 0xFF, this.radix, CHAR_BUFFER), + this.maxCharsRadixForByte, '0', 0))); return this; } @@ -664,7 +669,7 @@ public boolean isValues() { * @return the context */ public final JBBPTextWriter SetValueLinePrefix(final String text) { - this.prefixFirtValueAtLine = text == null ? "" : text; + this.prefixFirstValueAtLine = text == null ? "" : text; return this; } @@ -762,7 +767,8 @@ public JBBPTextWriter SetMaxValuesPerLine(final int value) { */ public JBBPTextWriter SetTabSpaces(final int numberOfSpacesPerTab) { if (numberOfSpacesPerTab <= 0) { - throw new IllegalArgumentException("Tab must contains positive number of space chars [" + numberOfSpacesPerTab + ']'); + throw new IllegalArgumentException( + "Tab must contains positive number of space chars [" + numberOfSpacesPerTab + ']'); } final int currentIdentSteps = this.indent / this.spacesInTab; this.spacesInTab = numberOfSpacesPerTab; @@ -796,7 +802,8 @@ public final JBBPTextWriter Radix(final int radix) { this.maxCharsRadixForByte = JBBPUtils.ulong2str(0xFFL, this.radix, CHAR_BUFFER).length(); this.maxCharsRadixForShort = JBBPUtils.ulong2str(0xFFFFL, this.radix, CHAR_BUFFER).length(); this.maxCharsRadixForInt = JBBPUtils.ulong2str(0xFFFFFFFFL, this.radix, CHAR_BUFFER).length(); - this.maxCharsRadixForLong = JBBPUtils.ulong2str(0xFFFFFFFFFFFFFFFFL, this.radix, CHAR_BUFFER).length(); + this.maxCharsRadixForLong = + JBBPUtils.ulong2str(0xFFFFFFFFFFFFFFFFL, this.radix, CHAR_BUFFER).length(); return this; } @@ -825,7 +832,9 @@ public JBBPTextWriter Short(final int value) throws IOException { } else { valueToWrite = value; } - printValueString(JBBPUtils.ensureMinTextLength(JBBPUtils.ulong2str(valueToWrite & 0xFFFFL, this.radix, CHAR_BUFFER), this.maxCharsRadixForShort, '0', 0)); + printValueString(JBBPUtils + .ensureMinTextLength(JBBPUtils.ulong2str(valueToWrite & 0xFFFFL, this.radix, CHAR_BUFFER), + this.maxCharsRadixForShort, '0', 0)); } else { printValueString(convertedByExtras); } @@ -853,11 +862,13 @@ public JBBPTextWriter Float(final float value) throws IOException { if (convertedByExtras == null) { final float valueToWrite; if (this.byteOrder == JBBPByteOrder.LITTLE_ENDIAN) { - valueToWrite = Float.intBitsToFloat((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(value))); + valueToWrite = + Float.intBitsToFloat((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(value))); } else { valueToWrite = value; } - printValueString(JBBPUtils.ensureMinTextLength(JBBPUtils.float2str(valueToWrite, this.radix), this.maxCharsRadixForShort, '0', 0)); + printValueString(JBBPUtils.ensureMinTextLength(JBBPUtils.float2str(valueToWrite, this.radix), + this.maxCharsRadixForShort, '0', 0)); } else { printValueString(convertedByExtras); } @@ -885,11 +896,13 @@ public JBBPTextWriter Double(final double value) throws IOException { if (convertedByExtras == null) { final double valueToWrite; if (this.byteOrder == JBBPByteOrder.LITTLE_ENDIAN) { - valueToWrite = Double.longBitsToDouble(JBBPFieldLong.reverseBits(Double.doubleToLongBits(value))); + valueToWrite = + Double.longBitsToDouble(JBBPFieldLong.reverseBits(Double.doubleToLongBits(value))); } else { valueToWrite = value; } - printValueString(JBBPUtils.ensureMinTextLength(JBBPUtils.double2str(valueToWrite, this.radix), this.maxCharsRadixForShort, '0', 0)); + printValueString(JBBPUtils.ensureMinTextLength(JBBPUtils.double2str(valueToWrite, this.radix), + this.maxCharsRadixForShort, '0', 0)); } else { printValueString(convertedByExtras); } @@ -1020,7 +1033,44 @@ public JBBPTextWriter Int(final int value) throws IOException { } else { valueToWrite = value; } - printValueString(JBBPUtils.ensureMinTextLength(JBBPUtils.ulong2str(valueToWrite & 0xFFFFFFFFL, this.radix, CHAR_BUFFER), this.maxCharsRadixForInt, '0', 0)); + printValueString(JBBPUtils.ensureMinTextLength( + JBBPUtils.ulong2str(valueToWrite & 0xFFFFFFFFL, this.radix, CHAR_BUFFER), + this.maxCharsRadixForInt, '0', 0)); + } else { + printValueString(convertedByExtras); + } + return this; + } + + /** + * Print unsigned integer value + * + * @param value value to be printed + * @return the context + * @throws IOException it will be thrown for transport error + * @since 2.0.4 + */ + public JBBPTextWriter UInt(final int value) throws IOException { + ensureValueMode(); + + String convertedByExtras = null; + for (final Extra e : this.extras) { + convertedByExtras = e.doConvertUIntToStr(this, value); + if (convertedByExtras != null) { + break; + } + } + + if (convertedByExtras == null) { + final long valueToWrite; + if (this.byteOrder == JBBPByteOrder.LITTLE_ENDIAN) { + valueToWrite = JBBPUtils.reverseByteOrder(value, 4); + } else { + valueToWrite = value; + } + printValueString(JBBPUtils.ensureMinTextLength( + JBBPUtils.ulong2str(valueToWrite & 0xFFFFFFFFL, this.radix, CHAR_BUFFER), + this.maxCharsRadixForInt, '0', 0)); } else { printValueString(convertedByExtras); } @@ -1038,6 +1088,18 @@ public JBBPTextWriter Int(final int[] values) throws IOException { return this.Int(values, 0, values.length); } + /** + * Print unsigned integer array. + * + * @param values unsigned integer array to be printed, must not be null + * @return the context + * @throws IOException it will be thrown for transport error + * @since 2.0.4 + */ + public JBBPTextWriter UInt(final int[] values) throws IOException { + return this.UInt(values, 0, values.length); + } + /** * Print values from integer array. * @@ -1054,6 +1116,23 @@ public JBBPTextWriter Int(final int[] values, int off, int len) throws IOExcepti return this; } + /** + * Print values from unsigned integer array. + * + * @param values unsigned integer array, must not be null + * @param off offset to the first element in array + * @param len number of elements to print + * @return the context + * @throws IOException it will be thrown for transport error + * @since 2.0.4 + */ + public JBBPTextWriter UInt(final int[] values, int off, int len) throws IOException { + while (len-- > 0) { + this.UInt(values[off++]); + } + return this; + } + /** * Increase indent. * @@ -1129,7 +1208,9 @@ public JBBPTextWriter Long(final long value) throws IOException { } else { valueToWrite = value; } - printValueString(JBBPUtils.ensureMinTextLength(JBBPUtils.ulong2str(valueToWrite, this.radix, CHAR_BUFFER), this.maxCharsRadixForLong, '0', 0)); + printValueString(JBBPUtils + .ensureMinTextLength(JBBPUtils.ulong2str(valueToWrite, this.radix, CHAR_BUFFER), + this.maxCharsRadixForLong, '0', 0)); } else { printValueString(convertedByExtras); } @@ -1231,8 +1312,8 @@ public JBBPTextWriter Comment(final String... comment) throws IOException { } if (c.indexOf('\n') >= 0) { - final String[] splitted = c.split("\\n", -1); - for (final String s : splitted) { + final String[] split = c.split("\\n", -1); + for (final String s : split) { this.ensureCommentMode(); this.write(s); } @@ -1255,7 +1336,8 @@ public String toString() { if (this.out instanceof StringWriter) { result = this.out.toString(); } else { - result = JBBPTextWriter.class.getName() + '(' + this.out.getClass().getName() + ")@" + System.identityHashCode(this); + result = JBBPTextWriter.class.getName() + '(' + this.out.getClass().getName() + ")@" + + System.identityHashCode(this); } return result; } @@ -1300,7 +1382,8 @@ public JBBPTextWriter Obj(final int objId, final Object... obj) throws IOExcepti * @return the context * @throws IOException it will be thrown for transport errors */ - public JBBPTextWriter Obj(final int objId, final Object[] array, int off, int len) throws IOException { + public JBBPTextWriter Obj(final int objId, final Object[] array, int off, int len) + throws IOException { while (len-- > 0) { this.Obj(objId, array[off++]); } @@ -1340,7 +1423,8 @@ public JBBPTextWriter Bin(final Object... objs) throws IOException { return this; } - protected void printAbstractFieldObject(final String postText, final JBBPAbstractField field) throws IOException { + protected void printAbstractFieldObject(final String postText, final JBBPAbstractField field) + throws IOException { final String postfix = (postText == null ? "" : " " + postText); if (field instanceof JBBPAbstractArrayField || field instanceof JBBPFieldStruct) { @@ -1349,7 +1433,8 @@ protected void printAbstractFieldObject(final String postText, final JBBPAbstrac HR(); IndentInc(); if (field instanceof JBBPAbstractArrayField) { - final JBBPAbstractArrayField array = (JBBPAbstractArrayField) field; + final JBBPAbstractArrayField array = + (JBBPAbstractArrayField) field; if (array.size() > 0) { if (array instanceof JBBPFieldArrayBit) { Byte(((JBBPFieldArrayBit) array).getArray()); @@ -1364,6 +1449,8 @@ protected void printAbstractFieldObject(final String postText, final JBBPAbstrac Byte(((JBBPFieldArrayByte) array).getArray()); } else if (array instanceof JBBPFieldArrayInt) { Int(((JBBPFieldArrayInt) array).getArray()); + } else if (array instanceof JBBPFieldArrayUInt) { + UInt(((JBBPFieldArrayUInt) array).getInternalArray()); } else if (array instanceof JBBPFieldArrayLong) { Long(((JBBPFieldArrayLong) array).getArray()); } else if (array instanceof JBBPFieldArrayShort) { @@ -1414,6 +1501,8 @@ protected void printAbstractFieldObject(final String postText, final JBBPAbstrac Byte(numeric.getAsInt()); } else if (numeric instanceof JBBPFieldInt) { Int(numeric.getAsInt()); + } else if (numeric instanceof JBBPFieldUInt) { + UInt(numeric.getAsInt()); } else if (numeric instanceof JBBPFieldLong) { Long(numeric.getAsLong()); } else if (numeric instanceof JBBPFieldShort) { @@ -1555,13 +1644,11 @@ public int getLinePosition() { return this.linePosition; } - @SuppressWarnings("NullableProblems") @Override public void write(final String str) throws IOException { this.write(str, 0, str.length()); } - @SuppressWarnings("NullableProblems") @Override public void write(final char[] cbuf) throws IOException { this.write(cbuf, 0, cbuf.length); @@ -1679,6 +1766,17 @@ public interface Extra { */ String doConvertIntToStr(JBBPTextWriter context, int value) throws IOException; + /** + * Convert unsigned integer value to string representation. + * + * @param context the context, must not be null + * @param value the unsigned integer value to be converted + * @return string representation of the integer value, must not return null + * @throws IOException it can be thrown for transport error + * @since 2.0.4 + */ + String doConvertUIntToStr(JBBPTextWriter context, int value) throws IOException; + /** * Convert float value to string representation. * @@ -1735,7 +1833,8 @@ public interface Extra { * anything * @throws IOException it will be thrown for transport error */ - String doConvertCustomField(JBBPTextWriter context, final Object obj, final Field field, final Bin annotation) throws IOException; + String doConvertCustomField(JBBPTextWriter context, final Object obj, final Field field, + final Bin annotation) throws IOException; } private final class MappedObjectLogger extends AbstractMappedClassFieldObserver { @@ -1743,25 +1842,26 @@ private final class MappedObjectLogger extends AbstractMappedClassFieldObserver private final Deque counterStack = new ArrayDeque<>(); private int arrayCounter; - protected void init() { + private void init() { arrayCounter = 0; counterStack.clear(); } private String makeFieldDescription(final Field field, final Bin annotation) { final StringBuilder result = new StringBuilder(); - if (annotation.name().length() == 0) { + if (annotation.name().isEmpty()) { result.append(field.getName()); } else { result.append(annotation.name()); } - if (annotation.comment().length() != 0) { + if (!annotation.comment().isEmpty()) { result.append(", ").append(annotation.comment()); } return result.toString(); } - private String makeStructDescription(final Object obj, final Field field, final Bin annotation) { + private String makeStructDescription(final Object obj, final Field field, + final Bin annotation) { final StringBuilder result = new StringBuilder(); final Class objClass = obj.getClass(); @@ -1776,12 +1876,16 @@ private String makeStructDescription(final Object obj, final Field field, final typeName = obj.getClass().getSimpleName(); } else { final Class fieldType = field.getType(); - typeName = fieldType.isArray() ? fieldType.getComponentType().getSimpleName() : fieldType.getSimpleName(); + typeName = fieldType.isArray() ? fieldType.getComponentType().getSimpleName() : + fieldType.getSimpleName(); } - final String name = annotation == null || annotation.name().length() == 0 ? typeName : annotation.name(); - final String fieldComment = annotation == null || annotation.comment().length() == 0 ? null : annotation.comment(); - final String objectComment = classAnno == null || classAnno.comment().length() == 0 ? null : classAnno.comment(); + final String name = + annotation == null || annotation.name().isEmpty() ? typeName : annotation.name(); + final String fieldComment = + annotation == null || annotation.comment().isEmpty() ? null : annotation.comment(); + final String objectComment = + classAnno == null || classAnno.comment().isEmpty() ? null : classAnno.comment(); result.append(name); if (fieldComment != null) { @@ -1822,13 +1926,15 @@ protected void onArrayEnd(final Object obj, final Field field, final Bin annotat } @Override - protected void onArrayStart(final Object obj, final Field field, final Bin annotation, final int length) { + protected void onArrayStart(final Object obj, final Field field, final Bin annotation, + final int length) { try { HR(); if (field.getType() == String.class) { Comment("STRING: " + makeFieldDescription(field, annotation)); } else { - Comment("START ARRAY : " + makeArrayDescription(field, annotation) + " OF " + field.getType().getComponentType().getSimpleName() + " [" + length + ']'); + Comment("START ARRAY : " + makeArrayDescription(field, annotation) + " OF " + + field.getType().getComponentType().getSimpleName() + " [" + length + ']'); } HR(); IndentInc(); @@ -1867,7 +1973,8 @@ protected void onStructStart(final Object obj, final Field field, final Bin anno } @Override - protected void onFieldLong(final Object obj, final Field field, final Bin annotation, final long value) { + protected void onFieldLong(final Object obj, final Field field, final Bin annotation, + final long value) { try { Long(value); if (this.arrayCounter == 0) { @@ -1879,7 +1986,8 @@ protected void onFieldLong(final Object obj, final Field field, final Bin annota } @Override - protected void onFieldInt(final Object obj, final Field field, final Bin annotation, final int value) { + protected void onFieldInt(final Object obj, final Field field, final Bin annotation, + final int value) { try { Int(value); if (this.arrayCounter == 0) { @@ -1891,7 +1999,21 @@ protected void onFieldInt(final Object obj, final Field field, final Bin annotat } @Override - protected void onFieldFloat(final Object obj, final Field field, final Bin annotation, final float value) { + protected void onFieldUInt(Object obj, Field field, Bin annotation, + int value) { + try { + UInt(value); + if (this.arrayCounter == 0) { + Comment(makeFieldDescription(field, annotation)); + } + } catch (IOException ex) { + throw new JBBPIOException("Can't log uint field", ex); + } + } + + @Override + protected void onFieldFloat(final Object obj, final Field field, final Bin annotation, + final float value) { try { Float(value); if (this.arrayCounter == 0) { @@ -1903,7 +2025,8 @@ protected void onFieldFloat(final Object obj, final Field field, final Bin annot } @Override - protected void onFieldString(final Object obj, final Field field, final Bin annotation, final String value) { + protected void onFieldString(final Object obj, final Field field, final Bin annotation, + final String value) { try { ensureValueMode(); final String prefix = prefixValue; @@ -1919,7 +2042,8 @@ protected void onFieldString(final Object obj, final Field field, final Bin anno } @Override - protected void onFieldDouble(final Object obj, final Field field, final Bin annotation, final double value) { + protected void onFieldDouble(final Object obj, final Field field, final Bin annotation, + final double value) { try { Double(value); if (this.arrayCounter == 0) { @@ -1931,7 +2055,8 @@ protected void onFieldDouble(final Object obj, final Field field, final Bin anno } @Override - protected void onFieldShort(final Object obj, final Field field, final Bin annotation, final boolean signed, final int value) { + protected void onFieldShort(final Object obj, final Field field, final Bin annotation, + final boolean signed, final int value) { try { Short(value); if (this.arrayCounter == 0) { @@ -1943,7 +2068,8 @@ protected void onFieldShort(final Object obj, final Field field, final Bin annot } @Override - protected void onFieldByte(final Object obj, final Field field, final Bin annotation, final boolean signed, final int value) { + protected void onFieldByte(final Object obj, final Field field, final Bin annotation, + final boolean signed, final int value) { try { Byte(value); if (this.arrayCounter == 0) { @@ -1955,7 +2081,8 @@ protected void onFieldByte(final Object obj, final Field field, final Bin annota } @Override - protected void onFieldBool(final Object obj, final Field field, final Bin annotation, final boolean value) { + protected void onFieldBool(final Object obj, final Field field, final Bin annotation, + final boolean value) { try { Byte(value ? 0x01 : 0x00); if (this.arrayCounter == 0) { @@ -1967,7 +2094,8 @@ protected void onFieldBool(final Object obj, final Field field, final Bin annota } @Override - protected void onFieldBits(final Object obj, final Field field, final Bin annotation, final JBBPBitNumber bitNumber, final int value) { + protected void onFieldBits(final Object obj, final Field field, final Bin annotation, + final JBBPBitNumber bitNumber, final int value) { try { Byte(value & bitNumber.getMask()); if (this.arrayCounter == 0) { @@ -1979,7 +2107,8 @@ protected void onFieldBits(final Object obj, final Field field, final Bin annota } @Override - protected void onFieldCustom(final Object obj, final Field field, final Bin annotation, final Object customFieldProcessor, final Object value) { + protected void onFieldCustom(final Object obj, final Field field, final Bin annotation, + final Object customFieldProcessor, final Object value) { try { if (extras.isEmpty()) { throw new IllegalStateException("There is not any registered extras"); @@ -2004,7 +2133,7 @@ protected void onFieldCustom(final Object obj, final Field field, final Bin anno } public void processObject(final Object obj) { - super.processObject(obj, null, this); + super.processObject(obj, null, null, this); } } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterExtraAdapter.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterExtraAdapter.java index 61813d2b..58727e95 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterExtraAdapter.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterExtraAdapter.java @@ -41,12 +41,14 @@ public void onClose(final JBBPTextWriter context) throws IOException { } @Override - public String doConvertByteToStr(final JBBPTextWriter context, final int value) throws IOException { + public String doConvertByteToStr(final JBBPTextWriter context, final int value) + throws IOException { return null; } @Override - public String doConvertShortToStr(final JBBPTextWriter context, final int value) throws IOException { + public String doConvertShortToStr(final JBBPTextWriter context, final int value) + throws IOException { return null; } @@ -61,22 +63,26 @@ public String doConvertDoubleToStr(JBBPTextWriter context, double value) throws } @Override - public String doConvertIntToStr(final JBBPTextWriter context, final int value) throws IOException { + public String doConvertIntToStr(final JBBPTextWriter context, final int value) + throws IOException { return null; } @Override - public String doConvertLongToStr(final JBBPTextWriter context, final long value) throws IOException { + public String doConvertLongToStr(final JBBPTextWriter context, final long value) + throws IOException { return null; } @Override - public String doConvertObjToStr(final JBBPTextWriter context, final int id, final Object obj) throws IOException { + public String doConvertObjToStr(final JBBPTextWriter context, final int id, final Object obj) + throws IOException { return null; } @Override - public String doConvertCustomField(final JBBPTextWriter context, final Object obj, final Field field, final Bin annotation) throws IOException { + public String doConvertCustomField(final JBBPTextWriter context, final Object obj, + final Field field, final Bin annotation) throws IOException { return null; } @@ -85,4 +91,8 @@ public void onReachedMaxValueNumberForLine(final JBBPTextWriter context) throws } + @Override + public String doConvertUIntToStr(JBBPTextWriter context, int value) throws IOException { + return null; + } } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPUtils.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPUtils.java index 47719ca1..4d33cf4f 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPUtils.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPUtils.java @@ -16,6 +16,14 @@ package com.igormaznitsa.jbbp.utils; +import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; +import com.igormaznitsa.jbbp.JBBPParser; +import com.igormaznitsa.jbbp.compiler.JBBPCompiledBlock; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.compiler.conversion.CompiledBlockVisitor; +import com.igormaznitsa.jbbp.compiler.conversion.IntConstValueEvaluator; +import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.compiler.varlen.JBBPIntegerValueEvaluator; import com.igormaznitsa.jbbp.io.JBBPBitNumber; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.io.JBBPByteOrder; @@ -23,18 +31,23 @@ import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiFunction; /** * Misc auxiliary methods to be used in the framework. * * @since 1.0 */ +@SuppressWarnings("StringRepeatCanBeUsed") public final class JBBPUtils { public static final String[] ARRAY_STRING_EMPTY = new String[0]; @@ -76,11 +89,11 @@ public static String utf8ToStr(final byte[] array) { * Check that a string is a number. * * @param num a string to be checked, it can be null - * @return true if the string represents a number, false if it is not number + * @return true if the string represents a number, false if it is not number, * or it is null */ public static boolean isNumber(final String num) { - if (num == null || num.length() == 0) { + if (num == null || num.isEmpty()) { return false; } final boolean firstIsDigit = Character.isDigit(num.charAt(0)); @@ -109,7 +122,8 @@ public static byte[] packInt(final int value) { } else if ((value & 0xFFFF0000) == 0) { return new byte[] {(byte) 0x80, (byte) (value >>> 8), (byte) value}; } else { - return new byte[] {(byte) 0x81, (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value}; + return new byte[] {(byte) 0x81, (byte) (value >>> 24), (byte) (value >>> 16), + (byte) (value >>> 8), (byte) value}; } } @@ -159,7 +173,8 @@ public static int unpackInt(final byte[] array, final JBBPIntCounter position) { final int result; switch (code) { case 0x80: { - result = ((array[position.getAndIncrement()] & 0xFF) << 8) | (array[position.getAndIncrement()] & 0xFF); + result = ((array[position.getAndIncrement()] & 0xFF) << 8) | + (array[position.getAndIncrement()] & 0xFF); } break; case 0x81: { @@ -170,7 +185,8 @@ public static int unpackInt(final byte[] array, final JBBPIntCounter position) { } break; default: - throw new IllegalArgumentException("Unsupported packed integer prefix [0x" + Integer.toHexString(code).toUpperCase(Locale.ENGLISH) + ']'); + throw new IllegalArgumentException("Unsupported packed integer prefix [0x" + + Integer.toHexString(code).toUpperCase(Locale.ENGLISH) + ']'); } return result; } @@ -210,20 +226,22 @@ public static String array2oct(final byte[] array) { * * @param array the array to be converted, it must not be null * @param prefix the prefix for each converted value, it can be null - * @param delimiter the delimeter for string representations + * @param delimiter the delimiter for string representations * @param brackets if true then place the result into square brackets * @param radix the base for conversion * @return the string representation of the byte array */ - public static String byteArray2String(final byte[] array, final String prefix, final String delimiter, final boolean brackets, final int radix) { + public static String byteArray2String(final byte[] array, final String prefix, + final String delimiter, final boolean brackets, + final int radix) { if (array == null) { return null; } - final int maxlen = Integer.toString(0xFF, radix).length(); + final int maxLength = Integer.toString(0xFF, radix).length(); final String zero = "00000000"; - final String normDelim = delimiter == null ? " " : delimiter; + final String normDelimiter = delimiter == null ? " " : delimiter; final String normPrefix = prefix == null ? "" : prefix; final StringBuilder result = new StringBuilder(array.length * 4); @@ -232,20 +250,20 @@ public static String byteArray2String(final byte[] array, final String prefix, f result.append('['); } - boolean nofirst = false; + boolean notFirst = false; for (final byte b : array) { - if (nofirst) { - result.append(normDelim); + if (notFirst) { + result.append(normDelimiter); } else { - nofirst = true; + notFirst = true; } result.append(normPrefix); final String v = Integer.toString(b & 0xFF, radix); - if (v.length() < maxlen) { - result.append(zero, 0, maxlen - v.length()); + if (v.length() < maxLength) { + result.append(zero, 0, maxLength - v.length()); } result.append(v.toUpperCase(Locale.ENGLISH)); } @@ -304,7 +322,7 @@ public static String bin2str(final byte[] values, final boolean separateBytes) { } /** - * Convert a byte array into string binary representation with defined bit + * Convert a byte array into string binary representation with defined a bit * order and possibility to separate bytes. * * @param values a byte array to be converted @@ -312,20 +330,21 @@ public static String bin2str(final byte[] values, final boolean separateBytes) { * @param separateBytes if true then bytes will be separated by spaces * @return the string representation of the array */ - public static String bin2str(final byte[] values, final JBBPBitOrder bitOrder, final boolean separateBytes) { + public static String bin2str(final byte[] values, final JBBPBitOrder bitOrder, + final boolean separateBytes) { if (values == null) { return null; } final StringBuilder result = new StringBuilder(values.length * (separateBytes ? 9 : 8)); - boolean nofirst = false; + boolean notFirst = false; for (final byte b : values) { if (separateBytes) { - if (nofirst) { + if (notFirst) { result.append(' '); } else { - nofirst = true; + notFirst = true; } } @@ -433,15 +452,15 @@ public static byte[] str2bin(final String values, final JBBPBitOrder bitOrder) { } /** - * Split a string for a char used as the delimeter. + * Split a string for a char used as the delimiter. * * @param str a string to be split - * @param splitChar a char to be used as delimeter - * @return array contains split string parts without delimeter chars + * @param splitChar a char to be used as delimiter + * @return array contains split string parts without delimiter chars */ public static String[] splitString(final String str, final char splitChar) { final int length = str.length(); - final StringBuilder bulder = new StringBuilder(Math.max(8, length)); + final StringBuilder builder = new StringBuilder(Math.max(8, length)); int counter = 1; for (int i = 0; i < length; i++) { @@ -456,14 +475,14 @@ public static String[] splitString(final String str, final char splitChar) { for (int i = 0; i < length; i++) { final char chr = str.charAt(i); if (chr == splitChar) { - result[position++] = bulder.toString(); - bulder.setLength(0); + result[position++] = builder.toString(); + builder.setLength(0); } else { - bulder.append(chr); + builder.append(chr); } } if (position < result.length) { - result[position] = bulder.toString(); + result[position] = builder.toString(); } return result; @@ -483,13 +502,14 @@ public static void assertNotNull(final Object object, final String message) { } /** - * Convert an integer number into human readable hexadecimal format. + * Convert an integer number into human-readable hexadecimal format. * * @param number a number to be converted - * @return a string with human readable hexadecimal number representation + * @return a string with human-readable hexadecimal number representation */ public static String int2msg(final int number) { - return number + " (0x" + Long.toHexString((long) number & 0xFFFFFFFFL).toUpperCase(Locale.ENGLISH) + ')'; + return number + " (0x" + + Long.toHexString((long) number & 0xFFFFFFFFL).toUpperCase(Locale.ENGLISH) + ')'; } /** @@ -519,11 +539,11 @@ public static void closeQuietly(final Closeable closeable) { } /** - * Convert chars of a string into a byte array contains the unicode codes. + * Convert chars of a string into a byte array contains the Unicode codes. * * @param byteOrder the byte order for the operation, must not be null * @param str the string which chars should be written, must not be null - * @return the byte array contains unicodes of the string written as byte + * @return the byte array contains uni-codes of the string written as byte * pairs * @since 1.1 */ @@ -586,23 +606,24 @@ public static byte[] reverseArray(final byte[] nullableArrayToBeInverted) { * the provided buffer is null or has not enough size * @since 1.1 */ - public static byte[] splitInteger(final int value, final boolean valueInLittleEndian, final byte[] buffer) { + public static byte[] splitInteger(final int value, final boolean valueInLittleEndian, + final byte[] buffer) { final byte[] result; if (buffer == null || buffer.length < 4) { result = new byte[4]; } else { result = buffer; } - int tmpvalue = value; + int tempValue = value; if (valueInLittleEndian) { for (int i = 0; i < 4; i++) { - result[i] = (byte) tmpvalue; - tmpvalue >>>= 8; + result[i] = (byte) tempValue; + tempValue >>>= 8; } } else { for (int i = 3; i >= 0; i--) { - result[i] = (byte) tmpvalue; - tmpvalue >>>= 8; + result[i] = (byte) tempValue; + tempValue >>>= 8; } } return result; @@ -620,23 +641,24 @@ public static byte[] splitInteger(final int value, final boolean valueInLittleEn * the provided buffer is null or has not enough size * @since 1.1 */ - public static byte[] splitLong(final long value, final boolean valueInLittleEndian, final byte[] buffer) { + public static byte[] splitLong(final long value, final boolean valueInLittleEndian, + final byte[] buffer) { final byte[] result; if (buffer == null || buffer.length < 8) { result = new byte[8]; } else { result = buffer; } - long tmpvalue = value; + long tempValue = value; if (valueInLittleEndian) { for (int i = 0; i < 8; i++) { - result[i] = (byte) tmpvalue; - tmpvalue >>>= 8; + result[i] = (byte) tempValue; + tempValue >>>= 8; } } else { for (int i = 7; i >= 0; i--) { - result[i] = (byte) tmpvalue; - tmpvalue >>>= 8; + result[i] = (byte) tempValue; + tempValue >>>= 8; } } return result; @@ -684,9 +706,9 @@ public static long reverseByteOrder(long value, int numOfLowerBytesToInvert) { int offsetInResult = (numOfLowerBytesToInvert - 1) * 8; while (numOfLowerBytesToInvert-- > 0) { - final long thebyte = value & 0xFF; + final long b = value & 0xFF; value >>>= 8; - result |= (thebyte << offsetInResult); + result |= (b << offsetInResult); offsetInResult -= 8; } @@ -783,7 +805,8 @@ public static String ulong2str(final long ulongValue, final int radix, final cha if (ulongValue > 0) { result = Long.toString(ulongValue, radix).toUpperCase(Locale.ENGLISH); } else { - final char[] buffer = charBuffer == null || charBuffer.length < 64 ? new char[64] : charBuffer; + final char[] buffer = + charBuffer == null || charBuffer.length < 64 ? new char[64] : charBuffer; int pos = buffer.length; long topPart = ulongValue >>> 32; long bottomPart = (ulongValue & 0xFFFFFFFFL) + ((topPart % radix) << 32); @@ -812,7 +835,8 @@ public static String ulong2str(final long ulongValue, final int radix, final cha * text has equals or greater length. * @since 1.1 */ - public static String ensureMinTextLength(final String text, final int neededLen, final char ch, final int mode) { + public static String ensureMinTextLength(final String text, final int neededLen, final char ch, + final int mode) { final int number = neededLen - text.length(); if (number <= 0) { return text; @@ -860,7 +884,7 @@ public static String ensureMinTextLength(final String text, final int neededLen, */ public static String removeLeadingZeros(final String str) { String result = str; - if (str != null && str.length() != 0) { + if (str != null && !str.isEmpty()) { int startIndex = 0; while (startIndex < str.length() - 1) { final char ch = str.charAt(startIndex); @@ -886,7 +910,7 @@ public static String removeLeadingZeros(final String str) { */ public static String removeTrailingZeros(final String str) { String result = str; - if (str != null && str.length() != 0) { + if (str != null && !str.isEmpty()) { int endIndex = str.length(); while (endIndex > 1) { final char ch = str.charAt(endIndex - 1); @@ -944,9 +968,9 @@ public static boolean arrayEndsWith(final byte[] array, final byte[] str) { if (array.length >= str.length) { result = true; int index = str.length; - int arrindex = array.length; + int arrayIndex = array.length; while (--index >= 0) { - if (array[--arrindex] != str[index]) { + if (array[--arrayIndex] != str[index]) { result = false; break; } @@ -972,8 +996,7 @@ public static int makeMask(final int value) { int msk = 1; do { msk <<= 1; - } - while (msk <= value); + } while (msk <= value); return msk - 1; } @@ -995,4 +1018,268 @@ public static boolean equals(final Object o1, final Object o2) { return o1.equals(o2); } + public static String toHexString(final long value, final int charsNum) { + String result = Long.toHexString(value).toUpperCase(Locale.ENGLISH); + if (charsNum >= result.length()) { + final StringBuilder buffer = new StringBuilder(charsNum); + for (int i = 0; i < charsNum - result.length(); i++) { + buffer.append('0'); + } + buffer.append(result); + result = buffer.toString(); + } + return result; + } + + /** + * Trace an input stream into a print writer. + * + * @param inStream input stream to be traced, must not be null + * @param out destination print stream, must not be null + * @throws IOException thrown if transport error + * @see #traceData(InputStream, int, int, String, String, String, String, char, boolean, PrintStream) + * @since 2.0.3 + */ + public static void traceData(final InputStream inStream, final PrintStream out) + throws IOException { + traceData( + inStream, + 4, + 8, + " ", + " ", + " | ", + " ", + '.', + true, + out + ); + } + + /** + * Trace an input stream into a print writer. + * + * @param inStream an input stream to be traced, must not be null + * @param valuesPerColumn number of value in one shown column + * @param columnsNumber number of eight byte columns + * @param afterAddressDelimiter string to be written after address section, must not be null + * @param interValueDelimiter string to be written after each value, must not be null + * @param interColumnDelimiter string to be written to show column, must not be null + * @param delimiterBeforeChars string to be written before chars section, must not be null + * @param nonPrintableChar char to be used for non-printable chars in chars section + * @param printAsChars true if char section is required, false otherwise + * @param out destination writer, must not be null + * @throws IOException thrown if any transport error + * @since 2.0.3 + */ + public static void traceData(final InputStream inStream, + int valuesPerColumn, + final int columnsNumber, + final String afterAddressDelimiter, + final String interValueDelimiter, + final String interColumnDelimiter, + final String delimiterBeforeChars, + final char nonPrintableChar, + final boolean printAsChars, + final PrintStream out) + throws IOException { + long address = 0L; + valuesPerColumn = valuesPerColumn <= 0 ? 1 : valuesPerColumn; + final int bytesPerLine = columnsNumber <= 0 ? 8 : columnsNumber * valuesPerColumn; + + final StringBuilder charBuffer = printAsChars ? new StringBuilder(bytesPerLine) : null; + + int lineByteCounter = 0; + + boolean ending = false; + + while (!Thread.currentThread().isInterrupted()) { + final int nextData; + if (ending) { + nextData = -1; + } else { + nextData = inStream.read(); + ending = nextData < 0; + } + + if (lineByteCounter == 0) { + out.print(toHexString(address, 8)); + out.print(afterAddressDelimiter); + } + if (charBuffer != null) { + charBuffer.append(nextData > 0x1F && nextData < 0xFF ? (char) nextData : nonPrintableChar); + } + out.print(nextData < 0 ? "--" : toHexString(nextData, 2)); + lineByteCounter++; + if (lineByteCounter == bytesPerLine) { + if (charBuffer != null) { + out.print(delimiterBeforeChars); + out.print(charBuffer); + charBuffer.setLength(0); + } + lineByteCounter = 0; + address += bytesPerLine; + out.println(); + if (ending) { + break; + } + } else if (lineByteCounter % valuesPerColumn == 0) { + out.print(interColumnDelimiter); + } else { + out.print(interValueDelimiter); + } + } + } + + /** + * Allows to calculate maximum static array size provided by script. It doesn't calculate any expressions, so that byte [1000*1000] a; will not be detected. + * Default size of non-static struct arrays will be recognized as 1. + * + * @param script script to be processed, must not be null + * @param customFieldTypeProcessor custom field type processor if needed, can be null if no custom types in use + * @return calculated biggest static array size with embedded structure awareness + * @since 3.0.0 + */ + public static long findMaxStaticArraySize(final String script, + final JBBPCustomFieldTypeProcessor customFieldTypeProcessor) { + return findMaxStaticArraySize(script, customFieldTypeProcessor, (fieldName, wholeStream) -> 1); + } + + /** + * Allows to calculate maximum static array size provided by script. It doesn't calculate any expressions, so that byte [1000*1000] a; will not be detected. + * + * @param script script to be processed, must not be null + * @param customFieldTypeProcessor custom field type processor if needed, can be null if no custom types in use + * @param expectedStructArraySizeSupplier supplier of default size for structures which size is noe static but calculable, + * it is a function which gets name info for named structure fields or null for anonymous fields + * and the flag that a whole stream should be read, as result it should return integer value of approximate expected size. + * @return calculated biggest static array size with embedded structure awareness + * @since 3.0.1 + */ + public static long findMaxStaticArraySize(final String script, + final JBBPCustomFieldTypeProcessor customFieldTypeProcessor, + final BiFunction expectedStructArraySizeSupplier) { + + final AtomicLong maxFound = new AtomicLong(); + final JBBPCompiledBlock compiledBlock = + JBBPParser.prepare(script, customFieldTypeProcessor).getCompiledBlock(); + final List structSizeStack = new ArrayList<>(); + + new CompiledBlockVisitor(0, compiledBlock) { + + private Integer extractStaticArraySize(int compiledBlockOffset, + JBBPIntegerValueEvaluator evaluator) { + if (evaluator instanceof IntConstValueEvaluator) { + return evaluator.eval(null, compiledBlockOffset, compiledBlock, null); + } + return null; + } + + private void processSize(final int size) { + long accum = size; + for (Integer i : structSizeStack) { + accum = Math.multiplyExact(accum, i); + } + maxFound.set(Math.max(accum, maxFound.get())); + } + + @Override + public void visitPrimitiveField(int offsetInCompiledBlock, int primitiveType, + JBBPNamedFieldInfo nullableNameFieldInfo, + JBBPByteOrder byteOrder, boolean readWholeStreamAsArray, + boolean altFieldType, + JBBPIntegerValueEvaluator nullableArraySize) { + + if (!readWholeStreamAsArray) { + final Integer staticSize = + extractStaticArraySize(offsetInCompiledBlock, nullableArraySize); + if (staticSize != null) { + processSize(staticSize); + } + } + } + + @Override + public void visitBitField(int offsetInCompiledBlock, JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nullableNameFieldInfo, + boolean readWholeStream, + JBBPIntegerValueEvaluator notNullFieldSize, + JBBPIntegerValueEvaluator nullableArraySize) { + if (!readWholeStream) { + final Integer staticSize = + extractStaticArraySize(offsetInCompiledBlock, nullableArraySize); + if (staticSize != null) { + processSize(staticSize); + } + } + } + + @Override + public void visitCustomField(int offsetInCompiledBlock, + JBBPFieldTypeParameterContainer notNullFieldType, + JBBPNamedFieldInfo nullableNameFieldInfo, + JBBPByteOrder byteOrder, boolean readWholeStream, + JBBPIntegerValueEvaluator nullableArraySizeEvaluator, + JBBPIntegerValueEvaluator extraDataValueEvaluator) { + if (!readWholeStream) { + final Integer staticSize = + extractStaticArraySize(offsetInCompiledBlock, nullableArraySizeEvaluator); + if (staticSize != null) { + processSize(staticSize); + } + } + } + + @Override + public void visitVarField(int offsetInCompiledBlock, JBBPNamedFieldInfo nullableNameFieldInfo, + JBBPByteOrder byteOrder, + boolean readWholeStream, + JBBPIntegerValueEvaluator nullableArraySize, + JBBPIntegerValueEvaluator extraDataValue) { + if (!readWholeStream) { + final Integer staticSize = + extractStaticArraySize(offsetInCompiledBlock, nullableArraySize); + if (staticSize != null) { + processSize(staticSize); + } + } + } + + @Override + public void visitStructureStart(final int offsetInCompiledBlock, + final JBBPByteOrder byteOrder, + final boolean readWholeStream, + final JBBPNamedFieldInfo nullableNameFieldInfo, + final JBBPIntegerValueEvaluator nullableArraySize) { + if (readWholeStream) { + structSizeStack.add( + expectedStructArraySizeSupplier.apply(nullableNameFieldInfo, readWholeStream)); + } else { + final Integer staticSize = + extractStaticArraySize(offsetInCompiledBlock, nullableArraySize); + if (staticSize == null) { + structSizeStack.add( + expectedStructArraySizeSupplier.apply(nullableNameFieldInfo, readWholeStream)); + } else { + processSize(staticSize); + structSizeStack.add(staticSize); + } + } + } + + @Override + public void visitStructureEnd(int offsetInCompiledBlock, + JBBPNamedFieldInfo nullableNameFieldInfo) { + structSizeStack.remove(structSizeStack.size() - 1); + } + + }.visit(); + + if (!structSizeStack.isEmpty()) { + throw new Error("Unexpectedly structure stack is not empty, contact developer!"); + } + + return maxFound.get(); + } + } diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JavaSrcTextBuffer.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JavaSrcTextBuffer.java index 52596231..46426e78 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JavaSrcTextBuffer.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JavaSrcTextBuffer.java @@ -180,10 +180,10 @@ public JavaSrcTextBuffer println(final String text) { * @return this instance */ public JavaSrcTextBuffer printLinesWithIndent(final String text) { - final String[] splitted = text.split("\n", -1); + final String[] split = text.split("\n", -1); - for (final String aSplitted : splitted) { - this.indent().println(aSplitted); + for (final String s : split) { + this.indent().println(s); } return this; @@ -196,10 +196,10 @@ public JavaSrcTextBuffer printLinesWithIndent(final String text) { * @return this instance */ public JavaSrcTextBuffer printCommentLinesWithIndent(final String text) { - final String[] splitted = text.split("\n", -1); + final String[] split = text.split("\n", -1); - for (final String aSplitted : splitted) { - this.indent().print("// ").println(aSplitted); + for (final String s : split) { + this.indent().print("// ").println(s); } return this; @@ -212,11 +212,11 @@ public JavaSrcTextBuffer printCommentLinesWithIndent(final String text) { * @return this instance */ public JavaSrcTextBuffer printCommentMultiLinesWithIndent(final String text) { - final String[] splitted = text.split("\n", -1); + final String[] split = text.split("\n", -1); this.indent().println("/*"); - for (final String aSplitted : splitted) { - this.indent().print(" * ").println(aSplitted); + for (final String s : split) { + this.indent().print(" * ").println(s); } this.indent().println(" */"); @@ -230,11 +230,11 @@ public JavaSrcTextBuffer printCommentMultiLinesWithIndent(final String text) { * @return this instance */ public JavaSrcTextBuffer printJavaDocLinesWithIndent(final String text) { - final String[] splitted = text.split("\n", -1); + final String[] split = text.split("\n", -1); this.indent().println("/**"); - for (final String aSplitted : splitted) { - this.indent().print(" * ").println(aSplitted); + for (final String s : split) { + this.indent().print(" * ").println(s); } this.indent().println(" */"); diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/ReflectUtils.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/ReflectUtils.java index d1710da7..c7d627af 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/ReflectUtils.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/ReflectUtils.java @@ -71,7 +71,8 @@ public static T newInstance(final Class klazz) { try { return klazz.getConstructor().newInstance(); } catch (Exception ex) { - throw new RuntimeException(String.format("Can't create instance of %s for error %s", klazz, ex.getMessage()), ex); + throw new RuntimeException( + String.format("Can't create instance of %s for error %s", klazz, ex.getMessage()), ex); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessorTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessorTest.java index 6c007e0a..7e7efeba 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessorTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessorTest.java @@ -16,8 +16,16 @@ package com.igormaznitsa.jbbp; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.io.JBBPByteOrder; @@ -28,12 +36,9 @@ import com.igormaznitsa.jbbp.model.JBBPFieldLong; import com.igormaznitsa.jbbp.model.JBBPFieldShort; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; -import org.junit.jupiter.api.Test; - import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPCustomFieldTypeProcessorTest { @@ -50,7 +55,8 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final String fieldName, final int extraData, final boolean isArray) { + public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, + final String fieldName, final int extraData, final boolean isArray) { callCounter.incrementAndGet(); assertNotNull(fieldType); @@ -83,13 +89,23 @@ public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final } @Override - public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final JBBPBitOrder bitOrder, final int parserFlags, final JBBPFieldTypeParameterContainer customFieldTypeInfo, final JBBPNamedFieldInfo fieldName, final int extraData, final boolean readWholeStream, final int arrayLength) throws IOException { + public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, + final JBBPBitOrder bitOrder, + final int parserFlags, + final JBBPFieldTypeParameterContainer customFieldTypeInfo, + final JBBPNamedFieldInfo fieldName, + final int extraData, + final boolean readWholeStream, + final int arrayLength, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { final String type = customFieldTypeInfo.getTypeName(); assertEquals(JBBPBitOrder.LSB0, bitOrder); assertEquals(JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF, parserFlags); - assertEquals(type.equals("some1") ? JBBPByteOrder.LITTLE_ENDIAN : JBBPByteOrder.BIG_ENDIAN, customFieldTypeInfo.getByteOrder()); + assertEquals(type.equals("some1") ? JBBPByteOrder.LITTLE_ENDIAN : JBBPByteOrder.BIG_ENDIAN, + customFieldTypeInfo.getByteOrder()); switch (type) { case "some1": @@ -103,7 +119,8 @@ public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final assertEquals("c", fieldName.getFieldName()); assertFalse(readWholeStream); assertEquals(-1, arrayLength); - return new JBBPFieldShort(fieldName, (short) in.readUnsignedShort(customFieldTypeInfo.getByteOrder())); + return new JBBPFieldShort(fieldName, + (short) in.readUnsignedShort(customFieldTypeInfo.getByteOrder())); case "some3": assertEquals(0, extraData); assertEquals("e", fieldName.getFieldName()); @@ -117,23 +134,29 @@ public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final } }; - final JBBPParser parser = JBBPParser.prepare("int a; 0; + final JBBPParser parser = JBBPParser.prepare("ubyte len; byte [len*2] a;") + .setExpressionArraySizeController(controller); + assertSame(controller, parser.getExpressionArraySizeController()); + } + + @Test + public void testNoChangeSize() throws Exception { + final AtomicInteger calls = new AtomicInteger(); + final JBBPParser parser = + JBBPParser.prepare("ubyte len; byte [len*2] a;").setExpressionArraySizeController( + (parser1, expressionEvaluator, fieldInfo, calculatedArraySize) -> { + calls.incrementAndGet(); + assertEquals("a", fieldInfo.getFieldName()); + assertEquals(4, calculatedArraySize); + return calculatedArraySize; + }); + parser.parse(new ByteArrayInputStream(new byte[] {2, 1, 2, 3, 4})); + assertEquals(1, calls.get()); + } + + @Test + public void testThrowException() { + final JBBPParser parser = + JBBPParser.prepare("ubyte len; byte [len*2] a;").setExpressionArraySizeController( + (parser1, expressionEvaluator, fieldInfo, calculatedArraySize) -> { + assertEquals("a", fieldInfo.getFieldName()); + if (calculatedArraySize > 2) { + throw new IllegalArgumentException(); + } + return calculatedArraySize; + }); + assertThrows(IllegalArgumentException.class, + () -> parser.parse(new ByteArrayInputStream(new byte[] {2, 1, 2, 3, 4}))); + } + + @Test + public void testChangeSize() throws Exception { + final JBBPParser parser = + JBBPParser.prepare("ubyte len; byte [len*2] a;").setExpressionArraySizeController( + (parser1, expressionEvaluator, fieldInfo, calculatedArraySize) -> { + assertEquals("a", fieldInfo.getFieldName()); + return calculatedArraySize - 1; + }); + assertEquals(3, parser.parse(new ByteArrayInputStream(new byte[] {2, 1, 2, 3, 4})) + .findFieldForNameAndType("a", + JBBPFieldArrayByte.class).size()); + } +} \ No newline at end of file diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserTest.java index 76db6388..7871c567 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserTest.java @@ -25,12 +25,16 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; - import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; import com.igormaznitsa.jbbp.exceptions.JBBPCompilationException; +import com.igormaznitsa.jbbp.exceptions.JBBPNumericFieldValueConversionException; import com.igormaznitsa.jbbp.exceptions.JBBPParsingException; +import com.igormaznitsa.jbbp.exceptions.JBBPReachedArraySizeLimitException; import com.igormaznitsa.jbbp.exceptions.JBBPTooManyFieldsFoundException; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; +import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.io.JBBPByteOrder; import com.igormaznitsa.jbbp.model.JBBPAbstractArrayField; import com.igormaznitsa.jbbp.model.JBBPAbstractField; @@ -44,6 +48,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldArrayShort; import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUByte; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayUInt; import com.igormaznitsa.jbbp.model.JBBPFieldArrayUShort; import com.igormaznitsa.jbbp.model.JBBPFieldBit; import com.igormaznitsa.jbbp.model.JBBPFieldBoolean; @@ -56,6 +61,7 @@ import com.igormaznitsa.jbbp.model.JBBPFieldString; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; import com.igormaznitsa.jbbp.model.JBBPFieldUByte; +import com.igormaznitsa.jbbp.model.JBBPFieldUInt; import com.igormaznitsa.jbbp.model.JBBPFieldUShort; import com.igormaznitsa.jbbp.utils.JBBPIntCounter; import com.igormaznitsa.jbbp.utils.TargetSources; @@ -89,7 +95,8 @@ public void testErrorDuringReadingOfNonNamedField() throws Exception { @Test public void testFieldNameCaseInsensetive_ExceptionForDuplicationOfFieldNames() throws Exception { - assertThrows(JBBPCompilationException.class, () -> JBBPParser.prepare("bool Field1; byte field1;")); + assertThrows(JBBPCompilationException.class, + () -> JBBPParser.prepare("bool Field1; byte field1;")); } @Test @@ -182,35 +189,47 @@ public void testCompile_Value_CompilationErrors() { @Test public void testParse_Value_Constant() throws Exception { final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[0])); - assertEquals(34, JBBPParser.prepare("val:34 value;").parse(stream).findFieldForType(JBBPFieldInt.class).getAsInt()); + assertEquals(34, + JBBPParser.prepare("val:34 value;").parse(stream).findFieldForType(JBBPFieldInt.class) + .getAsInt()); assertEquals(0L, stream.getCounter()); } @Test public void testParse_Value_NegativeConstant() throws Exception { final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[0])); - assertEquals(-34, JBBPParser.prepare("val:-34 value;").parse(stream).findFieldForType(JBBPFieldInt.class).getAsInt()); + assertEquals(-34, + JBBPParser.prepare("val:-34 value;").parse(stream).findFieldForType(JBBPFieldInt.class) + .getAsInt()); assertEquals(0L, stream.getCounter()); } @Test public void testParse_Value_Expression() throws Exception { - final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2})); - assertEquals(3, JBBPParser.prepare("ubyte a; ubyte b; val:(a+b) value;").parse(stream).findFieldForType(JBBPFieldInt.class).getAsInt()); + final JBBPBitInputStream stream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2})); + assertEquals(3, JBBPParser.prepare("ubyte a; ubyte b; val:(a+b) value;").parse(stream) + .findFieldForType(JBBPFieldInt.class).getAsInt()); assertEquals(2L, stream.getCounter()); } @Test public void testParse_Value_UseInExpression_NegativeResult() throws Exception { - final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2})); - assertEquals(-2, JBBPParser.prepare("ubyte a; ubyte b; val:(a-b) value; val:(value*2) secondvalue;").parse(stream).findFieldForNameAndType("secondvalue", JBBPFieldInt.class).getAsInt()); + final JBBPBitInputStream stream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2})); + assertEquals(-2, + JBBPParser.prepare("ubyte a; ubyte b; val:(a-b) value; val:(value*2) secondvalue;") + .parse(stream).findFieldForNameAndType("secondvalue", JBBPFieldInt.class).getAsInt()); assertEquals(2L, stream.getCounter()); } @Test public void testParse_Value_UseInExpression() throws Exception { - final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2})); - assertEquals(6, JBBPParser.prepare("ubyte a; ubyte b; val:(a+b) value; val:(value*2) secondvalue;").parse(stream).findFieldForNameAndType("secondvalue", JBBPFieldInt.class).getAsInt()); + final JBBPBitInputStream stream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2})); + assertEquals(6, + JBBPParser.prepare("ubyte a; ubyte b; val:(a+b) value; val:(value*2) secondvalue;") + .parse(stream).findFieldForNameAndType("secondvalue", JBBPFieldInt.class).getAsInt()); assertEquals(2L, stream.getCounter()); } @@ -305,21 +324,24 @@ public void testParse_UShort_ErrorForEOF() throws Exception { public void testParse_SingleDefaultNonamedUShort_Default() throws Exception { final JBBPParser parser = JBBPParser.prepare("ushort;"); final JBBPFieldStruct result = parser.parse(new byte[] {-1, -2}); - assertEquals(((-1 << 8) | (-2 & 0xFF)) & 0xFFFF, result.findFieldForType(JBBPFieldUShort.class).getAsInt()); + assertEquals(((-1 << 8) | (-2 & 0xFF)) & 0xFFFF, + result.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_SingleDefaultNonamedUShort_BigEndian() throws Exception { final JBBPParser parser = JBBPParser.prepare(">ushort;"); final JBBPFieldStruct result = parser.parse(new byte[] {-1, -2}); - assertEquals(((-1 << 8) | (-2 & 0xFF)) & 0xFFFF, result.findFieldForType(JBBPFieldUShort.class).getAsInt()); + assertEquals(((-1 << 8) | (-2 & 0xFF)) & 0xFFFF, + result.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_SingleDefaultNonamedUShort_LittleEndian() throws Exception { final JBBPParser parser = JBBPParser.prepare("floatj;"); final JBBPFieldStruct result = parser.parse(new byte[] {1, 2, 3, 4}); - assertEquals(2.3879393E-38f, result.findFieldForType(JBBPFieldFloat.class).getAsFloat(), TestUtils.FLOAT_DELTA); + assertEquals(2.3879393E-38f, result.findFieldForType(JBBPFieldFloat.class).getAsFloat(), + TestUtils.FLOAT_DELTA); } @Test public void testParse_SingleDefaultNonamedFloat_LittleEndian() throws Exception { final JBBPParser parser = JBBPParser.prepare("doublej;"); final JBBPFieldStruct result = parser.parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); - assertEquals(8.20788039913184E-304d, result.findFieldForType(JBBPFieldDouble.class).getAsDouble(), TestUtils.FLOAT_DELTA); + assertEquals(8.20788039913184E-304d, + result.findFieldForType(JBBPFieldDouble.class).getAsDouble(), TestUtils.FLOAT_DELTA); } @Test public void testParse_SingleDefaultNonamedDouble_LittleEndian() throws Exception { final JBBPParser parser = JBBPParser.prepare(" readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - assertNotNull(inStream); - final int value = inStream.readByte(); - assertEquals(33, value); - assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); - - assertNull(fieldName); - assertEquals(0, extraValue); - assertEquals(JBBPByteOrder.BIG_ENDIAN, byteOrder); - - counter.incrementAndGet(); - - return new JBBPFieldByte(fieldName, (byte) value); - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + fail("Must not be called"); + return null; + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + assertNotNull(inStream); + final int value = inStream.readByte(); + assertEquals(33, value); + assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); + + assertNull(fieldName); + assertEquals(0, extraValue); + assertEquals(JBBPByteOrder.BIG_ENDIAN, byteOrder); + + counter.incrementAndGet(); + + return new JBBPFieldByte(fieldName, (byte) value); + } + }, null); assertNotNull(struct); assertEquals(33, struct.findFieldForType(JBBPFieldByte.class).getAsInt()); @@ -473,7 +511,8 @@ public void testGetFlags() throws Exception { @Test public void testParse_Bit_ExtraNumericFieldAsExpression() throws Exception { - final JBBPParser parser = JBBPParser.prepare("ubyte a; bit:(a*4-12) b; bit:(a) c; bit:(a*2) d;"); + final JBBPParser parser = + JBBPParser.prepare("ubyte a; bit:(a*4-12) b; bit:(a) c; bit:(a*2) d;"); final JBBPFieldStruct parsed = parser.parse(new byte[] {4, 0x12, 0x34}); assertEquals(4, parsed.findFieldForNameAndType("a", JBBPFieldUByte.class).getAsInt()); assertEquals(2, parsed.findFieldForNameAndType("b", JBBPFieldBit.class).getAsInt()); @@ -483,11 +522,13 @@ public void testParse_Bit_ExtraNumericFieldAsExpression() throws Exception { @Test public void testParse_BitArray_ExtraNumericFieldAsExpression() throws Exception { - final JBBPParser parser = JBBPParser.prepare("ubyte s; ubyte a; bit:(a*4-12) [s] b; bit:(a*2) d;"); + final JBBPParser parser = + JBBPParser.prepare("ubyte s; ubyte a; bit:(a*4-12) [s] b; bit:(a*2) d;"); final JBBPFieldStruct parsed = parser.parse(new byte[] {2, 4, 0x12, 0x34}); assertEquals(2, parsed.findFieldForNameAndType("s", JBBPFieldUByte.class).getAsInt()); assertEquals(4, parsed.findFieldForNameAndType("a", JBBPFieldUByte.class).getAsInt()); - assertArrayEquals(new byte[] {2, 1}, parsed.findFieldForNameAndType("b", JBBPFieldArrayBit.class).getArray()); + assertArrayEquals(new byte[] {2, 1}, + parsed.findFieldForNameAndType("b", JBBPFieldArrayBit.class).getArray()); assertEquals(0x34, parsed.findFieldForNameAndType("d", JBBPFieldBit.class).getAsInt()); } @@ -510,20 +551,30 @@ public void testParse_Align_ExtraNumericFieldAsExpression() throws Exception { @Test public void testParse_Var_ExtraNumericFieldAsExpression() throws Exception { final JBBPParser parser = JBBPParser.prepare("ubyte a; var:(a/21) vvv; ubyte b;"); - final JBBPFieldStruct parsed = parser.parse(new byte[] {(byte) 123, 0x12, 0x34, 0x11, 0x22, 0x56}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - inStream.skip(3); - assertEquals(123 / 21, extraValue); - return new JBBPFieldInt(fieldName, 666); - } - }, null); + final JBBPFieldStruct parsed = parser + .parse(new byte[] {(byte) 123, 0x12, 0x34, 0x11, 0x22, 0x56}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, + int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, final JBBPByteOrder byteOrder, + JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + inStream.skip(3); + assertEquals(123 / 21, extraValue); + return new JBBPFieldInt(fieldName, 666); + } + }, null); assertEquals(123, parsed.findFieldForNameAndType("a", JBBPFieldUByte.class).getAsInt()); assertEquals(666, parsed.findFieldForNameAndType("vvv", JBBPFieldInt.class).getAsInt()); assertEquals(0x22, parsed.findFieldForNameAndType("b", JBBPFieldUByte.class).getAsInt()); @@ -531,24 +582,38 @@ public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final J @Test public void testParse_VarArray_ExtraNumericFieldAsExpression() throws Exception { - final JBBPParser parser = JBBPParser.prepare("ubyte s; ubyte a; var:(a/21) [s*2] vvv; ubyte b;"); - final JBBPFieldStruct parsed = parser.parse(new byte[] {4, (byte) 123, 0x12, 0x34, 0x11, 0x22, 0x56}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - inStream.skip(3); - assertEquals(123 / 21, extraValue); - assertEquals(8, arraySize); - return new JBBPFieldArrayByte(fieldName, new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - }, null); + final JBBPParser parser = + JBBPParser.prepare("ubyte s; ubyte a; var:(a/21) [s*2] vvv; ubyte b;"); + final JBBPFieldStruct parsed = parser + .parse(new byte[] {4, (byte) 123, 0x12, 0x34, 0x11, 0x22, 0x56}, + new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, + int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + inStream.skip(3); + assertEquals(123 / 21, extraValue); + assertEquals(8, arraySize); + return new JBBPFieldArrayByte(fieldName, new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, + final JBBPByteOrder byteOrder, + JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + }, null); assertEquals(123, parsed.findFieldForNameAndType("a", JBBPFieldUByte.class).getAsInt()); - assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, parsed.findFieldForNameAndType("vvv", JBBPFieldArrayByte.class).getArray()); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, + parsed.findFieldForNameAndType("vvv", JBBPFieldArrayByte.class).getArray()); assertEquals(0x22, parsed.findFieldForNameAndType("b", JBBPFieldUByte.class).getAsInt()); } @@ -557,30 +622,40 @@ public void testParse_NamedVarWithCustomOrder() throws Exception { final JBBPParser parser = JBBPParser.prepare("short k; readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - assertNotNull(inStream); - final int value = inStream.readByte(); - assertEquals(33, value); - assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); - - assertEquals("some", fieldName.getFieldName()); - assertEquals(-12345, extraValue); - assertEquals(JBBPByteOrder.LITTLE_ENDIAN, byteOrder); - - counter.incrementAndGet(); - - return new JBBPFieldByte(fieldName, (byte) value); - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + fail("Must not be called"); + return null; + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + assertNotNull(inStream); + final int value = inStream.readByte(); + assertEquals(33, value); + assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); + + assertEquals("some", fieldName.getFieldName()); + assertEquals(-12345, extraValue); + assertEquals(JBBPByteOrder.LITTLE_ENDIAN, byteOrder); + + counter.incrementAndGet(); + + return new JBBPFieldByte(fieldName, (byte) value); + } + }, null); assertEquals(33, struct.findFieldForNameAndType("some", JBBPFieldByte.class).getAsInt()); assertEquals(1, counter.get()); @@ -595,32 +670,46 @@ public void testParse_StringFieldInExpression_NoErrorDuringCompilation() throws @Test public void testParse_StringFieldInArihmeticExpression_ArihmeticException() throws Exception { final JBBPParser parser = JBBPParser.prepare("byte a; stringj b; byte[a+b];"); - assertThrows(ArithmeticException.class, () -> parser.parse(new byte[] {1, 3, 65, 66, 67, 0, 1, 2, 3})); + assertThrows(ArithmeticException.class, + () -> parser.parse(new byte[] {1, 3, 65, 66, 67, 0, 1, 2, 3})); } @Test - public void testParse_StringFieldAsSingleVariableInExpression_ArihmeticException() throws Exception { + public void testParse_StringFieldAsSingleVariableInExpression_ArihmeticException() + throws Exception { final JBBPParser parser = JBBPParser.prepare("stringj b; byte[b];"); - assertThrows(ArithmeticException.class, () -> parser.parse(new byte[] {3, 65, 66, 67, 0, 1, 2, 3})); + assertThrows(ArithmeticException.class, + () -> parser.parse(new byte[] {3, 65, 66, 67, 0, 1, 2, 3})); } @Test public void testParse_SingleNonamedVar_ErrorForNullResult() throws Exception { final JBBPParser parser = JBBPParser.prepare("short k; var; int;"); assertThrows(NullPointerException.class, () -> { - final JBBPFieldStruct struct = parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - return null; - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + fail("Must not be called"); + return null; + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, + final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + return null; + } + }, null); }); } @@ -629,19 +718,30 @@ public void testParse_SingleNonamedVar_ErrorForArrayResult() throws Exception { final JBBPParser parser = JBBPParser.prepare("short k; var; int;"); assertThrows(JBBPParsingException.class, () -> { - final JBBPFieldStruct struct = parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - return new JBBPFieldArrayByte(fieldName, new byte[] {1, 2, 3}); - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + fail("Must not be called"); + return null; + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, + final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + return new JBBPFieldArrayByte(fieldName, new byte[] {1, 2, 3}); + } + }, null); }); } @@ -650,20 +750,31 @@ public void testParse_SingleNonamedVar_ErrorForDifferentName() throws Exception final JBBPParser parser = JBBPParser.prepare("short k; var name; int;"); assertThrows(JBBPParsingException.class, () -> { - final JBBPFieldStruct struct = parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - assertNotNull(fieldName); - return new JBBPFieldByte(new JBBPNamedFieldInfo("jskdjhsd", "dlkjsf", 0), (byte) 1); - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + fail("Must not be called"); + return null; + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, + final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + assertNotNull(fieldName); + return new JBBPFieldByte(new JBBPNamedFieldInfo("jskdjhsd", "dlkjsf", 0), (byte) 1); + } + }, null); }); } @@ -673,34 +784,45 @@ public void testParse_SingleNonamedVarArray() throws Exception { final JBBPIntCounter counter = new JBBPIntCounter(); - final JBBPFieldStruct struct = parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - assertNotNull(inStream); - final int value = inStream.readByte(); - assertEquals(33, value); - assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); - - assertNull(fieldName); - assertEquals(0, extraValue); - assertEquals(18, arraySize); - assertEquals(JBBPByteOrder.BIG_ENDIAN, byteOrder); - - counter.incrementAndGet(); - - return new JBBPFieldArrayByte(fieldName, new byte[] {(byte) value}); - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + assertNotNull(inStream); + final int value = inStream.readByte(); + assertEquals(33, value); + assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); + + assertNull(fieldName); + assertEquals(0, extraValue); + assertEquals(18, arraySize); + assertEquals(JBBPByteOrder.BIG_ENDIAN, byteOrder); + + counter.incrementAndGet(); + + return new JBBPFieldArrayByte(fieldName, new byte[] {(byte) value}); + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + fail("Must not be called"); + return null; + } + }, null); assertNotNull(struct); - assertArrayEquals(new byte[] {33}, struct.findFieldForType(JBBPFieldArrayByte.class).getArray()); + assertArrayEquals(new byte[] {33}, + struct.findFieldForType(JBBPFieldArrayByte.class).getArray()); assertEquals(1, counter.get()); } @@ -710,34 +832,45 @@ public void testParse_NamedVarArrayWithCustomOrder() throws Exception { final JBBPIntCounter counter = new JBBPIntCounter(); - final JBBPFieldStruct struct = parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - assertNotNull(inStream); - final int value = inStream.readByte(); - assertEquals(33, value); - assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); - - assertEquals("some", fieldName.getFieldName()); - assertEquals(-12345, extraValue); - assertEquals(2334, arraySize); - assertEquals(JBBPByteOrder.LITTLE_ENDIAN, byteOrder); - - counter.incrementAndGet(); - - return new JBBPFieldArrayByte(fieldName, new byte[] {(byte) value}); - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + assertNotNull(inStream); + final int value = inStream.readByte(); + assertEquals(33, value); + assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); + + assertEquals("some", fieldName.getFieldName()); + assertEquals(-12345, extraValue); + assertEquals(2334, arraySize); + assertEquals(JBBPByteOrder.LITTLE_ENDIAN, byteOrder); + + counter.incrementAndGet(); + + return new JBBPFieldArrayByte(fieldName, new byte[] {(byte) value}); + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + fail("Must not be called"); + return null; + } + }, null); assertNotNull(struct); - assertArrayEquals(new byte[] {33}, struct.findFieldForNameAndType("some", JBBPFieldArrayByte.class).getArray()); + assertArrayEquals(new byte[] {33}, + struct.findFieldForNameAndType("some", JBBPFieldArrayByte.class).getArray()); assertEquals(1, counter.get()); } @@ -747,33 +880,44 @@ public void testParse_NamedVarArrayTillEndOfStream() throws Exception { final JBBPIntCounter counter = new JBBPIntCounter(); - final JBBPFieldStruct struct = parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - assertNotNull(inStream); - - assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); - - assertEquals("some", fieldName.getFieldName()); - assertEquals(0, extraValue); - assertTrue(arraySize < 0); - assertEquals(JBBPByteOrder.BIG_ENDIAN, byteOrder); - - counter.incrementAndGet(); - - return new JBBPFieldArrayByte(fieldName, inStream.readByteArray(-1)); - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + assertNotNull(inStream); + + assertEquals(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); + + assertEquals("some", fieldName.getFieldName()); + assertEquals(0, extraValue); + assertTrue(arraySize < 0); + assertEquals(JBBPByteOrder.BIG_ENDIAN, byteOrder); + + counter.incrementAndGet(); + + return new JBBPFieldArrayByte(fieldName, inStream.readByteArray(-1)); + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + fail("Must not be called"); + return null; + } + }, null); assertNotNull(struct); - assertArrayEquals(new byte[] {33, 1, 2, 3, 4}, struct.findFieldForNameAndType("some", JBBPFieldArrayByte.class).getArray()); + assertArrayEquals(new byte[] {33, 1, 2, 3, 4}, + struct.findFieldForNameAndType("some", JBBPFieldArrayByte.class).getArray()); assertEquals(1, counter.get()); } @@ -784,13 +928,21 @@ public void testParse_NamedVarArrayForZeroLength() throws Exception { final JBBPFieldStruct struct = parser.parse(new byte[] {0, 0}, new JBBPVarFieldProcessor() { @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) throws IOException { assertEquals(0, arraySize); return new JBBPFieldArrayByte(fieldName, new byte[0]); } @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { fail("Must not be called"); return null; } @@ -805,20 +957,31 @@ public void testParse_SingleNonamedVarArray_ErrorForNullResult() throws Exceptio final JBBPParser parser = JBBPParser.prepare("short k; var [k]; int;"); assertThrows(NullPointerException.class, () -> { - final JBBPFieldStruct struct = parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - assertEquals(0x0908, arraySize); - return null; - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + assertEquals(0x0908, arraySize); + return null; + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, + final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + fail("Must not be called"); + return null; + } + }, null); }); } @@ -827,20 +990,32 @@ public void testParse_SingleNonamedVarArray_ErrorForDifferentName() throws Excep final JBBPParser parser = JBBPParser.prepare("short k; var [234] name; int;"); assertThrows(JBBPParsingException.class, () -> { - final JBBPFieldStruct struct = parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - assertNotNull(fieldName); - return new JBBPFieldArrayByte(new JBBPNamedFieldInfo("jskdjhsd", "dlkjsf", 0), new byte[] {1}); - } - - @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - }, null); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, + final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + assertNotNull(fieldName); + return new JBBPFieldArrayByte(new JBBPNamedFieldInfo("jskdjhsd", "dlkjsf", 0), + new byte[] {1}); + } + + @Override + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, + final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + fail("Must not be called"); + return null; + } + }, null); }); } @@ -851,14 +1026,22 @@ public void testParse_BitFields_EOF() throws Exception { @Test public void testParse_BitFields_SizeProvidedThroughExpression() throws Exception { - assertEquals(4, JBBPParser.prepare("ubyte a; ubyte b; bit:(a+b) c;").parse(new byte[] {1, 2, (byte) 0xB4}).findFieldForType(JBBPFieldBit.class).getAsInt()); - assertEquals(20, JBBPParser.prepare("ubyte a; ubyte b; bit:(a+b) c;").parse(new byte[] {3, 2, (byte) 0xB4}).findFieldForType(JBBPFieldBit.class).getAsInt()); + assertEquals(4, + JBBPParser.prepare("ubyte a; ubyte b; bit:(a+b) c;").parse(new byte[] {1, 2, (byte) 0xB4}) + .findFieldForType(JBBPFieldBit.class).getAsInt()); + assertEquals(20, + JBBPParser.prepare("ubyte a; ubyte b; bit:(a+b) c;").parse(new byte[] {3, 2, (byte) 0xB4}) + .findFieldForType(JBBPFieldBit.class).getAsInt()); } @Test public void testParse_BitFields_ErrorForWrongValueOfBitFieldLength() throws Exception { - assertThrows(IllegalArgumentException.class, () -> JBBPParser.prepare("ubyte a; ubyte b; bit:(a+b) c;").parse(new byte[] {11, 2, (byte) 0xB4})); - assertThrows(IllegalArgumentException.class, () -> JBBPParser.prepare("ubyte a; ubyte b; bit:(a-b) c;").parse(new byte[] {2, 2, (byte) 0xB4})); + assertThrows(IllegalArgumentException.class, + () -> JBBPParser.prepare("ubyte a; ubyte b; bit:(a+b) c;") + .parse(new byte[] {11, 2, (byte) 0xB4})); + assertThrows(IllegalArgumentException.class, + () -> JBBPParser.prepare("ubyte a; ubyte b; bit:(a-b) c;") + .parse(new byte[] {2, 2, (byte) 0xB4})); } @Test @@ -868,13 +1051,17 @@ public void testParse_BitFieldArray_EOF() throws Exception { @Test public void testParse_BitFieldArrayWholeStream_Empty() throws Exception { - assertEquals(0, JBBPParser.prepare("bit:4 [_];").parse(new byte[0]).findFieldForType(JBBPFieldArrayBit.class).size()); + assertEquals(0, JBBPParser.prepare("bit:4 [_];").parse(new byte[0]) + .findFieldForType(JBBPFieldArrayBit.class).size()); } @Test public void testParse_SeveralPrimitiveFields() throws Exception { - final JBBPParser parser = JBBPParser.prepare("bit:4; bit:4; bool; byte; ubyte; short; ushort; int; long;"); - final JBBPFieldStruct result = parser.parse(new byte[] {0x12, 1, 87, (byte) 0xF3, 1, 2, (byte) 0xFE, 4, 6, 7, 8, 9, (byte) 0xFF, 1, 2, 3, 5, 6, 7, 8, 9}); + final JBBPParser parser = + JBBPParser.prepare("bit:4; bit:4; bool; byte; ubyte; short; ushort; int; long;"); + final JBBPFieldStruct result = parser.parse( + new byte[] {0x12, 1, 87, (byte) 0xF3, 1, 2, (byte) 0xFE, 4, 6, 7, 8, 9, (byte) 0xFF, 1, 2, + 3, 5, 6, 7, 8, 9}); assertEquals(2, result.findFirstFieldForType(JBBPFieldBit.class).getAsInt()); assertEquals(1, result.findLastFieldForType(JBBPFieldBit.class).getAsInt()); @@ -902,13 +1089,17 @@ public void testParse_Align_Default_EmptyStream_NoErrors() throws Exception { @Test public void testParse_Align_ErrorForEOF() throws Exception { - assertThrows(EOFException.class, () -> JBBPParser.prepare("byte; align:34;").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; align:34;").parse(new byte[] {1})); } @Test public void testParse_Align_Default() throws Exception { - final JBBPParser parser = JBBPParser.prepare("bit:4; align; bool; byte; ubyte; short; ushort; int; long;"); - final JBBPFieldStruct result = parser.parse(new byte[] {0x12, 1, 87, (byte) 0xF3, 1, 2, (byte) 0xFE, 4, 6, 7, 8, 9, (byte) 0xFF, 1, 2, 3, 5, 6, 7, 8, 9}); + final JBBPParser parser = + JBBPParser.prepare("bit:4; align; bool; byte; ubyte; short; ushort; int; long;"); + final JBBPFieldStruct result = parser.parse( + new byte[] {0x12, 1, 87, (byte) 0xF3, 1, 2, (byte) 0xFE, 4, 6, 7, 8, 9, (byte) 0xFF, 1, 2, + 3, 5, 6, 7, 8, 9}); assertEquals(2, result.findFieldForType(JBBPFieldBit.class).getAsInt()); assertTrue(result.findFieldForType(JBBPFieldBoolean.class).getAsBool()); assertEquals(87, result.findFieldForType(JBBPFieldByte.class).getAsInt()); @@ -941,7 +1132,8 @@ public void testParse_Skip_Default_ErrorForEOF() throws Exception { @Test public void testParse_Skip_ErrorForEOF() throws Exception { - assertThrows(EOFException.class, () -> JBBPParser.prepare("byte; skip:34;").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; skip:34;").parse(new byte[] {1})); } @Test @@ -998,56 +1190,72 @@ public void testParse_Align_Int_WithoutEffect() throws Exception { @Test public void testParse_FixedBitArray_EOFException() throws Exception { - assertThrows(EOFException.class, () -> JBBPParser.prepare("byte; bit:4[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; bit:4[1];").parse(new byte[] {1})); } @Test public void testParse_NonFixedBitArray_ParsedAsEmptyArray() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte; bit:4[_] array;").parse(new byte[] {1}); + final JBBPFieldStruct parsed = + JBBPParser.prepare("byte; bit:4[_] array;").parse(new byte[] {1}); assertEquals(0, parsed.findFieldForNameAndType("array", JBBPFieldArrayBit.class).size()); } - @Test - public void testParse_ProcessingOfExtraFieldValuesInSkippedStructureFields() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; struct1 [len] { int a; var:23231223 [1024] helloarray; int b; bit:3; bit:7 [10233]; var:-1332 hello; skip:34221223; bit:7; bit:1; align:3445; bit:2; int skippedInt; long lng; insidestruct {bit:1; bit:2; bit:3;} } int end; ").parse(new byte[] {0, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + private static void testArrayLimiter_2elementsLimit(final byte[] testData, final String script, + final JBBPVarFieldProcessor varFieldProcessor, + final JBBPCustomFieldTypeProcessor customFieldTypeProcessor) + throws Exception { + ByteArrayInputStream dataStream = new ByteArrayInputStream(testData); + final JBBPParser parser = JBBPParser.prepare(script, customFieldTypeProcessor); + parser.parse(dataStream, varFieldProcessor, null); + assertFalse(dataStream.available() > 0); - @Override - public JBBPAbstractArrayField readVarArray(JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } + final ByteArrayInputStream dataStreamLimit1 = new ByteArrayInputStream(testData); + assertThrows(JBBPReachedArraySizeLimitException.class, + () -> parser.parse(dataStreamLimit1, varFieldProcessor, null, () -> 2)); + assertTrue(dataStreamLimit1.available() > 0); - @Override - public JBBPAbstractField readVarField(JBBPBitInputStream inStream, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - }, null); - assertEquals(0x01020304, parsed.findFieldForNameAndType("end", JBBPFieldInt.class).getAsInt()); + final ByteArrayInputStream dataStreamLimit2 = new ByteArrayInputStream(testData); + assertEquals(2, + ((JBBPAbstractArrayField) parser.parse(dataStreamLimit2, varFieldProcessor, null, + () -> -2).getArray()[0]).size()); + assertTrue(dataStreamLimit2.available() > 0); } @Test public void testParse_ProcessingOfExtraFieldValuesInSkippedStructureFields1() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; struct1 [len] {var:-1332 hello; align:3445; } int end; ").parse(new byte[] {0, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - - @Override - public JBBPAbstractArrayField readVarArray(JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - - @Override - public JBBPAbstractField readVarField(JBBPBitInputStream inStream, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { - fail("Must not be called"); - return null; - } - }, null); + final JBBPFieldStruct parsed = + JBBPParser.prepare("byte len; struct1 [len] {var:-1332 hello; align:3445; } int end; ") + .parse(new byte[] {0, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, + int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + fail("Must not be called"); + return null; + } + + @Override + public JBBPAbstractField readVarField(JBBPBitInputStream inStream, + JBBPNamedFieldInfo fieldName, int extraValue, + JBBPByteOrder byteOrder, + JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + fail("Must not be called"); + return null; + } + }, null); assertEquals(0x01020304, parsed.findFieldForNameAndType("end", JBBPFieldInt.class).getAsInt()); } @Test public void testParse_FixedBitArray() throws Exception { - final JBBPFieldArrayBit bits = JBBPParser.prepare("bit:4 [8];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}).findFieldForType(JBBPFieldArrayBit.class); + final JBBPFieldArrayBit bits = + JBBPParser.prepare("bit:4 [8];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}) + .findFieldForType(JBBPFieldArrayBit.class); assertEquals(8, bits.size()); assertEquals(1, bits.getAsInt(0)); assertEquals(2, bits.getAsInt(1)); @@ -1061,7 +1269,9 @@ public void testParse_FixedBitArray() throws Exception { @Test public void testParse_NonFixedBitArray() throws Exception { - final JBBPFieldArrayBit bits = JBBPParser.prepare("bit:4 [_];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}).findFieldForType(JBBPFieldArrayBit.class); + final JBBPFieldArrayBit bits = + JBBPParser.prepare("bit:4 [_];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}) + .findFieldForType(JBBPFieldArrayBit.class); assertEquals(8, bits.size()); assertEquals(1, bits.getAsInt(0)); assertEquals(2, bits.getAsInt(1)); @@ -1075,7 +1285,8 @@ public void testParse_NonFixedBitArray() throws Exception { @Test public void testParse_FixedByteArray_EOFException() throws Exception { - assertThrows(EOFException.class, () -> JBBPParser.prepare("byte; byte[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; byte[1];").parse(new byte[] {1})); } @Test @@ -1086,7 +1297,9 @@ public void testParse_NonFixedByteArray_ParsedAsEmptyArray() throws Exception { @Test public void testParse_FixedByteArray_Default() throws Exception { - final JBBPFieldArrayByte bytes = JBBPParser.prepare("byte[4];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}).findFieldForType(JBBPFieldArrayByte.class); + final JBBPFieldArrayByte bytes = + JBBPParser.prepare("byte[4];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}) + .findFieldForType(JBBPFieldArrayByte.class); assertEquals(4, bytes.size()); assertEquals(0x21, bytes.getAsInt(0) & 0xFF); assertEquals(0x43, bytes.getAsInt(1) & 0xFF); @@ -1096,7 +1309,9 @@ public void testParse_FixedByteArray_Default() throws Exception { @Test public void testParse_FixedByteArray_BigEndian() throws Exception { - final JBBPFieldArrayByte bytes = JBBPParser.prepare(">byte[4];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}).findFieldForType(JBBPFieldArrayByte.class); + final JBBPFieldArrayByte bytes = + JBBPParser.prepare(">byte[4];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}) + .findFieldForType(JBBPFieldArrayByte.class); assertEquals(4, bytes.size()); assertEquals(0x21, bytes.getAsInt(0) & 0xFF); assertEquals(0x43, bytes.getAsInt(1) & 0xFF); @@ -1106,7 +1321,9 @@ public void testParse_FixedByteArray_BigEndian() throws Exception { @Test public void testParse_FixedByteArray_LittleEndian() throws Exception { - final JBBPFieldArrayByte bytes = JBBPParser.prepare("byte[_];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}).findFieldForType(JBBPFieldArrayByte.class); + final JBBPFieldArrayByte bytes = + JBBPParser.prepare(">byte[_];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}) + .findFieldForType(JBBPFieldArrayByte.class); assertEquals(4, bytes.size()); assertEquals(0x21, bytes.getAsInt(0) & 0xFF); assertEquals(0x43, bytes.getAsInt(1) & 0xFF); @@ -1136,7 +1357,9 @@ public void testParse_NonFixedByteArray_BigEndian() throws Exception { @Test public void testParse_NonFixedByteArray_LittleEndian() throws Exception { - final JBBPFieldArrayByte bytes = JBBPParser.prepare(" JBBPParser.prepare("byte; ubyte[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; ubyte[1];").parse(new byte[] {1})); } @Test public void testParse_NonFixedUByteArray_ParsedAsEmptyArray() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte; ubyte[_] array;").parse(new byte[] {1}); + final JBBPFieldStruct parsed = + JBBPParser.prepare("byte; ubyte[_] array;").parse(new byte[] {1}); assertEquals(0, parsed.findFieldForNameAndType("array", JBBPFieldArrayUByte.class).size()); } @Test public void testParse_FixedUByteArray_Default() throws Exception { - final JBBPFieldArrayUByte bytes = JBBPParser.prepare("ubyte[4];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}).findFieldForType(JBBPFieldArrayUByte.class); + final JBBPFieldArrayUByte bytes = + JBBPParser.prepare("ubyte[4];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}) + .findFieldForType(JBBPFieldArrayUByte.class); assertEquals(4, bytes.size()); assertEquals(0x21, bytes.getAsInt(0)); assertEquals(0x43, bytes.getAsInt(1)); @@ -1167,7 +1394,9 @@ public void testParse_FixedUByteArray_Default() throws Exception { @Test public void testParse_FixedUByteArray_BigEndian() throws Exception { - final JBBPFieldArrayUByte bytes = JBBPParser.prepare(">ubyte[4];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}).findFieldForType(JBBPFieldArrayUByte.class); + final JBBPFieldArrayUByte bytes = + JBBPParser.prepare(">ubyte[4];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}) + .findFieldForType(JBBPFieldArrayUByte.class); assertEquals(4, bytes.size()); assertEquals(0x21, bytes.getAsInt(0)); assertEquals(0x43, bytes.getAsInt(1)); @@ -1177,7 +1406,9 @@ public void testParse_FixedUByteArray_BigEndian() throws Exception { @Test public void testParse_FixedUByteArray_LittleEndian() throws Exception { - final JBBPFieldArrayUByte bytes = JBBPParser.prepare("ubyte[_];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}).findFieldForType(JBBPFieldArrayUByte.class); + final JBBPFieldArrayUByte bytes = + JBBPParser.prepare(">ubyte[_];").parse(new byte[] {0x21, 0x43, 0x65, (byte) 0x87}) + .findFieldForType(JBBPFieldArrayUByte.class); assertEquals(4, bytes.size()); assertEquals(0x21, bytes.getAsInt(0)); assertEquals(0x43, bytes.getAsInt(1)); @@ -1207,7 +1442,9 @@ public void testParse_NonFixedUByteArray_BigEndian() throws Exception { @Test public void testParse_NonFixedUByteArray_LittleEndian() throws Exception { - final JBBPFieldArrayUByte bytes = JBBPParser.prepare(" JBBPParser.prepare("byte; bool[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; bool[1];").parse(new byte[] {1})); } @Test @@ -1228,7 +1466,9 @@ public void testParse_NonFixedBoolArray_ParsedAsEmptyArray() throws Exception { @Test public void testParse_FixedBooleanArray_Default() throws Exception { - final JBBPFieldArrayBoolean bools = JBBPParser.prepare("bool[4];").parse(new byte[] {0, 0x43, 0x65, 0}).findFieldForType(JBBPFieldArrayBoolean.class); + final JBBPFieldArrayBoolean bools = + JBBPParser.prepare("bool[4];").parse(new byte[] {0, 0x43, 0x65, 0}) + .findFieldForType(JBBPFieldArrayBoolean.class); assertEquals(4, bools.size()); assertFalse(bools.getAsBool(0)); assertTrue(bools.getAsBool(1)); @@ -1238,7 +1478,9 @@ public void testParse_FixedBooleanArray_Default() throws Exception { @Test public void testParse_FixedBooleanArray_BigEndian() throws Exception { - final JBBPFieldArrayBoolean bools = JBBPParser.prepare(">bool[4];").parse(new byte[] {0, 0x43, 0x65, 0}).findFieldForType(JBBPFieldArrayBoolean.class); + final JBBPFieldArrayBoolean bools = + JBBPParser.prepare(">bool[4];").parse(new byte[] {0, 0x43, 0x65, 0}) + .findFieldForType(JBBPFieldArrayBoolean.class); assertEquals(4, bools.size()); assertFalse(bools.getAsBool(0)); assertTrue(bools.getAsBool(1)); @@ -1248,7 +1490,9 @@ public void testParse_FixedBooleanArray_BigEndian() throws Exception { @Test public void testParse_FixedBooleanArray_LittleEndian() throws Exception { - final JBBPFieldArrayBoolean bools = JBBPParser.prepare("bool[_];").parse(new byte[] {0, 0x43, 0x65, 0}).findFieldForType(JBBPFieldArrayBoolean.class); + final JBBPFieldArrayBoolean bools = + JBBPParser.prepare(">bool[_];").parse(new byte[] {0, 0x43, 0x65, 0}) + .findFieldForType(JBBPFieldArrayBoolean.class); assertEquals(4, bools.size()); assertFalse(bools.getAsBool(0)); assertTrue(bools.getAsBool(1)); @@ -1278,7 +1526,9 @@ public void testParse_NonFixedBooleanArray_BigEndian() throws Exception { @Test public void testParse_NonFixedBooleanArray_LittleEndian() throws Exception { - final JBBPFieldArrayBoolean bools = JBBPParser.prepare(" JBBPParser.prepare("byte; short[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; short[1];").parse(new byte[] {1})); } @Test public void testParse_NonFixedShortArray_ParsedAsEmptyArray() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte; short[_] array;").parse(new byte[] {1}); + final JBBPFieldStruct parsed = + JBBPParser.prepare("byte; short[_] array;").parse(new byte[] {1}); assertEquals(0, parsed.findFieldForNameAndType("array", JBBPFieldArrayShort.class).size()); } @Test public void testParse_FixedShortArray_Default() throws Exception { - final JBBPFieldArrayShort shorts = JBBPParser.prepare("short[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}).findFieldForType(JBBPFieldArrayShort.class); + final JBBPFieldArrayShort shorts = + JBBPParser.prepare("short[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}) + .findFieldForType(JBBPFieldArrayShort.class); assertEquals(2, shorts.size()); assertEquals((short) 0xF743, shorts.getAsInt(0)); assertEquals((short) 0x6500, shorts.getAsInt(1)); @@ -1307,7 +1561,9 @@ public void testParse_FixedShortArray_Default() throws Exception { @Test public void testParse_FixedShortArray_BigEndian() throws Exception { - final JBBPFieldArrayShort shorts = JBBPParser.prepare(">short[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}).findFieldForType(JBBPFieldArrayShort.class); + final JBBPFieldArrayShort shorts = + JBBPParser.prepare(">short[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}) + .findFieldForType(JBBPFieldArrayShort.class); assertEquals(2, shorts.size()); assertEquals((short) 0xF743, shorts.getAsInt(0)); assertEquals((short) 0x6500, shorts.getAsInt(1)); @@ -1315,7 +1571,9 @@ public void testParse_FixedShortArray_BigEndian() throws Exception { @Test public void testParse_FixedShortArray_LittleEndian() throws Exception { - final JBBPFieldArrayShort shorts = JBBPParser.prepare("short[_];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}).findFieldForType(JBBPFieldArrayShort.class); + final JBBPFieldArrayShort shorts = + JBBPParser.prepare(">short[_];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}) + .findFieldForType(JBBPFieldArrayShort.class); assertEquals(2, shorts.size()); assertEquals((short) 0xF743, shorts.getAsInt(0)); assertEquals((short) 0x6500, shorts.getAsInt(1)); @@ -1339,7 +1601,9 @@ public void testParse_NonFixedShortArray_BigEndian() throws Exception { @Test public void testParse_NonFixedShortArray_LittleEndian() throws Exception { - final JBBPFieldArrayShort shorts = JBBPParser.prepare(" JBBPParser.prepare("byte; ushort[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; ushort[1];").parse(new byte[] {1})); } @Test public void testParse_NonFixedUShortArray_ParsedAsEmptyArray() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte; ushort[_] array;").parse(new byte[] {1}); + final JBBPFieldStruct parsed = + JBBPParser.prepare("byte; ushort[_] array;").parse(new byte[] {1}); assertEquals(0, parsed.findFieldForNameAndType("array", JBBPFieldArrayUShort.class).size()); } @Test public void testParse_FixedUShortArray_Default() throws Exception { - final JBBPFieldArrayUShort shorts = JBBPParser.prepare("ushort[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}).findFieldForType(JBBPFieldArrayUShort.class); + final JBBPFieldArrayUShort shorts = + JBBPParser.prepare("ushort[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}) + .findFieldForType(JBBPFieldArrayUShort.class); assertEquals(2, shorts.size()); assertEquals(0xF743, shorts.getAsInt(0)); assertEquals(0x6500, shorts.getAsInt(1)); @@ -1366,7 +1634,9 @@ public void testParse_FixedUShortArray_Default() throws Exception { @Test public void testParse_FixedUShortArray_BigEndian() throws Exception { - final JBBPFieldArrayUShort shorts = JBBPParser.prepare(">ushort[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}).findFieldForType(JBBPFieldArrayUShort.class); + final JBBPFieldArrayUShort shorts = + JBBPParser.prepare(">ushort[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}) + .findFieldForType(JBBPFieldArrayUShort.class); assertEquals(2, shorts.size()); assertEquals(0xF743, shorts.getAsInt(0)); assertEquals(0x6500, shorts.getAsInt(1)); @@ -1374,7 +1644,9 @@ public void testParse_FixedUShortArray_BigEndian() throws Exception { @Test public void testParse_FixedUShortArray_LittleEndian() throws Exception { - final JBBPFieldArrayUShort shorts = JBBPParser.prepare("ushort[_];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}).findFieldForType(JBBPFieldArrayUShort.class); + final JBBPFieldArrayUShort shorts = + JBBPParser.prepare(">ushort[_];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0}) + .findFieldForType(JBBPFieldArrayUShort.class); assertEquals(2, shorts.size()); assertEquals(0xF743, shorts.getAsInt(0)); assertEquals(0x6500, shorts.getAsInt(1)); @@ -1398,7 +1674,9 @@ public void testParse_NonFixedUShortArray_BigEndian() throws Exception { @Test public void testParse_NonFixedUShortArray_LittleEndian() throws Exception { - final JBBPFieldArrayUShort shorts = JBBPParser.prepare(" JBBPParser.prepare("byte; int[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; int[1];").parse(new byte[] {1})); } @Test @@ -1417,7 +1696,9 @@ public void testParse_NonFixedIntArray_ParsedAsEmptyArray() throws Exception { @Test public void testParse_FixedIntArray_Default() throws Exception { - final JBBPFieldArrayInt ints = JBBPParser.prepare("int[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}).findFieldForType(JBBPFieldArrayInt.class); + final JBBPFieldArrayInt ints = JBBPParser.prepare("int[2];") + .parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}) + .findFieldForType(JBBPFieldArrayInt.class); assertEquals(2, ints.size()); assertEquals(0xF7436510, ints.getAsInt(0)); assertEquals(0x352367A0, ints.getAsInt(1)); @@ -1425,7 +1706,9 @@ public void testParse_FixedIntArray_Default() throws Exception { @Test public void testParse_FixedIntArray_BigEndian() throws Exception { - final JBBPFieldArrayInt ints = JBBPParser.prepare(">int[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}).findFieldForType(JBBPFieldArrayInt.class); + final JBBPFieldArrayInt ints = JBBPParser.prepare(">int[2];") + .parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}) + .findFieldForType(JBBPFieldArrayInt.class); assertEquals(2, ints.size()); assertEquals(0xF7436510, ints.getAsInt(0)); assertEquals(0x352367A0, ints.getAsInt(1)); @@ -1433,7 +1716,9 @@ public void testParse_FixedIntArray_BigEndian() throws Exception { @Test public void testParse_FixedIntArray_LittleEndian() throws Exception { - final JBBPFieldArrayInt ints = JBBPParser.prepare("int[_];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}).findFieldForType(JBBPFieldArrayInt.class); + final JBBPFieldArrayInt ints = JBBPParser.prepare(">int[_];") + .parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}) + .findFieldForType(JBBPFieldArrayInt.class); assertEquals(2, ints.size()); assertEquals(0xF7436510, ints.getAsInt(0)); assertEquals(0x352367A0, ints.getAsInt(1)); @@ -1457,7 +1746,9 @@ public void testParse_NonFixedIntArray_BigEndian() throws Exception { @Test public void testParse_NonFixedIntArray_LittleEndian() throws Exception { - final JBBPFieldArrayInt ints = JBBPParser.prepare(" JBBPParser.prepare("byte; floatj[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; floatj[1];").parse(new byte[] {1})); } @Test public void testParse_NonFixedFloatArray_ParsedAsEmptyArray() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte; floatj[_] array;").parse(new byte[] {1}); + final JBBPFieldStruct parsed = + JBBPParser.prepare("byte; floatj[_] array;").parse(new byte[] {1}); assertEquals(0, parsed.findFieldForNameAndType("array", JBBPFieldArrayFloat.class).size()); } @Test public void testParse_FixedFloatArray_Default() throws Exception { - final JBBPFieldArrayFloat ints = JBBPParser.prepare("floatj[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}).findFieldForType(JBBPFieldArrayFloat.class); + final JBBPFieldArrayFloat ints = JBBPParser.prepare("floatj[2];") + .parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}) + .findFieldForType(JBBPFieldArrayFloat.class); assertEquals(2, ints.size()); assertEquals(-3.963077E33f, ints.getAsFloat(0), TestUtils.FLOAT_DELTA); assertEquals(6.0873026E-7f, ints.getAsFloat(1), TestUtils.FLOAT_DELTA); @@ -1484,7 +1779,9 @@ public void testParse_FixedFloatArray_Default() throws Exception { @Test public void testParse_FixedFloatArray_BigEndian() throws Exception { - final JBBPFieldArrayFloat ints = JBBPParser.prepare(">floatj[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}).findFieldForType(JBBPFieldArrayFloat.class); + final JBBPFieldArrayFloat ints = JBBPParser.prepare(">floatj[2];") + .parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}) + .findFieldForType(JBBPFieldArrayFloat.class); assertEquals(2, ints.size()); assertEquals(-3.963077E33f, ints.getAsFloat(0), TestUtils.FLOAT_DELTA); assertEquals(6.0873026E-7f, ints.getAsFloat(1), TestUtils.FLOAT_DELTA); @@ -1492,7 +1789,9 @@ public void testParse_FixedFloatArray_BigEndian() throws Exception { @Test public void testParse_FixedFloatArray_LittleEndian() throws Exception { - final JBBPFieldArrayFloat ints = JBBPParser.prepare("floatj[_];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}).findFieldForType(JBBPFieldArrayFloat.class); + final JBBPFieldArrayFloat ints = JBBPParser.prepare(">floatj[_];") + .parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0}) + .findFieldForType(JBBPFieldArrayFloat.class); assertEquals(2, ints.size()); assertEquals(-3.963077E33f, ints.getAsFloat(0), TestUtils.FLOAT_DELTA); assertEquals(6.0873026E-7f, ints.getAsFloat(1), TestUtils.FLOAT_DELTA); @@ -1516,7 +1819,9 @@ public void testParse_NonFixedFloatArray_BigEndian() throws Exception { @Test public void testParse_NonFixedFloatArray_LittleEndian() throws Exception { - final JBBPFieldArrayFloat ints = JBBPParser.prepare(" JBBPParser.prepare("byte; long[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; long[1];").parse(new byte[] {1})); } @Test @@ -1535,7 +1841,9 @@ public void testParse_NonFixedLongArray_ParsedAsEmptyArray() throws Exception { @Test public void testParse_FixedLongArray_Default() throws Exception { - final JBBPFieldArrayLong longs = JBBPParser.prepare("long[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}).findFieldForType(JBBPFieldArrayLong.class); + final JBBPFieldArrayLong longs = JBBPParser.prepare("long[2];").parse( + new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, + (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}).findFieldForType(JBBPFieldArrayLong.class); assertEquals(2, longs.size()); assertEquals(0xF7436510352367A0L, longs.getAsLong(0)); assertEquals(0x323361CABE221230L, longs.getAsLong(1)); @@ -1543,7 +1851,9 @@ public void testParse_FixedLongArray_Default() throws Exception { @Test public void testParse_FixedLongArray_BigEndian() throws Exception { - final JBBPFieldArrayLong longs = JBBPParser.prepare(">long[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}).findFieldForType(JBBPFieldArrayLong.class); + final JBBPFieldArrayLong longs = JBBPParser.prepare(">long[2];").parse( + new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, + (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}).findFieldForType(JBBPFieldArrayLong.class); assertEquals(2, longs.size()); assertEquals(0xF7436510352367A0L, longs.getAsLong(0)); assertEquals(0x323361CABE221230L, longs.getAsLong(1)); @@ -1551,7 +1861,9 @@ public void testParse_FixedLongArray_BigEndian() throws Exception { @Test public void testParse_FixedLongArray_LittleEndian() throws Exception { - final JBBPFieldArrayLong longs = JBBPParser.prepare("long[_];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}).findFieldForType(JBBPFieldArrayLong.class); + final JBBPFieldArrayLong longs = JBBPParser.prepare(">long[_];").parse( + new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, + (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}).findFieldForType(JBBPFieldArrayLong.class); assertEquals(2, longs.size()); assertEquals(0xF7436510352367A0L, longs.getAsLong(0)); assertEquals(0x323361CABE221230L, longs.getAsLong(1)); @@ -1575,7 +1891,9 @@ public void testParse_NonFixedLongArray_BigEndian() throws Exception { @Test public void testParse_NonFixedLongArray_LittleEndian() throws Exception { - final JBBPFieldArrayLong longs = JBBPParser.prepare(" JBBPParser.prepare("byte; doublej[1];").parse(new byte[] {1})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; doublej[1];").parse(new byte[] {1})); } @Test public void testParse_NonFixedDoubleArray_ParsedAsEmptyArray() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte; doublej[_] array;").parse(new byte[] {1}); + final JBBPFieldStruct parsed = + JBBPParser.prepare("byte; doublej[_] array;").parse(new byte[] {1}); assertEquals(0, parsed.findFieldForNameAndType("array", JBBPFieldArrayDouble.class).size()); } + @Test + public void testParse_ProcessingOfExtraFieldValuesInSkippedStructureFields() throws Exception { + final JBBPFieldStruct parsed = JBBPParser.prepare( + "byte len; struct1 [len] { int a; var:23231223 [1024] helloarray; int b; bit:3; bit:7 [10233]; var:-1332 hello; skip:34221223; bit:7; bit:1; align:3445; bit:2; int skippedInt; long lng; insidestruct {bit:1; bit:2; bit:3;} } int end; ") + .parse(new byte[] {0, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { + + @Override + public JBBPAbstractArrayField readVarArray( + JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, + int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + fail("Must not be called"); + return null; + } + + @Override + public JBBPAbstractField readVarField(JBBPBitInputStream inStream, + JBBPNamedFieldInfo fieldName, int extraValue, + JBBPByteOrder byteOrder, + JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + fail("Must not be called"); + return null; + } + }, null); + assertEquals(0x01020304, parsed.findFieldForNameAndType("end", JBBPFieldInt.class).getAsInt()); + } + @Test public void testParse_FixedDoubleArray_Default() throws Exception { - final JBBPFieldArrayDouble longs = JBBPParser.prepare("doublej[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}).findFieldForType(JBBPFieldArrayDouble.class); + final JBBPFieldArrayDouble longs = JBBPParser.prepare("doublej[2];").parse( + new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, + (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}) + .findFieldForType(JBBPFieldArrayDouble.class); assertEquals(2, longs.size()); assertEquals(-3.126878492655484E266d, longs.getAsDouble(0), TestUtils.FLOAT_DELTA); assertEquals(7.189183308668011E-67d, longs.getAsDouble(1), TestUtils.FLOAT_DELTA); @@ -1602,7 +1954,10 @@ public void testParse_FixedDoubleArray_Default() throws Exception { @Test public void testParse_FixedDoubleArray_BigEndian() throws Exception { - final JBBPFieldArrayDouble longs = JBBPParser.prepare(">doublej[2];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}).findFieldForType(JBBPFieldArrayDouble.class); + final JBBPFieldArrayDouble longs = JBBPParser.prepare(">doublej[2];").parse( + new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, + (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}) + .findFieldForType(JBBPFieldArrayDouble.class); assertEquals(2, longs.size()); assertEquals(-3.126878492655484E266d, longs.getAsDouble(0), TestUtils.FLOAT_DELTA); assertEquals(7.189183308668011E-67d, longs.getAsDouble(1), TestUtils.FLOAT_DELTA); @@ -1610,7 +1965,10 @@ public void testParse_FixedDoubleArray_BigEndian() throws Exception { @Test public void testParse_FixedDoubleArray_LittleEndian() throws Exception { - final JBBPFieldArrayDouble longs = JBBPParser.prepare("doublej[_];").parse(new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}).findFieldForType(JBBPFieldArrayDouble.class); + final JBBPFieldArrayDouble longs = JBBPParser.prepare(">doublej[_];").parse( + new byte[] {(byte) 0xF7, 0x43, 0x65, 0x10, 0x35, 0x23, 0x67, (byte) 0xA0, 0x32, 0x33, 0x61, + (byte) 0xCA, (byte) 0xBE, 0x22, 0x12, 0x30}) + .findFieldForType(JBBPFieldArrayDouble.class); assertEquals(2, longs.size()); assertEquals(-3.126878492655484E266d, longs.getAsDouble(0), TestUtils.FLOAT_DELTA); assertEquals(7.189183308668011E-67d, longs.getAsDouble(1), TestUtils.FLOAT_DELTA); } - @Test - public void testParse_NonFixedDoubleArray_LittleEndian() throws Exception { - final JBBPFieldArrayDouble longs = JBBPParser.prepare(" JBBPParser.prepare("ubyte len; byte[len-4];").parse(new byte[] {2, 1, 2, 3, 4})); + assertThrows(JBBPParsingException.class, + () -> JBBPParser.prepare("ubyte len; byte[len-4];").parse(new byte[] {2, 1, 2, 3, 4})); } @Test public void testParse_NegativeArrayLength() throws Exception { - assertThrows(JBBPCompilationException.class, () -> JBBPParser.prepare("ubyte len; byte[-2];").parse(new byte[] {2, 1, 2, 3, 4})); + assertThrows(JBBPCompilationException.class, + () -> JBBPParser.prepare("ubyte len; byte[-2];").parse(new byte[] {2, 1, 2, 3, 4})); } @Test public void testParse_ErrorForLessDataThanExpected() throws Exception { - assertThrows(EOFException.class, () -> JBBPParser.prepare("ubyte len; byte[5];").parse(new byte[] {2, 1, 2, 3, 4})); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("ubyte len; byte[5];").parse(new byte[] {2, 1, 2, 3, 4})); } @Test public void testParse_WholeStructStream() throws Exception { - final JBBPFieldArrayStruct array = JBBPParser.prepare("struct [_] {byte;}").parse(new byte[] {1, 2, 3, 4}).findFieldForType(JBBPFieldArrayStruct.class); + final JBBPFieldArrayStruct array = + JBBPParser.prepare("struct [_] {byte;}").parse(new byte[] {1, 2, 3, 4}) + .findFieldForType(JBBPFieldArrayStruct.class); assertEquals(4, array.size()); assertEquals(1, array.getElementAt(0).findFieldForType(JBBPFieldByte.class).getAsInt()); assertEquals(2, array.getElementAt(1).findFieldForType(JBBPFieldByte.class).getAsInt()); @@ -1776,71 +2154,83 @@ public void testParse_WholeStructStream() throws Exception { @Test public void testParse_BitArray_IgnoredForZeroLength() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; bit:4 [len]; ushort;").parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; bit:4 [len]; ushort;") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); assertEquals(0, parsed.findFieldForType(JBBPFieldArrayBit.class).size()); assertEquals(0x0102, parsed.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_BoolArray_IgnoredForZeroLength() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; bool [len]; ushort;").parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; bool [len]; ushort;") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); assertEquals(0, parsed.findFieldForType(JBBPFieldArrayBoolean.class).size()); assertEquals(0x0102, parsed.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_ByteArray_IgnoredForZeroLength() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; byte [len]; ushort;").parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; byte [len]; ushort;") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); assertEquals(0, parsed.findFieldForType(JBBPFieldArrayByte.class).size()); assertEquals(0x0102, parsed.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_UByteArray_IgnoredForZeroLength() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; ubyte [len]; ushort;").parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; ubyte [len]; ushort;") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); assertEquals(0, parsed.findFieldForType(JBBPFieldArrayUByte.class).size()); assertEquals(0x0102, parsed.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_ShortArray_IgnoredForZeroLength() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; short [len]; ushort;").parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; short [len]; ushort;") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); assertEquals(0, parsed.findFieldForType(JBBPFieldArrayShort.class).size()); assertEquals(0x0102, parsed.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_UShortArray_IgnoredForZeroLength() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; ushort [len]; ushort;").parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; ushort [len]; ushort;") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); assertEquals(0, parsed.findFieldForType(JBBPFieldArrayUShort.class).size()); assertEquals(0x0102, parsed.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_IntArray_IgnoredForZeroLength() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; int [len]; ushort;").parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; int [len]; ushort;") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); assertEquals(0, parsed.findFieldForType(JBBPFieldArrayInt.class).size()); assertEquals(0x0102, parsed.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_LongArray_IgnoredForZeroLength() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; long [len]; ushort;").parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; long [len]; ushort;") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); assertEquals(0, parsed.findFieldForType(JBBPFieldArrayLong.class).size()); assertEquals(0x0102, parsed.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_StructArray_IgnoredForZeroLength() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; sss [len] { byte a; byte b; byte c;} ushort;").parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldStruct parsed = + JBBPParser.prepare("byte len; sss [len] { byte a; byte b; byte c;} ushort;") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); assertEquals(0, parsed.findFieldForType(JBBPFieldArrayStruct.class).size()); assertEquals(0x0102, parsed.findFieldForType(JBBPFieldUShort.class).getAsInt()); } @Test public void testParse_StructArray_FixedSize() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("sss [1] { byte a; byte b; byte c;}").parse(new byte[] {0x0, 0x01, (byte) 0x02}); - final JBBPFieldArrayStruct struct = parsed.findFieldForPathAndType("sss", JBBPFieldArrayStruct.class); + final JBBPFieldStruct parsed = JBBPParser.prepare("sss [1] { byte a; byte b; byte c;}") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldArrayStruct struct = + parsed.findFieldForPathAndType("sss", JBBPFieldArrayStruct.class); assertEquals(1, struct.size()); final JBBPFieldStruct readStruct = struct.getElementAt(0); assertEquals(0, readStruct.findFieldForNameAndType("a", JBBPFieldByte.class).getAsInt()); @@ -1850,8 +2240,10 @@ public void testParse_StructArray_FixedSize() throws Exception { @Test public void testParse_StructArray_WholeStream() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("sss [_] { byte a; byte b; byte c;}").parse(new byte[] {0x0, 0x01, (byte) 0x02}); - final JBBPFieldArrayStruct struct = parsed.findFieldForPathAndType("sss", JBBPFieldArrayStruct.class); + final JBBPFieldStruct parsed = JBBPParser.prepare("sss [_] { byte a; byte b; byte c;}") + .parse(new byte[] {0x0, 0x01, (byte) 0x02}); + final JBBPFieldArrayStruct struct = + parsed.findFieldForPathAndType("sss", JBBPFieldArrayStruct.class); assertEquals(1, struct.size()); final JBBPFieldStruct readStruct = struct.getElementAt(0); assertEquals(0, readStruct.findFieldForNameAndType("a", JBBPFieldByte.class).getAsInt()); @@ -1872,55 +2264,75 @@ public void testParse_EmptyStructArrayInsideStruct_WholeStream() throws Exceptio } @Test - public void testParse_SkipStructureForZeroItems() throws Exception { - final JBBPFieldStruct parsed = JBBPParser.prepare("byte len; sss [len]{ sss2[10]{ sss3{long;} sss4[45]{ushort; bool [11]; short; bit:4;} byte;}} byte end;").parse(new byte[] {0x00, 0x1F}); - assertEquals(0, parsed.findFieldForPathAndType("len", JBBPFieldByte.class).getAsInt()); - assertEquals(0, parsed.findFieldForPathAndType("sss", JBBPFieldArrayStruct.class).size()); - assertEquals(0x1F, parsed.findFieldForPathAndType("end", JBBPFieldByte.class).getAsInt()); + public void testParse_NonFixedDoubleArray_LittleEndian() throws Exception { + final JBBPFieldArrayDouble longs = JBBPParser.prepare(" parser.parse(stream)); } @Test public void testParse_NegativeExpressonResult_OneFieldAsExpression_FlagOff() throws Exception { - final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0xEF, 1, 2, 3})); + final JBBPBitInputStream stream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0xEF, 1, 2, 3})); final JBBPParser parser = JBBPParser.prepare("byte len; byte [len] arr;"); assertThrows(JBBPParsingException.class, () -> parser.parse(stream)); } @Test - public void testParse_NegativeExpressonResult_ExpressionWithNegativeResult_FlagOff() throws Exception { - final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {2, 1, 2, 3})); + public void testParse_NegativeExpressonResult_ExpressionWithNegativeResult_FlagOff() + throws Exception { + final JBBPBitInputStream stream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {2, 1, 2, 3})); final JBBPParser parser = JBBPParser.prepare("byte len; byte [len - 8] arr;"); assertThrows(JBBPParsingException.class, () -> parser.parse(stream)); @@ -2027,17 +2449,22 @@ public void testParse_NegativeExpressonResult_ExpressionWithNegativeResult_FlagO @Test public void testParse_NegativeExpressonResult_OneFieldAsExpression_FlagOn() throws Exception { - final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0xEF, 1, 2, 3})); - final JBBPParser parser = JBBPParser.prepare("byte len; byte [len] arr;", JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO); + final JBBPBitInputStream stream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0xEF, 1, 2, 3})); + final JBBPParser parser = JBBPParser + .prepare("byte len; byte [len] arr;", JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO); final JBBPFieldStruct result = parser.parse(stream); assertEquals((byte) 0xEF, result.findFieldForType(JBBPFieldByte.class).getAsInt()); assertEquals(0, result.findFieldForType(JBBPFieldArrayByte.class).getArray().length); } @Test - public void testParse_NegativeExpressonResult_ExpressionWithNegativResult_FlagOn() throws Exception { - final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {4, 1, 2, 3})); - final JBBPParser parser = JBBPParser.prepare("byte len; byte [len-8] arr;", JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO); + public void testParse_NegativeExpressonResult_ExpressionWithNegativResult_FlagOn() + throws Exception { + final JBBPBitInputStream stream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {4, 1, 2, 3})); + final JBBPParser parser = JBBPParser + .prepare("byte len; byte [len-8] arr;", JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO); final JBBPFieldStruct result = parser.parse(stream); assertEquals(4, result.findFieldForType(JBBPFieldByte.class).getAsInt()); assertEquals(0, result.findFieldForType(JBBPFieldArrayByte.class).getArray().length); @@ -2045,8 +2472,10 @@ public void testParse_NegativeExpressonResult_ExpressionWithNegativResult_FlagOn @Test public void testParse_NoErrorForIgnoreRemainingFieldsFlag() throws Exception { - final JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4})); - final JBBPParser parser = JBBPParser.prepare("int a; int b;", JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF); + final JBBPBitInputStream stream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4})); + final JBBPParser parser = + JBBPParser.prepare("int a; int b;", JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF); final JBBPFieldStruct result = parser.parse(stream); assertEquals(1, result.getArray().length); assertEquals("a", result.getArray()[0].getFieldName()); @@ -2057,7 +2486,8 @@ public void testParse_NoErrorForIgnoreRemainingFieldsFlag() throws Exception { public void testConvertToSrc_Java_NamedPackage() { final JBBPParser parser = JBBPParser.prepare("byte a;"); - final List src = parser.convertToSrc(TargetSources.JAVA, "some.package.SomeClass"); + final List src = + parser.convertToSrc(TargetSources.JAVA, "some.package.SomeClass"); assertEquals(1, src.size()); assertEquals("byte a;", src.get(0).getMetadata().getProperty("script")); @@ -2075,4 +2505,112 @@ public void testConvertToSrc_Java_DefaultPackage() { assertTrue(src.get(0).getResult().get("SomeClass.java").length() > 128); } + @Test + public void testParse_SkipStructureForZeroItems() throws Exception { + final JBBPFieldStruct parsed = JBBPParser.prepare( + "byte len; sss [len]{ sss2[10]{ sss3{long;} sss4[45]{ushort; bool [11]; short; bit:4;} byte;}} byte end;") + .parse(new byte[] {0x00, 0x1F}); + assertEquals(0, parsed.findFieldForPathAndType("len", JBBPFieldByte.class).getAsInt()); + assertEquals(0, parsed.findFieldForPathAndType("sss", JBBPFieldArrayStruct.class).size()); + assertEquals(0x1F, parsed.findFieldForPathAndType("end", JBBPFieldByte.class).getAsInt()); + } + + @Test + public void testUintUseInExpression() throws Exception { + final JBBPParser parser = JBBPParser.prepare("uint length; uint[(length * 2) >> 1] array;"); + final JBBPFieldStruct struct = parser.parse( + new byte[] {0, 0, 0, 2, (byte) 0xFF, (byte) 0xF0, (byte) 0xE0, (byte) 0x12, 0x01, 0x02, + 0x03, 0x04}); + final JBBPFieldUInt length = struct.findFieldForPathAndType("length", JBBPFieldUInt.class); + final JBBPFieldArrayUInt array = + struct.findFieldForPathAndType("array", JBBPFieldArrayUInt.class); + + assertEquals(2, length.getAsInt()); + assertEquals(2, array.size()); + + JBBPNumericFieldValueConversionException exception = + assertThrows(JBBPNumericFieldValueConversionException.class, + () -> array.getElementAt(0).getAsInt()); + assertTrue(exception.toString().contains("0xFFF0E012")); + + assertEquals(0xFFF0E012L, array.getElementAt(0).getAsLong()); + assertEquals(0x01020304, array.getElementAt(1).getAsInt()); + } + + @Test + public void testLimitedWholeStreamArrayRead() throws Exception { + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "bit:4 [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "bool [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "byte [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "ubyte [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "short [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "ushort [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "int [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "uint [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "long [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "floatj [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "doublej [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "doublej [_] test;", null, null); + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), + "test [_] { byte a; byte b; byte c; byte d;}", null, null); + + testArrayLimiter_2elementsLimit( + TestUtils.makeStringArray(JBBPByteOrder.BIG_ENDIAN, "hello", "world", "one", "two", "three", + "four"), "stringj [_] test;", null, null); + + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "var [_] test;", + new JBBPVarFieldProcessor() { + @Override + public JBBPAbstractArrayField readVarArray( + JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, + int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap, + JBBPArraySizeLimiter arraySizeLimiter) throws IOException { + if (arraySize >= 0) { + throw new IllegalArgumentException("Expected whole stream read"); + } + final byte[] result = inStream.readByteArray(arraySize, arraySizeLimiter); + return new JBBPFieldArrayByte(fieldName, result); + } + + @Override + public JBBPAbstractField readVarField(JBBPBitInputStream inStream, + JBBPNamedFieldInfo fieldName, int extraValue, + JBBPByteOrder byteOrder, + JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { + throw new UnsupportedOperationException("Must not be called"); + } + }, null); + + testArrayLimiter_2elementsLimit(TestUtils.getRandomBytes(128), "some [_] test;", null, + new JBBPCustomFieldTypeProcessor() { + @Override + public String[] getCustomFieldTypes() { + return new String[] {"some"}; + } + + @Override + public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, + int extraData, boolean isArray) { + return "some".equals(fieldType.getTypeName()); + } + + @Override + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + if (!readWholeStream) { + throw new IllegalArgumentException("Expected only read whole stream array"); + } + + final byte[] read = in.readByteArray(-1, JBBPByteOrder.BIG_ENDIAN, arraySizeLimiter); + return new JBBPFieldArrayByte(fieldName, read); + } + }); + } + } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/TestUtils.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/TestUtils.java index 40eeb645..79ab5b6e 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/TestUtils.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/TestUtils.java @@ -18,8 +18,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals; - +import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; +import com.igormaznitsa.jbbp.io.JBBPByteOrder; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.Locale; +import java.util.Random; import org.apache.commons.codec.digest.PureJavaCrc32; /** @@ -44,7 +48,8 @@ public enum TestUtils { * @return value, can be null * @throws Exception it will be thrown if any error */ - public static T getField(final Object instance, final String fieldName, final Class klazz) throws Exception { + public static T getField(final Object instance, final String fieldName, final Class klazz) + throws Exception { final String[] fields = fieldName.split("\\."); Object result = instance; for (final String f : fields) { @@ -64,7 +69,8 @@ public static T getField(final Object instance, final String fieldName, fina * @return value, can be null * @throws Exception it will be thrown if any error */ - public static T getFieldThroughGetters(final Object instance, final String fieldName, final Class klazz) throws Exception { + public static T getFieldThroughGetters(final Object instance, final String fieldName, + final Class klazz) throws Exception { final String[] fields = fieldName.split("\\."); Object result = instance; for (final String f : fields) { @@ -83,8 +89,12 @@ public static T getFieldThroughGetters(final Object instance, final String f * @param chunkCrc chunk crc field value * @param chunkData chunk data, must not be null */ - public static void assertPngChunk(final String etalonName, final int etalonLength, final int chunkType, final int chunkLength, final int chunkCrc, final byte[] chunkData) { - final int chunkEtalonName = (etalonName.charAt(0) << 24) | (etalonName.charAt(1) << 16) | (etalonName.charAt(2) << 8) | etalonName.charAt(3); + public static void assertPngChunk(final String etalonName, final int etalonLength, + final int chunkType, final int chunkLength, final int chunkCrc, + final byte[] chunkData) { + final int chunkEtalonName = + (etalonName.charAt(0) << 24) | (etalonName.charAt(1) << 16) | (etalonName.charAt(2) << 8) | + etalonName.charAt(3); assertEquals(chunkEtalonName, chunkType, "Chunk must be " + etalonName); assertEquals(etalonLength, chunkLength, "Chunk length must be " + etalonLength); @@ -96,8 +106,9 @@ public static void assertPngChunk(final String etalonName, final int etalonLengt crc32.update(etalonName.charAt(3)); if (etalonLength != 0) { - assertEquals(etalonLength, chunkData.length, "Data array " + etalonName + " must be " + etalonLength); - for(final byte b : chunkData) { + assertEquals(etalonLength, chunkData.length, + "Data array " + etalonName + " must be " + etalonLength); + for (final byte b : chunkData) { crc32.update(b & 0xFF); } } @@ -107,6 +118,23 @@ public static void assertPngChunk(final String etalonName, final int etalonLengt } public static String wavInt2Str(final int value) { - return new String(new char[] {(char) (value & 0xFF), (char) ((value >>> 8) & 0xFF), (char) ((value >>> 16) & 0xFF), (char) (value >>> 24)}); + return new String(new char[] {(char) (value & 0xFF), (char) ((value >>> 8) & 0xFF), + (char) ((value >>> 16) & 0xFF), (char) (value >>> 24)}); + } + + public static byte[] getRandomBytes(final int size) { + final byte[] result = new byte[size]; + final Random random = new Random(System.nanoTime()); + random.nextBytes(result); + return result; + } + + public static byte[] makeStringArray(final JBBPByteOrder byteOrder, final String... text) + throws IOException { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (final JBBPBitOutputStream stream = new JBBPBitOutputStream(out)) { + stream.writeStringArray(text, byteOrder); + } + return out.toByteArray(); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/JBBPCompilerTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/JBBPCompilerTest.java index 4f3ff7f8..67add8bf 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/JBBPCompilerTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/JBBPCompilerTest.java @@ -16,15 +16,21 @@ package com.igormaznitsa.jbbp.compiler; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + + import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPTokenType; import com.igormaznitsa.jbbp.exceptions.JBBPCompilationException; import com.igormaznitsa.jbbp.exceptions.JBBPTokenizerException; import com.igormaznitsa.jbbp.utils.JBBPIntCounter; import com.igormaznitsa.jbbp.utils.JBBPUtils; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - -import static org.junit.jupiter.api.Assertions.*; public class JBBPCompilerTest { @@ -48,12 +54,17 @@ public void testCompile_AllowedStructInsideStructWhichShouldBeReadTillEnd() thro @Test public void testCompile_ErrorSituationsReadTillEnd() { - assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("ubyte [_]; ubyte [_];")); - assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("ubyte [_]; a {byte;};")); - assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("byte;test [_] {byte;} int error;")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("ubyte [_]; ubyte [_];")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("ubyte [_]; a {byte;};")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("byte;test [_] {byte;} int error;")); assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("ubyte [_]; byte;")); - assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("a [_] { byte a; } b [_] { byte a;}")); - assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("a [_] { b [_] { byte a;}}")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("a [_] { byte a; } b [_] { byte a;}")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("a [_] { b [_] { byte a;}}")); } @Test @@ -61,8 +72,10 @@ public void testCompile_StructForWholeStreamAsSecondField() throws Exception { final JBBPCompiledBlock block = JBBPCompiler.compile("byte;test [_] {byte;}"); assertEquals(6, block.getCompiledData().length); assertEquals(JBBPCompiler.CODE_BYTE, block.getCompiledData()[0]); - assertEquals(JBBPCompiler.CODE_STRUCT_START | JBBPCompiler.FLAG_WIDE | JBBPCompiler.FLAG_NAMED, block.getCompiledData()[1] & 0xFF); - assertEquals(JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM, block.getCompiledData()[2] & 0xFF); + assertEquals(JBBPCompiler.CODE_STRUCT_START | JBBPCompiler.FLAG_WIDE | JBBPCompiler.FLAG_NAMED, + block.getCompiledData()[1] & 0xFF); + assertEquals(JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM, + block.getCompiledData()[2] & 0xFF); assertEquals(JBBPCompiler.CODE_BYTE, block.getCompiledData()[3]); assertEquals(JBBPCompiler.CODE_STRUCT_END, block.getCompiledData()[4]); assertEquals(1, block.getCompiledData()[5]); @@ -72,9 +85,12 @@ public void testCompile_StructForWholeStreamAsSecondField() throws Exception { public void testCompile_WholeStreamArrayInsideStructure() throws Exception { final JBBPCompiledBlock block = JBBPCompiler.compile("test {byte [_];}"); assertEquals(5, block.getCompiledData().length); - assertEquals(JBBPCompiler.CODE_STRUCT_START | JBBPCompiler.FLAG_NAMED, block.getCompiledData()[0]); - assertEquals(JBBPCompiler.CODE_BYTE | JBBPCompiler.FLAG_WIDE, block.getCompiledData()[1] & 0xFF); - assertEquals(JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM, block.getCompiledData()[2] & 0xFF); + assertEquals(JBBPCompiler.CODE_STRUCT_START | JBBPCompiler.FLAG_NAMED, + block.getCompiledData()[0]); + assertEquals(JBBPCompiler.CODE_BYTE | JBBPCompiler.FLAG_WIDE, + block.getCompiledData()[1] & 0xFF); + assertEquals(JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM, + block.getCompiledData()[2] & 0xFF); assertEquals(JBBPCompiler.CODE_STRUCT_END, block.getCompiledData()[3]); assertEquals(0, block.getCompiledData()[4]); } @@ -83,9 +99,12 @@ public void testCompile_WholeStreamArrayInsideStructure() throws Exception { public void testCompile_WholeStreamStructureArrayInsideStructure() throws Exception { final JBBPCompiledBlock block = JBBPCompiler.compile("test { whole[_]{ byte;}}"); assertEquals(8, block.getCompiledData().length); - assertEquals(JBBPCompiler.CODE_STRUCT_START | JBBPCompiler.FLAG_NAMED, block.getCompiledData()[0]); - assertEquals(JBBPCompiler.CODE_STRUCT_START | JBBPCompiler.FLAG_NAMED | JBBPCompiler.FLAG_WIDE, block.getCompiledData()[1] & 0xFF); - assertEquals(JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM, block.getCompiledData()[2] & 0xFF); + assertEquals(JBBPCompiler.CODE_STRUCT_START | JBBPCompiler.FLAG_NAMED, + block.getCompiledData()[0]); + assertEquals(JBBPCompiler.CODE_STRUCT_START | JBBPCompiler.FLAG_NAMED | JBBPCompiler.FLAG_WIDE, + block.getCompiledData()[1] & 0xFF); + assertEquals(JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM, + block.getCompiledData()[2] & 0xFF); assertEquals(JBBPCompiler.CODE_BYTE, block.getCompiledData()[3]); assertEquals(JBBPCompiler.CODE_STRUCT_END, block.getCompiledData()[4]); assertEquals(1, block.getCompiledData()[5]); @@ -148,7 +167,8 @@ public void testCompile_ErrorForArraySkipField() throws Exception { @Test public void testCompile_ZeroSkipValueIsAllowed() throws Exception { - assertArrayEquals(new byte[] {JBBPCompiler.CODE_SKIP, 0}, JBBPCompiler.compile("skip:0;").getCompiledData()); + assertArrayEquals(new byte[] {JBBPCompiler.CODE_SKIP, 0}, + JBBPCompiler.compile("skip:0;").getCompiledData()); } @Test @@ -173,7 +193,8 @@ public void testCompile_ArraySize_ExpressionWithAllOperators_NoExceptions() thro } @Test - public void testCompile_ExtraFieldData_ExpressionWithAllOperators_NoExceptions() throws Exception { + public void testCompile_ExtraFieldData_ExpressionWithAllOperators_NoExceptions() + throws Exception { assertNotNull(JBBPCompiler.compile("bit:((1+2-3)*4/(5<<6>>7)>>>3%1&89|22^34-~45) a;")); } @@ -265,7 +286,9 @@ public void testCompile_NonamedVarWithPositiveExtra() throws Exception { @Test public void testCompile_NonamedVarWithNegativeExtra() throws Exception { final byte[] compiled = JBBPCompiler.compile("var:-1;").getCompiledData(); - assertArrayEquals(new byte[] {JBBPCompiler.CODE_VAR, (byte) 0x81, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}, compiled); + assertArrayEquals( + new byte[] {JBBPCompiler.CODE_VAR, (byte) 0x81, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF}, compiled); } @Test @@ -283,25 +306,33 @@ public void testCompile_NamedVarWithPositiveExtra() throws Exception { @Test public void testCompile_NamedVarWithNegativeExtra() throws Exception { final byte[] compiled = JBBPCompiler.compile("var:-1 VVV;").getCompiledData(); - assertArrayEquals(new byte[] {JBBPCompiler.CODE_VAR | JBBPCompiler.FLAG_NAMED, (byte) 0x81, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}, compiled); + assertArrayEquals( + new byte[] {JBBPCompiler.CODE_VAR | JBBPCompiler.FLAG_NAMED, (byte) 0x81, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}, compiled); } @Test public void testCompile_NamedVarArrayWithoutExtra() throws Exception { final byte[] compiled = JBBPCompiler.compile("var [98] VVV;").getCompiledData(); - assertArrayEquals(new byte[] {JBBPCompiler.CODE_VAR | JBBPCompiler.FLAG_NAMED | JBBPCompiler.FLAG_ARRAY, 98, 0}, compiled); + assertArrayEquals( + new byte[] {JBBPCompiler.CODE_VAR | JBBPCompiler.FLAG_NAMED | JBBPCompiler.FLAG_ARRAY, 98, + 0}, compiled); } @Test public void testCompile_NamedVarArrayWithPositiveExtra() throws Exception { final byte[] compiled = JBBPCompiler.compile("var:12 [98] VVV;").getCompiledData(); - assertArrayEquals(new byte[] {JBBPCompiler.CODE_VAR | JBBPCompiler.FLAG_ARRAY | JBBPCompiler.FLAG_NAMED, 98, 12}, compiled); + assertArrayEquals( + new byte[] {JBBPCompiler.CODE_VAR | JBBPCompiler.FLAG_ARRAY | JBBPCompiler.FLAG_NAMED, 98, + 12}, compiled); } @Test public void testCompile_NamedVarArrayWithNegativeExtra() throws Exception { final byte[] compiled = JBBPCompiler.compile("var:-1 [98] VVV;").getCompiledData(); - assertArrayEquals(new byte[] {JBBPCompiler.CODE_VAR | JBBPCompiler.FLAG_ARRAY | JBBPCompiler.FLAG_NAMED, 98, (byte) 0x81, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}, compiled); + assertArrayEquals( + new byte[] {JBBPCompiler.CODE_VAR | JBBPCompiler.FLAG_ARRAY | JBBPCompiler.FLAG_NAMED, 98, + (byte) 0x81, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}, compiled); } @Test @@ -408,7 +439,8 @@ public void testCompile_SingleNamedIntLittleEndianField() throws Exception { final JBBPCompiledBlock block = JBBPCompiler.compile(" JBBPCompiler.compile("out { int [4] len; some {byte [len] HeLLo;} }")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("out { int [4] len; some {byte [len] HeLLo;} }")); } @Test public void testCompile_ErrorForFieldInStructArrayAsVarLength() throws Exception { - assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("struct [10] {int [4] len;} some {byte [struct.len] HeLLo;} ")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("struct [10] {int [4] len;} some {byte [struct.len] HeLLo;} ")); } @Test public void testCompile_ErrorForFieldInStructAsVarLength() throws Exception { - assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("struct [10] {int len;} some {byte [struct.len] HeLLo;} ")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("struct [10] {int len;} some {byte [struct.len] HeLLo;} ")); } @Test public void testCompile_ErrorForUnknownFieldAsArrayLength() throws Exception { - assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("some {byte [struct.len] HeLLo;} ")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("some {byte [struct.len] HeLLo;} ")); } @Test @@ -525,8 +566,10 @@ public void testCompile_ArrayWithUndefinedLength() throws Exception { assertEquals(2, compiled.getCompiledData().length); assertNotNull(field); assertEquals(0, field.getFieldOffsetInCompiledBlock()); - assertEquals(JBBPCompiler.CODE_BYTE | JBBPCompiler.FLAG_NAMED | JBBPCompiler.FLAG_WIDE, compiled.getCompiledData()[0] & 0xFF); - assertEquals(JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM, compiled.getCompiledData()[1] & 0xFF); + assertEquals(JBBPCompiler.CODE_BYTE | JBBPCompiler.FLAG_NAMED | JBBPCompiler.FLAG_WIDE, + compiled.getCompiledData()[0] & 0xFF); + assertEquals(JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM, + compiled.getCompiledData()[1] & 0xFF); } @Test @@ -538,7 +581,8 @@ public void testCompile_StructFieldWithNameOfExternalField() throws Exception { @Test public void testCompile_FixedStructArray() throws Exception { - final JBBPCompiledBlock compiled = JBBPCompiler.compile("int value; inner [2] { byte a; byte b;}"); + final JBBPCompiledBlock compiled = + JBBPCompiler.compile("int value; inner [2] { byte a; byte b;}"); assertArrayEquals(new byte[] { JBBPCompiler.CODE_INT | JBBPCompiler.FLAG_NAMED, @@ -563,7 +607,8 @@ public void testCompile_ErrorForNonAllowedArguments() throws Exception { assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("reset$$:1;")); assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("reset$$ hello;")); assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("reset$$ [445];")); - assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("reset$$ [445] hello;")); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("reset$$ [445] hello;")); } @Test @@ -573,7 +618,8 @@ public void testCompile_ErrorForResetWithExtraValue() throws Exception { @Test public void testCompile_Reset() throws Exception { - assertArrayEquals(new byte[] {JBBPCompiler.CODE_RESET_COUNTER}, JBBPCompiler.compile("reset$$;").getCompiledData()); + assertArrayEquals(new byte[] {JBBPCompiler.CODE_RESET_COUNTER}, + JBBPCompiler.compile("reset$$;").getCompiledData()); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJBBPToJavaConverterCompilationTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJBBPToJavaConverterCompilationTest.java index a1042c3b..549fa53a 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJBBPToJavaConverterCompilationTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJBBPToJavaConverterCompilationTest.java @@ -21,11 +21,11 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; - import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.mapper.JBBPMapper; @@ -67,36 +67,53 @@ private void assertCompilation(final String classSrc) throws Exception { @Test void testVarNamesAsJavaTypes() throws Exception { - final JBBPParser parser = JBBPParser.prepare("ubyte;int integer; int number; int try; int byte; int _byte; int _byte_; int char; int short; int long; int double; int float; int [long+double+char] string;"); - assertCompilation(makeSources(parser, "some multiline text\nto be added into header", true, true, false)); + final JBBPParser parser = JBBPParser.prepare( + "ubyte;int integer; int number; int try; int byte; int _byte; int _byte_; int char; int short; int long; int double; int float; int [long+double+char] string;"); + assertCompilation( + makeSources(parser, "some multiline text\nto be added into header", true, true, false)); } @Test void testExpression() throws Exception { - final JBBPParser parser = JBBPParser.prepare("bit:8 bitf; var somevar; bool bbb; long aaa; ubyte kkk; {{int lrn; {int [(lrn/aaa*1*(2*somevar-4)&$joomla)/(100%9>>bitf)&56|~kkk^78&bbb];}}}"); - assertCompilation(makeSources(parser, "some multiline text\nto be added into header", false, false, false)); - assertCompilation(makeSources(parser, "some multiline text\nto be added into header", true, true, true)); + final JBBPParser parser = JBBPParser.prepare( + "bit:8 bitf; var somevar; bool bbb; long aaa; ubyte kkk; {{int lrn; {int [(lrn/aaa*1*(2*somevar-4)&$joomla)/(100%9>>bitf)&56|~kkk^78&bbb];}}}"); + assertCompilation( + makeSources(parser, "some multiline text\nto be added into header", false, false, false)); + assertCompilation( + makeSources(parser, "some multiline text\nto be added into header", true, true, true)); } @Test void testGenerateBinAnnotation() { - final JBBPParser parser = JBBPParser.prepare("bit:3 someBit; bit:4 [12] bitArray; some {int a; floatj b; doublej[23] darr;}"); - assertFalse(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).build().convert().contains("@Bin")); - assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).addBinAnnotations().build().convert().contains("@Bin")); + final JBBPParser parser = JBBPParser + .prepare("bit:3 someBit; bit:4 [12] bitArray; some {int a; floatj b; doublej[23] darr;}"); + assertFalse( + JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).build().convert() + .contains("@Bin")); + assertTrue( + JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).addBinAnnotations() + .build().convert().contains("@Bin")); } @Test void testGenNewInstanceMethod() { - final JBBPParser parser = JBBPParser.prepare("bit:3 someBit; bit:4 [12] bitArray; some {int a; floatj b; doublej[23] darr;}"); - assertFalse(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).build().convert().contains("Object " + JBBPMapper.MAKE_CLASS_INSTANCE_METHOD_NAME)); - assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).addNewInstanceMethods().build().convert().contains("Object " + JBBPMapper.MAKE_CLASS_INSTANCE_METHOD_NAME)); + final JBBPParser parser = JBBPParser + .prepare("bit:3 someBit; bit:4 [12] bitArray; some {int a; floatj b; doublej[23] darr;}"); + assertFalse( + JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).build().convert() + .contains("Object " + JBBPMapper.MAKE_CLASS_INSTANCE_METHOD_NAME)); + assertTrue( + JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).addNewInstanceMethods() + .build().convert().contains("Object " + JBBPMapper.MAKE_CLASS_INSTANCE_METHOD_NAME)); } @Test void testForceAbstract() throws Exception { final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertFalse(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setDoMainClassAbstract(false).build().convert().contains("abstract")); - assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setDoMainClassAbstract(true).build().convert().contains("abstract")); + assertFalse(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME) + .setDoMainClassAbstract(false).build().convert().contains("abstract")); + assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME) + .setDoMainClassAbstract(true).build().convert().contains("abstract")); } @Test @@ -110,7 +127,8 @@ void testMakeInternalClassObjects_StaticClasses() throws Exception { .convert(); assertTrue(text.contains("public A makeA(){ this.a = new A(this); return this.a; }")); assertTrue(text.contains("public B makeB(){ this.b = new B(_Root_); return this.b; }")); - assertTrue(text.contains("public C[] makeC(int _Len_){ this.c = new C[_Len_]; for(int i=0;i < _Len_;i++) this.c[i]=new C(_Root_); return this.c; }")); + assertTrue(text.contains( + "public C[] makeC(int _Len_){ this.c = new C[_Len_]; for(int i=0;i < _Len_;i++) this.c[i]=new C(_Root_); return this.c; }")); } @Test @@ -124,7 +142,8 @@ void testMakeInternalClassObjects_NoMakersWithoutGettersSetters() throws Excepti .convert(); assertFalse(text.contains("public A makeA(){ this.a = new A(this); return this.a; }")); assertFalse(text.contains("public B makeB(){ this.b = new B(_Root_); return this.b; }")); - assertFalse(text.contains("public C[] makeC(int _Len_){ this.c = new C[_Len_]; for(int i=0;i < _Len_;i++) this.c[i]=new C(_Root_); return this.c; }")); + assertFalse(text.contains( + "public C[] makeC(int _Len_){ this.c = new C[_Len_]; for(int i=0;i < _Len_;i++) this.c[i]=new C(_Root_); return this.c; }")); } @Test @@ -139,7 +158,8 @@ void testMakeInternalClassObjects_NonStaticClasses() throws Exception { .convert(); assertTrue(text.contains("public A makeA(){ this.a = new A(this); return this.a; }")); assertTrue(text.contains("public B makeB(){ this.b = new B(_Root_); return this.b; }")); - assertTrue(text.contains("public C[] makeC(int _Len_){ this.c = new C[_Len_]; for(int i=0;i < _Len_;i++) this.c[i]=new C(_Root_); return this.c; }")); + assertTrue(text.contains( + "public C[] makeC(int _Len_){ this.c = new C[_Len_]; for(int i=0;i < _Len_;i++) this.c[i]=new C(_Root_); return this.c; }")); } @Test @@ -187,38 +207,52 @@ void testMapSubstructToInterface() throws Exception { @Test void testCustomText() throws Exception { final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassCustomText("public void test(){}").build().convert().contains("public void test(){}")); + assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME) + .setMainClassCustomText("public void test(){}").build().convert() + .contains("public void test(){}")); } @Test void testSuperclass() throws Exception { final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setSuperClass("com.igormaznitsa.Super").build().convert().contains("extends com.igormaznitsa.Super ")); + assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME) + .setSuperClass("com.igormaznitsa.Super").build().convert() + .contains("extends com.igormaznitsa.Super ")); } @Test void testInterfaces() throws Exception { final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassImplements("com.igormaznitsa.InterfaceA", "com.igormaznitsa.InterfaceB").build().convert().contains("implements com.igormaznitsa.InterfaceA,com.igormaznitsa.InterfaceB ")); + assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME) + .setMainClassImplements("com.igormaznitsa.InterfaceA", "com.igormaznitsa.InterfaceB") + .build().convert() + .contains("implements com.igormaznitsa.InterfaceA,com.igormaznitsa.InterfaceB ")); } @Test void testClassPackage() throws Exception { final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertFalse(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).build().convert().contains("package ")); - assertFalse(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassPackage("").build().convert().contains("package ")); - assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassPackage("hello.world").build().convert().contains("package hello.world;")); + assertFalse( + JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).build().convert() + .contains("package ")); + assertFalse( + JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassPackage("") + .build().convert().contains("package ")); + assertTrue(JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME) + .setMainClassPackage("hello.world").build().convert().contains("package hello.world;")); } @Test void testGettersSetters() throws Exception { final JBBPParser parser = JBBPParser.prepare("byte a;"); - String text = JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).build().convert(); + String text = + JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).build().convert(); assertTrue(text.contains("public byte a;")); assertFalse(text.contains("public void setA(byte value) {")); assertFalse(text.contains("public byte getA() {")); - text = JBBPToJavaConverter.makeBuilder(parser).setAddGettersSetters(true).setMainClassName(CLASS_NAME).build().convert(); + text = JBBPToJavaConverter.makeBuilder(parser).setAddGettersSetters(true) + .setMainClassName(CLASS_NAME).build().convert(); assertFalse(text.contains("public byte a;")); assertTrue(text.contains("protected byte a;")); @@ -228,18 +262,23 @@ void testGettersSetters() throws Exception { @Test void testZ80snap1() throws Exception { - final JBBPParser parser = JBBPParser.prepare("byte reg_a; byte reg_f; assertCompilation(makeSources(parser, null, false, false, false))); - assertThrows(Exception.class, () -> assertCompilation(makeSources(parser, null, true, false, false))); + void testStringFieldAsLength_CompilationErrorForStringFieldInArithmeticException() + throws Exception { + final JBBPParser parser = + JBBPParser.prepare("stringj str; stringj [str] strarr; stringj [_] all;"); + assertThrows(Exception.class, + () -> assertCompilation(makeSources(parser, null, false, false, false))); + assertThrows(Exception.class, + () -> assertCompilation(makeSources(parser, null, true, false, false))); } @Test - void testStringFieldInExpression_CompilationErrorForStringFieldInArithmeticException() throws Exception { - final JBBPParser parser = JBBPParser.prepare("stringj str; byte a; stringj [str+a] strarr; stringj [_] all;"); - assertThrows(Exception.class, () -> assertCompilation(makeSources(parser, null, false, false, false))); - assertThrows(Exception.class, () -> assertCompilation(makeSources(parser, null, true, false, false))); + void testStringFieldInExpression_CompilationErrorForStringFieldInArithmeticException() + throws Exception { + final JBBPParser parser = + JBBPParser.prepare("stringj str; byte a; stringj [str+a] strarr; stringj [_] all;"); + assertThrows(Exception.class, + () -> assertCompilation(makeSources(parser, null, false, false, false))); + assertThrows(Exception.class, + () -> assertCompilation(makeSources(parser, null, true, false, false))); } @Test @@ -372,29 +431,40 @@ void testPngParsing() throws Exception { @Test void testPrimitiveFieldsInExpression() throws Exception { - final JBBPParser parser = JBBPParser.prepare("long lfield; int ifield; byte bfield; ggg {ubyte ubfield; short shfield;} ushort ushfield; bit:4 bitfield; byte [bfield*ggg.shfield<> 3 << 2) >>> 1 + (13 - 1) / 2 + ((11 + 22) * 33 / 44 % 55) - (123 & 345 | 234 ^ ~123) & 255, "(11 * (8 - 7)) % 13 + ( 1234>>3<<2)>>>1 + (13 - 1) / 2 + ((11 + 22) * 33 / 44 % 55) - (123 & 345 | 234 ^ ~123) & 255"); + assertExpression((11 * (8 - 7)) % 13 + (1234 >> 3 << 2) >>> + 1 + (13 - 1) / 2 + ((11 + 22) * 33 / 44 % 55) - (123 & 345 | 234 ^ ~123) & 255, + "(11 * (8 - 7)) % 13 + ( 1234>>3<<2)>>>1 + (13 - 1) / 2 + ((11 + 22) * 33 / 44 % 55) - (123 & 345 | 234 ^ ~123) & 255"); } @Test public void testSynthesidExpression() throws Exception { final Random rnd = new Random(5111975); - final String[] operatorsTwo = new String[] {"-", "+", "*", "/", "%", ">>", ">>>", "<<", "^", "|", "&"}; + final String[] operatorsTwo = + new String[] {"-", "+", "*", "/", "%", ">>", ">>>", "<<", "^", "|", "&"}; final String[] operatorsOne = new String[] {"-", "+", "~"}; int rightCounter = 0; @@ -141,17 +147,21 @@ public void testSynthesidExpression() throws Exception { Object theInstance; final StringBuilder src = new StringBuilder(); try { - theInstance = compileAndMakeInstanceSrc("byte [" + expression + "] array;", " public static int makeExpressionResult(){ return " + expression + ";}", src); + theInstance = compileAndMakeInstanceSrc("byte [" + expression + "] array;", + " public static int makeExpressionResult(){ return " + expression + ";}", src); } catch (Exception ex) { fail("Can't compile : " + expression); return; } try { - final int etalon = (Integer) theInstance.getClass().getMethod("makeExpressionResult").invoke(null); + final int etalon = + (Integer) theInstance.getClass().getMethod("makeExpressionResult").invoke(null); if (etalon > 0 && etalon < 100000) { System.out.println("Testing expression : " + expression); - assertEquals(etalon, getField(callRead(theInstance, new JBBPBitInputStream(UNLIMITED_STREAM)), "array", byte[].class).length, src.toString()); + assertEquals(etalon, + getField(callRead(theInstance, new JBBPBitInputStream(UNLIMITED_STREAM)), "array", + byte[].class).length, src.toString()); rightCounter++; } } catch (InvocationTargetException ex) { diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverterReadWriteTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverterReadWriteTest.java index 5e83278c..37af2d47 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverterReadWriteTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverterReadWriteTest.java @@ -16,11 +16,25 @@ package com.igormaznitsa.jbbp.compiler.conversion; +import static com.igormaznitsa.jbbp.TestUtils.assertPngChunk; +import static com.igormaznitsa.jbbp.TestUtils.getField; +import static com.igormaznitsa.jbbp.TestUtils.getFieldThroughGetters; +import static com.igormaznitsa.jbbp.TestUtils.wavInt2Str; +import static java.util.Objects.requireNonNull; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.TestUtils; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; @@ -30,18 +44,13 @@ import com.igormaznitsa.jbbp.model.JBBPFieldInt; import com.igormaznitsa.jbbp.testaux.AbstractJBBPToJavaConverterTest; import com.igormaznitsa.jbbp.utils.ReflectUtils; -import org.apache.commons.io.IOUtils; -import org.junit.jupiter.api.Test; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; - -import static com.igormaznitsa.jbbp.TestUtils.*; -import static org.junit.jupiter.api.Assertions.*; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; /** * Test reading writing with converted classes from parser. @@ -49,40 +58,19 @@ public class JBBPToJavaConverterReadWriteTest extends AbstractJBBPToJavaConverterTest { private byte[] loadResource(final String name) throws Exception { - try(final InputStream result = this.getClass().getClassLoader().getResourceAsStream("com/igormaznitsa/jbbp/it/" + name)){ + try (final InputStream result = requireNonNull(this.getClass().getClassLoader() + .getResourceAsStream("com/igormaznitsa/jbbp/it/" + name))) { return IOUtils.toByteArray(result); } } - public static class TestSuperclass { - public String str; - public String[] strarr; - public float flt; - public float[] fltarr; - public double dbl; - public double[] dblarr; - public char len; - - public class Ins { - public byte[] a; - public byte b; - public byte c; - - public class InsIns { - public byte a; - } - - public InsIns insins; - } - - public Ins[] ins; - } - @Test public void testReadWrite_ExtendsSuperClassAndUseItsFields() throws Exception { final JBBPParser parser = JBBPParser.prepare( "stringj str;" + "stringj [2] strarr;" + + "uint uintf;" + + "uint [2] uintarr;" + "floatj flt;" + "floatj [2] fltarr;" + "doublej dbl;" @@ -100,9 +88,9 @@ public void testReadWrite_ExtendsSuperClassAndUseItsFields() throws Exception { this.printGeneratedClassText = true; - final Map superclasses = new HashMap<>(); - superclasses.put("ins",TestSuperclass.Ins.class.getCanonicalName()); - superclasses.put("ins.insins",TestSuperclass.Ins.InsIns.class.getCanonicalName()); + final Map superclasses = new HashMap<>(); + superclasses.put("ins", TestSuperclass.Ins.class.getCanonicalName()); + superclasses.put("ins.insins", TestSuperclass.Ins.InsIns.class.getCanonicalName()); final String thePackage = JBBPToJavaConverterReadWriteTest.class.getPackage().getName(); @@ -117,22 +105,27 @@ public void testReadWrite_ExtendsSuperClassAndUseItsFields() throws Exception { .build() .convert(); + System.out.println(text); + final String fullClassName = thePackage + '.' + CLASS_NAME; final ClassLoader classLoader = saveAndCompile(new JavaClassContent(fullClassName, text)); final Object instance = ReflectUtils.newInstance(classLoader.loadClass(fullClassName)); - assertTrue(instance instanceof TestSuperclass); + assertInstanceOf(TestSuperclass.class, instance); - final byte [] etalon = new byte[] { + final byte[] etalon = new byte[] { 0, 2, 49, 50, 1, 51, + (byte) 0xFA, (byte) 0xFB, (byte) 0xFC, (byte) 0xFD, + (byte) 0x1A, (byte) 0x1B, (byte) 0x1C, (byte) 0x1D, (byte) 0x2A, (byte) 0x2B, (byte) 0x2C, + (byte) 0x2D, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 2, - 1,2, - 3,4,5 + 1, 2, + 3, 4, 5 }; callRead(instance, etalon); @@ -141,13 +134,16 @@ public void testReadWrite_ExtendsSuperClassAndUseItsFields() throws Exception { assertNull(null, parsed.str); assertArrayEquals(new String[] {"12", "3"}, parsed.strarr); + assertEquals(0xFAFBFCFDL, parsed.uintf); + assertArrayEquals(new long[] {0x1A1B1C1DL, 0x2A2B2C2DL}, parsed.uintarr); assertEquals(2.3879393E-38f, parsed.flt); assertArrayEquals(new float[] {6.301941E-36f, 1.661634E-33f}, parsed.fltarr); assertEquals(8.20788039913184E-304d, parsed.dbl); - assertArrayEquals(new double[] {4.0383818836028145E-265d, 1.9074368412237584E-226d}, parsed.dblarr); + assertArrayEquals(new double[] {4.0383818836028145E-265d, 1.9074368412237584E-226d}, + parsed.dblarr); assertEquals(1, parsed.ins.length); - assertArrayEquals(new byte[]{1,2}, parsed.ins[0].a); + assertArrayEquals(new byte[] {1, 2}, parsed.ins[0].a); assertEquals(3, parsed.ins[0].b); assertEquals(4, parsed.ins[0].c); assertEquals(5, parsed.ins[0].insins.a); @@ -160,13 +156,16 @@ public void testReaWrite_StructMappedToInterface_Array_GettersSettersOn() throws final JBBPParser parser = JBBPParser.prepare("z { x { y [_] { byte a;}}}"); final Map interfaceMap = new HashMap<>(); interfaceMap.put("z.x.y", ByteTestInterface.class.getCanonicalName()); - final String text = JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassPackage(PACKAGE_NAME).setAddGettersSetters(true).setMapSubClassesInterfaces(interfaceMap).build().convert(); + final String text = JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME) + .setMainClassPackage(PACKAGE_NAME).setAddGettersSetters(true) + .setMapSubClassesInterfaces(interfaceMap).build().convert(); final String fullClassName = PACKAGE_NAME + '.' + CLASS_NAME; final ClassLoader classLoader = saveAndCompile(new JavaClassContent(fullClassName, text)); final Object instance = ReflectUtils.newInstance(classLoader.loadClass(fullClassName)); callRead(instance, new byte[] {0, 1, 2, 3, 4, 5}); - final ByteTestInterface[] data = getFieldThroughGetters(instance, "z.x.y", ByteTestInterface[].class); + final ByteTestInterface[] data = + getFieldThroughGetters(instance, "z.x.y", ByteTestInterface[].class); for (int i = 0; i < 6; i++) { assertEquals(i, data[i].getA()); } @@ -179,13 +178,16 @@ public void testReaWrite_StructMappedToInterface_NotArray_GettersSettersOn() thr final JBBPParser parser = JBBPParser.prepare("z { x { y { byte a;}}}"); final Map interfaceMap = new HashMap<>(); interfaceMap.put("z.x.y", ByteTestInterface.class.getCanonicalName()); - final String text = JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassPackage(PACKAGE_NAME).setAddGettersSetters(true).setMapSubClassesInterfaces(interfaceMap).build().convert(); + final String text = JBBPToJavaConverter.makeBuilder(parser).setMainClassName(CLASS_NAME) + .setMainClassPackage(PACKAGE_NAME).setAddGettersSetters(true) + .setMapSubClassesInterfaces(interfaceMap).build().convert(); final String fullClassName = PACKAGE_NAME + '.' + CLASS_NAME; final ClassLoader classLoader = saveAndCompile(new JavaClassContent(fullClassName, text)); final Object instance = ReflectUtils.newInstance(classLoader.loadClass(fullClassName)); callRead(instance, new byte[] {42}); - final ByteTestInterface data = getFieldThroughGetters(instance, "z.x.y", ByteTestInterface.class); + final ByteTestInterface data = + getFieldThroughGetters(instance, "z.x.y", ByteTestInterface.class); assertEquals(42, data.getA()); assertArrayEquals(new byte[] {42}, callWrite(instance)); @@ -197,12 +199,14 @@ public void testReadWrite_BooleanArrayWholeStream() throws Exception { assertNull(getField(instance, "boolarray", boolean[].class), "by default must be null"); final byte[] etalon = new byte[] {1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1}; callRead(instance, etalon.clone()); - assertArrayEquals(new boolean[] {true, false, true, true, false, true, true, true, false, false, false, true, true, true, true}, getField(instance, "boolarray", boolean[].class)); + assertArrayEquals( + new boolean[] {true, false, true, true, false, true, true, true, false, false, false, true, + true, true, true}, getField(instance, "boolarray", boolean[].class)); assertArrayEquals(etalon, callWrite(instance)); } @Test - public void testReadWite_ByteArrayWholeStream() throws Exception { + public void testReadWrite_ByteArrayWholeStream() throws Exception { final Object instance = compileAndMakeInstance("byte [_] byteArray;"); assertNull(getField(instance, "bytearray", byte[].class), "by default must be null"); @@ -215,18 +219,19 @@ public void testReadWite_ByteArrayWholeStream() throws Exception { } @Test - public void testReadWite_Float_SingleValue() throws Exception { + public void testReadWrite_Float_SingleValue() throws Exception { final Object instance = compileAndMakeInstance("floatj value;"); final byte[] etalon = new byte[] {1, 2, 3, 4}; callRead(instance, etalon.clone()); - assertEquals(2.3879393E-38f, getField(instance, "value", Float.class).floatValue(), TestUtils.FLOAT_DELTA); + assertEquals(2.3879393E-38f, getField(instance, "value", Float.class), + TestUtils.FLOAT_DELTA); assertArrayEquals(etalon, callWrite(instance)); } @Test - public void testReadWite_FloatArrayWholeStream() throws Exception { + public void testReadWrite_FloatArrayWholeStream() throws Exception { final Object instance = compileAndMakeInstance("floatj [_] floatArray;"); assertNull(getField(instance, "floatarray", float[].class), "by default must be null"); @@ -234,12 +239,13 @@ public void testReadWite_FloatArrayWholeStream() throws Exception { callRead(instance, etalon.clone()); - assertArrayEquals(new float[] {2.3879393E-38f, 6.301941E-36f, 1.5417845E-33f, 2.6042668E-12f}, getField(instance, "floatarray", float[].class), TestUtils.FLOAT_DELTA); + assertArrayEquals(new float[] {2.3879393E-38f, 6.301941E-36f, 1.5417845E-33f, 2.6042668E-12f}, + getField(instance, "floatarray", float[].class), TestUtils.FLOAT_DELTA); assertArrayEquals(etalon, callWrite(instance)); } @Test - public void testReadWite_String_SingleValue() throws Exception { + public void testReadWrite_String_SingleValue() throws Exception { final Object instance = compileAndMakeInstance("stringj value;"); final byte[] etalon = new byte[] {3, 65, 66, 67}; @@ -250,8 +256,9 @@ public void testReadWite_String_SingleValue() throws Exception { } @Test - public void testReadWite_Val_CalculatedLength() throws Exception { - final Object instance = compileAndMakeInstance("ubyte a; ubyte b; val:(a-b) c; val:(c+8) d; byte [d] data;"); + public void testReadWrite_Val_CalculatedLength() throws Exception { + final Object instance = + compileAndMakeInstance("ubyte a; ubyte b; val:(a-b) c; val:(c+8) d; byte [d] data;"); final byte[] etalon = new byte[] {2, 8, 33, 44}; callRead(instance, etalon.clone()); @@ -261,7 +268,7 @@ public void testReadWite_Val_CalculatedLength() throws Exception { } @Test - public void testReadWite_Bit_SingleValueWhichLengthCalclatedThrouhExpression() throws Exception { + public void testReadWrite_Bit_SingleValueWhichLengthCalclatedThrouhExpression() throws Exception { final Object instance = compileAndMakeInstance("ubyte a; ubyte b; bit:(a+b) c;"); final byte[] etalon = new byte[] {1, 2, (byte) 0xB4}; @@ -272,7 +279,7 @@ public void testReadWite_Bit_SingleValueWhichLengthCalclatedThrouhExpression() t } @Test - public void testReadWite_StringArrayWholeStream() throws Exception { + public void testReadWrite_StringArrayWholeStream() throws Exception { final Object instance = compileAndMakeInstance("stringj [_] strArray;"); assertNull(getField(instance, "strarray", String[].class), "by default must be null"); @@ -280,36 +287,69 @@ public void testReadWite_StringArrayWholeStream() throws Exception { callRead(instance, etalon.clone()); - assertArrayEquals(new String[] {"ABC", null, "123"}, getField(instance, "strarray", String[].class)); + assertArrayEquals(new String[] {"ABC", null, "123"}, + getField(instance, "strarray", String[].class)); assertArrayEquals(etalon, callWrite(instance)); } @Test - public void testReadWite_Double_SingleValue() throws Exception { + public void testReadWrite_Double_SingleValue() throws Exception { final Object instance = compileAndMakeInstance("doublej value;"); final byte[] etalon = new byte[] {1, 2, 3, 4, 5, 6, 7, 8}; callRead(instance, etalon.clone()); - assertEquals(8.20788039913184E-304d, getField(instance, "value", Double.class).doubleValue(), TestUtils.FLOAT_DELTA); + assertEquals(8.20788039913184E-304d, getField(instance, "value", Double.class), + TestUtils.FLOAT_DELTA); assertArrayEquals(etalon, callWrite(instance)); } @Test - public void testReadWite_DoubleArrayWholeStream() throws Exception { + public void testReadWrite_UInt_SingleValue() throws Exception { + final Object instance = compileAndMakeInstance("uint value;"); + final byte[] etalon = new byte[] {(byte) 0xFF, 2, 3, 4}; + + callRead(instance, etalon.clone()); + + assertEquals(0xFF020304L, getField(instance, "value", Long.class).longValue()); + assertArrayEquals(etalon, callWrite(instance)); + } + + @Test + public void testReadWrite_DoubleArrayWholeStream() throws Exception { final Object instance = compileAndMakeInstance("doublej [_] doubleArray;"); assertNull(getField(instance, "doublearray", double[].class), "by default must be null"); - final byte[] etalon = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 22, 33, 44, 55, 66, 77, 3, 5, 9, 11, 33, 12, 10, 45}; + final byte[] etalon = + new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 22, 33, 44, 55, 66, 77, 3, 5, 9, 11, 33, 12, 10, + 45}; + + callRead(instance, etalon.clone()); + + assertArrayEquals( + new double[] {8.20788039913184E-304d, 2.494444648262547E-265d, 4.117024896955411E-294d}, + getField(instance, "doublearray", double[].class), TestUtils.FLOAT_DELTA); + assertArrayEquals(etalon, callWrite(instance)); + } + + @Test + public void testReadWrite_UIntArrayWholeStream() throws Exception { + final Object instance = compileAndMakeInstance("uint [_] uintArray;"); + assertNull(getField(instance, "uintarray", long[].class), "by default must be null"); + + final byte[] etalon = + new byte[] {(byte) 0xFF, 2, 3, 4, 5, 6, 7, 8, 9, 0, 22, 33}; callRead(instance, etalon.clone()); - assertArrayEquals(new double[] {8.20788039913184E-304d, 2.494444648262547E-265d, 4.117024896955411E-294d}, getField(instance, "doublearray", double[].class), TestUtils.FLOAT_DELTA); + assertArrayEquals( + new long[] {0xFF020304L, 0x05060708L, 0x09001621L}, + getField(instance, "uintarray", long[].class)); assertArrayEquals(etalon, callWrite(instance)); } @Test - public void testReadWite_BitArrayWholeStream() throws Exception { + public void testReadWrite_BitArrayWholeStream() throws Exception { final Object instance = compileAndMakeInstance("bit [_] bitArray;"); assertNull(getField(instance, "bitarray", byte[].class), "by default must be null"); @@ -323,7 +363,7 @@ public void testReadWite_BitArrayWholeStream() throws Exception { } @Test - public void testReadWite_FloatFieldAsCounter() throws Exception { + public void testReadWrite_FloatFieldAsCounter() throws Exception { final Object instance = compileAndMakeInstance("floatj len; byte [len] data;"); assertNull(getField(instance, "data", byte[].class), "by default must be null"); @@ -331,13 +371,13 @@ public void testReadWite_FloatFieldAsCounter() throws Exception { callRead(instance, data.clone()); - assertEquals(3.3f, getField(instance, "len", Float.class).floatValue(), TestUtils.FLOAT_DELTA); + assertEquals(3.3f, getField(instance, "len", Float.class), TestUtils.FLOAT_DELTA); assertArrayEquals(new byte[] {1, 2, 3}, getField(instance, "data", byte[].class)); assertArrayEquals(data, callWrite(instance)); } @Test - public void testReadWite_FloatFieldAsCounter_Expression() throws Exception { + public void testReadWrite_FloatFieldAsCounter_Expression() throws Exception { final Object instance = compileAndMakeInstance("floatj len; byte [len/2] data;"); assertNull(getField(instance, "data", byte[].class), "by default must be null"); @@ -345,13 +385,13 @@ public void testReadWite_FloatFieldAsCounter_Expression() throws Exception { callRead(instance, data.clone()); - assertEquals(4.3f, getField(instance, "len", Float.class).floatValue(), TestUtils.FLOAT_DELTA); + assertEquals(4.3f, getField(instance, "len", Float.class), TestUtils.FLOAT_DELTA); assertArrayEquals(new byte[] {1, 2}, getField(instance, "data", byte[].class)); assertArrayEquals(data, callWrite(instance)); } @Test - public void testReadWite_DoubleFloatFieldAsCounter() throws Exception { + public void testReadWrite_DoubleFloatFieldAsCounter() throws Exception { final Object instance = compileAndMakeInstance("doublej len; byte [len] data;"); assertNull(getField(instance, "data", byte[].class), "by default must be null"); @@ -359,13 +399,14 @@ public void testReadWite_DoubleFloatFieldAsCounter() throws Exception { callRead(instance, data.clone()); - assertEquals(3.3d, getField(instance, "len", Double.class).doubleValue(), TestUtils.FLOAT_DELTA); + assertEquals(3.3d, getField(instance, "len", Double.class), + TestUtils.FLOAT_DELTA); assertArrayEquals(new byte[] {1, 2, 3}, getField(instance, "data", byte[].class)); assertArrayEquals(data, callWrite(instance)); } @Test - public void testReadWite_DoubleFloatFieldAsCounter_Expression() throws Exception { + public void testReadWrite_DoubleFloatFieldAsCounter_Expression() throws Exception { final Object instance = compileAndMakeInstance("doublej len; byte [len/2] data;"); assertNull(getField(instance, "data", byte[].class), "by default must be null"); @@ -373,14 +414,17 @@ public void testReadWite_DoubleFloatFieldAsCounter_Expression() throws Exception callRead(instance, data.clone()); - assertEquals(4.3d, getField(instance, "len", Double.class).doubleValue(), TestUtils.FLOAT_DELTA); + assertEquals(4.3d, getField(instance, "len", Double.class), + TestUtils.FLOAT_DELTA); assertArrayEquals(new byte[] {1, 2}, getField(instance, "data", byte[].class)); assertArrayEquals(data, callWrite(instance)); } @Test public void testReadWriteWithOptionallyIgnoredStructure() throws Exception { - final Object instance = compileAndMakeInstance(PACKAGE_NAME + '.' + CLASS_NAME, "byte a; optional { byte b; }", JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF, null); + final Object instance = + compileAndMakeInstance(PACKAGE_NAME + '.' + CLASS_NAME, "byte a; optional { byte b; }", + JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF, null); callRead(instance, new byte[] {1}); assertEquals(1, getField(instance, "a", Byte.class).byteValue()); @@ -391,7 +435,9 @@ public void testReadWriteWithOptionallyIgnoredStructure() throws Exception { @Test public void testReadWriteWithOptionallyIgnoredStructureArray() throws Exception { - final Object instance = compileAndMakeInstance(PACKAGE_NAME + '.' + CLASS_NAME, "byte a; optional [_] { byte b; }", JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF, null); + final Object instance = + compileAndMakeInstance(PACKAGE_NAME + '.' + CLASS_NAME, "byte a; optional [_] { byte b; }", + JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF, null); callRead(instance, new byte[] {1}); assertEquals(1, getField(instance, "a", Byte.class).byteValue()); @@ -401,7 +447,7 @@ public void testReadWriteWithOptionallyIgnoredStructureArray() throws Exception } @Test - public void testReadWite_PNG() throws Exception { + public void testReadWrite_PNG() throws Exception { final Object instance = compileAndMakeInstance("long header;" + "// chunks\n" + "chunk [_]{" @@ -411,7 +457,8 @@ public void testReadWite_PNG() throws Exception { + " int crc;" + "}"); final byte[] pngEtalon = loadResource("picture.png"); - final String[] chunkNames = new String[] {"IHDR", "gAMA", "bKGD", "pHYs", "tIME", "tEXt", "IDAT", "IEND"}; + final String[] chunkNames = + new String[] {"IHDR", "gAMA", "bKGD", "pHYs", "tIME", "tEXt", "IDAT", "IEND"}; final int[] chunkSizes = new int[] {0x0D, 0x04, 0x06, 0x09, 0x07, 0x19, 0x0E5F, 0x00}; callRead(instance, pngEtalon.clone()); @@ -421,7 +468,9 @@ public void testReadWite_PNG() throws Exception { int i = 0; for (final Object chunk : getField(instance, "chunk", Object[].class)) { - assertPngChunk(chunkNames[i], chunkSizes[i], getField(chunk, "type", Integer.class), getField(chunk, "length", Integer.class), getField(chunk, "crc", Integer.class), getField(chunk, "data", byte[].class)); + assertPngChunk(chunkNames[i], chunkSizes[i], getField(chunk, "type", Integer.class), + getField(chunk, "length", Integer.class), getField(chunk, "crc", Integer.class), + getField(chunk, "data", byte[].class)); i++; } @@ -429,7 +478,7 @@ public void testReadWite_PNG() throws Exception { } @Test - public void testReadWite_WAV() throws Exception { + public void testReadWrite_WAV() throws Exception { final Object instance = compileAndMakeInstance("> 8) & 0xFF; int a = (value >> 16) & 0xFF;" - + " if (byteOrder == JBBPByteOrder.BIG_ENDIAN) {" - + " out.write(a); out.write(b); out.write(c);" - + " } else {" - + " out.write(c); out.write(b); out.write(a);" - + " }" - + " }" - + " public JBBPAbstractField readCustomFieldType(Object sourceStruct, JBBPBitInputStream inStream, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException{" - + " if (sourceStruct == null) throw new Error(\"Struct must not be null\");" - + " if (readWholeStream || arraySize>=0) {" - + " if (readWholeStream) {" - + " if (extraValue!=3) throw new Error(\"must be 3\");" - + " com.igormaznitsa.jbbp.utils.DynamicIntBuffer buffer = new com.igormaznitsa.jbbp.utils.DynamicIntBuffer();" - + " while(inStream.hasAvailableData()){ buffer.write(readThree(inStream, typeParameterContainer.getByteOrder())); }" - + " return new JBBPFieldArrayInt(nullableNamedFieldInfo, buffer.toIntArray());" - + " } else {" - + " if (extraValue!=2) throw new Error(\"must be 2\");" - + " int [] arra = new int[arraySize];" - + " for (int i=0;i=0 || wholeArray) {" - + " if (wholeArray && extraValue!=3) throw new Error(\"wrong extra\");" - + " if (arraySize>=0 && extraValue!=2) throw new Error(\"wrong extra\");" - + " int [] arra = ((JBBPFieldArrayInt) fieldValue).getArray();" - + " int len = wholeArray ? arra.length : arraySize;" - + " for(int i=0;i> 8) & 0xFF; int a = (value >> 16) & 0xFF;" + + " if (byteOrder == JBBPByteOrder.BIG_ENDIAN) {" + + " out.write(a); out.write(b); out.write(c);" + + " } else {" + + " out.write(c); out.write(b); out.write(a);" + + " }" + + " }" + + + " public JBBPAbstractField readCustomFieldType(Object sourceStruct, JBBPBitInputStream inStream, JBBPFieldTypeParameterContainer typeParameterContainer, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException{" + + " if (sourceStruct == null) throw new Error(\"Struct must not be null\");" + + " if (readWholeStream || arraySize>=0) {" + + " if (readWholeStream) {" + + " if (extraValue!=3) throw new Error(\"must be 3\");" + + + " com.igormaznitsa.jbbp.utils.DynamicIntBuffer buffer = new com.igormaznitsa.jbbp.utils.DynamicIntBuffer();" + + + " while(inStream.hasAvailableData()){ buffer.write(readThree(inStream, typeParameterContainer.getByteOrder())); }" + + + " return new JBBPFieldArrayInt(nullableNamedFieldInfo, buffer.toIntArray());" + + " } else {" + + " if (extraValue!=2) throw new Error(\"must be 2\");" + + " int [] arra = new int[arraySize];" + + + " for (int i=0;i=0 || wholeArray) {" + + " if (wholeArray && extraValue!=3) throw new Error(\"wrong extra\");" + + " if (arraySize>=0 && extraValue!=2) throw new Error(\"wrong extra\");" + + " int [] arra = ((JBBPFieldArrayInt) fieldValue).getArray();" + + " int len = wholeArray ? arra.length : arraySize;" + + + " for(int i=0;i> 8) & 0xFF; int a = (value >> 16) & 0xFF;" - + " if (byteOrder == JBBPByteOrder.BIG_ENDIAN) {" - + " out.write(a); out.write(b); out.write(c);" - + " } else {" - + " out.write(c); out.write(b); out.write(a);" - + " }" - + " }" - + "public JBBPAbstractField readVarField(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException{" - + " if (extraValue!=12) throw new Error(\"wrong extra\");" - + " return new JBBPFieldInt(nullableNamedFieldInfo, readThree(inStream, byteOrder));" - + "}" - + "public JBBPAbstractArrayField readVarArray(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException {" - + " if (sourceStruct == null) throw new Error(\"Struct must not be null\");" - + " if (extraValue!=4) throw new Error(\"wrong extra\");" - + " if (readWholeStream) {" - + " com.igormaznitsa.jbbp.utils.DynamicIntBuffer buffer = new com.igormaznitsa.jbbp.utils.DynamicIntBuffer();" - + " while(inStream.hasAvailableData()){ buffer.write(readThree(inStream, byteOrder)); }" - + " return new JBBPFieldArrayInt(nullableNamedFieldInfo, buffer.toIntArray());" - + " } else {" - + " int [] arra = new int[arraySize];" - + " for (int i=0;i array, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, int arraySizeToWrite) throws IOException{" - + " if (sourceStruct == null) throw new Error(\"Struct must not be null\");" - + " if (extraValue!=4) throw new Error(\"wrong extra\");" - + " int [] arra = ((JBBPFieldArrayInt) array).getArray();" - + " int len = arraySizeToWrite < 0 ? arra.length : arraySizeToWrite;" - + " for(int i=0;i> 8) & 0xFF; int a = (value >> 16) & 0xFF;" + + " if (byteOrder == JBBPByteOrder.BIG_ENDIAN) {" + + " out.write(a); out.write(b); out.write(c);" + + " } else {" + + " out.write(c); out.write(b); out.write(a);" + + " }" + + " }" + + + "public JBBPAbstractField readVarField(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue) throws IOException{" + + " if (extraValue!=12) throw new Error(\"wrong extra\");" + + + " return new JBBPFieldInt(nullableNamedFieldInfo, readThree(inStream, byteOrder));" + + "}" + + + "public JBBPAbstractArrayField readVarArray(Object sourceStruct, JBBPBitInputStream inStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, boolean readWholeStream, int arraySize) throws IOException {" + + " if (sourceStruct == null) throw new Error(\"Struct must not be null\");" + + " if (extraValue!=4) throw new Error(\"wrong extra\");" + + " if (readWholeStream) {" + + + " com.igormaznitsa.jbbp.utils.DynamicIntBuffer buffer = new com.igormaznitsa.jbbp.utils.DynamicIntBuffer();" + + + " while(inStream.hasAvailableData()){ buffer.write(readThree(inStream, byteOrder)); }" + + + " return new JBBPFieldArrayInt(nullableNamedFieldInfo, buffer.toIntArray());" + + " } else {" + + " int [] arra = new int[arraySize];" + + + " for (int i=0;i array, JBBPBitOutputStream outStream, JBBPByteOrder byteOrder, JBBPNamedFieldInfo nullableNamedFieldInfo, int extraValue, int arraySizeToWrite) throws IOException{" + + " if (sourceStruct == null) throw new Error(\"Struct must not be null\");" + + " if (extraValue!=4) throw new Error(\"wrong extra\");" + + " int [] arra = ((JBBPFieldArrayInt) array).getArray();" + + " int len = arraySizeToWrite < 0 ? arra.length : arraySizeToWrite;" + + " for(int i=0;i callRead(instance, etalon.clone())); @@ -879,7 +977,8 @@ public void testRead_ExpressionResult_NegativeExpression_NegativeResultNotAllowe @Test public void testRead_ExpressionResult_NegativeExpression_NegativeResultAsZero() throws Exception { - final Object instance = compileAndMakeInstance("byte len; byte [len-9] arr;", JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO); + final Object instance = compileAndMakeInstance("byte len; byte [len-9] arr;", + JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO); final byte[] etalon = new byte[] {8, 1, 2, 3, 4}; callRead(instance, etalon.clone()); assertEquals(8, getField(instance, "len", Byte.class).byteValue()); @@ -928,11 +1027,16 @@ public void testReadWrite_NetPacket() throws Exception { final byte[] netPacketEtalon = loadResource("tcppacket.bin"); - final JBBPBitInputStream inStream = new JBBPBitInputStream(new ByteArrayInputStream(netPacketEtalon)); + final JBBPBitInputStream inStream = + new JBBPBitInputStream(new ByteArrayInputStream(netPacketEtalon)); callRead(ethernetHeader, inStream); - assertArrayEquals(new byte[] {(byte) 0x60, (byte) 0x67, (byte) 0x20, (byte) 0xE1, (byte) 0xF9, (byte) 0xF8}, getField(ethernetHeader, "macdestination", byte[].class), "Destination MAC"); - assertArrayEquals(new byte[] {(byte) 0x00, (byte) 0x26, (byte) 0x44, (byte) 0x74, (byte) 0xFE, (byte) 0x66}, getField(ethernetHeader, "macsource", byte[].class), "Source MAC"); + assertArrayEquals( + new byte[] {(byte) 0x60, (byte) 0x67, (byte) 0x20, (byte) 0xE1, (byte) 0xF9, (byte) 0xF8}, + getField(ethernetHeader, "macdestination", byte[].class), "Destination MAC"); + assertArrayEquals( + new byte[] {(byte) 0x00, (byte) 0x26, (byte) 0x44, (byte) 0x74, (byte) 0xFE, (byte) 0x66}, + getField(ethernetHeader, "macsource", byte[].class), "Source MAC"); final int etherTypeOrLength = getField(ethernetHeader, "ethertypeorlength", Character.class); assertEquals(0x800, etherTypeOrLength, "Ethernet type or length"); @@ -941,26 +1045,36 @@ public void testReadWrite_NetPacket() throws Exception { assertEquals(4, getField(ipHeader, "version", Byte.class).intValue(), "IP Version"); - final int internetHeaderLength = getField(ipHeader, "internetheaderlength", Byte.class).intValue(); + final int internetHeaderLength = + getField(ipHeader, "internetheaderlength", Byte.class).intValue(); assertEquals(5, internetHeaderLength, "Length of the IP header (in 4 byte items)"); - assertEquals(0, getField(ipHeader, "dscp", Byte.class).intValue(), "Differentiated Services Code Point"); - assertEquals(0, getField(ipHeader, "ecn", Byte.class).intValue(), "Explicit Congestion Notification"); + assertEquals(0, getField(ipHeader, "dscp", Byte.class).intValue(), + "Differentiated Services Code Point"); + assertEquals(0, getField(ipHeader, "ecn", Byte.class).intValue(), + "Explicit Congestion Notification"); final int ipTotalPacketLength = getField(ipHeader, "totalpacketlength", Character.class); - assertEquals(159, ipTotalPacketLength, "Entire IP packet size, including header and data, in bytes"); - assertEquals(30810, getField(ipHeader, "identification", Character.class).charValue(), "Identification"); + assertEquals(159, ipTotalPacketLength, + "Entire IP packet size, including header and data, in bytes"); + assertEquals(30810, getField(ipHeader, "identification", Character.class).charValue(), + "Identification"); - final int ipFlagsAndFragmentOffset = getField(ipHeader, "ipflagsandfragmentoffset", Character.class); + final int ipFlagsAndFragmentOffset = + getField(ipHeader, "ipflagsandfragmentoffset", Character.class); assertEquals(0x2, ipFlagsAndFragmentOffset >>> 13, "Extracted IP flags"); assertEquals(0x00, ipFlagsAndFragmentOffset & 0x1FFF, "Extracted Fragment offset"); assertEquals(0x39, getField(ipHeader, "ttl", Character.class).charValue(), "Time To Live"); - assertEquals(0x06, getField(ipHeader, "protocol", Character.class).charValue(), "Protocol (RFC-790)"); - assertEquals(0x7DB6, getField(ipHeader, "headerchecksum", Character.class).charValue(), "IPv4 Header Checksum"); - assertEquals(0xD5C7B393, getField(ipHeader, "sourceaddress", Integer.class).intValue(), "Source IP address"); - assertEquals(0xC0A80145, getField(ipHeader, "destinationaddress", Integer.class).intValue(), "Destination IP address"); + assertEquals(0x06, getField(ipHeader, "protocol", Character.class).charValue(), + "Protocol (RFC-790)"); + assertEquals(0x7DB6, getField(ipHeader, "headerchecksum", Character.class).charValue(), + "IPv4 Header Checksum"); + assertEquals(0xD5C7B393, getField(ipHeader, "sourceaddress", Integer.class).intValue(), + "Source IP address"); + assertEquals(0xC0A80145, getField(ipHeader, "destinationaddress", Integer.class).intValue(), + "Destination IP address"); assertEquals(0, getField(ipHeader, "options", byte[].class).length); @@ -970,7 +1084,8 @@ public void testReadWrite_NetPacket() throws Exception { assertEquals(40018, getField(tcpHeader, "sourceport", Character.class).charValue()); assertEquals(56344, getField(tcpHeader, "destinationport", Character.class).charValue()); assertEquals(0xE0084171, getField(tcpHeader, "sequencenumber", Integer.class).intValue()); - assertEquals(0xAB616F71, getField(tcpHeader, "acknowledgementnumber", Integer.class).intValue()); + assertEquals(0xAB616F71, + getField(tcpHeader, "acknowledgementnumber", Integer.class).intValue()); assertEquals(0, getField(tcpHeader, "fin", Byte.class).intValue()); assertEquals(0, getField(tcpHeader, "syn", Byte.class).intValue()); @@ -991,7 +1106,8 @@ public void testReadWrite_NetPacket() throws Exception { assertEquals(0, getField(tcpHeader, "option", byte[].class).length); - final int payloadDataLength = ipTotalPacketLength - (internetHeaderLength * 4) - (int) inStream.getCounter(); + final int payloadDataLength = + ipTotalPacketLength - (internetHeaderLength * 4) - (int) inStream.getCounter(); final byte[] data = inStream.readByteArray(payloadDataLength); assertEquals(119, data.length); @@ -1016,4 +1132,29 @@ public interface ByteTestInterface { byte getA(); } + public static class TestSuperclass { + + public long uintf; + public long[] uintarr; + public String str; + public String[] strarr; + public float flt; + public float[] fltarr; + public double dbl; + public double[] dblarr; + public char len; + public Ins[] ins; + + public class Ins { + public byte[] a; + public byte b; + public byte c; + public InsIns insins; + + public class InsIns { + public byte a; + } + } + } + } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/ParserToJBBPToJavaClassConverterJBBPFlagsTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/ParserToJBBPToJavaClassConverterJBBPFlagsTest.java index de9d7c85..fe27b911 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/ParserToJBBPToJavaClassConverterJBBPFlagsTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/ParserToJBBPToJavaClassConverterJBBPFlagsTest.java @@ -16,16 +16,16 @@ package com.igormaznitsa.jbbp.compiler.conversion; -import com.igormaznitsa.jbbp.JBBPParser; -import com.igormaznitsa.jbbp.testaux.AbstractJBBPToJavaConverterTest; -import org.junit.jupiter.api.Test; - -import java.io.EOFException; - import static com.igormaznitsa.jbbp.TestUtils.getField; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; + +import com.igormaznitsa.jbbp.JBBPParser; +import com.igormaznitsa.jbbp.testaux.AbstractJBBPToJavaConverterTest; +import java.io.EOFException; +import org.junit.jupiter.api.Test; + /** * Test parser flags for converted sources. */ @@ -41,7 +41,8 @@ public void testFlag_SkipRemainingFieldsIfEOF() throws Exception { } catch (EOFException ex) { } - instance = compileAndMakeInstance("byte a; byte b;", JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF); + instance = + compileAndMakeInstance("byte a; byte b;", JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF); try { callRead(instance, new byte[] {11}); assertEquals(11, getField(instance, "a", Byte.class).intValue()); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/RandomAutoTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/RandomAutoTest.java index a7d5f3fa..e0eb5a73 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/RandomAutoTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/RandomAutoTest.java @@ -1,63 +1,21 @@ package com.igormaznitsa.jbbp.compiler.conversion; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.igormaznitsa.jbbp.io.JBBPBitNumber; import com.igormaznitsa.jbbp.io.JBBPByteOrder; import com.igormaznitsa.jbbp.testaux.AbstractJBBPToJavaConverterTest; import com.igormaznitsa.jbbp.utils.JBBPDslBuilder; -import org.junit.jupiter.api.Test; - import java.util.ArrayList; import java.util.List; import java.util.Random; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class RandomAutoTest extends AbstractJBBPToJavaConverterTest { private final Random RND = new Random(12345); - private static class StructLen { - final int arrayLength; - - int bitLength = 0; - - StructLen() { - this(1); - } - - StructLen(final int arrayLength) { - this.arrayLength = arrayLength; - } - - void add(final int bitLength) { - this.bitLength += bitLength; - } - - int make() { - return this.arrayLength * bitLength; - } - - } - - static class Result { - final String script; - final int bitLength; - final int fieldsNumber; - final int structNumber; - final int booleanDataItemCounter; - final long typeFlags; - - Result(final String script, final int bitLength, final int fieldsNumber, final int structNumber, final int booleanDtaItemCounter, final long typeFlags) { - this.script = script; - this.bitLength = bitLength; - this.fieldsNumber = fieldsNumber; - this.structNumber = structNumber; - this.booleanDataItemCounter = booleanDtaItemCounter; - this.typeFlags = typeFlags; - } - } - int makeArrayLengthNumber() { return RND.nextInt(16) + 1; } @@ -93,12 +51,48 @@ String makeRndName() { String genRandomString(final int length) { final StringBuilder builder = new StringBuilder(length); - for(int i=0;i 10000000); + + generatedFields |= result.typeFlags; + + System.out.printf("Test %d, data bit length = %d, fields = %d, structs = %d%n", testIndex, + result.bitLength, result.fieldsNumber, result.structNumber); + + final byte[] testData = makeRandomDataArray(result.bitLength); + final Object clazzInstance = compileAndMakeInstance(result.script); + callRead(clazzInstance, testData); + assertEquals(testData.length, callWrite(clazzInstance).length, result.script); + + testIndex++; + } + + assertEquals(0x1FFFFFFFL, generatedFields, "All field types must be presented"); + } + + private byte[] makeRandomDataArray(final int bitLength) { + final int bytelen = (bitLength / 8) + ((bitLength & 7) != 0 ? 1 : 0); + assertTrue(bytelen > 0, "Bit length : " + bitLength); + final byte[] result = new byte[bytelen]; + RND.nextBytes(result); + return result; + } + Result generate(final int items, final boolean generateNames) { final JBBPDslBuilder builder = JBBPDslBuilder.Begin(); @@ -128,7 +122,7 @@ Result generate(final int items, final boolean generateNames) { final StructLen len = counterStack.remove(0); counterStack.get(0).add(len.make()); } else { - final int rndType = RND.nextInt(27); + final int rndType = RND.nextInt(29); typeFlags |= (1 << rndType); switch (rndType) { case 0: { // STRUCT @@ -179,7 +173,7 @@ Result generate(final int items, final boolean generateNames) { builder.Bool(generateNames ? makeRndName() : null); counterStack.get(0).add(8); fieldsTotal++; - booleanDataItems ++; + booleanDataItems++; } break; case 6: { // BOOL_ARRAY @@ -285,20 +279,33 @@ Result generate(final int items, final boolean generateNames) { fieldsTotal++; } break; - case 22: { // DOUBLE + case 22: { // UINT + builder.UInt(generateNames ? makeRndName() : null); + counterStack.get(0).add(32); + fieldsTotal++; + } + break; + case 23: { // UINT_ARRAY + final int arrayLen = makeArrayLengthNumber(); + builder.UIntArray(generateNames ? makeRndName() : null, String.valueOf(arrayLen)); + counterStack.get(0).add(arrayLen * 32); + fieldsTotal++; + } + break; + case 24: { // DOUBLE builder.Double(generateNames ? makeRndName() : null); counterStack.get(0).add(64); fieldsTotal++; } break; - case 23: { // DOUBLE_ARRAY + case 25: { // DOUBLE_ARRAY final int arrayLen = makeArrayLengthNumber(); builder.DoubleArray(generateNames ? makeRndName() : null, String.valueOf(arrayLen)); counterStack.get(0).add(arrayLen * 64); fieldsTotal++; } break; - case 24: { // STRUCT END + case 26: { // STRUCT END if (activeStructCounter > 0) { i--; activeStructCounter--; @@ -308,11 +315,11 @@ Result generate(final int items, final boolean generateNames) { } } break; - case 25: { // COMMENT + case 27: { // COMMENT builder.Comment(genRandomString(this.RND.nextInt(32))); } break; - case 26: { // COMMENT NEW LINE + case 28: { // COMMENT NEW LINE builder.NewLineComment(genRandomString(this.RND.nextInt(32))); } break; @@ -327,42 +334,50 @@ Result generate(final int items, final boolean generateNames) { counterStack.get(0).add(len.make()); } - return new Result(builder.End(), counterStack.get(0).make(), fieldsTotal, structsTotal, booleanDataItems, typeFlags); + return new Result(builder.End(), counterStack.get(0).make(), fieldsTotal, structsTotal, + booleanDataItems, typeFlags); } - private byte[] makeRandomDataArray(final int bitLength) { - final int bytelen = (bitLength / 8) + ((bitLength & 7) != 0 ? 1 : 0); - assertTrue(bytelen > 0, "Bit length : " + bitLength); - final byte[] result = new byte[bytelen]; - RND.nextBytes(result); - return result; - } + private static class StructLen { + final int arrayLength; - @Test - public void testCompileParseAndWriteArray() throws Exception { - int testIndex = 1; + int bitLength = 0; - long generatedFields = 0L; + StructLen() { + this(1); + } - for (int i = 5; i < 500; i += 3) { - Result result; - do { - result = generate(i, true); - } while (result.bitLength > 10000000); + StructLen(final int arrayLength) { + this.arrayLength = arrayLength; + } - generatedFields |= result.typeFlags; + void add(final int bitLength) { + this.bitLength += bitLength; + } - System.out.println(String.format("Test %d, data bit length = %d, fields = %d, sructs = %d", testIndex, result.bitLength, result.fieldsNumber, result.structNumber)); + int make() { + return this.arrayLength * bitLength; + } - final byte[] testData = makeRandomDataArray(result.bitLength); - final Object clazzInstance = compileAndMakeInstance(result.script); - callRead(clazzInstance, testData); - assertEquals(testData.length, callWrite(clazzInstance).length, result.script); + } - testIndex++; - } + static class Result { + final String script; + final int bitLength; + final int fieldsNumber; + final int structNumber; + final int booleanDataItemCounter; + final long typeFlags; - assertEquals(0x7FFFFFFL, generatedFields, "All field types must be presented"); + Result(final String script, final int bitLength, final int fieldsNumber, final int structNumber, + final int booleanDtaItemCounter, final long typeFlags) { + this.script = script; + this.bitLength = bitLength; + this.fieldsNumber = fieldsNumber; + this.structNumber = structNumber; + this.booleanDataItemCounter = booleanDtaItemCounter; + this.typeFlags = typeFlags; + } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPFieldTypeParameterContainerTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPFieldTypeParameterContainerTest.java index 0c52dcb4..2fecb063 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPFieldTypeParameterContainerTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/tokenizer/JBBPFieldTypeParameterContainerTest.java @@ -16,19 +16,21 @@ package com.igormaznitsa.jbbp.compiler.tokenizer; -import com.igormaznitsa.jbbp.io.JBBPByteOrder; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; + +import com.igormaznitsa.jbbp.io.JBBPByteOrder; +import org.junit.jupiter.api.Test; + public class JBBPFieldTypeParameterContainerTest { @Test public void testConstructorAndGetters() { final String name = "name"; final String extra = "extra"; - final JBBPFieldTypeParameterContainer params = new JBBPFieldTypeParameterContainer(JBBPByteOrder.BIG_ENDIAN, name, extra); + final JBBPFieldTypeParameterContainer params = + new JBBPFieldTypeParameterContainer(JBBPByteOrder.BIG_ENDIAN, name, extra); assertSame(name, params.getTypeName()); assertSame(extra, params.getExtraData()); assertEquals(JBBPByteOrder.BIG_ENDIAN, params.getByteOrder()); @@ -36,10 +38,17 @@ public void testConstructorAndGetters() { @Test public void testToString() { - assertEquals("int hello", new JBBPFieldTypeParameterContainer(JBBPByteOrder.BIG_ENDIAN, "int hello", null).toString()); - assertEquals("[<- 123] hello;", ex.getErrorPart()); } } @@ -72,6 +79,7 @@ public void testStructureEndAndErrorForArrayFieldWithoutType() { fail("Must throw Tokenizer exception"); } catch (JBBPTokenizerException ex) { assertEquals(2, ex.getPosition()); + assertEquals("} ->[<- 123] hello;", ex.getErrorPart()); } } @@ -128,6 +136,7 @@ public void testSingleLine_ErrorForUnsupportedText() { fail("Must throw parser exception"); } catch (JBBPTokenizerException ex) { assertEquals(0, ex.getPosition()); + assertEquals("-> <- some", ex.getErrorPart()); } } @@ -222,6 +231,7 @@ public void testError_ForWrongByteOrderFormatChar() { fail("Must throw parser exception for wrong symbol of byte order"); } catch (JBBPTokenizerException ex) { assertEquals(3, ex.getPosition()); + assertEquals("->!<- int hello;", ex.getErrorPart()); } } @@ -240,6 +250,7 @@ public void testStructure_Named_Start_ErrorForDisabledCharAtName() { fail("Must throw parser exception for disabled dot char at name"); } catch (JBBPTokenizerException ex) { assertEquals(3, ex.getPosition()); + assertEquals("->s<- truct.a {", ex.getErrorPart()); } } @@ -253,6 +264,7 @@ public void testRegularField_ErrorForDisabledCharAtName() { fail("Must throw parser exception for disabled dot char at name"); } catch (JBBPTokenizerException ex) { assertEquals(3, ex.getPosition()); + assertEquals("->i<- nt.a;", ex.getErrorPart()); } } @@ -266,6 +278,7 @@ public void testStructure_Named_Start_ErrorForDollarAsTheFirstChar() { fail("Must throw parser exception for disabled dot char at name"); } catch (JBBPTokenizerException ex) { assertEquals(3, ex.getPosition()); + assertEquals("->$<- struct {", ex.getErrorPart()); } } @@ -279,6 +292,7 @@ public void testRegularField_Name_ErrorForDollarAsTheFirstChar() { fail("Must throw parser exception for disabled dot char at name"); } catch (JBBPTokenizerException ex) { assertEquals(3, ex.getPosition()); + assertEquals("->$<- int;", ex.getErrorPart()); } } @@ -361,6 +375,7 @@ public void testStructure_Array_ErrorForWrongNameSizeOrder() { fail("Must throw parser exception"); } catch (JBBPTokenizerException ex) { assertEquals(2, ex.getPosition()); + assertEquals("->[<- 333] test", ex.getErrorPart()); } } @@ -398,6 +413,7 @@ public void testStructure_Array_ErrorForTypeDefinition() { fail("Must throw parser exception for wrong struct end definition"); } catch (JBBPTokenizerException ex) { assertEquals(0, ex.getPosition()); + assertEquals("-> <- int", ex.getErrorPart()); } } @@ -412,6 +428,7 @@ public void testStructure_ErrorForTypeDefinition() { fail("Must throw parser exception for wrong struct end definition"); } catch (JBBPTokenizerException ex) { assertEquals(4, ex.getPosition()); + assertEquals("->i<- nt struct{", ex.getErrorPart()); } } @@ -429,6 +446,7 @@ public void testErrorForNonRecognizedStringInMiddleOfText() { fail("Must throw exception"); } catch (JBBPTokenizerException ex) { assertEquals(8, ex.getPosition()); + assertEquals("test ->\\u000a<- wrong", ex.getErrorPart()); } } @@ -490,7 +508,9 @@ public void testParseScript_WithoutStructures() { } } - private void assertParsedItem(final JBBPToken item, final JBBPTokenType itemType, final String fieldType, final String length, final String fieldName) { + private void assertParsedItem(final JBBPToken item, final JBBPTokenType itemType, + final String fieldType, final String length, + final String fieldName) { assertNotNull(item); assertEquals(itemType, item.getType()); if (fieldType == null) { @@ -521,12 +541,30 @@ public void testParse_Field_Nonamed_Align() { @Test public void testParse_StructureArrayStartWithComplexExpressionAsSize() { - final JBBPTokenizer parser = new JBBPTokenizer("ColorMap [ (Header.ColorMapType & 1) * Header.CMapLength] {"); + final JBBPTokenizer parser = + new JBBPTokenizer("ColorMap [ (Header.ColorMapType & 1) * Header.CMapLength] {"); final Iterator iterator = parser.iterator(); - assertParsedItem(iterator.next(), JBBPTokenType.STRUCT_START, null, "(Header.ColorMapType & 1) * Header.CMapLength", "ColorMap"); + assertParsedItem(iterator.next(), JBBPTokenType.STRUCT_START, null, + "(Header.ColorMapType & 1) * Header.CMapLength", "ColorMap"); assertFalse(iterator.hasNext()); } + @Test + public void testParse_wrongEndOfStruct() { + try { + JBBPParser.prepare( + "byte[5] blob5; " + + "accountFlags {" + + " byte[32] address; " + + "}; " + + "byte[7] blob7;" + ); + } catch (JBBPTokenizerException ex) { + assertEquals(49, ex.getPosition()); + assertEquals("address; } ->;<- byte[7]", ex.getErrorPart()); + } + } + @Test public void testParse_VarFieldArrayWithNegativeExtra() { final JBBPTokenizer parser = new JBBPTokenizer("var:-123 [size] name;"); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPExpressionEvaluatorTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPExpressionEvaluatorTest.java index eb659e8d..da14e6d4 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPExpressionEvaluatorTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPExpressionEvaluatorTest.java @@ -16,7 +16,12 @@ package com.igormaznitsa.jbbp.compiler.varlen; -import com.igormaznitsa.jbbp.JBBPExternalValueProvider; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import com.igormaznitsa.jbbp.JBBPNamedNumericFieldMap; import com.igormaznitsa.jbbp.compiler.JBBPCompiledBlock; import com.igormaznitsa.jbbp.compiler.JBBPCompiler; @@ -26,41 +31,42 @@ import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.model.JBBPFieldInt; import com.igormaznitsa.jbbp.utils.JBBPUtils; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPExpressionEvaluatorTest { @Test public void testExpression_Error_ConstantsWithoutOperators() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator(" 1 334", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator(" 1 334", null, null)); } @Test public void testExpression_Error_OnlyBrackets() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator(" ( ( ( ( ) )) ) ", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator(" ( ( ( ( ) )) ) ", null, null)); } @Test public void testExpression_Error_NonClosedBracket() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator("(34+45 ", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("(34+45 ", null, null)); } @Test public void testExpression_Error_NonOpenedBracket() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator("34+45) ", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("34+45) ", null, null)); } @Test public void testExpression_Error_Spaces() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator(" ", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator(" ", null, null)); } @Test @@ -70,72 +76,86 @@ public void testExpression_Error_Empty() { @Test public void testExpression_Error_OnlyUnaryPlus() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator("+", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("+", null, null)); } @Test public void testExpression_Error_OnlyUnaryMinus() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator("-", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("-", null, null)); } @Test public void testExpression_Error_OnlyNot() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator("~", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("~", null, null)); } @Test public void testExpression_Error_WrongFirstUnaryOperator() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator("%345", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("%345", null, null)); } @Test public void testExpression_Error_WrongUnaryOperator() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator("222%%345", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("222%%345", null, null)); } @Test public void testExpression_Error_OnlyNonUnaryOperator() { - assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator("*", null, null)); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("*", null, null)); } @Test public void testExpression_Error_MulWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("123*", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("123*", null, null).eval(null, 0, null, null)); } @Test public void testExpression_Error_SubWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("123-", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("123-", null, null).eval(null, 0, null, null)); } @Test public void testExpression_Error_AddWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("123+", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("123+", null, null).eval(null, 0, null, null)); } @Test public void testExpression_Error_ModWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("123%", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("123%", null, null).eval(null, 0, null, null)); } @Test public void testExpression_Error_DivWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("123/", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("123/", null, null).eval(null, 0, null, null)); } @Test public void testExpression_Error_AndWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("123&", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("123&", null, null).eval(null, 0, null, null)); } @Test public void testExpression_Error_OrWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("123|", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("123|", null, null).eval(null, 0, null, null)); } @Test public void testExpression_Error_XorWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("123^", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("123^", null, null).eval(null, 0, null, null)); } @Test @@ -163,7 +183,9 @@ public void testExpression_Variable() { JBBPExpressionEvaluator expr = new JBBPExpressionEvaluator("hello", list, compiled); final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); map.putField(new JBBPFieldInt(info, 1234)); - assertEquals(1234, expr.eval(null, 0, JBBPCompiledBlock.prepare().setCompiledData(compiled).setNamedFieldData(list).setSource("no source").build(), map)); + assertEquals(1234, expr.eval(null, 0, + JBBPCompiledBlock.prepare().setCompiledData(compiled).setNamedFieldData(list) + .setSource("no source").build(), map)); } @Test @@ -172,17 +194,24 @@ public void testExpression_ExpressionWithVariable() { final byte[] compiled = new byte[] {JBBPCompiler.CODE_INT | JBBPCompiler.FLAG_NAMED}; final List list = Collections.singletonList(info); - JBBPExpressionEvaluator expr = new JBBPExpressionEvaluator("2*hello*6/4+3*2-11%3&hello-~hello", list, compiled); + JBBPExpressionEvaluator expr = + new JBBPExpressionEvaluator("2*hello*6/4+3*2-11%3&hello-~hello", list, compiled); final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); map.putField(new JBBPFieldInt(info, 8)); - assertEquals(2 * 8 * 6 / 4 + 3 * 2 - 11 % 3 & 8 - ~8, expr.eval(null, 0, JBBPCompiledBlock.prepare().setCompiledData(compiled).setNamedFieldData(list).setSource("no source").build(), map)); + assertEquals(2 * 8 * 6 / 4 + 3 * 2 - 11 % 3 & 8 - ~8, expr.eval(null, 0, + JBBPCompiledBlock.prepare().setCompiledData(compiled).setNamedFieldData(list) + .setSource("no source").build(), map)); } @Test - public void testExpression_MustNotThrowStackOverfow() throws Exception { - JBBPExpressionEvaluator expr = new JBBPExpressionEvaluator("1+(2+(3+(4+(5+(6+(7+(8+(9+(10+(11+(12+(13+(14+(15+(16+(17+(18+(19+(20*2)))))))))))))))))))", null, null); + public void testExpression_MustNotThrowStackOverflow() throws Exception { + JBBPExpressionEvaluator expr = new JBBPExpressionEvaluator( + "1+(2+(3+(4+(5+(6+(7+(8+(9+(10+(11+(12+(13+(14+(15+(16+(17+(18+(19+(20*2)))))))))))))))))))", + null, null); assertEquals(21, expr.getMaxStackDepth()); - assertEquals(1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + (10 + (11 + (12 + (13 + (14 + (15 + (16 + (17 + (18 + (19 + (20 * 2))))))))))))))))))), expr.eval(null, 0, null, null)); + assertEquals(1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + + (9 + (10 + (11 + (12 + (13 + (14 + (15 + (16 + (17 + (18 + (19 + (20 * 2))))))))))))))))))), + expr.eval(null, 0, null, null)); } @Test @@ -271,7 +300,9 @@ public void testExpression_SingleCharNamedVar_Mul() { assertEquals(2, expr.getMaxStackDepth()); final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); map.putField(new JBBPFieldInt(varA, 123)); - assertEquals(123 * 2, expr.eval(null, 0, JBBPCompiledBlock.prepare().setCompiledData(compiled).setNamedFieldData(list).setSource("no source").build(), map)); + assertEquals(123 * 2, expr.eval(null, 0, + JBBPCompiledBlock.prepare().setCompiledData(compiled).setNamedFieldData(list) + .setSource("no source").build(), map)); } @Test @@ -402,9 +433,11 @@ public void testExpression_TestComplexUnaryInConstantExpression() { @Test public void testExpression_ComplexLogicalWithConstants() { - JBBPExpressionEvaluator expr = new JBBPExpressionEvaluator("~23*-1234&~123/(34+89)|3232%56^~2234", null, null); + JBBPExpressionEvaluator expr = + new JBBPExpressionEvaluator("~23*-1234&~123/(34+89)|3232%56^~2234", null, null); assertEquals(4, expr.getMaxStackDepth()); - assertEquals((~23 * -1234 & ~123 / (34 + 89)) | (3232 % 56 ^ ~2234), expr.eval(null, 0, null, null)); + assertEquals((~23 * -1234 & ~123 / (34 + 89)) | (3232 % 56 ^ ~2234), + expr.eval(null, 0, null, null)); } @Test @@ -416,7 +449,8 @@ public void testExpression_LeftShift() { @Test public void testExpression_LeftShift_ErrorWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("1234<<", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("1234<<", null, null).eval(null, 0, null, null)); } @Test @@ -428,7 +462,8 @@ public void testExpression_RightShift() { @Test public void testExpression_RightShift_ErrorWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("1234 >>", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("1234 >>", null, null).eval(null, 0, null, null)); } @Test @@ -447,40 +482,47 @@ public void testExpression_RightSignShiftWithInversion() { @Test public void testExpression_RightSignShift_ErrorWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, () -> new JBBPExpressionEvaluator("1234 >>>", null, null).eval(null, 0, null, null)); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("1234 >>>", null, null).eval(null, 0, null, null)); } @Test public void testExpression_ReverseByte() { - JBBPExpressionEvaluator expr = new JBBPExpressionEvaluator("((($v*2050&139536)|($v*32800&558144))*65793>>16)&255", null, null); + JBBPExpressionEvaluator expr = + new JBBPExpressionEvaluator("((($v*2050&139536)|($v*32800&558144))*65793>>16)&255", null, + null); assertEquals(3, expr.getMaxStackDepth()); - assertEquals(JBBPUtils.reverseBitsInByte((byte) 123) & 0xFF, expr.eval(null, 0, null, new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { - if ("v".equals(fieldName)) { - return 123; - } else { - fail("Unexpected field [" + fieldName + ']'); - return 0; - } - }))); + assertEquals(JBBPUtils.reverseBitsInByte((byte) 123) & 0xFF, expr.eval(null, 0, null, + new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { + if ("v".equals(fieldName)) { + return 123; + } else { + fail("Unexpected field [" + fieldName + ']'); + return 0; + } + }))); } @Test public void testExpression_CheckExternalField() { final int value = 1234; - final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { - if (fieldName.equals("value")) { - return value; - } - assertNotNull(numericFieldMap); - assertNotNull(compiledBlock); - fail("Unexpected request for value [" + fieldName + ']'); - return -1; - }); + final JBBPNamedNumericFieldMap map = + new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { + if (fieldName.equals("value")) { + return value; + } + assertNotNull(numericFieldMap); + assertNotNull(compiledBlock); + fail("Unexpected request for value [" + fieldName + ']'); + return -1; + }); final List list = new ArrayList<>(); final byte[] compiled = new byte[] {0}; - final JBBPCompiledBlock compiledBlock = JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none").setNamedFieldData(list).build(); + final JBBPCompiledBlock compiledBlock = + JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none") + .setNamedFieldData(list).build(); JBBPExpressionEvaluator expr = new JBBPExpressionEvaluator("123*($value-45/3)", list, compiled); assertEquals(4, expr.getMaxStackDepth()); @@ -496,25 +538,30 @@ public void testExpression_NotAfterMinus() throws Exception { @Test public void testExpression_CheckExternalFieldAndStreamOffset() throws Exception { final int value = 1234; - final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { - if (fieldName.equals("value")) { - return value; - } - assertNotNull(numericFieldMap); - assertNotNull(compiledBlock); - fail("Unexpected request for value [" + fieldName + ']'); - return -1; - }); + final JBBPNamedNumericFieldMap map = + new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { + if (fieldName.equals("value")) { + return value; + } + assertNotNull(numericFieldMap); + assertNotNull(compiledBlock); + fail("Unexpected request for value [" + fieldName + ']'); + return -1; + }); final List list = new ArrayList<>(); final byte[] compiled = new byte[] {0}; - final JBBPCompiledBlock compiledBlock = JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none").setNamedFieldData(list).build(); + final JBBPCompiledBlock compiledBlock = + JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none") + .setNamedFieldData(list).build(); - JBBPExpressionEvaluator expr = new JBBPExpressionEvaluator("123*($value-45/3)*$$", list, compiled); + JBBPExpressionEvaluator expr = + new JBBPExpressionEvaluator("123*($value-45/3)*$$", list, compiled); assertEquals(4, expr.getMaxStackDepth()); - final JBBPBitInputStream inStream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5})); + final JBBPBitInputStream inStream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5})); inStream.read(); inStream.read(); inStream.read(); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPOnlyFieldEvaluatorTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPOnlyFieldEvaluatorTest.java index 7b9f0160..b9fe0bd0 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPOnlyFieldEvaluatorTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/varlen/JBBPOnlyFieldEvaluatorTest.java @@ -16,19 +16,20 @@ package com.igormaznitsa.jbbp.compiler.varlen; -import com.igormaznitsa.jbbp.JBBPExternalValueProvider; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + + import com.igormaznitsa.jbbp.JBBPNamedNumericFieldMap; import com.igormaznitsa.jbbp.compiler.JBBPCompiledBlock; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.model.JBBPFieldInt; -import org.junit.jupiter.api.Test; - import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPOnlyFieldEvaluatorTest { @@ -44,7 +45,9 @@ public void testNumericValue() { list.add(nameInfo); final byte[] compiled = new byte[] {0}; - final JBBPCompiledBlock compiledBlock = JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none").setNamedFieldData(list).build(); + final JBBPCompiledBlock compiledBlock = + JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none") + .setNamedFieldData(list).build(); JBBPOnlyFieldEvaluator expr = new JBBPOnlyFieldEvaluator(null, 0); assertEquals(value, expr.eval(null, 0, compiledBlock, map)); @@ -53,20 +56,23 @@ public void testNumericValue() { @Test public void testExternalValue() { final int value = 1234; - final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { - if (fieldName.equals("value")) { - return value; - } - assertNotNull(numericFieldMap); - assertNotNull(compiledBlock); - fail("Unexpected request for value [" + fieldName + ']'); - return -1; - }); + final JBBPNamedNumericFieldMap map = + new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { + if (fieldName.equals("value")) { + return value; + } + assertNotNull(numericFieldMap); + assertNotNull(compiledBlock); + fail("Unexpected request for value [" + fieldName + ']'); + return -1; + }); final List list = new ArrayList<>(); final byte[] compiled = new byte[] {0}; - final JBBPCompiledBlock compiledBlock = JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none").setNamedFieldData(list).build(); + final JBBPCompiledBlock compiledBlock = + JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none") + .setNamedFieldData(list).build(); JBBPOnlyFieldEvaluator expr = new JBBPOnlyFieldEvaluator("value", -1); assertEquals(value, expr.eval(null, 0, compiledBlock, map)); @@ -75,20 +81,23 @@ public void testExternalValue() { @Test public void testExternalValueNamedAsFirstCharDollar() { final int value = 1234; - final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { - if (fieldName.equals("$value")) { - return value; - } - assertNotNull(numericFieldMap); - assertNotNull(compiledBlock); - fail("Unexpected request for value [" + fieldName + ']'); - return -1; - }); + final JBBPNamedNumericFieldMap map = + new JBBPNamedNumericFieldMap((fieldName, numericFieldMap, compiledBlock) -> { + if (fieldName.equals("$value")) { + return value; + } + assertNotNull(numericFieldMap); + assertNotNull(compiledBlock); + fail("Unexpected request for value [" + fieldName + ']'); + return -1; + }); final List list = new ArrayList<>(); final byte[] compiled = new byte[] {0}; - final JBBPCompiledBlock compiledBlock = JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none").setNamedFieldData(list).build(); + final JBBPCompiledBlock compiledBlock = + JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none") + .setNamedFieldData(list).build(); JBBPOnlyFieldEvaluator expr = new JBBPOnlyFieldEvaluator("$value", -1); assertEquals(value, expr.eval(null, 0, compiledBlock, map)); @@ -99,11 +108,14 @@ public void testCounterOfStreamAsParameter() throws Exception { final List list = new ArrayList<>(); final byte[] compiled = new byte[] {0}; - final JBBPCompiledBlock compiledBlock = JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none").setNamedFieldData(list).build(); + final JBBPCompiledBlock compiledBlock = + JBBPCompiledBlock.prepare().setCompiledData(compiled).setSource("none") + .setNamedFieldData(list).build(); JBBPOnlyFieldEvaluator expr = new JBBPOnlyFieldEvaluator("$", -1); - final JBBPBitInputStream inStream = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5})); + final JBBPBitInputStream inStream = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5})); inStream.read(); inStream.read(); inStream.read(); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/exceptions/JBBPMapperExceptionTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/exceptions/JBBPMapperExceptionTest.java index d250dcb6..c9c7385a 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/exceptions/JBBPMapperExceptionTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/exceptions/JBBPMapperExceptionTest.java @@ -16,17 +16,20 @@ package com.igormaznitsa.jbbp.exceptions; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.model.JBBPAbstractField; import com.igormaznitsa.jbbp.model.JBBPFieldByte; -import org.junit.jupiter.api.Test; - import java.lang.reflect.Field; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPMapperExceptionTest { - private final JBBPAbstractField field = new JBBPFieldByte(new JBBPNamedFieldInfo("test.test", "test", 0), (byte) 1); + private final JBBPAbstractField field = + new JBBPFieldByte(new JBBPNamedFieldInfo("test.test", "test", 0), (byte) 1); private final Exception cause = new Exception(); private final String message = "Message"; @@ -37,7 +40,8 @@ public void testConstructorAndGetters() throws Exception { assertNotNull(clazzField); - final JBBPMapperException ex = new JBBPMapperException(this.message, this.field, clazz, clazzField, this.cause); + final JBBPMapperException ex = + new JBBPMapperException(this.message, this.field, clazz, clazzField, this.cause); assertSame(this.message, ex.getMessage()); assertSame(this.field, ex.getField()); assertSame(clazz, ex.getMappingClass()); @@ -49,7 +53,8 @@ public void testToString() throws Exception { final Class clazz = Integer.class; final Field clazzField = Integer.class.getDeclaredFields()[0]; assertNotNull(clazzField); - final JBBPMapperException ex = new JBBPMapperException(this.message, this.field, clazz, clazzField, this.cause); + final JBBPMapperException ex = + new JBBPMapperException(this.message, this.field, clazz, clazzField, this.cause); assertTrue(ex.toString().contains(clazzField.toString())); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/exceptions/JBBPTokenizerExceptionTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/exceptions/JBBPTokenizerExceptionTest.java new file mode 100644 index 00000000..3b6c3077 --- /dev/null +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/exceptions/JBBPTokenizerExceptionTest.java @@ -0,0 +1,43 @@ +package com.igormaznitsa.jbbp.exceptions; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +import org.junit.jupiter.api.Test; + +class JBBPTokenizerExceptionTest { + @Test + public void testNullAsArg() { + assertEquals("null (pos=0, errorPart=\"\")", + new JBBPTokenizerException(null, null, 0).toString()); + assertEquals(" (pos=0, errorPart=\"\")", new JBBPTokenizerException("", null, 0).toString()); + assertEquals("null (pos=0, errorPart=\"\")", + new JBBPTokenizerException(null, "", 0).toString()); + assertEquals("null (pos=5, errorPart=\"\")", + new JBBPTokenizerException(null, null, 5).toString()); + assertEquals(" (pos=5, errorPart=\"\")", new JBBPTokenizerException("", null, 5).toString()); + assertEquals("null (pos=5, errorPart=\"\")", + new JBBPTokenizerException(null, "", 5).toString()); + assertEquals("null (pos=-5, errorPart=\"\")", + new JBBPTokenizerException(null, null, -5).toString()); + assertEquals(" (pos=-5, errorPart=\"\")", new JBBPTokenizerException("", null, -5).toString()); + assertEquals("null (pos=-5, errorPart=\"\")", + new JBBPTokenizerException(null, "", -5).toString()); + } + + @Test + public void testWrongErrorPos() { + assertEquals("hello (pos=23, errorPart=\"\")", + new JBBPTokenizerException("hello", "world", 23).toString()); + assertEquals("hello (pos=-1, errorPart=\"\")", + new JBBPTokenizerException("hello", "world", -1).toString()); + } + + @Test + public void testCornerPositions() { + assertEquals("hello (pos=0, errorPart=\"->w<- orld\")", + new JBBPTokenizerException("hello", "world", 0).toString()); + assertEquals("hello (pos=4, errorPart=\"worl ->d<-\")", + new JBBPTokenizerException("hello", "world", 4).toString()); + } +} \ No newline at end of file diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/io/BitIOCommonTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/io/BitIOCommonTest.java index ca030c18..f7b4f477 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/io/BitIOCommonTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/io/BitIOCommonTest.java @@ -16,13 +16,12 @@ package com.igormaznitsa.jbbp.io; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.Random; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class BitIOCommonTest { @@ -49,17 +48,19 @@ public void testWriteReadString() throws Exception { outLittl.close(); final byte[] writtenBig = buffBig.toByteArray(); - final byte[] writtenLittl = buffLittl.toByteArray(); + final byte[] writtenLittle = buffLittl.toByteArray(); - final String restoredBig = new JBBPBitInputStream(new ByteArrayInputStream(writtenBig)).readString(JBBPByteOrder.BIG_ENDIAN); - final String restoredLittl = new JBBPBitInputStream(new ByteArrayInputStream(writtenLittl)).readString(JBBPByteOrder.LITTLE_ENDIAN); + final String restoredBig = new JBBPBitInputStream(new ByteArrayInputStream(writtenBig)) + .readString(JBBPByteOrder.BIG_ENDIAN); + final String restoredLittle = new JBBPBitInputStream(new ByteArrayInputStream(writtenLittle)) + .readString(JBBPByteOrder.LITTLE_ENDIAN); assertEquals(text, restoredBig, "Iteration#" + i); - assertEquals(text, restoredLittl, "Iteration#" + i); + assertEquals(text, restoredLittle, "Iteration#" + i); - buffer.append((char)('A' + rnd.nextInt(11))); - buffer.append((char)('Б' + rnd.nextInt(22))); + buffer.append((char) ('A' + rnd.nextInt(11))); + buffer.append((char) ('Б' + rnd.nextInt(22))); } } @@ -82,20 +83,21 @@ public void testWriteRead() throws Exception { final JBBPBitOutputStream out = new JBBPBitOutputStream(buff); - int writenBits = 0; + int writtenBits = 0; for (int i = 0; i < LEN; i++) { - writenBits += len[i]; + writtenBits += len[i]; out.writeBits(array[i], JBBPBitNumber.decode(len[i])); } out.close(); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(buff.toByteArray())); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(buff.toByteArray())); for (int i = 0; i < LEN; i++) { assertEquals(array[i] & 0xFF, in.readBits(JBBPBitNumber.decode(len[i])), "Index i=" + i); } - if (writenBits % 8 == 0) { + if (writtenBits % 8 == 0) { assertEquals(-1, in.read()); } else { assertEquals(0, in.read()); @@ -129,7 +131,8 @@ public void testWriteRead_MSB0() throws Exception { out.close(); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(buff.toByteArray()), JBBPBitOrder.MSB0); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(buff.toByteArray()), JBBPBitOrder.MSB0); for (int i = 0; i < LEN; i++) { assertEquals(array[i] & 0xFF, in.readBits(JBBPBitNumber.decode(len[i])), "Index i=" + i); } @@ -154,7 +157,8 @@ public void testWriteRead_NotFullByteAsLSB0AndReadAsMSB0() throws Exception { out.writeBits(0, JBBPBitNumber.BITS_1); out.flush(); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(buffer.toByteArray()), JBBPBitOrder.MSB0); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(buffer.toByteArray()), JBBPBitOrder.MSB0); assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); @@ -195,7 +199,8 @@ public void testWriteRead_LSB0() throws Exception { out.close(); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(buff.toByteArray()), JBBPBitOrder.LSB0); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(buff.toByteArray()), JBBPBitOrder.LSB0); for (int i = 0; i < LEN; i++) { assertEquals(array[i] & 0xFF, in.readBits(JBBPBitNumber.decode(len[i])), "Index i=" + i); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPBitInputStreamTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPBitInputStreamTest.java index 4ea7a7d2..e66dcb3e 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPBitInputStreamTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPBitInputStreamTest.java @@ -16,31 +16,46 @@ package com.igormaznitsa.jbbp.io; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_1; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_2; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_3; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_4; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_5; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_8; +import static com.igormaznitsa.jbbp.io.JBBPByteOrder.BIG_ENDIAN; +import static com.igormaznitsa.jbbp.utils.JBBPUtils.bin2str; +import static com.igormaznitsa.jbbp.utils.JBBPUtils.str2bin; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; - import com.igormaznitsa.jbbp.TestUtils; +import com.igormaznitsa.jbbp.exceptions.JBBPReachedArraySizeLimitException; import com.igormaznitsa.jbbp.utils.JBBPUtils; import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.IOException; import java.util.Random; +import java.util.function.Supplier; +import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; public class JBBPBitInputStreamTest { - private static final String TEST_BYTES = "01001100_01110000_11110000_01111100_00001111_11000000_01100111_00000000_10011111"; - private static final String TEST_BYTES_EXTRABIT = "0 01001100_01110000_11110000_01111100_00001111_11000000_01100111_00000000_10011111"; + private static final String TEST_BYTES = + "01001100_01110000_11110000_01111100_00001111_11000000_01100111_00000000_10011111"; + private static final String TEST_BYTES_EXTRABIT = + "0 01001100_01110000_11110000_01111100_00001111_11000000_01100111_00000000_10011111"; private static byte[] intArrayToByteArray(final int... array) { final byte[] bytearray = new byte[array.length]; for (int i = 0; i < array.length; i++) { if ((array[i] & 0xFFFFFF00) != 0) { - fail("Unconvertable byte value [" + array[i] + ']'); + fail("Non-convertible byte value [" + array[i] + ']'); } bytearray[i] = (byte) array[i]; } @@ -52,37 +67,138 @@ private static JBBPBitInputStream asInputStream(final int... array) { } private static JBBPBitInputStream asInputStreamMSB0(final int... array) { - return new JBBPBitInputStream(new ByteArrayInputStream(intArrayToByteArray(array)), JBBPBitOrder.MSB0); + return new JBBPBitInputStream(new ByteArrayInputStream(intArrayToByteArray(array)), + JBBPBitOrder.MSB0); + } + + @Test + public void testIsDetectedPartlyReadBitField() throws Exception { + final Supplier oneByteStream = + () -> new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1}), true); + final Supplier oneByteStreamNoAccumulated = + () -> new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1}), false); + + JBBPBitInputStream in = oneByteStream.get(); + assertTrue(in.isEnablePartialBitsOnEOF()); + assertFalse(in.isDetectedPartlyReadBitField()); + in.read(); + assertFalse(in.isDetectedPartlyReadBitField()); + + in = oneByteStream.get(); + assertFalse(in.isDetectedPartlyReadBitField()); + assertEquals(1, in.read(new byte[1], 0, 1)); + assertFalse(in.isDetectedPartlyReadBitField()); + + in = oneByteStream.get(); + assertFalse(in.isDetectedPartlyReadBitField()); + in.readBits(BITS_1); + assertFalse(in.isDetectedPartlyReadBitField()); + in.read(); + assertTrue(in.isDetectedPartlyReadBitField()); + + in = oneByteStream.get(); + assertFalse(in.isDetectedPartlyReadBitField()); + in.readBits(BITS_1); + assertEquals(1, in.read(new byte[1], 0, 1)); + assertTrue(in.isDetectedPartlyReadBitField()); + + in = oneByteStreamNoAccumulated.get(); + assertFalse(in.isEnablePartialBitsOnEOF()); + assertFalse(in.isDetectedPartlyReadBitField()); + in.read(); + assertFalse(in.isDetectedPartlyReadBitField()); + + in = oneByteStreamNoAccumulated.get(); + assertFalse(in.isDetectedPartlyReadBitField()); + assertEquals(1, in.read(new byte[1], 0, 1)); + assertFalse(in.isDetectedPartlyReadBitField()); + + in = oneByteStreamNoAccumulated.get(); + assertFalse(in.isDetectedPartlyReadBitField()); + in.readBits(BITS_1); + assertFalse(in.isDetectedPartlyReadBitField()); + assertEquals(0, in.read(new byte[1], 0, 1)); + assertTrue(in.isDetectedPartlyReadBitField()); + } + + @Test + public void testReadMsb0Direct() throws Exception { + byte[] data = str2bin("00000001_101_00001000_00000_01_00_1011_00000"); + + JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(data), JBBPBitOrder.MSB0_DIRECT); + assertEquals(1, in.readBits(BITS_8)); + assertEquals(5, in.readBits(BITS_3)); + assertEquals(8, in.readBits(BITS_8)); + assertEquals(0, in.readBits(BITS_5)); + assertEquals(1, in.readBits(BITS_2)); + assertEquals(0, in.readBits(BITS_2)); + assertEquals(11, in.readBits(BITS_4)); + assertEquals(0, in.readBits(BITS_5)); + assertEquals(0, in.readBits(BITS_3)); + assertEquals(-1, in.readBits(BITS_1)); + } + + @Test + public void testReadLsb0Msb0Msb0Direct() throws Exception { + final byte[] data = new byte[] {0b0000_0001}; + + JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(data)); + assertEquals(0b0001, in.readBits(BITS_4)); + assertEquals(0b0000, in.readBits(BITS_4)); + assertEquals(0b0000_0001, new JBBPBitInputStream(new ByteArrayInputStream(data)).read()); + + in = new JBBPBitInputStream(new ByteArrayInputStream(data), JBBPBitOrder.LSB0); + assertEquals(0b0001, in.readBits(BITS_4)); + assertEquals(0b0000, in.readBits(BITS_4)); + assertEquals(0b0000_0001, + new JBBPBitInputStream(new ByteArrayInputStream(data), JBBPBitOrder.LSB0).read()); + + in = new JBBPBitInputStream(new ByteArrayInputStream(data), JBBPBitOrder.MSB0); + assertEquals(0b0000, in.readBits(BITS_4)); + assertEquals(0b1000, in.readBits(BITS_4)); + assertEquals(0b1000_0000, + new JBBPBitInputStream(new ByteArrayInputStream(data), JBBPBitOrder.MSB0).read()); + + in = new JBBPBitInputStream(new ByteArrayInputStream(data), JBBPBitOrder.MSB0_DIRECT); + assertEquals(0b0000, in.readBits(BITS_4)); + assertEquals(0b0001, in.readBits(BITS_4)); + assertEquals(0b0000_0001, + new JBBPBitInputStream(new ByteArrayInputStream(data), JBBPBitOrder.MSB0_DIRECT).read()); } @Test public void testReadUnsignedShort_EOFforEmpty_BigEndian_EOFException() throws Exception { - assertThrows(EOFException.class, () -> asInputStream().readUnsignedShort(JBBPByteOrder.BIG_ENDIAN)); + assertThrows(EOFException.class, + () -> asInputStream().readUnsignedShort(BIG_ENDIAN)); } @Test public void testReadUnsignedShort_EOFforEmpty_LittleEndian_EOFException() throws Exception { - assertThrows(EOFException.class, () -> asInputStream().readUnsignedShort(JBBPByteOrder.LITTLE_ENDIAN)); + assertThrows(EOFException.class, + () -> asInputStream().readUnsignedShort(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadUnsignedShort_EOFforOneByte_BigEndian_EOFException() throws Exception { - assertThrows(EOFException.class, () -> asInputStream((byte) 1).readUnsignedShort(JBBPByteOrder.BIG_ENDIAN)); + assertThrows(EOFException.class, + () -> asInputStream((byte) 1).readUnsignedShort(BIG_ENDIAN)); } @Test public void testReadUnsignedShort_EOFforOneByte_LittleEndian_EOFException() throws Exception { - assertThrows(EOFException.class, () -> asInputStream((byte) 1).readUnsignedShort(JBBPByteOrder.LITTLE_ENDIAN)); + assertThrows(EOFException.class, + () -> asInputStream((byte) 1).readUnsignedShort(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadUnsignedShort_BigEndian() throws Exception { - assertEquals(0x1234, asInputStream(0x12, 0x34).readUnsignedShort(JBBPByteOrder.BIG_ENDIAN)); + assertEquals(0x1234, asInputStream(0x12, 0x34).readUnsignedShort(BIG_ENDIAN)); } @Test public void testReadUnsignedShort_BigEndian_MSB0() throws Exception { - assertEquals(0x482C, asInputStreamMSB0(0x12, 0x34).readUnsignedShort(JBBPByteOrder.BIG_ENDIAN)); + assertEquals(0x482C, asInputStreamMSB0(0x12, 0x34).readUnsignedShort(BIG_ENDIAN)); } @Test @@ -92,87 +208,105 @@ public void testReadUnsignedShort_LittleEndian() throws Exception { @Test public void testReadUnsignedShort_LittleEndian_MSB0() throws Exception { - assertEquals(0x2C48, asInputStreamMSB0(0x12, 0x34).readUnsignedShort(JBBPByteOrder.LITTLE_ENDIAN)); + assertEquals(0x2C48, + asInputStreamMSB0(0x12, 0x34).readUnsignedShort(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadInt_BigEndian() throws Exception { - assertEquals(0x12345678, asInputStream(0x12, 0x34, 0x56, 0x78).readInt(JBBPByteOrder.BIG_ENDIAN)); + assertEquals(0x12345678, + asInputStream(0x12, 0x34, 0x56, 0x78).readInt(BIG_ENDIAN)); } @Test public void testReadInt_BigEndian_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56).readInt(JBBPByteOrder.BIG_ENDIAN)); + assertThrows(EOFException.class, + () -> asInputStream(0x12, 0x34, 0x56).readInt(BIG_ENDIAN)); } @Test public void testReadInt_BigEndian_MSB0() throws Exception { - assertEquals(0x482C6A1E, asInputStreamMSB0(0x12, 0x34, 0x56, 0x78).readInt(JBBPByteOrder.BIG_ENDIAN)); + assertEquals(0x482C6A1E, + asInputStreamMSB0(0x12, 0x34, 0x56, 0x78).readInt(BIG_ENDIAN)); } @Test public void testReadStringArray_BigEndan_FixedSize() throws Exception { - assertArrayEquals(new String[] {null, "", "ABC"}, asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(3, JBBPByteOrder.BIG_ENDIAN)); + assertArrayEquals(new String[] {null, "", "ABC"}, asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0) + .readStringArray(3, BIG_ENDIAN)); } @Test public void testReadStringArray_ErrorForEOF() { - assertThrows(IOException.class, () -> asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(8, JBBPByteOrder.BIG_ENDIAN)); - assertThrows(IOException.class, () -> asInputStream().readStringArray(8, JBBPByteOrder.BIG_ENDIAN)); - assertThrows(IOException.class, () -> asInputStream().readStringArray(8, JBBPByteOrder.LITTLE_ENDIAN)); - assertThrows(IOException.class, () -> asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(8, JBBPByteOrder.LITTLE_ENDIAN)); + assertThrows(IOException.class, () -> asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0) + .readStringArray(8, BIG_ENDIAN)); + assertThrows(IOException.class, + () -> asInputStream().readStringArray(8, BIG_ENDIAN)); + assertThrows(IOException.class, + () -> asInputStream().readStringArray(8, JBBPByteOrder.LITTLE_ENDIAN)); + assertThrows(IOException.class, () -> asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0) + .readStringArray(8, JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadStringArray_ErrorForWrongPrefix() { - assertThrows(IOException.class, () -> asInputStream(0x80, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(3, JBBPByteOrder.BIG_ENDIAN)); - assertThrows(IOException.class, () -> asInputStream(0x91, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(3, JBBPByteOrder.LITTLE_ENDIAN)); + assertThrows(IOException.class, () -> asInputStream(0x80, 0x00, 3, 65, 66, 67, 0, 0) + .readStringArray(3, BIG_ENDIAN)); + assertThrows(IOException.class, () -> asInputStream(0x91, 0x00, 3, 65, 66, 67, 0, 0) + .readStringArray(3, JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadStringArray_LittleEndan_FixedSize() throws Exception { - assertArrayEquals(new String[] {null, "", "ABC"}, asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(3, JBBPByteOrder.LITTLE_ENDIAN)); + assertArrayEquals(new String[] {null, "", "ABC"}, asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0) + .readStringArray(3, JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadStringArray_WholeStream_ResultEmptyArray() throws Exception { - assertArrayEquals(new String[0], asInputStream().readStringArray(-1, JBBPByteOrder.LITTLE_ENDIAN)); - assertArrayEquals(new String[0], asInputStream().readStringArray(-1, JBBPByteOrder.BIG_ENDIAN)); + assertArrayEquals(new String[0], + asInputStream().readStringArray(-1, JBBPByteOrder.LITTLE_ENDIAN)); + assertArrayEquals(new String[0], asInputStream().readStringArray(-1, BIG_ENDIAN)); } @Test public void testReadStringArray_BigEndan_WholeStream() throws Exception { - assertArrayEquals(new String[] {null, "", "ABC", "", ""}, asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(-1, JBBPByteOrder.BIG_ENDIAN)); + assertArrayEquals(new String[] {null, "", "ABC", "", ""}, + asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0) + .readStringArray(-1, BIG_ENDIAN)); } @Test public void testReadStringArray_LittleEndan_WholeStream() throws Exception { - assertArrayEquals(new String[] {null, "", "ABC", "", ""}, asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(-1, JBBPByteOrder.LITTLE_ENDIAN)); + assertArrayEquals(new String[] {null, "", "ABC", "", ""}, + asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0) + .readStringArray(-1, JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadString_BigEndan_Null() throws Exception { - assertEquals(null, asInputStream(0xFF).readString(JBBPByteOrder.BIG_ENDIAN)); + assertNull(asInputStream(0xFF).readString(BIG_ENDIAN)); } @Test public void testReadString_BigEndan_Empty() throws Exception { - assertEquals("", asInputStream(0x00).readString(JBBPByteOrder.BIG_ENDIAN)); + assertEquals("", asInputStream(0x00).readString(BIG_ENDIAN)); } @Test public void testReadString_BigEndan_ShortString() throws Exception { - assertEquals("ABC", asInputStream(0x03, 65, 66, 67).readString(JBBPByteOrder.BIG_ENDIAN)); + assertEquals("ABC", asInputStream(0x03, 65, 66, 67).readString(BIG_ENDIAN)); } @Test public void testReadString_BigEndan_Msb0_ShortString() throws Exception { - assertEquals("zzzz", asInputStreamMSB0(0x20, '^', '^', '^', '^').readString(JBBPByteOrder.BIG_ENDIAN)); + assertEquals("zzzz", + asInputStreamMSB0(0x20, '^', '^', '^', '^').readString(BIG_ENDIAN)); } @Test public void testReadString_LittleEndan_Null() throws Exception { - assertEquals(null, asInputStream(0xFF).readString(JBBPByteOrder.LITTLE_ENDIAN)); + assertNull(asInputStream(0xFF).readString(JBBPByteOrder.LITTLE_ENDIAN)); } @Test @@ -187,129 +321,173 @@ public void testReadString_LittleEndian_ShortString() throws Exception { @Test public void testReadFloat_BigEndian_MSB0() throws Exception { - assertEquals(176552.47f, asInputStreamMSB0(0x12, 0x34, 0x56, 0x78).readFloat(JBBPByteOrder.BIG_ENDIAN), TestUtils.FLOAT_DELTA); + assertEquals(176552.47f, + asInputStreamMSB0(0x12, 0x34, 0x56, 0x78).readFloat(BIG_ENDIAN), + TestUtils.FLOAT_DELTA); } @Test public void testReadInt_BigEndian_MSB0_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStreamMSB0(0x12, 0x34, 0x56).readInt(JBBPByteOrder.BIG_ENDIAN)); + assertThrows(EOFException.class, + () -> asInputStreamMSB0(0x12, 0x34, 0x56).readInt(BIG_ENDIAN)); } @Test public void testReadFloat_BigEndian_MSB0_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStreamMSB0(0x12, 0x34, 0x56).readFloat(JBBPByteOrder.BIG_ENDIAN)); + assertThrows(EOFException.class, + () -> asInputStreamMSB0(0x12, 0x34, 0x56).readFloat(BIG_ENDIAN)); } @Test public void testReadInt_LittleEndian() throws Exception { - assertEquals(0x78563412, asInputStream(0x12, 0x34, 0x56, 0x78).readInt(JBBPByteOrder.LITTLE_ENDIAN)); + assertEquals(0x78563412, + asInputStream(0x12, 0x34, 0x56, 0x78).readInt(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadFloat_LittleEndian() throws Exception { - assertEquals(1.7378244E34f, asInputStream(0x12, 0x34, 0x56, 0x78).readFloat(JBBPByteOrder.LITTLE_ENDIAN), TestUtils.FLOAT_DELTA); + assertEquals(1.7378244E34f, + asInputStream(0x12, 0x34, 0x56, 0x78).readFloat(JBBPByteOrder.LITTLE_ENDIAN), + TestUtils.FLOAT_DELTA); } @Test public void testReadInt_LittleEndian_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56).readInt(JBBPByteOrder.LITTLE_ENDIAN)); + assertThrows(EOFException.class, + () -> asInputStream(0x12, 0x34, 0x56).readInt(JBBPByteOrder.LITTLE_ENDIAN)); } @Test - public void testReadFloat_LittleEndian_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56).readFloat(JBBPByteOrder.LITTLE_ENDIAN)); + public void testReadFloat_LittleEndian_EOF() { + assertThrows(EOFException.class, + () -> asInputStream(0x12, 0x34, 0x56).readFloat(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadInt_LittleEndian_MSB0() throws Exception { - assertEquals(0x1E6A2C48, asInputStreamMSB0(0x12, 0x34, 0x56, 0x78).readInt(JBBPByteOrder.LITTLE_ENDIAN)); + assertEquals(0x1E6A2C48, + asInputStreamMSB0(0x12, 0x34, 0x56, 0x78).readInt(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadFloat_LittleEndian_MSB0() throws Exception { - assertEquals(1.2397014E-20f, asInputStreamMSB0(0x12, 0x34, 0x56, 0x78).readFloat(JBBPByteOrder.LITTLE_ENDIAN), TestUtils.FLOAT_DELTA); + assertEquals(1.2397014E-20f, + asInputStreamMSB0(0x12, 0x34, 0x56, 0x78).readFloat(JBBPByteOrder.LITTLE_ENDIAN), + TestUtils.FLOAT_DELTA); } @Test - public void testReadInt_LittleEndian_MSB0_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStreamMSB0(0x12, 0x34, 0x56).readInt(JBBPByteOrder.LITTLE_ENDIAN)); + public void testReadInt_LittleEndian_MSB0_EOF() { + assertThrows(EOFException.class, + () -> asInputStreamMSB0(0x12, 0x34, 0x56).readInt(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadFloat_LittleEndian_MSB0_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStreamMSB0(0x12, 0x34, 0x56).readFloat(JBBPByteOrder.LITTLE_ENDIAN)); + assertThrows(EOFException.class, + () -> asInputStreamMSB0(0x12, 0x34, 0x56).readFloat(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadLong_BigEndian() throws Exception { - assertEquals(0x12345678AABBCCDDL, asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD).readLong(JBBPByteOrder.BIG_ENDIAN)); + assertEquals(0x12345678AABBCCDDL, asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD) + .readLong(BIG_ENDIAN)); } @Test public void testReadDouble_BigEndian() throws Exception { - assertEquals(5.626349538661693E-221d, asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD).readDouble(JBBPByteOrder.BIG_ENDIAN), TestUtils.FLOAT_DELTA); + assertEquals(5.626349538661693E-221d, + asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD) + .readDouble(BIG_ENDIAN), TestUtils.FLOAT_DELTA); } @Test - public void testReadLong_BigEndian_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC).readLong(JBBPByteOrder.BIG_ENDIAN)); + public void testReadLong_BigEndian_EOF() { + assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC) + .readLong(BIG_ENDIAN)); } @Test public void testReadDouble_BigEndian_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC).readDouble(JBBPByteOrder.BIG_ENDIAN)); + assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC) + .readDouble(BIG_ENDIAN)); } @Test public void testReadLong_LittleEndian() throws Exception { - assertEquals(0xDDCCBBAA78563412L, asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD).readLong(JBBPByteOrder.LITTLE_ENDIAN)); + assertEquals(0xDDCCBBAA78563412L, asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD) + .readLong(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testReadDouble_LittleEndian() throws Exception { - assertEquals(-7.00761088740633E143d, asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD).readDouble(JBBPByteOrder.LITTLE_ENDIAN), TestUtils.FLOAT_DELTA); + assertEquals(-7.00761088740633E143d, + asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD) + .readDouble(JBBPByteOrder.LITTLE_ENDIAN), TestUtils.FLOAT_DELTA); } @Test - public void testReadLong_LittleEndian_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC).readLong(JBBPByteOrder.LITTLE_ENDIAN)); + public void testReadLong_LittleEndian_EOF() { + assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC) + .readLong(JBBPByteOrder.LITTLE_ENDIAN)); } @Test - public void testReadDouble_LittleEndian_EOF() throws Exception { - assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC).readDouble(JBBPByteOrder.LITTLE_ENDIAN)); + public void testReadDouble_LittleEndian_EOF() { + assertThrows(EOFException.class, () -> asInputStream(0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC) + .readDouble(JBBPByteOrder.LITTLE_ENDIAN)); } @Test public void testRead9bit() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0xDA, 1})); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0xDA, 1})); + + assertFalse(in.isDetectedPartlyReadBitField()); + + assertEquals(0xA, in.readBits(BITS_4)); + assertFalse(in.isDetectedPartlyReadBitField()); + + assertEquals(0x1D, in.readBits(BITS_5)); + assertFalse(in.isDetectedPartlyReadBitField()); - assertEquals(0xA, in.readBits(JBBPBitNumber.BITS_4)); - assertEquals(0x1D, in.readBits(JBBPBitNumber.BITS_5)); assertEquals(0, in.read()); + assertTrue(in.isDetectedPartlyReadBitField()); + assertEquals(-1, in.read()); + assertFalse(in.isDetectedPartlyReadBitField()); } @Test public void testRead9bit_MSB0() throws Exception { final JBBPBitInputStream in = asInputStreamMSB0(0xD9, 1); - assertEquals(0x0B, in.readBits(JBBPBitNumber.BITS_4)); - assertEquals(0x09, in.readBits(JBBPBitNumber.BITS_5)); + assertFalse(in.isDetectedPartlyReadBitField()); + + assertEquals(0x0B, in.readBits(BITS_4)); + assertFalse(in.isDetectedPartlyReadBitField()); + + assertEquals(0x09, in.readBits(BITS_5)); + assertFalse(in.isDetectedPartlyReadBitField()); + assertEquals(0x40, in.read()); + assertTrue(in.isDetectedPartlyReadBitField()); + assertEquals(-1, in.read()); + assertFalse(in.isDetectedPartlyReadBitField()); } @Test public void testGetBitBuffer() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0xAA})); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0xAA})); assertEquals(0, in.getBitBuffer()); - assertEquals(0xA, in.readBits(JBBPBitNumber.BITS_4)); + assertEquals(0xA, in.readBits(BITS_4)); assertEquals(0xA, in.getBitBuffer()); } @Test - public void testGetOrder() throws Exception { + public void testGetOrder() { assertEquals(JBBPBitOrder.MSB0, new JBBPBitInputStream(null, JBBPBitOrder.MSB0).getBitOrder()); assertEquals(JBBPBitOrder.LSB0, new JBBPBitInputStream(null, JBBPBitOrder.LSB0).getBitOrder()); assertEquals(JBBPBitOrder.LSB0, new JBBPBitInputStream(null).getBitOrder()); @@ -317,18 +495,18 @@ public void testGetOrder() throws Exception { @Test public void testAlignByte() throws Exception { - final byte[] testarray = JBBPUtils.str2bin("01111001 10111000"); + final byte[] testarray = str2bin("01111001 10111000"); final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testarray)); in.alignByte(); assertEquals(0, in.getCounter()); - assertEquals(0x19, in.readBits(JBBPBitNumber.BITS_5)); + assertEquals(0x19, in.readBits(BITS_5)); assertEquals(0, in.getCounter()); in.alignByte(); assertEquals(1, in.getCounter()); - assertEquals(0x8, in.readBits(JBBPBitNumber.BITS_4)); + assertEquals(0x8, in.readBits(BITS_4)); assertEquals(1, in.getCounter()); - assertEquals(0xB, in.readBits(JBBPBitNumber.BITS_4)); + assertEquals(0xB, in.readBits(BITS_4)); assertEquals(2, in.getCounter()); assertEquals(-1, in.read()); assertEquals(2, in.getCounter()); @@ -336,12 +514,12 @@ public void testAlignByte() throws Exception { @Test public void testAlignByte_IfWeHaveBufferedByteInBitBuffer() throws Exception { - final byte[] testarray = JBBPUtils.str2bin("01111001 10111000"); + final byte[] testArray = str2bin("01111001 10111000"); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testarray)); - assertEquals(0x19, in.readBits(JBBPBitNumber.BITS_5)); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testArray)); + assertEquals(0x19, in.readBits(BITS_5)); assertEquals(0, in.getCounter()); - assertEquals(0x03, in.readBits(JBBPBitNumber.BITS_3)); + assertEquals(0x03, in.readBits(BITS_3)); assertEquals(1, in.getCounter()); assertTrue(in.hasAvailableData()); assertEquals(1, in.getCounter()); @@ -354,33 +532,33 @@ public void testAlignByte_IfWeHaveBufferedByteInBitBuffer() throws Exception { @Test public void testReadStream_AsBits() throws IOException { - final byte[] testarray = JBBPUtils.str2bin(TEST_BYTES, JBBPBitOrder.MSB0); + final byte[] testArray = str2bin(TEST_BYTES, JBBPBitOrder.MSB0); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testarray)); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testArray)); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1));//0 - assertEquals(1, in.readBits(JBBPBitNumber.BITS_1)); + assertEquals(0, in.readBits(BITS_1));//0 + assertEquals(1, in.readBits(BITS_1)); assertEquals(0, in.getCounter()); assertEquals(6, in.getBufferedBitsNumber()); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_2));//2 - assertEquals(3, in.readBits(JBBPBitNumber.BITS_2)); + assertEquals(0, in.readBits(BITS_2));//2 + assertEquals(3, in.readBits(BITS_2)); assertEquals(0, in.getCounter()); assertEquals(2, in.getBufferedBitsNumber()); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_3));//6 - assertEquals(7, in.readBits(JBBPBitNumber.BITS_3)); + assertEquals(0, in.readBits(BITS_3));//6 + assertEquals(7, in.readBits(BITS_3)); assertEquals(1, in.getCounter()); assertEquals(4, in.getBufferedBitsNumber()); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_4));//12 + assertEquals(0, in.readBits(BITS_4));//12 assertEquals(2, in.getCounter()); - assertEquals(15, in.readBits(JBBPBitNumber.BITS_4)); + assertEquals(15, in.readBits(BITS_4)); assertEquals(2, in.getCounter()); assertEquals(4, in.getBufferedBitsNumber()); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_5));//20 - assertEquals(31, in.readBits(JBBPBitNumber.BITS_5)); + assertEquals(0, in.readBits(BITS_5));//20 + assertEquals(31, in.readBits(BITS_5)); assertEquals(3, in.getCounter()); assertEquals(2, in.getBufferedBitsNumber()); @@ -409,35 +587,37 @@ public void testReadStream_AsBits() throws IOException { @Test public void testReadStream_BitByBit() throws IOException { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {0x01})); - assertEquals(1, in.readBits(JBBPBitNumber.BITS_1)); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {0x01})); + assertEquals(1, in.readBits(BITS_1)); assertEquals(0, in.getCounter()); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); - assertEquals(-1, in.readBits(JBBPBitNumber.BITS_1)); + assertEquals(0, in.readBits(BITS_1)); + assertEquals(0, in.readBits(BITS_1)); + assertEquals(0, in.readBits(BITS_1)); + assertEquals(0, in.readBits(BITS_1)); + assertEquals(0, in.readBits(BITS_1)); + assertEquals(0, in.readBits(BITS_1)); + assertEquals(0, in.readBits(BITS_1)); + assertEquals(-1, in.readBits(BITS_1)); assertEquals(1, in.getCounter()); } @Test public void testReadStream_7bits_Default() throws IOException { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("11011100", JBBPBitOrder.MSB0))); + final JBBPBitInputStream in = new JBBPBitInputStream( + new ByteArrayInputStream(str2bin("11011100", JBBPBitOrder.MSB0))); assertEquals(0x3B, in.readBits(JBBPBitNumber.BITS_7)); assertEquals(0, in.getCounter()); } @Test public void testReadStream_AsBytes() throws IOException { - final byte[] testarray = JBBPUtils.str2bin(TEST_BYTES, JBBPBitOrder.MSB0); + final byte[] testArray = str2bin(TEST_BYTES, JBBPBitOrder.MSB0); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testarray)); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testArray)); - for (int i = 0; i < testarray.length; i++) { - assertEquals(testarray[i] & 0xFF, in.read(), "Byte " + i); + for (int i = 0; i < testArray.length; i++) { + assertEquals(testArray[i] & 0xFF, in.read(), "Byte " + i); } assertEquals(9, in.getCounter()); assertEquals(-1, in.read()); @@ -445,23 +625,23 @@ public void testReadStream_AsBytes() throws IOException { @Test public void testReadStream_AsArray() throws IOException { - final byte[] testarray = JBBPUtils.str2bin(TEST_BYTES, JBBPBitOrder.MSB0); + final byte[] testArray = str2bin(TEST_BYTES, JBBPBitOrder.MSB0); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testarray)); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testArray)); final byte[] read = new byte[9]; assertEquals(9, in.read(read)); assertEquals(-1, in.read()); assertEquals(9, in.getCounter()); - assertArrayEquals(testarray, read); + assertArrayEquals(testArray, read); } @Test public void testReadStream_AsPartOfArray() throws IOException { - final byte[] testarray = JBBPUtils.str2bin(TEST_BYTES, JBBPBitOrder.MSB0); + final byte[] testArray = str2bin(TEST_BYTES, JBBPBitOrder.MSB0); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testarray)); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testArray)); final byte[] buff = new byte[27]; assertEquals(5, in.read(buff, 9, 5)); @@ -473,7 +653,7 @@ public void testReadStream_AsPartOfArray() throws IOException { } for (int i = 9; i < 14; i++) { - assertEquals(testarray[i - 9], buff[i]); + assertEquals(testArray[i - 9], buff[i]); } for (int i = 14; i < 27; i++) { @@ -484,9 +664,10 @@ public void testReadStream_AsPartOfArray() throws IOException { @Test public void testReadStream_AsPartOfArray_MSB0() throws IOException { - final byte[] testarray = JBBPUtils.str2bin(TEST_BYTES, JBBPBitOrder.MSB0); + final byte[] testArray = str2bin(TEST_BYTES, JBBPBitOrder.MSB0); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(testarray), JBBPBitOrder.MSB0); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(testArray), JBBPBitOrder.MSB0); final byte[] buff = new byte[27]; assertEquals(5, in.read(buff, 9, 5)); @@ -498,7 +679,7 @@ public void testReadStream_AsPartOfArray_MSB0() throws IOException { } for (int i = 9; i < 14; i++) { - assertEquals(JBBPUtils.reverseBitsInByte(testarray[i - 9]), buff[i]); + assertEquals(JBBPUtils.reverseBitsInByte(testArray[i - 9]), buff[i]); } for (int i = 14; i < 27; i++) { @@ -509,11 +690,12 @@ public void testReadStream_AsPartOfArray_MSB0() throws IOException { @Test public void testReadStream_AsPartOfArray_1bitOffset() throws IOException { - final byte[] testarray = JBBPUtils.str2bin(TEST_BYTES, JBBPBitOrder.MSB0); + final byte[] testarray = str2bin(TEST_BYTES, JBBPBitOrder.MSB0); - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin(TEST_BYTES_EXTRABIT, JBBPBitOrder.MSB0))); + final JBBPBitInputStream in = new JBBPBitInputStream( + new ByteArrayInputStream(str2bin(TEST_BYTES_EXTRABIT, JBBPBitOrder.MSB0))); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); + assertEquals(0, in.readBits(BITS_1)); final byte[] read = new byte[27]; assertEquals(5, in.read(read, 9, 5)); @@ -536,57 +718,43 @@ public void testReadStream_AsPartOfArray_1bitOffset() throws IOException { @Test public void testMarkForReadBits() throws IOException { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("10010110_00101000_10101010", JBBPBitOrder.MSB0))); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + str2bin("10010110_00101000_10101010", JBBPBitOrder.MSB0))); - assertEquals(0x9, in.readBits(JBBPBitNumber.BITS_4)); + assertEquals(0x9, in.readBits(BITS_4)); assertEquals(0x6, in.readBits(JBBPBitNumber.BITS_6)); assertTrue(in.markSupported()); in.mark(1024); - assertEquals(5, in.readBits(JBBPBitNumber.BITS_3)); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_3)); + assertEquals(5, in.readBits(BITS_3)); + assertEquals(0, in.readBits(BITS_3)); assertEquals(0x55, in.read()); in.reset(); - assertEquals(5, in.readBits(JBBPBitNumber.BITS_3)); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_3)); + assertEquals(5, in.readBits(BITS_3)); + assertEquals(0, in.readBits(BITS_3)); assertEquals(0x55, in.read()); assertEquals(-1, in.read()); } @Test - public void testReadBits_ExceptionForWrongArgument() throws Exception { - final JBBPBitInputStream inLe = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin(TEST_BYTES, JBBPBitOrder.LSB0))); - - try { - inLe.readBits(JBBPBitNumber.decode(0)); - fail("Must throw IAE"); - } catch (IllegalArgumentException ex) { - - } - - try { - inLe.readBits(JBBPBitNumber.decode(-5)); - fail("Must throw IAE"); - } catch (IllegalArgumentException ex) { - - } - - try { - inLe.readBits(JBBPBitNumber.decode(9)); - fail("Must throw IAE"); - } catch (IllegalArgumentException ex) { - - } + public void testReadBits_ExceptionForWrongArgument() { + final JBBPBitInputStream inLe = new JBBPBitInputStream( + new ByteArrayInputStream(str2bin(TEST_BYTES, JBBPBitOrder.LSB0))); + assertThrows(IllegalArgumentException.class, () -> inLe.readBits(JBBPBitNumber.decode(0))); + assertThrows(IllegalArgumentException.class, () -> inLe.readBits(JBBPBitNumber.decode(-5))); + assertThrows(IllegalArgumentException.class, () -> inLe.readBits(JBBPBitNumber.decode(9))); } @Test public void testSkipBytes() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("01010101_01010101_01010101_00011000_01010101_01010101_00000001", JBBPBitOrder.MSB0))); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + str2bin("01010101_01010101_01010101_00011000_01010101_01010101_00000001", + JBBPBitOrder.MSB0))); assertEquals(3, in.skip(3)); assertEquals(0x18, in.read()); @@ -597,7 +765,9 @@ public void testSkipBytes() throws Exception { @Test public void testAlignBytes() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("01010101_01010101_01011101_00011000_01010101_01010101_00000001", JBBPBitOrder.MSB0))); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + str2bin("01010101_01010101_01011101_00011000_01010101_01010101_00000001", + JBBPBitOrder.MSB0))); assertEquals(0xAA, in.read()); in.align(3); @@ -605,18 +775,14 @@ public void testAlignBytes() throws Exception { in.align(6); assertEquals(0x80, in.read()); assertEquals(-1, in.read()); - - try { - in.align(10); - fail("Must throw EOF"); - } catch (EOFException ex) { - - } + assertThrows(EOFException.class, () -> in.align(10)); } @Test public void testRead_WithoutOffset() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("01010111_01010111_01010111_00011000_01010101_01100011_00000001", JBBPBitOrder.MSB0))); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + str2bin("01010111_01010111_01010111_00011000_01010101_01100011_00000001", + JBBPBitOrder.MSB0))); assertEquals(0xEA, in.read()); assertEquals(0xEA, in.read()); @@ -630,9 +796,11 @@ public void testRead_WithoutOffset() throws Exception { @Test public void testRead_1bitOffset() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("1 01010111_01010111_01010111_00011000_01010111_01100011_00101101", JBBPBitOrder.MSB0))); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + str2bin("1 01010111_01010111_01010111_00011000_01010111_01100011_00101101", + JBBPBitOrder.MSB0))); - assertEquals(1, in.readBits(JBBPBitNumber.BITS_1)); + assertEquals(1, in.readBits(BITS_1)); assertEquals(0xEA, in.read()); assertEquals(0xEA, in.read()); @@ -647,9 +815,11 @@ public void testRead_1bitOffset() throws Exception { @Test public void testSkipBytes_1bitOffset() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("0 01010101_01010101_01010101 00011000_01010101_010110110_0000001", JBBPBitOrder.MSB0))); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + str2bin("0 01010101_01010101_01010101 00011000_01010101_010110110_0000001", + JBBPBitOrder.MSB0))); - assertEquals(0, in.readBits(JBBPBitNumber.BITS_1)); + assertEquals(0, in.readBits(BITS_1)); assertEquals(0, in.getCounter()); @@ -677,8 +847,10 @@ public void testSkipBytes_1bitOffset() throws Exception { @Test public void testReadArray_Bits_WholeStream() throws Exception { - JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("00101001_11001011_10111110", JBBPBitOrder.LSB0))); - assertArrayEquals(new byte[] {1, 2, 2, 0, 3, 2, 0, 3, 2, 3, 3, 2}, in.readBitsArray(-1, JBBPBitNumber.BITS_2)); + JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + str2bin("00101001_11001011_10111110", JBBPBitOrder.LSB0))); + assertArrayEquals(new byte[] {1, 2, 2, 0, 3, 2, 0, 3, 2, 3, 3, 2}, + in.readBitsArray(-1, BITS_2)); assertEquals(3, in.getCounter()); final Random rnd = new Random(1234); @@ -711,21 +883,24 @@ public void testReadArray_Bits_WholeStream() throws Exception { @Test public void testReadArray_Bits_ThreeItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("00101001_11001011_10111110", JBBPBitOrder.LSB0))); - assertArrayEquals(new byte[] {1, 2, 2}, in.readBitsArray(3, JBBPBitNumber.BITS_2)); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + str2bin("00101001_11001011_10111110", JBBPBitOrder.LSB0))); + assertArrayEquals(new byte[] {1, 2, 2}, in.readBitsArray(3, BITS_2)); } @Test - public void testReadArray_Bits_EOF() throws Exception { + public void testReadArray_Bits_EOF() { assertThrows(EOFException.class, () -> { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("00101001_11001011_10111110", JBBPBitOrder.LSB0))); - in.readBitsArray(58, JBBPBitNumber.BITS_2); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + str2bin("00101001_11001011_10111110", JBBPBitOrder.LSB0))); + in.readBitsArray(58, BITS_2); }); } @Test public void testReadArray_Bytes_WholeStream() throws Exception { - JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 0}, in.readByteArray(-1)); assertEquals(8, in.getCounter()); @@ -758,34 +933,40 @@ public void testReadArray_Bytes_WholeStream() throws Exception { @Test public void testReadArray_Bytes_ThreeItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); assertArrayEquals(new byte[] {1, 2, 3,}, in.readByteArray(3)); } @Test public void testReadArray_Bytes_BIG_ENDIAN_ThreeItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); - assertArrayEquals(new byte[] {1, 2, 3,}, in.readByteArray(3, JBBPByteOrder.BIG_ENDIAN)); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + assertArrayEquals(new byte[] {1, 2, 3,}, in.readByteArray(3, BIG_ENDIAN)); } @Test public void testReadArray_Bytes_LITTLE_ENDIAN_ThreeItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); assertArrayEquals(new byte[] {3, 2, 1,}, in.readByteArray(3, JBBPByteOrder.LITTLE_ENDIAN)); } @Test - public void testReadArray_Bytes_EOF() throws Exception { + public void testReadArray_Bytes_EOF() { assertThrows(EOFException.class, () -> { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); in.readByteArray(259); }); } @Test public void testReadArray_Short_WholeStream() throws Exception { - JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); - assertArrayEquals(new short[] {0x0102, 0x0304, 0x0506, 0x0700}, in.readShortArray(-1, JBBPByteOrder.BIG_ENDIAN)); + JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + assertArrayEquals(new short[] {0x0102, 0x0304, 0x0506, 0x0700}, + in.readShortArray(-1, BIG_ENDIAN)); assertEquals(8, in.getCounter()); final Random rnd = new Random(1234); @@ -794,7 +975,7 @@ public void testReadArray_Short_WholeStream() throws Exception { rnd.nextBytes(buff); in = new JBBPBitInputStream(new ByteArrayInputStream(buff)); - final short[] read = in.readShortArray(-1, JBBPByteOrder.BIG_ENDIAN); + final short[] read = in.readShortArray(-1, BIG_ENDIAN); assertEquals(buff.length, in.getCounter()); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE, read.length); @@ -809,7 +990,7 @@ public void testReadArray_Short_WholeStream() throws Exception { in = new JBBPBitInputStream(new ByteArrayInputStream(big)); - final short[] readbig = in.readShortArray(-1, JBBPByteOrder.BIG_ENDIAN); + final short[] readbig = in.readShortArray(-1, BIG_ENDIAN); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 64, readbig.length); for (int i = 0; i < readbig.length; i++) { @@ -821,8 +1002,10 @@ public void testReadArray_Short_WholeStream() throws Exception { @Test public void testReadArray_UShort_WholeStream() throws Exception { - JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); - assertArrayEquals(new char[] {0x0102, 0x0304, 0x0506, 0x0700}, in.readUShortArray(-1, JBBPByteOrder.BIG_ENDIAN)); + JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + assertArrayEquals(new char[] {0x0102, 0x0304, 0x0506, 0x0700}, + in.readUShortArray(-1, BIG_ENDIAN)); assertEquals(8, in.getCounter()); final Random rnd = new Random(1234); @@ -831,7 +1014,7 @@ public void testReadArray_UShort_WholeStream() throws Exception { rnd.nextBytes(buff); in = new JBBPBitInputStream(new ByteArrayInputStream(buff)); - final char[] read = in.readUShortArray(-1, JBBPByteOrder.BIG_ENDIAN); + final char[] read = in.readUShortArray(-1, BIG_ENDIAN); assertEquals(buff.length, in.getCounter()); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE, read.length); @@ -846,7 +1029,7 @@ public void testReadArray_UShort_WholeStream() throws Exception { in = new JBBPBitInputStream(new ByteArrayInputStream(big)); - final char[] readbig = in.readUShortArray(-1, JBBPByteOrder.BIG_ENDIAN); + final char[] readbig = in.readUShortArray(-1, BIG_ENDIAN); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 64, readbig.length); for (int i = 0; i < readbig.length; i++) { @@ -858,30 +1041,35 @@ public void testReadArray_UShort_WholeStream() throws Exception { @Test public void testReadArray_Short_TwoItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); - assertArrayEquals(new short[] {0x0102, 0x0304}, in.readShortArray(2, JBBPByteOrder.BIG_ENDIAN)); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + assertArrayEquals(new short[] {0x0102, 0x0304}, in.readShortArray(2, BIG_ENDIAN)); assertEquals(4, in.getCounter()); } @Test public void testReadArray_UShort_TwoItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); - assertArrayEquals(new char[] {0x0102, 0x0304}, in.readUShortArray(2, JBBPByteOrder.BIG_ENDIAN)); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + assertArrayEquals(new char[] {0x0102, 0x0304}, in.readUShortArray(2, BIG_ENDIAN)); assertEquals(4, in.getCounter()); } @Test - public void testReadArray_Short_EOF() throws Exception { + public void testReadArray_Short_EOF() { assertThrows(EOFException.class, () -> { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); - in.readShortArray(259, JBBPByteOrder.BIG_ENDIAN); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); + in.readShortArray(259, BIG_ENDIAN); }); } @Test public void testReadArray_Int_WholeStream() throws Exception { - JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); - assertArrayEquals(new int[] {0x01020304, 0x05060700, 0xFECABE01}, in.readIntArray(-1, JBBPByteOrder.BIG_ENDIAN)); + JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); + assertArrayEquals(new int[] {0x01020304, 0x05060700, 0xFECABE01}, + in.readIntArray(-1, BIG_ENDIAN)); assertEquals(12, in.getCounter()); final Random rnd = new Random(1234); @@ -890,14 +1078,16 @@ public void testReadArray_Int_WholeStream() throws Exception { rnd.nextBytes(buff); in = new JBBPBitInputStream(new ByteArrayInputStream(buff)); - final int[] read = in.readIntArray(-1, JBBPByteOrder.BIG_ENDIAN); + final int[] read = in.readIntArray(-1, BIG_ENDIAN); assertEquals(buff.length, in.getCounter()); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE, read.length); for (int i = 0; i < read.length; i++) { final int val = read[i]; final int j = i * 4; - assertEquals(val, ((buff[j] << 24) | ((buff[j + 1] & 0xFF) << 16) | ((buff[j + 2] & 0xFF) << 8) | (buff[j + 3] & 0xFF))); + assertEquals(val, + ((buff[j] << 24) | ((buff[j + 1] & 0xFF) << 16) | ((buff[j + 2] & 0xFF) << 8) | + (buff[j + 3] & 0xFF))); } final byte[] big = new byte[JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 128]; @@ -905,20 +1095,315 @@ public void testReadArray_Int_WholeStream() throws Exception { in = new JBBPBitInputStream(new ByteArrayInputStream(big)); - final int[] readbig = in.readIntArray(-1, JBBPByteOrder.BIG_ENDIAN); + final int[] readbig = in.readIntArray(-1, BIG_ENDIAN); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 32, readbig.length); for (int i = 0; i < readbig.length; i++) { final int val = readbig[i]; final int j = i * 4; - assertEquals(val, ((big[j] << 24) | ((big[j + 1] & 0xFF) << 16) | ((big[j + 2] & 0xFF) << 8) | (big[j + 3] & 0xFF))); + assertEquals(val, ((big[j] << 24) | ((big[j + 1] & 0xFF) << 16) | ((big[j + 2] & 0xFF) << 8) | + (big[j + 3] & 0xFF))); + } + } + + private void testWholeStreamArrayRead( + final int expectedReadWholeSize, + final StreamAndIntSupplier readWhole, + final StreamAndIntSupplier readWholeWithException, + final int expectedReadLimitedSize, + final StreamAndIntSupplier readWholeLimited + ) throws Exception { + final Pair readWholeData = readWhole.getData(); + assertEquals(expectedReadWholeSize, readWholeData.getRight()); + assertFalse(readWholeData.getLeft().isDetectedArrayLimit()); + + assertThrows(JBBPReachedArraySizeLimitException.class, readWholeWithException::getData); + + final Pair readWholeLimitedData = readWholeLimited.getData(); + assertEquals(expectedReadLimitedSize, readWholeLimitedData.getRight()); + assertTrue(readWholeLimitedData.getLeft().isDetectedArrayLimit()); + } + + @Test + public void testReadArray_WholeWithLimiter_Bits() throws Exception { + final byte[] testData = new byte[] {1, 2, 3}; + this.testWholeStreamArrayRead( + 6, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readBitsArray(-1, BITS_4, () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readBitsArray(-1, + BITS_4, () -> 3).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readBitsArray(-1, + BITS_4, () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_Boolean() throws Exception { + final byte[] testData = new byte[] {1, 2, 3, 4, 5, 6}; + this.testWholeStreamArrayRead( + 6, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readBoolArray(-1, + () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readBoolArray(-1, + () -> 3).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readBoolArray(-1, + () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_Byte() throws Exception { + final byte[] testData = new byte[] {1, 2, 3, 4, 5, 6}; + this.testWholeStreamArrayRead( + 6, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readByteArray(-1, + () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readByteArray(-1, + () -> 3).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readByteArray(-1, + () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_Short() throws Exception { + final byte[] testData = new byte[] {1, 2, 3, 4, 5, 6}; + this.testWholeStreamArrayRead( + 3, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readShortArray(-1, + BIG_ENDIAN, () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readShortArray(-1, + BIG_ENDIAN, () -> 2).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readShortArray(-1, + BIG_ENDIAN, () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_UShort() throws Exception { + final byte[] testData = new byte[] {1, 2, 3, 4, 5, 6}; + this.testWholeStreamArrayRead( + 3, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readUShortArray(-1, + BIG_ENDIAN, () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readUShortArray(-1, + BIG_ENDIAN, () -> 2).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readUShortArray(-1, + BIG_ENDIAN, () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_Int() throws Exception { + final byte[] testData = TestUtils.getRandomBytes(128); + this.testWholeStreamArrayRead( + 32, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readIntArray(-1, + BIG_ENDIAN, () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readIntArray(-1, + BIG_ENDIAN, () -> 2).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readIntArray(-1, + BIG_ENDIAN, () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_UInt() throws Exception { + final byte[] testData = TestUtils.getRandomBytes(128); + this.testWholeStreamArrayRead( + 32, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readUIntArray(-1, + BIG_ENDIAN, () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readUIntArray(-1, + BIG_ENDIAN, () -> 2).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readUIntArray(-1, + BIG_ENDIAN, () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_Long() throws Exception { + final byte[] testData = TestUtils.getRandomBytes(128); + this.testWholeStreamArrayRead( + 16, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readLongArray(-1, + BIG_ENDIAN, () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readLongArray(-1, + BIG_ENDIAN, () -> 2).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readLongArray(-1, + BIG_ENDIAN, () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_Float() throws Exception { + final byte[] testData = TestUtils.getRandomBytes(128); + this.testWholeStreamArrayRead( + 32, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readFloatArray(-1, + BIG_ENDIAN, () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readFloatArray(-1, + BIG_ENDIAN, () -> 2).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readFloatArray(-1, + BIG_ENDIAN, () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_String() throws Exception { + final byte[] testData = + TestUtils.makeStringArray(BIG_ENDIAN, "hello", "world", "one", "two", "three", "four"); + this.testWholeStreamArrayRead( + 6, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readStringArray(-1, + BIG_ENDIAN, () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readStringArray(-1, + BIG_ENDIAN, () -> 2).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readStringArray(-1, + BIG_ENDIAN, () -> -2).length); + }); + } + + @Test + public void testReadArray_WholeWithLimiter_Double() throws Exception { + final byte[] testData = TestUtils.getRandomBytes(128); + this.testWholeStreamArrayRead( + 16, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readDoubleArray(-1, + BIG_ENDIAN, () -> 0).length); + }, + () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readDoubleArray(-1, + BIG_ENDIAN, () -> 2).length); + }, + 2, () -> { + JBBPBitInputStream stream = new JBBPBitInputStream(new ByteArrayInputStream(testData)); + return Pair.of(stream, stream.readDoubleArray(-1, + BIG_ENDIAN, () -> -2).length); + }); + } + + @Test + public void testReadArray_UInt_WholeStream() throws Exception { + JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); + assertArrayEquals(new long[] {0x01020304L, 0x05060700L, 0xFECABE01L}, + in.readUIntArray(-1, BIG_ENDIAN)); + assertEquals(12, in.getCounter()); + + final Random rnd = new Random(1234); + + final byte[] buff = new byte[JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 4]; + rnd.nextBytes(buff); + + in = new JBBPBitInputStream(new ByteArrayInputStream(buff)); + final long[] read = in.readUIntArray(-1, BIG_ENDIAN); + assertEquals(buff.length, in.getCounter()); + + assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE, read.length); + for (int i = 0; i < read.length; i++) { + final long val = read[i]; + final int j = i * 4; + assertEquals(val, + ((long) ((buff[j] << 24) | ((buff[j + 1] & 0xFF) << 16) | ((buff[j + 2] & 0xFF) << 8) | + (buff[j + 3] & 0xFF))) & 0xFFFFFFFFL); + } + + final byte[] big = new byte[JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 128]; + rnd.nextBytes(big); + + in = new JBBPBitInputStream(new ByteArrayInputStream(big)); + + final long[] readBig = in.readUIntArray(-1, BIG_ENDIAN); + + assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 32, readBig.length); + for (int i = 0; i < readBig.length; i++) { + final long val = readBig[i]; + final int j = i * 4; + assertEquals(val, + ((long) ((big[j] << 24) | ((big[j + 1] & 0xFF) << 16) | ((big[j + 2] & 0xFF) << 8) | + (big[j + 3] & 0xFF))) & 0xFFFFFFFFL); } } @Test public void testReadArray_Float_WholeStream() throws Exception { - JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); - assertArrayEquals(new float[] {2.3879393E-38f, 6.3019354E-36f, -1.3474531E38f}, in.readFloatArray(-1, JBBPByteOrder.BIG_ENDIAN), TestUtils.FLOAT_DELTA); + JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); + assertArrayEquals(new float[] {2.3879393E-38f, 6.3019354E-36f, -1.3474531E38f}, + in.readFloatArray(-1, BIG_ENDIAN), TestUtils.FLOAT_DELTA); assertEquals(12, in.getCounter()); final Random rnd = new Random(1234); @@ -927,14 +1412,16 @@ public void testReadArray_Float_WholeStream() throws Exception { rnd.nextBytes(buff); in = new JBBPBitInputStream(new ByteArrayInputStream(buff)); - final float[] read = in.readFloatArray(-1, JBBPByteOrder.BIG_ENDIAN); + final float[] read = in.readFloatArray(-1, BIG_ENDIAN); assertEquals(buff.length, in.getCounter()); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE, read.length); for (int i = 0; i < read.length; i++) { final float val = read[i]; final int j = i * 4; - assertEquals(val, Float.intBitsToFloat((buff[j] << 24) | ((buff[j + 1] & 0xFF) << 16) | ((buff[j + 2] & 0xFF) << 8) | (buff[j + 3] & 0xFF)), TestUtils.FLOAT_DELTA); + assertEquals(val, Float.intBitsToFloat( + (buff[j] << 24) | ((buff[j + 1] & 0xFF) << 16) | ((buff[j + 2] & 0xFF) << 8) | + (buff[j + 3] & 0xFF)), TestUtils.FLOAT_DELTA); } final byte[] big = new byte[JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 128]; @@ -942,50 +1429,79 @@ public void testReadArray_Float_WholeStream() throws Exception { in = new JBBPBitInputStream(new ByteArrayInputStream(big)); - final float[] readbig = in.readFloatArray(-1, JBBPByteOrder.BIG_ENDIAN); + final float[] readbig = in.readFloatArray(-1, BIG_ENDIAN); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 32, readbig.length); for (int i = 0; i < readbig.length; i++) { final float val = readbig[i]; final int j = i * 4; - assertEquals(val, Float.intBitsToFloat((big[j] << 24) | ((big[j + 1] & 0xFF) << 16) | ((big[j + 2] & 0xFF) << 8) | (big[j + 3] & 0xFF)), TestUtils.FLOAT_DELTA); + assertEquals(val, Float.intBitsToFloat( + (big[j] << 24) | ((big[j + 1] & 0xFF) << 16) | ((big[j + 2] & 0xFF) << 8) | + (big[j + 3] & 0xFF)), TestUtils.FLOAT_DELTA); } } @Test public void testReadArray_Int_TwoItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); - assertArrayEquals(new int[] {0x01020304, 0x05060700}, in.readIntArray(2, JBBPByteOrder.BIG_ENDIAN)); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); + assertArrayEquals(new int[] {0x01020304, 0x05060700}, + in.readIntArray(2, BIG_ENDIAN)); + assertEquals(8, in.getCounter()); + } + + @Test + public void testReadArray_UInt_TwoItems() throws Exception { + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); + assertArrayEquals(new long[] {0x01020304L, 0x05060700L}, + in.readUIntArray(2, BIG_ENDIAN)); assertEquals(8, in.getCounter()); } @Test public void testReadArray_Float_TwoItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); - assertArrayEquals(new float[] {2.3879393E-38f, 6.3019354E-36f}, in.readFloatArray(2, JBBPByteOrder.BIG_ENDIAN), TestUtils.FLOAT_DELTA); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); + assertArrayEquals(new float[] {2.3879393E-38f, 6.3019354E-36f}, + in.readFloatArray(2, BIG_ENDIAN), TestUtils.FLOAT_DELTA); assertEquals(8, in.getCounter()); } @Test - public void testReadArray_Int_EOF() throws Exception { + public void testReadArray_Int_EOF() { + assertThrows(EOFException.class, () -> { + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); + in.readIntArray(259, BIG_ENDIAN); + }); + } + + @Test + public void testReadArray_UInt_EOF() { assertThrows(EOFException.class, () -> { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); - in.readIntArray(259, JBBPByteOrder.BIG_ENDIAN); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); + in.readUIntArray(259, BIG_ENDIAN); }); } @Test public void testReadArray_DoubleInt_EOF() throws Exception { assertThrows(EOFException.class, () -> { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); - in.readFloatArray(259, JBBPByteOrder.BIG_ENDIAN); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01})); + in.readFloatArray(259, BIG_ENDIAN); }); } @Test public void testReadArray_Long_WholeStream() throws Exception { - JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); - assertArrayEquals(new long[] {0x0102030405060700L, 0xFECABE0102030405L, 0x0607080901020304L}, in.readLongArray(-1, JBBPByteOrder.BIG_ENDIAN)); + JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, + 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); + assertArrayEquals(new long[] {0x0102030405060700L, 0xFECABE0102030405L, 0x0607080901020304L}, + in.readLongArray(-1, BIG_ENDIAN)); assertEquals(24, in.getCounter()); final Random rnd = new Random(1234); @@ -994,14 +1510,17 @@ public void testReadArray_Long_WholeStream() throws Exception { rnd.nextBytes(buff); in = new JBBPBitInputStream(new ByteArrayInputStream(buff)); - final long[] read = in.readLongArray(-1, JBBPByteOrder.BIG_ENDIAN); + final long[] read = in.readLongArray(-1, BIG_ENDIAN); assertEquals(buff.length, in.getCounter()); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE, read.length); for (int i = 0; i < read.length; i++) { final long val = read[i]; final int j = i * 8; - assertEquals(val, (((long) buff[j] << 56) | (((long) buff[j + 1] & 0xFFL) << 48) | (((long) buff[j + 2] & 0xFFL) << 40) | (((long) buff[j + 3] & 0xFFL) << 32) | (((long) buff[j + 4] & 0xFFL) << 24) | (((long) buff[j + 5] & 0xFFL) << 16) | (((long) buff[j + 6] & 0xFFL) << 8) | ((long) buff[j + 7] & 0xFF))); + assertEquals(val, (((long) buff[j] << 56) | (((long) buff[j + 1] & 0xFFL) << 48) | + (((long) buff[j + 2] & 0xFFL) << 40) | (((long) buff[j + 3] & 0xFFL) << 32) | + (((long) buff[j + 4] & 0xFFL) << 24) | (((long) buff[j + 5] & 0xFFL) << 16) | + (((long) buff[j + 6] & 0xFFL) << 8) | ((long) buff[j + 7] & 0xFF))); } final byte[] big = new byte[JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 128]; @@ -1009,20 +1528,27 @@ public void testReadArray_Long_WholeStream() throws Exception { in = new JBBPBitInputStream(new ByteArrayInputStream(big)); - final long[] readbig = in.readLongArray(-1, JBBPByteOrder.BIG_ENDIAN); + final long[] readbig = in.readLongArray(-1, BIG_ENDIAN); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 16, readbig.length); for (int i = 0; i < readbig.length; i++) { final long val = readbig[i]; final int j = i * 8; - assertEquals(val, (((long) big[j] << 56) | (((long) big[j + 1] & 0xFFL) << 48) | (((long) big[j + 2] & 0xFFL) << 40) | (((long) big[j + 3] & 0xFFL) << 32) | (((long) big[j + 4] & 0xFFL) << 24) | (((long) big[j + 5] & 0xFFL) << 16) | (((long) big[j + 6] & 0xFFL) << 8) | ((long) big[j + 7] & 0xFF))); + assertEquals(val, (((long) big[j] << 56) | (((long) big[j + 1] & 0xFFL) << 48) | + (((long) big[j + 2] & 0xFFL) << 40) | (((long) big[j + 3] & 0xFFL) << 32) | + (((long) big[j + 4] & 0xFFL) << 24) | (((long) big[j + 5] & 0xFFL) << 16) | + (((long) big[j + 6] & 0xFFL) << 8) | ((long) big[j + 7] & 0xFF))); } } @Test public void testReadArray_Double_WholeStream() throws Exception { - JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); - assertArrayEquals(new double[] {8.207880399131826E-304d, -5.730900111929792E302d, 1.268802825418157E-279d}, in.readDoubleArray(-1, JBBPByteOrder.BIG_ENDIAN), TestUtils.FLOAT_DELTA); + JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, + 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); + assertArrayEquals( + new double[] {8.207880399131826E-304d, -5.730900111929792E302d, 1.268802825418157E-279d}, + in.readDoubleArray(-1, BIG_ENDIAN), TestUtils.FLOAT_DELTA); assertEquals(24, in.getCounter()); final Random rnd = new Random(1234); @@ -1031,14 +1557,19 @@ public void testReadArray_Double_WholeStream() throws Exception { rnd.nextBytes(buff); in = new JBBPBitInputStream(new ByteArrayInputStream(buff)); - final double[] read = in.readDoubleArray(-1, JBBPByteOrder.BIG_ENDIAN); + final double[] read = in.readDoubleArray(-1, BIG_ENDIAN); assertEquals(buff.length, in.getCounter()); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE, read.length); for (int i = 0; i < read.length; i++) { final double val = read[i]; final int j = i * 8; - assertEquals(val, Double.longBitsToDouble(((long) buff[j] << 56) | (((long) buff[j + 1] & 0xFFL) << 48) | (((long) buff[j + 2] & 0xFFL) << 40) | (((long) buff[j + 3] & 0xFFL) << 32) | (((long) buff[j + 4] & 0xFFL) << 24) | (((long) buff[j + 5] & 0xFFL) << 16) | (((long) buff[j + 6] & 0xFFL) << 8) | ((long) buff[j + 7] & 0xFF)), TestUtils.FLOAT_DELTA); + assertEquals(val, Double.longBitsToDouble( + ((long) buff[j] << 56) | (((long) buff[j + 1] & 0xFFL) << 48) | + (((long) buff[j + 2] & 0xFFL) << 40) | (((long) buff[j + 3] & 0xFFL) << 32) | + (((long) buff[j + 4] & 0xFFL) << 24) | (((long) buff[j + 5] & 0xFFL) << 16) | + (((long) buff[j + 6] & 0xFFL) << 8) | ((long) buff[j + 7] & 0xFF)), + TestUtils.FLOAT_DELTA); } final byte[] big = new byte[JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 128]; @@ -1046,49 +1577,66 @@ public void testReadArray_Double_WholeStream() throws Exception { in = new JBBPBitInputStream(new ByteArrayInputStream(big)); - final double[] readbig = in.readDoubleArray(-1, JBBPByteOrder.BIG_ENDIAN); + final double[] readbig = in.readDoubleArray(-1, BIG_ENDIAN); assertEquals(JBBPBitInputStream.INITIAL_ARRAY_BUFFER_SIZE * 16, readbig.length); for (int i = 0; i < readbig.length; i++) { final double val = readbig[i]; final int j = i * 8; - assertEquals(val, Double.longBitsToDouble(((long) big[j] << 56) | (((long) big[j + 1] & 0xFFL) << 48) | (((long) big[j + 2] & 0xFFL) << 40) | (((long) big[j + 3] & 0xFFL) << 32) | (((long) big[j + 4] & 0xFFL) << 24) | (((long) big[j + 5] & 0xFFL) << 16) | (((long) big[j + 6] & 0xFFL) << 8) | ((long) big[j + 7] & 0xFF)), TestUtils.FLOAT_DELTA); + assertEquals(val, Double.longBitsToDouble( + ((long) big[j] << 56) | (((long) big[j + 1] & 0xFFL) << 48) | + (((long) big[j + 2] & 0xFFL) << 40) | (((long) big[j + 3] & 0xFFL) << 32) | + (((long) big[j + 4] & 0xFFL) << 24) | (((long) big[j + 5] & 0xFFL) << 16) | + (((long) big[j + 6] & 0xFFL) << 8) | ((long) big[j + 7] & 0xFF)), + TestUtils.FLOAT_DELTA); } } @Test public void testReadArray_Long_TwoItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); - assertArrayEquals(new long[] {0x0102030405060700L, 0xFECABE0102030405L}, in.readLongArray(2, JBBPByteOrder.BIG_ENDIAN)); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, + 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); + assertArrayEquals(new long[] {0x0102030405060700L, 0xFECABE0102030405L}, + in.readLongArray(2, BIG_ENDIAN)); assertEquals(16, in.getCounter()); } @Test public void testReadArray_Double_TwoItems() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); - assertArrayEquals(new double[] {8.207880399131826E-304d, -5.730900111929792E302d}, in.readDoubleArray(2, JBBPByteOrder.BIG_ENDIAN), TestUtils.FLOAT_DELTA); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, + 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); + assertArrayEquals(new double[] {8.207880399131826E-304d, -5.730900111929792E302d}, + in.readDoubleArray(2, BIG_ENDIAN), TestUtils.FLOAT_DELTA); assertEquals(16, in.getCounter()); } @Test public void testReadArray_Long_EOF() throws Exception { assertThrows(EOFException.class, () -> { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); - in.readLongArray(259, JBBPByteOrder.BIG_ENDIAN); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, + 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); + in.readLongArray(259, BIG_ENDIAN); }); } @Test public void testReadArray_Double_EOF() throws Exception { assertThrows(EOFException.class, () -> { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); - in.readDoubleArray(259, JBBPByteOrder.BIG_ENDIAN); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, + 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); + in.readDoubleArray(259, BIG_ENDIAN); }); } @Test public void testResetCounter_ForStartOfStream() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, + 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); in.resetCounter(); assertEquals(1, in.readByte()); assertEquals(1, in.getCounter()); @@ -1096,8 +1644,10 @@ public void testResetCounter_ForStartOfStream() throws Exception { @Test public void testResetCounter_ForCachedBits() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); - assertEquals(1, in.readBits(JBBPBitNumber.BITS_3)); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 0, (byte) 0xFE, (byte) 0xCA, (byte) 0xBE, (byte) 0x01, 2, + 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4})); + assertEquals(1, in.readBits(BITS_3)); assertEquals(0, in.getCounter()); assertTrue(in.getBufferedBitsNumber() != 0); in.resetCounter(); @@ -1128,40 +1678,99 @@ public void testReadBooleanArray_WholeStream() throws Exception { assertEquals(testarray.length, read.length); for (int i = 0; i < read.length; i++) { - assertTrue(read[i] == (testarray[i] != 0)); + assertEquals(read[i], (testarray[i] != 0)); } } @Test - public void testReadNotFullByteArrayAfterBitReading() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xDD})); - assertEquals(0x2, in.readBits(JBBPBitNumber.BITS_4)); + public void testReadNotFullByteArrayAfterBitReading_disableAccumulatedBitsOnEof() + throws Exception { + final JBBPBitInputStream in = new JBBPBitInputStream( + new ByteArrayInputStream(str2bin("00010010_00110100_01010110_11011101")), false); + assertEquals(0x2, in.readBits(BITS_4)); + assertEquals(0, in.getCounter()); + + final byte[] readArray = new byte[6]; + assertFalse(in.isDetectedPartlyReadBitField()); + final int read = in.read(readArray, 0, readArray.length); + assertTrue(in.isDetectedPartlyReadBitField()); + assertEquals(3, read); + assertEquals(4, in.getCounter()); + + assertEquals(0b01000001, readArray[0] & 0xFF, bin2str(readArray)); + assertEquals(0b01100011, readArray[1] & 0xFF, bin2str(readArray)); + assertEquals(0b11010101, readArray[2] & 0xFF, bin2str(readArray)); + assertEquals(0, readArray[3], bin2str(readArray)); + assertEquals(0, readArray[4], bin2str(readArray)); + assertEquals(0, readArray[5], bin2str(readArray)); + } + + @Test + public void testReadNotFullByteArrayAfterBitReading_MSB0_disableAccumulatedBitsOnEof() + throws Exception { + final JBBPBitInputStream in = new JBBPBitInputStream( + new ByteArrayInputStream(str2bin("00010010_00110100_01010110_11011101")), + JBBPBitOrder.MSB0, false); + assertEquals(0x8, in.readBits(BITS_4)); + assertEquals(0, in.getCounter()); + + final byte[] readArray = new byte[6]; + assertFalse(in.isDetectedPartlyReadBitField()); + final int read = in.read(readArray, 0, readArray.length); + assertTrue(in.isDetectedPartlyReadBitField()); + assertEquals(3, read); + assertEquals(4, in.getCounter()); + + assertEquals(0b11000100, readArray[0] & 0xFF, bin2str(readArray)); + assertEquals(0b10100010, readArray[1] & 0xFF, bin2str(readArray)); + assertEquals(0b10110110, readArray[2] & 0xFF, bin2str(readArray)); + assertEquals(0, readArray[3], bin2str(readArray)); + assertEquals(0, readArray[4], bin2str(readArray)); + assertEquals(0, readArray[5], bin2str(readArray)); + } + + @Test + public void testReadNotFullByteArrayAfterBitReading() + throws Exception { + final JBBPBitInputStream in = new JBBPBitInputStream( + new ByteArrayInputStream(new byte[] {(byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xDD})); + assertEquals(0x2, in.readBits(BITS_4)); assertEquals(0, in.getCounter()); final byte[] readarray = new byte[6]; - final int read = in.read(readarray, 0, readarray.length); + assertFalse(in.isDetectedPartlyReadBitField()); + final int read = in.read(readarray, 0, readarray.length, true); + assertTrue(in.isDetectedPartlyReadBitField()); assertEquals(4, read); assertEquals(4, in.getCounter()); - assertArrayEquals(new byte[] {(byte) 0x41, (byte) 0x63, (byte) 0xD5, (byte) 0x0D, 0, 0}, readarray); + assertArrayEquals(new byte[] {(byte) 0x41, (byte) 0x63, (byte) 0xD5, (byte) 0x0D, 0, 0}, + readarray); } @Test - public void testReadNotFullByteArrayAfterBitReading_MSB0() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {(byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xDD}), JBBPBitOrder.MSB0); - assertEquals(0x8, in.readBits(JBBPBitNumber.BITS_4)); + public void testReadNotFullByteArrayAfterBitReading_MSB0() + throws Exception { + final JBBPBitInputStream in = new JBBPBitInputStream( + new ByteArrayInputStream(new byte[] {(byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0xDD}), + JBBPBitOrder.MSB0); + assertEquals(0x8, in.readBits(BITS_4)); final byte[] readarray = new byte[6]; + assertFalse(in.isDetectedPartlyReadBitField()); final int read = in.read(readarray, 0, readarray.length); - + assertTrue(in.isDetectedPartlyReadBitField()); assertEquals(4, read); assertEquals(4, in.getCounter()); - assertArrayEquals(new byte[] {(byte) 0xC4, (byte) 0xA2, (byte) 0xB6, (byte) 0x0B, 0, 0}, readarray); + assertArrayEquals(new byte[] {(byte) 0xC4, (byte) 0xA2, (byte) 0xB6, (byte) 0x0B, 0, 0}, + readarray); } + @Test public void testCheckThatCounterResetDoesntResetFullBitBuffer() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 0x7F})); + final JBBPBitInputStream in = + new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 0x7F})); assertEquals(0, in.getBufferedBitsNumber()); assertTrue(in.hasAvailableData()); assertEquals(0, in.getCounter()); @@ -1169,7 +1778,7 @@ public void testCheckThatCounterResetDoesntResetFullBitBuffer() throws Exception in.resetCounter(); assertEquals(0, in.getCounter()); assertEquals(8, in.getBufferedBitsNumber()); - assertEquals(1, in.readBits(JBBPBitNumber.BITS_1)); + assertEquals(1, in.readBits(BITS_1)); assertEquals(7, in.getBufferedBitsNumber()); assertEquals(0, in.getCounter()); in.resetCounter(); @@ -1182,73 +1791,79 @@ public void testCheckThatCounterResetDoesntResetFullBitBuffer() throws Exception @Test public void testByteCounterWithHasAvailableData() throws Exception { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})); + final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream( + new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})); assertTrue(in.hasAvailableData()); assertEquals(0, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(0, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(0, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(0, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(0, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(0, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(0, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(0, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(1, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(1, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(1, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(1, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(1, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(1, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(1, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(1, in.getCounter()); - assertTrue(in.readBits(JBBPBitNumber.BITS_1) >= 0); + assertTrue(in.readBits(BITS_1) >= 0); assertTrue(in.hasAvailableData()); assertEquals(2, in.getCounter()); } + @FunctionalInterface + private interface StreamAndIntSupplier { + Pair getData() throws Exception; + } + } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStreamTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStreamTest.java index 57e2a6b0..03aed720 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStreamTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPBitOutputStreamTest.java @@ -16,20 +16,29 @@ package com.igormaznitsa.jbbp.io; -import com.igormaznitsa.jbbp.utils.JBBPUtils; -import com.igormaznitsa.jbbp.utils.SpecialTestUtils; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_2; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_3; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_4; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_5; +import static com.igormaznitsa.jbbp.io.JBBPBitNumber.BITS_8; +import static com.igormaznitsa.jbbp.utils.JBBPUtils.array2bin; +import static com.igormaznitsa.jbbp.utils.JBBPUtils.array2hex; +import static com.igormaznitsa.jbbp.utils.JBBPUtils.str2bin; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import com.igormaznitsa.jbbp.utils.SpecialTestUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Random; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPBitOutputStreamTest { - private static byte[] writeString(final JBBPByteOrder order, final String str) throws IOException { + private static byte[] writeString(final JBBPByteOrder order, final String str) + throws IOException { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final JBBPBitOutputStream out = new JBBPBitOutputStream(bos); out.writeString(str, order); @@ -37,7 +46,8 @@ private static byte[] writeString(final JBBPByteOrder order, final String str) t return bos.toByteArray(); } - private static byte[] writeStrings(final JBBPByteOrder order, final String... array) throws IOException { + private static byte[] writeStrings(final JBBPByteOrder order, final String... array) + throws IOException { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final JBBPBitOutputStream out = new JBBPBitOutputStream(bos); out.writeStringArray(array, order); @@ -52,10 +62,10 @@ public void testResetCounter_BitBufferEmpty() throws Exception { assertEquals(0L, out.getCounter()); out.write(1); - assertTrue(out.getBufferedBitsNumber() == 0); + assertEquals(0, out.getBufferedBitsNumber()); assertEquals(1L, out.getCounter()); out.resetCounter(); - assertTrue(out.getBufferedBitsNumber() == 0); + assertEquals(0, out.getBufferedBitsNumber()); assertEquals(0L, out.getCounter()); } @@ -70,7 +80,7 @@ public void testResetCounter_BitBufferNotEmpty() throws Exception { assertTrue(out.getBufferedBitsNumber() > 0); assertEquals(1L, out.getCounter()); out.resetCounter(); - assertTrue(out.getBufferedBitsNumber() == 0); + assertEquals(0, out.getBufferedBitsNumber()); assertEquals(0L, out.getCounter()); out.write(2); out.close(); @@ -98,198 +108,279 @@ public void testGetOrder() throws Exception { @Test public void testWriteBytes_BIG_ENDIAN_wholeArray() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeBytes(new byte[] {1, 2, 3, 4, 5}, -1, JBBPByteOrder.BIG_ENDIAN); out.flush(); assertEquals(5, out.getCounter()); - assertArrayEquals(new byte[] {1, 2, 3, 4, 5}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5}, outBuffer.toByteArray()); } @Test public void testWriteBytes_BIG_ENDIAN_zeroArray() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeBytes(new byte[] {1, 2, 3, 4, 5}, 0, JBBPByteOrder.BIG_ENDIAN); out.flush(); assertEquals(0, out.getCounter()); - assertArrayEquals(new byte[0], outBiuffer.toByteArray()); + assertArrayEquals(new byte[0], outBuffer.toByteArray()); } @Test public void testWriteBytes_BIG_ENDIAN_threeItemsOfArray() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeBytes(new byte[] {1, 2, 3, 4, 5}, 3, JBBPByteOrder.BIG_ENDIAN); out.flush(); assertEquals(3, out.getCounter()); - assertArrayEquals(new byte[] {1, 2, 3}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {1, 2, 3}, outBuffer.toByteArray()); } @Test public void testWriteBytes_LITTLE_ENDIAN_threeItemsOfArray() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeBytes(new byte[] {1, 2, 3, 4, 5}, 3, JBBPByteOrder.LITTLE_ENDIAN); out.flush(); assertEquals(3, out.getCounter()); - assertArrayEquals(new byte[] {3, 2, 1}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {3, 2, 1}, outBuffer.toByteArray()); } @Test public void testWriteBytes_LITTLE_ENDIAN_zeroArray() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeBytes(new byte[] {1, 2, 3, 4, 5}, 0, JBBPByteOrder.LITTLE_ENDIAN); out.flush(); assertEquals(0, out.getCounter()); - assertArrayEquals(new byte[0], outBiuffer.toByteArray()); + assertArrayEquals(new byte[0], outBuffer.toByteArray()); } @Test public void testWriteBytes_LITTLE_ENDIAN_wholeArray() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeBytes(new byte[] {1, 2, 3, 4, 5}, -1, JBBPByteOrder.LITTLE_ENDIAN); out.flush(); assertEquals(5, out.getCounter()); - assertArrayEquals(new byte[] {5, 4, 3, 2, 1}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {5, 4, 3, 2, 1}, outBuffer.toByteArray()); } @Test public void testWriteByte() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.write(0x12); assertEquals(1, out.getCounter()); out.flush(); assertEquals(1, out.getCounter()); - assertArrayEquals(new byte[] {0x12}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {0x12}, outBuffer.toByteArray()); } @Test public void testWriteByte_MSB0() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer, JBBPBitOrder.MSB0); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer, JBBPBitOrder.MSB0); assertEquals(0, out.getCounter()); out.write(0x12); assertEquals(1, out.getCounter()); out.flush(); assertEquals(1, out.getCounter()); - assertArrayEquals(new byte[] {0x48}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {0x48}, outBuffer.toByteArray()); + } + + @Test + public void testWriteByte_MSB0DIRECT() throws Exception { + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer, JBBPBitOrder.MSB0_DIRECT); + assertEquals(0, out.getCounter()); + out.write(0b1100_1110); + assertEquals(1, out.getCounter()); + out.flush(); + assertEquals(1, out.getCounter()); + assertArrayEquals(new byte[] {(byte) 0b1100_1110}, outBuffer.toByteArray()); } @Test public void testWriteShort_BigEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeShort(0x1234, JBBPByteOrder.BIG_ENDIAN); assertEquals(2, out.getCounter()); out.flush(); assertEquals(2, out.getCounter()); - assertArrayEquals(new byte[] {0x12, 0x34}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {0x12, 0x34}, outBuffer.toByteArray()); } @Test public void testWriteShort_BigEndian_MSB0() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer, JBBPBitOrder.MSB0); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer, JBBPBitOrder.MSB0); assertEquals(0, out.getCounter()); out.writeShort(0x1234, JBBPByteOrder.BIG_ENDIAN); assertEquals(2, out.getCounter()); out.flush(); assertEquals(2, out.getCounter()); - assertArrayEquals(new byte[] {0x48, 0x2C}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {0x48, 0x2C}, outBuffer.toByteArray()); + } + + @Test + public void testWrite_MSB0DIRECT() throws Exception { + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer, JBBPBitOrder.MSB0_DIRECT); + assertEquals(0, out.getCounter()); + + out.writeBits(1, BITS_8); + out.writeBits(5, BITS_3); + out.writeBits(8, BITS_8); + out.writeBits(0, BITS_5); + out.writeBits(1, BITS_2); + out.writeBits(0, BITS_2); + out.writeBits(11, BITS_4); + out.writeBits(0, BITS_5); + out.writeBits(0, BITS_3); + + out.flush(); + final byte[] result = outBuffer.toByteArray(); + + assertArrayEquals(str2bin("00000001_101_00001000_00000_01_00_1011_00000"), result, + array2bin(result)); + } + + @Test + public void testWriteShort_BigEndian_MSB0DIRECT() throws Exception { + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer, JBBPBitOrder.MSB0_DIRECT); + assertEquals(0, out.getCounter()); + out.writeShort(0b11010101_01101110, JBBPByteOrder.BIG_ENDIAN); + assertEquals(2, out.getCounter()); + out.flush(); + assertEquals(2, out.getCounter()); + final byte[] result = outBuffer.toByteArray(); + assertArrayEquals(new byte[] {(byte) 0b11010101, (byte) 0b01101110}, result, + array2bin(result)); + } + + @Test + public void testWriteShort_LittleEndian_MSB0DIRECT() throws Exception { + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer, JBBPBitOrder.MSB0_DIRECT); + assertEquals(0, out.getCounter()); + out.writeShort(0b11010101_01101110, JBBPByteOrder.LITTLE_ENDIAN); + assertEquals(2, out.getCounter()); + out.flush(); + assertEquals(2, out.getCounter()); + final byte[] result = outBuffer.toByteArray(); + assertArrayEquals(new byte[] {(byte) 0b01101110, (byte) 0b11010101}, result, + array2bin(result)); } @Test public void testWriteShort_LittleEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeShort(0x1234, JBBPByteOrder.LITTLE_ENDIAN); assertEquals(2, out.getCounter()); out.flush(); assertEquals(2, out.getCounter()); - assertArrayEquals(new byte[] {0x34, 0x12}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {0x34, 0x12}, outBuffer.toByteArray()); } @Test public void testWriteShort_LittleEndian_MSB0() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer, JBBPBitOrder.MSB0); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer, JBBPBitOrder.MSB0); assertEquals(0, out.getCounter()); out.writeShort(0x1234, JBBPByteOrder.LITTLE_ENDIAN); assertEquals(2, out.getCounter()); out.flush(); assertEquals(2, out.getCounter()); - assertArrayEquals(new byte[] {0x2C, 0x48}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {0x2C, 0x48}, outBuffer.toByteArray()); } @Test public void testWriteInt_BigEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeInt(0x12345678, JBBPByteOrder.BIG_ENDIAN); assertEquals(4, out.getCounter()); out.flush(); assertEquals(4, out.getCounter()); - assertArrayEquals(new byte[] {0x12, 0x34, 0x56, 0x78}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {0x12, 0x34, 0x56, 0x78}, outBuffer.toByteArray()); + } + + @Test + public void testWriteUInt_BigEndian() throws Exception { + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); + assertEquals(0, out.getCounter()); + out.writeUInt(0xF1E2B3C4, JBBPByteOrder.BIG_ENDIAN); + assertEquals(4, out.getCounter()); + out.flush(); + assertEquals(4, out.getCounter()); + final byte[] result = outBuffer.toByteArray(); + assertArrayEquals(new byte[] {(byte) 0xF1, (byte) 0xE2, (byte) 0xB3, (byte) 0xC4}, result, + array2hex(result)); } @Test public void testWriteFloat_BigEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeFloat(9.2345f, JBBPByteOrder.BIG_ENDIAN); assertEquals(4, out.getCounter()); out.flush(); assertEquals(4, out.getCounter()); - assertArrayEquals(new byte[] {(byte) 65, (byte) 19, (byte) -64, (byte) -125}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {(byte) 65, (byte) 19, (byte) -64, (byte) -125}, + outBuffer.toByteArray()); } @Test public void testWriteInt_LittleEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeInt(0x12345678, JBBPByteOrder.LITTLE_ENDIAN); assertEquals(4, out.getCounter()); out.flush(); assertEquals(4, out.getCounter()); - assertArrayEquals(new byte[] {0x78, 0x56, 0x34, 0x12}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {0x78, 0x56, 0x34, 0x12}, outBuffer.toByteArray()); } @Test public void testWriteFloat_LittleEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeFloat(9.2345f, JBBPByteOrder.LITTLE_ENDIAN); assertEquals(4, out.getCounter()); out.flush(); assertEquals(4, out.getCounter()); - assertArrayEquals(new byte[] {(byte) -125, (byte) -64, (byte) 19, (byte) 65}, outBiuffer.toByteArray()); + assertArrayEquals(new byte[] {(byte) -125, (byte) -64, (byte) 19, (byte) 65}, + outBuffer.toByteArray()); } @Test public void testWriteStringArray_BigEndian() throws Exception { - assertArrayEquals(new byte[] {(byte) 0xFF, 0, 0x03, 65, 66, 67}, writeStrings(JBBPByteOrder.BIG_ENDIAN, null, "", "ABC")); + assertArrayEquals(new byte[] {(byte) 0xFF, 0, 0x03, 65, 66, 67}, + writeStrings(JBBPByteOrder.BIG_ENDIAN, null, "", "ABC")); } @Test public void testWriteStringArray_LittleEndian() throws Exception { - assertArrayEquals(new byte[] {(byte) 0xFF, 0, 0x03, 65, 66, 67}, writeStrings(JBBPByteOrder.LITTLE_ENDIAN, null, "", "ABC")); + assertArrayEquals(new byte[] {(byte) 0xFF, 0, 0x03, 65, 66, 67}, + writeStrings(JBBPByteOrder.LITTLE_ENDIAN, null, "", "ABC")); } @Test @@ -319,55 +410,64 @@ public void testWriteString_LittleEndian_Empty() throws Exception { @Test public void testWriteString_LittleEndian_ShortString() throws Exception { - assertArrayEquals(new byte[] {0x03, 65, 66, 67}, writeString(JBBPByteOrder.LITTLE_ENDIAN, "ABC")); + assertArrayEquals(new byte[] {0x03, 65, 66, 67}, + writeString(JBBPByteOrder.LITTLE_ENDIAN, "ABC")); } @Test public void testWriteLong_BigEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeLong(0x12345678AABBCCDDL, JBBPByteOrder.BIG_ENDIAN); assertEquals(8, out.getCounter()); out.flush(); assertEquals(8, out.getCounter()); - assertArrayEquals(new byte[] {0x12, 0x34, 0x56, 0x78, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD}, outBiuffer.toByteArray()); + assertArrayEquals( + new byte[] {0x12, 0x34, 0x56, 0x78, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD}, + outBuffer.toByteArray()); } @Test public void testWriteDouble_BigEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeDouble(1.12345678234324d, JBBPByteOrder.BIG_ENDIAN); assertEquals(8, out.getCounter()); out.flush(); assertEquals(8, out.getCounter()); - assertArrayEquals(new byte[] {(byte) 63, (byte) -15, (byte) -7, (byte) -83, (byte) -47, (byte) -86, (byte) 35, (byte) 64}, outBiuffer.toByteArray()); + assertArrayEquals( + new byte[] {(byte) 63, (byte) -15, (byte) -7, (byte) -83, (byte) -47, (byte) -86, (byte) 35, + (byte) 64}, outBuffer.toByteArray()); } @Test public void testWriteLong_LittleEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeLong(0x12345678AABBCCDDL, JBBPByteOrder.LITTLE_ENDIAN); assertEquals(8, out.getCounter()); out.flush(); assertEquals(8, out.getCounter()); - assertArrayEquals(new byte[] {(byte) 0xDD, (byte) 0xCC, (byte) 0XBB, (byte) 0xAA, 0x78, 0x56, 0x34, 0x12}, outBiuffer.toByteArray()); + assertArrayEquals( + new byte[] {(byte) 0xDD, (byte) 0xCC, (byte) 0XBB, (byte) 0xAA, 0x78, 0x56, 0x34, 0x12}, + outBuffer.toByteArray()); } @Test public void testWriteDouble_LittleEndian() throws Exception { - final ByteArrayOutputStream outBiuffer = new ByteArrayOutputStream(); - final JBBPBitOutputStream out = new JBBPBitOutputStream(outBiuffer); + final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); + final JBBPBitOutputStream out = new JBBPBitOutputStream(outBuffer); assertEquals(0, out.getCounter()); out.writeDouble(-23.345213455d, JBBPByteOrder.LITTLE_ENDIAN); assertEquals(8, out.getCounter()); out.flush(); assertEquals(8, out.getCounter()); - assertArrayEquals(new byte[] {(byte) 58, (byte) 93, (byte) -77, (byte) -24, (byte) 95, (byte) 88, (byte) 55, (byte) -64}, outBiuffer.toByteArray()); + assertArrayEquals( + new byte[] {(byte) 58, (byte) 93, (byte) -77, (byte) -24, (byte) 95, (byte) 88, (byte) 55, + (byte) -64}, outBuffer.toByteArray()); } @Test @@ -396,8 +496,11 @@ public void testWriteArrayPartlyWithOffset1Bit() throws Exception { assertEquals(0, out.getCounter()); - final byte[] ORIG_ARRAY = JBBPUtils.str2bin("10101001 01100100 10000101 01000010 10010100 10010010 00100100 10001010", JBBPBitOrder.MSB0); - final byte[] ARRAY_1BIT_OFFSET = JBBPUtils.str2bin("1 10000101 01000010 10010100 10010010 00100100", JBBPBitOrder.MSB0); + final byte[] ORIG_ARRAY = + str2bin("10101001 01100100 10000101 01000010 10010100 10010010 00100100 10001010", + JBBPBitOrder.MSB0); + final byte[] ARRAY_1BIT_OFFSET = + str2bin("1 10000101 01000010 10010100 10010010 00100100", JBBPBitOrder.MSB0); out.writeBits(1, JBBPBitNumber.BITS_1); assertEquals(0, out.getCounter()); @@ -433,7 +536,7 @@ public void testWriteWholeArray() throws Exception { public void testGetBufferedBitsNumber() throws Exception { final JBBPBitOutputStream out = new JBBPBitOutputStream(new ByteArrayOutputStream()); out.writeBits(1, JBBPBitNumber.BITS_1); - out.writeBits(3, JBBPBitNumber.BITS_2); + out.writeBits(3, BITS_2); assertEquals(3, out.getBufferedBitsNumber()); assertEquals(0, out.getCounter()); } @@ -442,24 +545,30 @@ public void testGetBufferedBitsNumber() throws Exception { public void testGetBitBuffer() throws Exception { final JBBPBitOutputStream out = new JBBPBitOutputStream(new ByteArrayOutputStream()); out.writeBits(1, JBBPBitNumber.BITS_1); - out.writeBits(3, JBBPBitNumber.BITS_2); + out.writeBits(3, BITS_2); assertEquals(7, out.getBitBuffer()); assertEquals(0, out.getCounter()); } @Test public void testWriteBit_ErrorForZeroSize() throws Exception { - assertThrows(IllegalArgumentException.class, () -> new JBBPBitOutputStream(new ByteArrayOutputStream()).writeBits(4, JBBPBitNumber.decode(0))); + assertThrows(IllegalArgumentException.class, + () -> new JBBPBitOutputStream(new ByteArrayOutputStream()) + .writeBits(4, JBBPBitNumber.decode(0))); } @Test public void testWriteBit_ErrorForNegativeSize() throws Exception { - assertThrows(IllegalArgumentException.class, () -> new JBBPBitOutputStream(new ByteArrayOutputStream()).writeBits(4, JBBPBitNumber.decode(-1))); + assertThrows(IllegalArgumentException.class, + () -> new JBBPBitOutputStream(new ByteArrayOutputStream()) + .writeBits(4, JBBPBitNumber.decode(-1))); } @Test public void testWriteBit_ErrorForTooBigSize() throws Exception { - assertThrows(IllegalArgumentException.class, () -> new JBBPBitOutputStream(new ByteArrayOutputStream()).writeBits(4, JBBPBitNumber.decode(9))); + assertThrows(IllegalArgumentException.class, + () -> new JBBPBitOutputStream(new ByteArrayOutputStream()) + .writeBits(4, JBBPBitNumber.decode(9))); } @Test @@ -467,8 +576,12 @@ public void testWriteWholeArrayWith1Bit() throws Exception { final ByteArrayOutputStream buff = new ByteArrayOutputStream(); final JBBPBitOutputStream out = new JBBPBitOutputStream(buff); - final byte[] ORIG_ARRAY = JBBPUtils.str2bin("10101001 01100100 10000101 01000010 10010100 10010010 00100100 10001010", JBBPBitOrder.MSB0); - final byte[] ORIG_ARRAY_1BIT_OFFSET = JBBPUtils.str2bin("1 10101001 01100100 10000101 01000010 10010100 10010010 00100100 10001010", JBBPBitOrder.MSB0); + final byte[] ORIG_ARRAY = + str2bin("10101001 01100100 10000101 01000010 10010100 10010010 00100100 10001010", + JBBPBitOrder.MSB0); + final byte[] ORIG_ARRAY_1BIT_OFFSET = + str2bin("1 10101001 01100100 10000101 01000010 10010100 10010010 00100100 10001010", + JBBPBitOrder.MSB0); out.writeBits(1, JBBPBitNumber.BITS_1); out.write(ORIG_ARRAY); @@ -532,7 +645,7 @@ public void testWrite() throws Exception { for (int i = 0; i < 256; ) { out.write(i++); - out.writeBits(i++, JBBPBitNumber.BITS_8); + out.writeBits(i++, BITS_8); } assertEquals(256, out.getCounter()); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPOutTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPOutTest.java index 7b069b0a..12b2efa1 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPOutTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPOutTest.java @@ -23,15 +23,14 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; - import com.igormaznitsa.jbbp.exceptions.JBBPIllegalArgumentException; import com.igormaznitsa.jbbp.mapper.Bin; import com.igormaznitsa.jbbp.mapper.BinType; import com.igormaznitsa.jbbp.model.JBBPFieldInt; import com.igormaznitsa.jbbp.model.JBBPFieldLong; +import com.igormaznitsa.jbbp.utils.BinAnnotationWrapper; import com.igormaznitsa.jbbp.utils.JBBPUtils; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; @@ -45,36 +44,54 @@ public void testString() throws Exception { assertArrayEquals(new byte[] {0}, BeginBin().String("").End().toByteArray()); assertArrayEquals(new byte[] {3, 65, 66, 67}, BeginBin().String("ABC").End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0xFF}, BeginBin(JBBPBitOrder.LSB0).String(null).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xFF}, + BeginBin(JBBPBitOrder.LSB0).String(null).End().toByteArray()); assertArrayEquals(new byte[] {0}, BeginBin(JBBPBitOrder.LSB0).String("").End().toByteArray()); - assertArrayEquals(new byte[] {3, 65, 66, 67}, BeginBin(JBBPBitOrder.LSB0).String("ABC").End().toByteArray()); + assertArrayEquals(new byte[] {3, 65, 66, 67}, + BeginBin(JBBPBitOrder.LSB0).String("ABC").End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0xFF}, BeginBin(JBBPBitOrder.MSB0).String(null).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xFF}, + BeginBin(JBBPBitOrder.MSB0).String(null).End().toByteArray()); assertArrayEquals(new byte[] {0}, BeginBin(JBBPBitOrder.MSB0).String("").End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0xc0, (byte) 0x82, (byte) 0x42, (byte) 0xC2}, BeginBin(JBBPBitOrder.MSB0).String("ABC").End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xc0, (byte) 0x82, (byte) 0x42, (byte) 0xC2}, + BeginBin(JBBPBitOrder.MSB0).String("ABC").End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0xFF}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).String(null).End().toByteArray()); - assertArrayEquals(new byte[] {0}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).String("").End().toByteArray()); - assertArrayEquals(new byte[] {3, 65, 66, 67}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).String("ABC").End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xFF}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).String(null).End().toByteArray()); + assertArrayEquals(new byte[] {0}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).String("").End().toByteArray()); + assertArrayEquals(new byte[] {3, 65, 66, 67}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).String("ABC").End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0xFF}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).String(null).End().toByteArray()); - assertArrayEquals(new byte[] {0}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).String("").End().toByteArray()); - assertArrayEquals(new byte[] {3, 65, 66, 67}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).String("ABC").End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xFF}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).String(null).End().toByteArray()); + assertArrayEquals(new byte[] {0}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).String("").End().toByteArray()); + assertArrayEquals(new byte[] {3, 65, 66, 67}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).String("ABC").End().toByteArray()); } @Test public void testStrings() throws Exception { - assertArrayEquals(new byte[] {(byte)0x03, 65, 66, 67, (byte)0x00, (byte)0xFF, 3, 48, 49, 50}, BeginBin().Strings("ABC", "", null, "012").End().toByteArray()); - assertArrayEquals(new byte[] {(byte)0x03, 65, 66, 67, (byte)0x00, (byte)0xFF, 3, 48, 49, 50}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Strings("ABC", "", null, "012").End().toByteArray()); - assertArrayEquals(new byte[] {(byte)0x03, 65, 66, 67, (byte)0x00, (byte)0xFF, 3, 48, 49, 50}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Strings("ABC", "", null, "012").End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x03, 65, 66, 67, (byte) 0x00, (byte) 0xFF, 3, 48, 49, 50}, + BeginBin().Strings("ABC", "", null, "012").End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x03, 65, 66, 67, (byte) 0x00, (byte) 0xFF, 3, 48, 49, 50}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Strings("ABC", "", null, "012").End() + .toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x03, 65, 66, 67, (byte) 0x00, (byte) 0xFF, 3, 48, 49, 50}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Strings("ABC", "", null, "012").End() + .toByteArray()); } @Test public void testBeginBin() throws Exception { assertArrayEquals(new byte[] {1}, BeginBin().Byte(1).End().toByteArray()); - assertArrayEquals(new byte[] {0x02, 0x01}, BeginBin(JBBPByteOrder.LITTLE_ENDIAN).Short(0x0102).End().toByteArray()); - assertArrayEquals(new byte[] {0x40, (byte) 0x80}, BeginBin(JBBPByteOrder.LITTLE_ENDIAN, JBBPBitOrder.MSB0).Short(0x0102).End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0x80}, BeginBin(JBBPBitOrder.MSB0).Byte(1).End().toByteArray()); + assertArrayEquals(new byte[] {0x02, 0x01}, + BeginBin(JBBPByteOrder.LITTLE_ENDIAN).Short(0x0102).End().toByteArray()); + assertArrayEquals(new byte[] {0x40, (byte) 0x80}, + BeginBin(JBBPByteOrder.LITTLE_ENDIAN, JBBPBitOrder.MSB0).Short(0x0102).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x80}, + BeginBin(JBBPBitOrder.MSB0).Byte(1).End().toByteArray()); assertArrayEquals(new byte[] {(byte) 0x80}, BeginBin(1).Byte(0x80).End().toByteArray()); final ByteArrayOutputStream buffer1 = new ByteArrayOutputStream(); @@ -87,9 +104,12 @@ public void testBeginBin() throws Exception { @Test public void testSkip() throws Exception { - assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0xFF}, BeginBin().Bit(1).Skip(0).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0x01, 0x00, (byte) 0xFF}, BeginBin().Bit(1).Skip(1).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0x01, 0x00, 0x00, (byte) 0xFF}, BeginBin().Bit(1).Skip(2).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0xFF}, + BeginBin().Bit(1).Skip(0).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x01, 0x00, (byte) 0xFF}, + BeginBin().Bit(1).Skip(1).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x01, 0x00, 0x00, (byte) 0xFF}, + BeginBin().Bit(1).Skip(2).Byte(0xFF).End().toByteArray()); } @Test @@ -99,12 +119,14 @@ public void testSkip_ErrorForNegativeValue() throws Exception { @Test public void testAlign() throws Exception { - assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0xFF}, BeginBin().Bit(1).Align().Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0xFF}, + BeginBin().Bit(1).Align().Byte(0xFF).End().toByteArray()); } @Test public void testResetCounter() throws Exception { - assertArrayEquals(new byte[] {1, 2, 0, 0, (byte) 0xFF}, BeginBin().Byte(1).ResetCounter().Byte(2).Align(3).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {1, 2, 0, 0, (byte) 0xFF}, + BeginBin().Byte(1).ResetCounter().Byte(2).Align(3).Byte(0xFF).End().toByteArray()); } @Test @@ -135,20 +157,37 @@ public void testGetByteCounter() throws Exception { @Test public void testAlignWithArgument() throws Exception { assertEquals(0, BeginBin().Align(2).End().toByteArray().length); - assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0xFF}, BeginBin().Bit(1).Align(1).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0xFF}, + BeginBin().Bit(1).Align(1).Byte(0xFF).End().toByteArray()); assertArrayEquals(new byte[] {(byte) 0xFF}, BeginBin().Align(3).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {0x01, (byte) 0xFF}, BeginBin().Bit(1).Align(1).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {0x01, 0x00, (byte) 0xFF}, BeginBin().Bit(1).Align(2).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {0x01, 0x00, 0x00, 0x00, (byte) 0xFF}, BeginBin().Bit(1).Align(4).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {0x01, 0x02, 0x00, 0x00, (byte) 0xFF}, BeginBin().Byte(1, 2).Align(4).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x00, 0x00, (byte) 0xFF}, BeginBin().Byte(1, 2, 3).Align(5).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x00, (byte) 0xFF}, BeginBin().Byte(1, 2, 3, 4).Align(5).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, (byte) 0xFF}, BeginBin().Byte(1, 2, 3, 4, 5).Align(5).Byte(0xFF).End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0x01, 0x00, 0x02, 0x00, (byte) 0x03}, BeginBin().Align(2).Byte(1).Align(2).Byte(2).Align(2).Byte(3).End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0xF1, 0x00, (byte) 0x01, 0x00, 0x02, 0x00, (byte) 0x03}, BeginBin().Byte(0xF1).Align(2).Byte(1).Align(2).Byte(2).Align(2).Byte(3).End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0xF1, 0x00, 0x00, (byte) 0x01, 0x00, 0x00, 0x02, 0x00, 00, (byte) 0x03}, BeginBin().Byte(0xF1).Align(3).Byte(1).Align(3).Byte(2).Align(3).Byte(3).End().toByteArray()); - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x00, (byte) 0xF1}, BeginBin().Int(0x01020304).Align(5).Byte(0xF1).End().toByteArray()); - assertArrayEquals(new byte[] {0x01, 0x00, 0x00, 0x00, 0x00, (byte) 0xF1}, BeginBin().Bit(1).Align(5).Byte(0xF1).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, (byte) 0xFF}, + BeginBin().Bit(1).Align(1).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x00, (byte) 0xFF}, + BeginBin().Bit(1).Align(2).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x00, 0x00, 0x00, (byte) 0xFF}, + BeginBin().Bit(1).Align(4).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x00, 0x00, (byte) 0xFF}, + BeginBin().Byte(1, 2).Align(4).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x00, 0x00, (byte) 0xFF}, + BeginBin().Byte(1, 2, 3).Align(5).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x00, (byte) 0xFF}, + BeginBin().Byte(1, 2, 3, 4).Align(5).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, (byte) 0xFF}, + BeginBin().Byte(1, 2, 3, 4, 5).Align(5).Byte(0xFF).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x01, 0x00, 0x02, 0x00, (byte) 0x03}, + BeginBin().Align(2).Byte(1).Align(2).Byte(2).Align(2).Byte(3).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xF1, 0x00, (byte) 0x01, 0x00, 0x02, 0x00, (byte) 0x03}, + BeginBin().Byte(0xF1).Align(2).Byte(1).Align(2).Byte(2).Align(2).Byte(3).End() + .toByteArray()); + assertArrayEquals( + new byte[] {(byte) 0xF1, 0x00, 0x00, (byte) 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, + (byte) 0x03}, + BeginBin().Byte(0xF1).Align(3).Byte(1).Align(3).Byte(2).Align(3).Byte(3).End() + .toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x00, (byte) 0xF1}, + BeginBin().Int(0x01020304).Align(5).Byte(0xF1).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x00, 0x00, 0x00, 0x00, (byte) 0xF1}, + BeginBin().Bit(1).Align(5).Byte(0xF1).End().toByteArray()); } @Test @@ -163,32 +202,39 @@ public void testByte() throws Exception { @Test public void testByteArrayAsInts() throws Exception { - assertArrayEquals(new byte[] {1, 3, 0, 2, 4, 1, 3, 7}, BeginBin().Byte(1, 3, 0, 2, 4, 1, 3, 7).End().toByteArray()); + assertArrayEquals(new byte[] {1, 3, 0, 2, 4, 1, 3, 7}, + BeginBin().Byte(1, 3, 0, 2, 4, 1, 3, 7).End().toByteArray()); } @Test public void testByteArrayAsByteArray() throws Exception { - assertArrayEquals(new byte[] {1, 3, 0, 2, 4, 1, 3, 7}, BeginBin().Byte(new byte[] {1, 3, 0, 2, 4, 1, 3, 7}).End().toByteArray()); + assertArrayEquals(new byte[] {1, 3, 0, 2, 4, 1, 3, 7}, + BeginBin().Byte(new byte[] {1, 3, 0, 2, 4, 1, 3, 7}).End().toByteArray()); } @Test public void testByteArrayAsString() throws Exception { - assertArrayEquals(new byte[] {(byte) 'a', (byte) 'b', (byte) 'c'}, BeginBin().Byte("abc").End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 'a', (byte) 'b', (byte) 'c'}, + BeginBin().Byte("abc").End().toByteArray()); } @Test public void testByteArrayAsString_RussianChars() throws Exception { - assertArrayEquals(new byte[] {(byte) 0x20, (byte) 0x43, (byte) 0x41}, BeginBin().Byte("Рус").End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x20, (byte) 0x43, (byte) 0x41}, + BeginBin().Byte("Рус").End().toByteArray()); } @Test public void testUtf8_OnlyLatinChars() throws Exception { - assertArrayEquals(new byte[] {(byte) 'a', (byte) 'b', (byte) 'c'}, BeginBin().Utf8("abc").End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 'a', (byte) 'b', (byte) 'c'}, + BeginBin().Utf8("abc").End().toByteArray()); } @Test public void testUtf8_RussianChars() throws Exception { - assertArrayEquals(new byte[] {(byte) 0xD0, (byte) 0xA0, (byte) 0xD1, (byte) 0x83, (byte) 0xD1, (byte) 0x81}, BeginBin().Utf8("Рус").End().toByteArray()); + assertArrayEquals( + new byte[] {(byte) 0xD0, (byte) 0xA0, (byte) 0xD1, (byte) 0x83, (byte) 0xD1, (byte) 0x81}, + BeginBin().Utf8("Рус").End().toByteArray()); } @Test @@ -198,45 +244,57 @@ public void testBit() throws Exception { @Test public void testBit_MSB0() throws Exception { - assertArrayEquals(new byte[] {(byte) 0x80}, BeginBin(JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.MSB0).Bit(1).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x80}, + BeginBin(JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.MSB0).Bit(1).End().toByteArray()); } @Test public void testBit_LSB0() throws Exception { - assertArrayEquals(new byte[] {(byte) 0x01}, BeginBin(JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.LSB0).Bit(1).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x01}, + BeginBin(JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.LSB0).Bit(1).End().toByteArray()); } @Test public void testBits_Int() throws Exception { - assertArrayEquals(new byte[] {0xD}, BeginBin().Bits(JBBPBitNumber.BITS_4, 0xFD).End().toByteArray()); + assertArrayEquals(new byte[] {0xD}, + BeginBin().Bits(JBBPBitNumber.BITS_4, 0xFD).End().toByteArray()); } @Test public void testBits_IntArray() throws Exception { - assertArrayEquals(new byte[] {(byte) 0xED}, BeginBin().Bits(JBBPBitNumber.BITS_4, 0xFD, 0xFE).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xED}, + BeginBin().Bits(JBBPBitNumber.BITS_4, 0xFD, 0xFE).End().toByteArray()); } @Test public void testBits_ByteArray() throws Exception { - assertArrayEquals(new byte[] {(byte) 0xED}, BeginBin().Bits(JBBPBitNumber.BITS_4, new byte[] {(byte) 0xFD, (byte) 0x8E}).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xED}, + BeginBin().Bits(JBBPBitNumber.BITS_4, new byte[] {(byte) 0xFD, (byte) 0x8E}).End() + .toByteArray()); } @Test public void testBitArrayAsInts() throws Exception { - assertArrayEquals(new byte[] {(byte) 0xE3}, BeginBin().Bit(1, 3, 0, 2, 4, 1, 3, 7).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xE3}, + BeginBin().Bit(1, 3, 0, 2, 4, 1, 3, 7).End().toByteArray()); assertArrayEquals(new byte[] {(byte) 0x0B}, BeginBin().Bit(1, 3, 0, 7).End().toByteArray()); } @Test public void testBitArrayAsBytes() throws Exception { - assertArrayEquals(new byte[] {(byte) 0xE3}, BeginBin().Bit(new byte[] {(byte) 1, (byte) 3, (byte) 0, (byte) 2, (byte) 4, (byte) 1, (byte) 3, (byte) 7}).End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0x0B}, BeginBin().Bit(new byte[] {(byte) 1, (byte) 3, (byte) 0, (byte) 7}).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xE3}, BeginBin().Bit( + new byte[] {(byte) 1, (byte) 3, (byte) 0, (byte) 2, (byte) 4, (byte) 1, (byte) 3, (byte) 7}) + .End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x0B}, + BeginBin().Bit(new byte[] {(byte) 1, (byte) 3, (byte) 0, (byte) 7}).End().toByteArray()); } @Test public void testBitArrayAsBooleans() throws Exception { - assertArrayEquals(new byte[] {(byte) 0xE3}, BeginBin().Bit(true, true, false, false, false, true, true, true).End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 0x0B}, BeginBin().Bit(true, true, false, true).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xE3}, + BeginBin().Bit(true, true, false, false, false, true, true, true).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x0B}, + BeginBin().Bit(true, true, false, true).End().toByteArray()); } @Test @@ -246,7 +304,8 @@ public void testShort() throws Exception { @Test public void testShort_BigEndian() throws Exception { - assertArrayEquals(new byte[] {0x01, 0x02}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short(0x0102).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short(0x0102).End().toByteArray()); } @Test @@ -256,112 +315,173 @@ public void testShort_String_NPEForNullString() throws Exception { @Test public void testShort_String_BigEndian() throws Exception { - assertArrayEquals(JBBPUtils.str2UnicodeByteArray(JBBPByteOrder.BIG_ENDIAN, "Hello"), BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short("Hello").End().toByteArray()); + assertArrayEquals(JBBPUtils.str2UnicodeByteArray(JBBPByteOrder.BIG_ENDIAN, "Hello"), + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short("Hello").End().toByteArray()); } @Test public void testShort_String_LittleEndian() throws Exception { - assertArrayEquals(JBBPUtils.str2UnicodeByteArray(JBBPByteOrder.LITTLE_ENDIAN, "Hello"), BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Short("Hello").End().toByteArray()); + assertArrayEquals(JBBPUtils.str2UnicodeByteArray(JBBPByteOrder.LITTLE_ENDIAN, "Hello"), + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Short("Hello").End().toByteArray()); } @Test public void testShort_LittleEndian() throws Exception { - assertArrayEquals(new byte[] {0x02, 0x01}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Short(0x0102).End().toByteArray()); + assertArrayEquals(new byte[] {0x02, 0x01}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Short(0x0102).End().toByteArray()); } @Test public void testShortArray_AsIntegers() throws Exception { - assertArrayEquals(new byte[] {1, 2, 3, 4}, BeginBin().Short(0x0102, 0x0304).End().toByteArray()); + assertArrayEquals(new byte[] {1, 2, 3, 4}, + BeginBin().Short(0x0102, 0x0304).End().toByteArray()); } @Test public void testShortArray_AsIntegers_BigEndian() throws Exception { - assertArrayEquals(new byte[] {1, 2, 3, 4}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short(0x0102, 0x0304).End().toByteArray()); + assertArrayEquals(new byte[] {1, 2, 3, 4}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short(0x0102, 0x0304).End().toByteArray()); } @Test public void testShortArray_AsChars_BigEndian() throws Exception { - assertArrayEquals(new byte[] {1, 2, 3, 4}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short(new char[] {0x0102, 0x0304}).End().toByteArray()); + assertArrayEquals(new byte[] {1, 2, 3, 4}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short(new char[] {0x0102, 0x0304}).End() + .toByteArray()); } @Test public void testShortArray_AsIntegers_LittleEndian() throws Exception { - assertArrayEquals(new byte[] {2, 1, 4, 3}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Short(0x0102, 0x0304).End().toByteArray()); + assertArrayEquals(new byte[] {2, 1, 4, 3}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Short(0x0102, 0x0304).End() + .toByteArray()); } @Test public void testShortArray_AsShorts() throws Exception { - assertArrayEquals(new byte[] {1, 2, 3, 4}, BeginBin().Short(new short[] {(short) 0x0102, (short) 0x0304}).End().toByteArray()); + assertArrayEquals(new byte[] {1, 2, 3, 4}, + BeginBin().Short(new short[] {(short) 0x0102, (short) 0x0304}).End().toByteArray()); } @Test public void testShortArray_AsShortArray() throws Exception { - assertArrayEquals(new byte[] {1, 2, 3, 4}, BeginBin().Short(new short[] {(short) 0x0102, (short) 0x0304}).End().toByteArray()); + assertArrayEquals(new byte[] {1, 2, 3, 4}, + BeginBin().Short(new short[] {(short) 0x0102, (short) 0x0304}).End().toByteArray()); } @Test public void testInt() throws Exception { - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04}, BeginBin().Int(0x01020304).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04}, + BeginBin().Int(0x01020304).End().toByteArray()); + } + + @Test + public void testUInt() throws Exception { + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04}, + BeginBin().UInt(0x01020304).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xF1}, + BeginBin().UInt(0xFFFFFFFF1L).End().toByteArray()); } @Test public void testIntArray() throws Exception { - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, BeginBin().Int(0x01020304, 0x05060708).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + BeginBin().Int(0x01020304, 0x05060708).End().toByteArray()); + } + + @Test + public void testUIntArray() throws Exception { + assertArrayEquals(new byte[] {(byte) 0xF1, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + BeginBin().UInt(0x1F1020304L, 0x05060708L).End().toByteArray()); } @Test public void testInt_BigEndian() throws Exception { - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Int(0x01020304).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Int(0x01020304).End().toByteArray()); + } + + @Test + public void testUInt_BigEndian() throws Exception { + assertArrayEquals(new byte[] {(byte) 0xF1, 0x02, 0x03, 0x04}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).UInt(0x1F1020304L).End().toByteArray()); } @Test public void testInt_LittleEndian() throws Exception { - assertArrayEquals(new byte[] {0x04, 0x03, 0x02, 0x01}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Int(0x01020304).End().toByteArray()); + assertArrayEquals(new byte[] {0x04, 0x03, 0x02, 0x01}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Int(0x01020304).End().toByteArray()); + } + + @Test + public void testUInt_LittleEndian() throws Exception { + assertArrayEquals(new byte[] {0x04, 0x03, 0x02, (byte) 0xF1}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).UInt(0x1F1020304L).End().toByteArray()); } @Test public void testFloat_BigEndian() throws Exception { final int flt = Float.floatToIntBits(Float.MAX_VALUE); - assertArrayEquals(new byte[] {(byte) (flt >>> 24), (byte) (flt >>> 16), (byte) (flt >>> 8), (byte) flt}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Float(Float.MAX_VALUE).End().toByteArray()); + assertArrayEquals( + new byte[] {(byte) (flt >>> 24), (byte) (flt >>> 16), (byte) (flt >>> 8), (byte) flt}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Float(Float.MAX_VALUE).End().toByteArray()); } @Test public void testFloat_LittleEndian() throws Exception { final int flt = Float.floatToIntBits(Float.MAX_VALUE); - assertArrayEquals(new byte[] {(byte) flt, (byte) (flt >>> 8), (byte) (flt >>> 16), (byte) (flt >>> 24)}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Float(Float.MAX_VALUE).End().toByteArray()); + assertArrayEquals( + new byte[] {(byte) flt, (byte) (flt >>> 8), (byte) (flt >>> 16), (byte) (flt >>> 24)}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Float(Float.MAX_VALUE).End() + .toByteArray()); } @Test public void testLong() throws Exception { - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, BeginBin().Long(0x0102030405060708L).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + BeginBin().Long(0x0102030405060708L).End().toByteArray()); } @Test public void testLongArray() throws Exception { - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}, BeginBin().Long(0x0102030405060708L, 0x1112131415161718L).End().toByteArray()); + assertArrayEquals( + new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18}, + BeginBin().Long(0x0102030405060708L, 0x1112131415161718L).End().toByteArray()); } @Test public void testLong_BigEndian() throws Exception { - assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Long(0x0102030405060708L).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Long(0x0102030405060708L).End() + .toByteArray()); } @Test public void testLong_LittleEndian() throws Exception { - assertArrayEquals(new byte[] {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Long(0x0102030405060708L).End().toByteArray()); + assertArrayEquals(new byte[] {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Long(0x0102030405060708L).End() + .toByteArray()); } @Test public void testDouble_BigEndian() throws Exception { final long dbl = Double.doubleToLongBits(Double.MAX_VALUE); - final byte[] array = BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Double(Double.MAX_VALUE).End().toByteArray(); - assertArrayEquals(new byte[] {(byte) (dbl >>> 56), (byte) (dbl >>> 48), (byte) (dbl >>> 40), (byte) (dbl >>> 32), (byte) (dbl >>> 24), (byte) (dbl >>> 16), (byte) (dbl >>> 8), (byte) dbl}, array); + final byte[] array = + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Double(Double.MAX_VALUE).End().toByteArray(); + assertArrayEquals(new byte[] {(byte) (dbl >>> 56), (byte) (dbl >>> 48), (byte) (dbl >>> 40), + (byte) (dbl >>> 32), (byte) (dbl >>> 24), (byte) (dbl >>> 16), (byte) (dbl >>> 8), + (byte) dbl}, array); } @Test public void testDouble_LittleEndian() throws Exception { final long dbl = Double.doubleToLongBits(Double.MAX_VALUE); - assertArrayEquals(new byte[] {(byte) dbl, (byte) (dbl >>> 8), (byte) (dbl >>> 16), (byte) (dbl >>> 24), (byte) (dbl >>> 32), (byte) (dbl >>> 40), (byte) (dbl >>> 48), (byte) (dbl >>> 56)}, BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Double(Double.MAX_VALUE).End().toByteArray()); + assertArrayEquals( + new byte[] {(byte) dbl, (byte) (dbl >>> 8), (byte) (dbl >>> 16), (byte) (dbl >>> 24), + (byte) (dbl >>> 32), (byte) (dbl >>> 40), (byte) (dbl >>> 48), (byte) (dbl >>> 56)}, + BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).Double(Double.MAX_VALUE).End() + .toByteArray()); } @Test @@ -556,7 +676,8 @@ public void testExceptionForBitOrderConfilctInCaseOfUsageBitOutputStream() throw final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); final JBBPBitOutputStream bitstream = new JBBPBitOutputStream(buffer, JBBPBitOrder.LSB0); - assertThrows(IllegalArgumentException.class, () -> BeginBin(bitstream, JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.MSB0)); + assertThrows(IllegalArgumentException.class, + () -> BeginBin(bitstream, JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.MSB0)); } @Test @@ -578,8 +699,10 @@ public void testComplexWriting_1() throws Exception { assertEquals(47, array.length); assertArrayEquals(new byte[] { (byte) 0x55, 5, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 1, 0, 1, 1, - (byte) 0xAB, (byte) 0xCD, (byte) 0xEF, 0x23, (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE, - 0x12, 0x34, 0x56, 0x78, (byte) 0x9A, (byte) 0xBC, (byte) 0xDE, (byte) 0xF1, 0x21, 0x23, 0x56, 0x23, (byte) 0x90, (byte) 0x91, (byte) 0xAB, 0x32, + (byte) 0xAB, (byte) 0xCD, (byte) 0xEF, 0x23, (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, + (byte) 0xBE, + 0x12, 0x34, 0x56, 0x78, (byte) 0x9A, (byte) 0xBC, (byte) 0xDE, (byte) 0xF1, 0x21, 0x23, + 0x56, 0x23, (byte) 0x90, (byte) 0x91, (byte) 0xAB, 0x32, 0x4A, 0x46, 0x49, 0x46, (byte) 0x20, (byte) 0x43, (byte) 0x41 }, array); @@ -618,7 +741,8 @@ class Test { Bin(new Test(0x12, 0x13)). End().toByteArray(); - assertArrayEquals(new byte[] {(byte) 0xCC, (byte) 0xDD, (byte) 0xAA, (byte) 0x12, (byte) 0x13}, array); + assertArrayEquals(new byte[] {(byte) 0xCC, (byte) 0xDD, (byte) 0xAA, (byte) 0x12, (byte) 0x13}, + array); } @Test @@ -729,28 +853,86 @@ class Test { this.c = c; } } - assertArrayEquals(new byte[] {1, (byte) 0x40, 3}, BeginBin().Bin(new Test((byte) 1, (byte) 2, (byte) 3)).End().toByteArray()); + assertArrayEquals(new byte[]{1, (byte) 0x40, 3}, + BeginBin().Bin(new Test((byte) 1, (byte) 2, (byte) 3)).End().toByteArray()); + } + + @Test + public void testBin_UndefinedType_Byte_WithFilter() throws Exception { + class Test { + + @Bin(order = 3) + byte c; + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) + byte b; + @Bin(order = 1) + byte a; + + Test(byte a, byte b, byte c) { + this.a = a; + this.b = b; + this.c = c; + } + } + assertArrayEquals(new byte[]{1, 3}, + BeginBin().Bin(new Test((byte) 1, (byte) 2, (byte) 3), (b, f) -> f == null || !f.getName().equals("b")).End().toByteArray()); } @Test public void testBin_Byte_StringAsByteArray() throws Exception { assertArrayEquals(new byte[0], BeginBin().Byte("", JBBPBitOrder.LSB0).End().toByteArray()); assertArrayEquals(new byte[0], BeginBin().Byte("", JBBPBitOrder.MSB0).End().toByteArray()); - assertArrayEquals(new byte[] {65, 66, 67, 68}, BeginBin().Byte("ABCD", JBBPBitOrder.LSB0).End().toByteArray()); - assertArrayEquals(new byte[] {(byte) 130, 66, (byte) 194, 34}, BeginBin().Byte("ABCD", JBBPBitOrder.MSB0).End().toByteArray()); + assertArrayEquals(new byte[]{65, 66, 67, 68}, + BeginBin().Byte("ABCD", JBBPBitOrder.LSB0).End().toByteArray()); + assertArrayEquals(new byte[]{(byte) 130, 66, (byte) 194, 34}, + BeginBin().Byte("ABCD", JBBPBitOrder.MSB0).End().toByteArray()); } @Test public void testBin_Byte_StringAsShortArray() throws Exception { assertArrayEquals(new byte[0], BeginBin().Short("", JBBPBitOrder.LSB0).End().toByteArray()); assertArrayEquals(new byte[0], BeginBin().Short("", JBBPBitOrder.MSB0).End().toByteArray()); - assertArrayEquals(new byte[] {0x04, 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14}, BeginBin().Short("АБВГД", JBBPBitOrder.LSB0).End().toByteArray()); - assertArrayEquals(new byte[] {0x08, 0x20, (byte) 0x88, 0x20, (byte) 0x48, 0x20, (byte) 0xC8, 0x20, (byte) 0x28, 0x20}, BeginBin().Short("АБВГД", JBBPBitOrder.MSB0).End().toByteArray()); + assertArrayEquals(new byte[] {0x04, 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14}, + BeginBin().Short("АБВГД", JBBPBitOrder.LSB0).End().toByteArray()); + assertArrayEquals( + new byte[] {0x08, 0x20, (byte) 0x88, 0x20, (byte) 0x48, 0x20, (byte) 0xC8, 0x20, + (byte) 0x28, 0x20}, BeginBin().Short("АБВГД", JBBPBitOrder.MSB0).End().toByteArray()); } @Test public void testBin_StaticField() throws Exception { - assertArrayEquals(new byte[] {1, (byte) 0x40, 3}, BeginBin().Bin(new TestWithStaticField((byte) 1, (byte) 2, (byte) 3)).End().toByteArray()); + assertArrayEquals(new byte[] {1, (byte) 0x40, 3}, + BeginBin().Bin(new TestWithStaticField((byte) 1, (byte) 2, (byte) 3)).End().toByteArray()); + } + + @Test + public void testBin_LongUintField() throws Exception { + assertArrayEquals(new byte[] {(byte) 0xFA, (byte) 0xBC, (byte) 0xDE, (byte) 0x01}, + BeginBin().Bin(new TestWithLongUintField(0x1FABCDE01L)).End().toByteArray()); + } + + @Test + public void testBin_IntUintField() throws Exception { + assertArrayEquals(new byte[] {(byte) 0xFA, (byte) 0xBC, (byte) 0xDE, (byte) 0x01}, + BeginBin().Bin(new TestWithIntUintField(0xFABCDE01)).End().toByteArray()); + } + + @Test + public void testBin_LongUintArrayField() throws Exception { + assertArrayEquals( + new byte[] {(byte) 0xFA, (byte) 0xBC, (byte) 0xDE, (byte) 0x01, (byte) 0x02, (byte) 0x03, + (byte) 0x04, (byte) 0x05}, + BeginBin().Bin(new TestWithLongUintArrayField(new long[] {0x1FABCDE01L, 0x0102030405L})) + .End().toByteArray()); + } + + @Test + public void testBin_IntUintArrayField() throws Exception { + assertArrayEquals( + new byte[] {(byte) 0xFA, (byte) 0xBC, (byte) 0xDE, (byte) 0x01, (byte) 0x02, (byte) 0x03, + (byte) 0x04, (byte) 0x05}, + BeginBin().Bin(new TestWithIntUintArrayField(new int[] {0xFABCDE01, 0x02030405})).End() + .toByteArray()); } @Test @@ -770,7 +952,66 @@ class Test { this.c = c; } } - assertArrayEquals(new byte[] {1, (byte) 0x80, 0}, BeginBin().Bin(new Test(true, true, false)).End().toByteArray()); + assertArrayEquals(new byte[] {1, (byte) 0x80, 0}, + BeginBin().Bin(new Test(true, true, false)).End().toByteArray()); + } + + @Test + public void testBin_ForceByteOrder() throws Exception { + class DefaultByteOrder { + @Bin + int value = 0x01020304; + } + + class BigEndianByteOrder { + @Bin(byteOrder = JBBPByteOrder.BIG_ENDIAN) + int value = 0x01020304; + } + + class LittleEndianByteOrder { + @Bin(byteOrder = JBBPByteOrder.LITTLE_ENDIAN) + int value = 0x01020304; + } + + class LittleEndianByteOrderWithStructure { + + @Bin(byteOrder = JBBPByteOrder.LITTLE_ENDIAN, order = 1) + int value = 0x01020304; + @Bin(order = 2) + Internal internal = new Internal(); + + class Internal { + @Bin(byteOrder = JBBPByteOrder.BIG_ENDIAN) + int value = 0x05060708; + } + } + + final byte[] defaultOrder = JBBPOut.BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN) + .BinForceByteOrder(new DefaultByteOrder()).End().toByteArray(); + assertArrayEquals(new byte[] {4, 3, 2, 1}, defaultOrder); + + final byte[] bigEndianOrder = JBBPOut.BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN) + .BinForceByteOrder(new BigEndianByteOrder()).End().toByteArray(); + assertArrayEquals(new byte[] {4, 3, 2, 1}, bigEndianOrder); + + final byte[] littleEndianOrder = JBBPOut.BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN) + .BinForceByteOrder(new LittleEndianByteOrder()).End().toByteArray(); + assertArrayEquals(new byte[] {1, 2, 3, 4}, littleEndianOrder); + + final byte[] littleEndianOrderWithStruct = + JBBPOut.BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN) + .BinForceByteOrder(new LittleEndianByteOrderWithStructure()).End().toByteArray(); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, littleEndianOrderWithStruct); + + final byte[] littleEndianOrderWithStructBin = + JBBPOut.BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN) + .Bin(new LittleEndianByteOrderWithStructure()).End().toByteArray(); + assertArrayEquals(new byte[] {4, 3, 2, 1, 5, 6, 7, 8}, littleEndianOrderWithStructBin); + + final byte[] littleEndianOrderWithStructLe = + JBBPOut.BeginBin().ByteOrder(JBBPByteOrder.LITTLE_ENDIAN) + .BinForceByteOrder(new LittleEndianByteOrderWithStructure()).End().toByteArray(); + assertArrayEquals(new byte[] {4, 3, 2, 1, 8, 7, 6, 5}, littleEndianOrderWithStructLe); } @Test @@ -790,7 +1031,36 @@ class Test { this.c = c; } } - assertArrayEquals(new byte[] {(byte) 0x55, 0x0C}, BeginBin().Bin(new Test((byte) 0x05, (byte) 0x0A, (byte) 0x0C)).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x55, 0x0C}, + BeginBin().Bin(new Test((byte) 0x05, (byte) 0x0A, (byte) 0x0C)).End().toByteArray()); + } + + @Test + public void testBin_OverrideAnnotationValues() throws Exception { + class Test { + @Bin(bitNumber = JBBPBitNumber.BITS_4, type = BinType.BIT) + byte a = (byte) 0b10101010; + } + + assertArrayEquals(new byte[]{(byte) 0b00001010}, + BeginBin().Bin(new Test(), null, null, null).End().toByteArray()); + assertArrayEquals(new byte[]{(byte) 0b10101010}, BeginBin() + .Bin(new Test(), new BinAnnotationWrapper().setBitNumber(JBBPBitNumber.BITS_8), null).End() + .toByteArray()); + assertArrayEquals(new byte[] {(byte) 0b00000101}, + BeginBin().Bin(new Test(), new BinAnnotationWrapper().setBitOrder(JBBPBitOrder.MSB0), null) + .End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0b10101010}, + BeginBin().Bin(new Test(), new BinAnnotationWrapper().setType(BinType.BYTE), null).End() + .toByteArray()); + + final JBBPCustomFieldWriter customFieldWriter = + (context, outStream, instanceToSave, instanceCustomField, fieldAnnotation, value) -> outStream.write( + 123); + + assertArrayEquals(new byte[] {(byte) 123}, + BeginBin().Bin(new Test(), new BinAnnotationWrapper().setCustom(true), customFieldWriter) + .End().toByteArray()); } @Test @@ -811,7 +1081,9 @@ class Test { } } - assertArrayEquals(new byte[] {0x01, 0x02, 0x20, (byte) 0xC0, 0x05, 0x06}, BeginBin().Bin(new Test((short) 0x0102, (short) 0x0304, (short) 0x0506)).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x20, (byte) 0xC0, 0x05, 0x06}, + BeginBin().Bin(new Test((short) 0x0102, (short) 0x0304, (short) 0x0506)).End() + .toByteArray()); } @Test @@ -832,7 +1104,8 @@ class Test { } } - assertArrayEquals(new byte[] {0x01, 0x02, 0x20, (byte) 0xC0, 0x05, 0x06}, BeginBin().Bin(new Test((char) 0x0102, (char) 0x0304, (char) 0x0506)).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02, 0x20, (byte) 0xC0, 0x05, 0x06}, + BeginBin().Bin(new Test((char) 0x0102, (char) 0x0304, (char) 0x0506)).End().toByteArray()); } @Test @@ -853,7 +1126,10 @@ class Test { } } - assertArrayEquals(new byte[] {(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0x22, (byte) 0xCC, (byte) 0x44, (byte) 0x88, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE}, BeginBin().Bin(new Test(0xAABBCCDD, 0x11223344, 0xBBCCDDEE)).End().toByteArray()); + assertArrayEquals( + new byte[] {(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0x22, (byte) 0xCC, + (byte) 0x44, (byte) 0x88, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE}, + BeginBin().Bin(new Test(0xAABBCCDD, 0x11223344, 0xBBCCDDEE)).End().toByteArray()); } @Test @@ -876,7 +1152,8 @@ class Test { assertArrayEquals(JBBPUtils.concat( JBBPUtils.splitInteger(Float.floatToIntBits(0.456f), false, null), - JBBPUtils.splitInteger((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(8.1123f)), false, null), + JBBPUtils.splitInteger((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(8.1123f)), false, + null), JBBPUtils.splitInteger(Float.floatToIntBits(56.123f), false, null) ), BeginBin().Bin(new Test(0.456f, 8.1123f, 56.123f)).End().toByteArray()); } @@ -903,7 +1180,8 @@ class Test { JBBPUtils.splitLong(0xFFAABBCCDD001122L, false, null), JBBPUtils.splitLong(JBBPFieldLong.reverseBits(0x0102030405060708L), false, null), JBBPUtils.splitLong(0x11223344556677AAL, false, null) - ), BeginBin().Bin(new Test(0xFFAABBCCDD001122L, 0x0102030405060708L, 0x11223344556677AAL)).End().toByteArray()); + ), BeginBin().Bin(new Test(0xFFAABBCCDD001122L, 0x0102030405060708L, 0x11223344556677AAL)).End() + .toByteArray()); } @Test @@ -926,7 +1204,9 @@ class Test { assertArrayEquals(JBBPUtils.concat( JBBPUtils.splitLong(Double.doubleToLongBits(34350.456d), false, null), - JBBPUtils.splitLong(JBBPFieldLong.reverseBits(Double.doubleToLongBits(8829374.1123d)), false, null), + JBBPUtils + .splitLong(JBBPFieldLong.reverseBits(Double.doubleToLongBits(8829374.1123d)), false, + null), JBBPUtils.splitLong(Double.doubleToLongBits(3256.123d), false, null) ), BeginBin().Bin(new Test(34350.456d, 8829374.1123d, 3256.123d)).End().toByteArray()); } @@ -962,7 +1242,46 @@ class Test { } } - assertArrayEquals(new byte[] {1, 3, 4, 2}, BeginBin().Bin(new Test((byte) 1, (byte) 2, new Inside((byte) 3, (byte) 4))).End().toByteArray()); + assertArrayEquals(new byte[]{1, 3, 4, 2}, + BeginBin().Bin(new Test((byte) 1, (byte) 2, new Inside((byte) 3, (byte) 4))).End() + .toByteArray()); + } + + @Test + public void testBin_UndefinedType_Struct_WithFilter() throws Exception { + class Inside { + + @Bin(order = 1) + byte a; + @Bin(order = 2) + byte b; + + Inside(byte a, byte b) { + this.a = a; + this.b = b; + } + } + + class Test { + + @Bin(order = 2) + Inside c; + @Bin(order = 1) + byte a; + @Bin(order = 3) + byte b; + + Test(byte a, byte b, Inside c) { + this.a = a; + this.b = b; + this.c = c; + } + } + + assertArrayEquals(new byte[]{1, 4, 2}, + BeginBin().Bin(new Test((byte) 1, (byte) 2, new Inside((byte) 3, (byte) 4)), + (b, f) -> f == null || !(f.getDeclaringClass().getSimpleName().equals("Inside") && f.getName().equals("a"))).End() + .toByteArray()); } @Test @@ -983,7 +1302,8 @@ class Test { } } assertArrayEquals(new byte[] {(byte) 0xAA, (byte) 0x21, (byte) 0x43, (byte) 0x6A, (byte) 0x0E}, - BeginBin().Bin(new Test((byte) 0xAA, new byte[] {1, 2, 3, 4}, new byte[] {5, 6, 7})).End().toByteArray()); + BeginBin().Bin(new Test((byte) 0xAA, new byte[] {1, 2, 3, 4}, new byte[] {5, 6, 7})).End() + .toByteArray()); } @Test @@ -1000,7 +1320,8 @@ class Test { this.lsbarray = lsbarray; } } - assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0xA0, (byte) 0x60, (byte) 0xE0}, + assertArrayEquals( + new byte[] {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0xA0, (byte) 0x60, (byte) 0xE0}, BeginBin().Bin(new Test(new byte[] {1, 2, 3}, new byte[] {5, 6, 7})).End().toByteArray()); } @@ -1019,7 +1340,9 @@ class Test { } } assertArrayEquals(new byte[] {0x01, 0x00, 0x01, (byte) 0x80, 0x00, (byte) 0x80}, - BeginBin().Bin(new Test(new boolean[] {true, false, true}, new boolean[] {true, false, true})).End().toByteArray()); + BeginBin() + .Bin(new Test(new boolean[] {true, false, true}, new boolean[] {true, false, true})) + .End().toByteArray()); } @Test @@ -1073,8 +1396,12 @@ class Test { this.lsbarray = lsbarray; } } - assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x03, (byte) 0xA0, (byte) 0x60, (byte) 0x60, (byte) 0xE0, (byte) 0xE0, (byte) 0x00}, - BeginBin().Bin(new Test(new short[] {0x0101, 0x0102, 0x0103}, new short[] {0x0605, 0x0706, 0x0007})).End().toByteArray()); + assertArrayEquals( + new byte[] {(byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x03, + (byte) 0xA0, (byte) 0x60, (byte) 0x60, (byte) 0xE0, (byte) 0xE0, (byte) 0x00}, + BeginBin().Bin( + new Test(new short[] {0x0101, 0x0102, 0x0103}, new short[] {0x0605, 0x0706, 0x0007})) + .End().toByteArray()); } @Test @@ -1091,7 +1418,9 @@ class Test { this.lsbarray = lsbarray; } } - assertArrayEquals(new byte[] {(byte) 0x04, (byte) 0x1F, (byte) 0x04, (byte) 0x20, (byte) 0x18, (byte) 0x20, (byte) 0x48, (byte) 0x20}, + assertArrayEquals( + new byte[] {(byte) 0x04, (byte) 0x1F, (byte) 0x04, (byte) 0x20, (byte) 0x18, (byte) 0x20, + (byte) 0x48, (byte) 0x20}, BeginBin().Bin(new Test("ПР", "ИВ")).End().toByteArray()); } @@ -1109,9 +1438,12 @@ class Test { this.lsbarray = lsbarray; } } - assertArrayEquals(new byte[] {(byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, (byte) 0x77, (byte) 0x88, + assertArrayEquals( + new byte[] {(byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + (byte) 0x77, (byte) 0x88, (byte) 0x48, (byte) 0xF7, (byte) 0xB3, (byte) 0xD5}, - BeginBin().Bin(new Test(new int[] {0x11223344, 0x55667788}, new int[] {0xABCDEF12})).End().toByteArray()); + BeginBin().Bin(new Test(new int[] {0x11223344, 0x55667788}, new int[] {0xABCDEF12})).End() + .toByteArray()); } @Test @@ -1129,11 +1461,18 @@ class Test { } } assertArrayEquals(JBBPUtils.concat( - JBBPUtils.splitInteger(Float.floatToIntBits(23.4546f), false, null), JBBPUtils.splitInteger(Float.floatToIntBits(123.32f), false, null), - JBBPUtils.splitInteger((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(11.98872f)), false, null), - JBBPUtils.splitInteger((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(-234.322f)), false, null) + JBBPUtils.splitInteger(Float.floatToIntBits(23.4546f), false, null), + JBBPUtils.splitInteger(Float.floatToIntBits(123.32f), false, null), + JBBPUtils + .splitInteger((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(11.98872f)), false, + null), + JBBPUtils + .splitInteger((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(-234.322f)), false, + null) ), - BeginBin().Bin(new Test(new float[] {23.4546f, 123.32f}, new float[] {11.98872f, -234.322f})).End().toByteArray()); + BeginBin() + .Bin(new Test(new float[] {23.4546f, 123.32f}, new float[] {11.98872f, -234.322f})) + .End().toByteArray()); } @Test @@ -1151,11 +1490,13 @@ class Test { } } assertArrayEquals(JBBPUtils.concat( - JBBPUtils.splitLong(0x1122334455667788L, false, null), JBBPUtils.splitLong(0xAABBCCDDEEFF1122L, false, null), + JBBPUtils.splitLong(0x1122334455667788L, false, null), + JBBPUtils.splitLong(0xAABBCCDDEEFF1122L, false, null), JBBPUtils.splitLong(JBBPFieldLong.reverseBits(0x0102030405060708L), false, null), JBBPUtils.splitLong(JBBPFieldLong.reverseBits(0xCAFEBABE12345334L), false, null) ), - BeginBin().Bin(new Test(new long[] {0x1122334455667788L, 0xAABBCCDDEEFF1122L}, new long[] {0x0102030405060708L, 0xCAFEBABE12345334L})).End().toByteArray()); + BeginBin().Bin(new Test(new long[] {0x1122334455667788L, 0xAABBCCDDEEFF1122L}, + new long[] {0x0102030405060708L, 0xCAFEBABE12345334L})).End().toByteArray()); } @Test @@ -1186,7 +1527,9 @@ class Test { } } assertArrayEquals(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, - BeginBin().Bin(new Test((byte) 0x01, new Inner[] {new Inner((byte) 0x02, (byte) 0x03), new Inner((byte) 0x04, (byte) 0x05), new Inner((byte) 0x06, (byte) 0x07)})).End().toByteArray()); + BeginBin().Bin(new Test((byte) 0x01, + new Inner[] {new Inner((byte) 0x02, (byte) 0x03), new Inner((byte) 0x04, (byte) 0x05), + new Inner((byte) 0x06, (byte) 0x07)})).End().toByteArray()); } @@ -1223,7 +1566,8 @@ class Test { } } - assertThrows(JBBPIllegalArgumentException.class, () -> BeginBin().Bin(new Test((byte) 12, (byte) 24))); + assertThrows(JBBPIllegalArgumentException.class, + () -> BeginBin().Bin(new Test((byte) 12, (byte) 24))); } @@ -1241,17 +1585,18 @@ class Test { } } - assertArrayEquals(new byte[] {1, 2, 3}, BeginBin().Bin(new Test((byte) 1, (byte) 0), (context, outStream, instanceToSave, instanceCustomField, fieldAnnotation, value) -> { - assertNotNull(context); - assertNotNull(outStream); - assertNotNull(instanceToSave); - assertNotNull(instanceCustomField); - assertNotNull(fieldAnnotation); - assertEquals("b", instanceCustomField.getName()); - assertTrue(instanceToSave.getClass() == instanceCustomField.getDeclaringClass()); + assertArrayEquals(new byte[] {1, 2, 3}, BeginBin().Bin(new Test((byte) 1, (byte) 0), + (context, outStream, instanceToSave, instanceCustomField, fieldAnnotation, value) -> { + assertNotNull(context); + assertNotNull(outStream); + assertNotNull(instanceToSave); + assertNotNull(instanceCustomField); + assertNotNull(fieldAnnotation); + assertEquals("b", instanceCustomField.getName()); + assertSame(instanceToSave.getClass(), instanceCustomField.getDeclaringClass()); - context.Byte(2, 3); - }).End().toByteArray()); + context.Byte(2, 3); + }).End().toByteArray()); } @Bin @@ -1272,5 +1617,43 @@ private static class TestWithStaticField { } } + @Bin + private static class TestWithLongUintField { + @Bin(type = BinType.UINT) + long a; + + TestWithLongUintField(long value) { + this.a = value; + } + } + + @Bin + private static class TestWithIntUintField { + @Bin(type = BinType.UINT) + int a; + + TestWithIntUintField(int value) { + this.a = value; + } + } + + @Bin + private static class TestWithLongUintArrayField { + @Bin(type = BinType.UINT_ARRAY) + long[] a; + TestWithLongUintArrayField(long[] value) { + this.a = value; + } + } + + @Bin + private static class TestWithIntUintArrayField { + @Bin(type = BinType.UINT_ARRAY) + int[] a; + + TestWithIntUintArrayField(int[] value) { + this.a = value; + } + } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/AbstractParserIntegrationTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/AbstractParserIntegrationTest.java index 20ca17ea..62559ea4 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/AbstractParserIntegrationTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/AbstractParserIntegrationTest.java @@ -16,33 +16,34 @@ package com.igormaznitsa.jbbp.it; -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import org.apache.commons.io.IOUtils; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; - -import static org.junit.jupiter.api.Assertions.*; +import org.apache.commons.io.IOUtils; public abstract class AbstractParserIntegrationTest { + public static String normalizeEol(final String text) { + return text + .replace("\r\n", "\n") + .replace("\n\r", "\n") + .replace("\r", ""); + } + public void assertFileContent(final String fileName, final String content) throws Exception { final String fileText; - try(InputStream inStream = this.getResourceAsInputStream(fileName)) { + try (InputStream inStream = this.getResourceAsInputStream(fileName)) { fileText = IOUtils.toString(inStream, StandardCharsets.UTF_8); } assertEquals(normalizeEol(fileText), normalizeEol(content), "File content must be equals"); } - public static String normalizeEol(final String text) { - return text - .replace("\r\n","\n") - .replace("\n\r","\n") - .replace("\r",""); - } - public InputStream getResourceAsInputStream(final String resourceName) { final InputStream result = this.getClass().getResourceAsStream(resourceName); if (result == null) { @@ -52,8 +53,9 @@ public InputStream getResourceAsInputStream(final String resourceName) { } public void assertResource(final String resourceName, final byte[] content) throws Exception { - try(InputStream in = this.getResourceAsInputStream(resourceName)) { - assertArrayEquals(new JBBPBitInputStream(in).readByteArray(-1), content, "Content of '" + resourceName + "'"); + try (InputStream in = this.getResourceAsInputStream(resourceName)) { + assertArrayEquals(new JBBPBitInputStream(in).readByteArray(-1), content, + "Content of '" + resourceName + "'"); } } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/BasedOnQuestionsAndCasesTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/BasedOnQuestionsAndCasesTest.java index 19aafb84..e41919ef 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/BasedOnQuestionsAndCasesTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/BasedOnQuestionsAndCasesTest.java @@ -18,22 +18,28 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; - +import static org.junit.jupiter.api.Assertions.assertNull; import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitNumber; import com.igormaznitsa.jbbp.io.JBBPBitOrder; +import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; import com.igormaznitsa.jbbp.io.JBBPByteOrder; +import com.igormaznitsa.jbbp.io.JBBPCustomFieldWriter; import com.igormaznitsa.jbbp.io.JBBPOut; import com.igormaznitsa.jbbp.mapper.Bin; import com.igormaznitsa.jbbp.mapper.BinType; +import com.igormaznitsa.jbbp.mapper.JBBPMapperCustomFieldProcessor; import com.igormaznitsa.jbbp.model.JBBPAbstractField; import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; import com.igormaznitsa.jbbp.model.JBBPFieldArrayLong; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayString; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct; import com.igormaznitsa.jbbp.model.JBBPFieldInt; import com.igormaznitsa.jbbp.model.JBBPFieldLong; import com.igormaznitsa.jbbp.model.JBBPFieldString; @@ -41,12 +47,16 @@ import com.igormaznitsa.jbbp.model.JBBPNumericField; import com.igormaznitsa.jbbp.utils.JBBPDslBuilder; import com.igormaznitsa.jbbp.utils.JBBPTextWriter; +import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.junit.jupiter.api.Test; @@ -56,6 +66,68 @@ */ public class BasedOnQuestionsAndCasesTest extends AbstractParserIntegrationTest { + /** + * Case 03-dec-2024 + *

+ * Sequential read of bit sequence + *

+   * 00000001 101 00001000 00000
+   * ________ ___ ________
+   * ^        ^    ^
+   * |        |    byte2
+   * |        bits
+   * byte1
+   * 
+ * + * @throws Exception for any error + */ + @Test + void testReadMSB0WithoutReverse() throws Exception { + class Example { + + protected static final int _ParserFlags_ = 0; + + public byte byte1; + public byte bits; + public byte byte2; + + + public Example() { + } + + public Example read(final JBBPBitInputStream In) throws IOException { + this.byte1 = (byte) In.readByte(); + this.bits = In.readBitField(JBBPBitNumber.BITS_3); + this.byte2 = (byte) In.readByte(); + + return this; + } + + public Example write(final JBBPBitOutputStream Out) throws IOException { + Out.write(this.byte1); + Out.writeBits(this.bits, JBBPBitNumber.BITS_3); + Out.write(this.byte2); + + return this; + } + } + + // 00000001 10100001 00000000 + var data = new byte[] {0x01, (byte) 0xa1, 0x00}; + + var example = new Example(); + example.read(new JBBPBitInputStream(new ByteArrayInputStream(data), JBBPBitOrder.MSB0_DIRECT)); + + var expected = new Example(); + expected.byte1 = 1; // 00000001 + expected.bits = 5; // 00000101 + expected.byte2 = 8; // 00001000 + + assertEquals(expected.bits, example.bits); + assertEquals(expected.byte1, example.byte1); + assertEquals(expected.byte2, example.byte2); + } + /** * Case 13-aug-2015 *

@@ -76,13 +148,16 @@ class YearMonthDay { @Bin(type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_5, order = 3, bitOrder = JBBPBitOrder.MSB0) byte day; } - final YearMonthDay parsed = JBBPParser.prepare("bit:6 year; bit:4 month; bit:5 day;", JBBPBitOrder.MSB0).parse(new byte[] {(byte) 0x3D, (byte) 0xF8}).mapTo(new YearMonthDay()); + final YearMonthDay parsed = + JBBPParser.prepare("bit:6 year; bit:4 month; bit:5 day;", JBBPBitOrder.MSB0) + .parse(new byte[] {(byte) 0x3D, (byte) 0xF8}).mapTo(new YearMonthDay()); assertEquals(0x0F, parsed.year); assertEquals(0x07, parsed.month); assertEquals(0x1C, parsed.day & 0xFF); - assertArrayEquals(new byte[] {(byte) 0x3D, (byte) 0xF8}, JBBPOut.BeginBin(JBBPBitOrder.MSB0).Bin(parsed).End().toByteArray()); + assertArrayEquals(new byte[] {(byte) 0x3D, (byte) 0xF8}, + JBBPOut.BeginBin(JBBPBitOrder.MSB0).Bin(parsed).End().toByteArray()); } /** @@ -113,26 +188,28 @@ class TetraTimestamp { } - TetraTimestamp parsed = JBBPParser.prepare("bit:2 timezone; bit:2 reserved; bit:4 month; bit:5 day; bit:5 hour; bit:6 minute;", JBBPBitOrder.MSB0).parse(TEST_DATA).mapTo(new TetraTimestamp()); + TetraTimestamp parsed = JBBPParser.prepare( + "bit:2 timezone; bit:2 reserved; bit:4 month; bit:5 day; bit:5 hour; bit:6 minute;", + JBBPBitOrder.MSB0).parse(TEST_DATA).mapTo(new TetraTimestamp()); assertEquals(2, parsed.month); assertEquals(8, parsed.day); assertEquals(10, parsed.hour); assertEquals(1, parsed.minute); - assertArrayEquals(TEST_DATA, JBBPOut.BeginBin(JBBPBitOrder.MSB0).Bin(parsed).End().toByteArray()); + assertArrayEquals(TEST_DATA, + JBBPOut.BeginBin(JBBPBitOrder.MSB0).Bin(parsed).End().toByteArray()); } /** * Case 28-jul-2016 * Simultaneous usage of expression evaluator from multiple threads. - * * Issue #10, assertArrayLength throws exception in multi-thread * * @throws Exception for any error */ @Test - public void testMutlithredUsageOfParser() throws Exception { + public void testMultiThreadUsageOfParser() throws Exception { final JBBPParser parserIP = JBBPParser.prepare("skip:14; // skip bytes till the frame\n" + "bit:4 InternetHeaderLength;" + "bit:4 Version;" @@ -191,9 +268,13 @@ public void testMutlithredUsageOfParser() throws Exception { for (int i = 0; i < ITERATIONS; i++) { try { Thread.sleep(System.nanoTime() & 0xF); - final byte[] ippacket = parserTCP.parse(theData).findFieldForNameAndType("Data", JBBPFieldArrayByte.class).getArray(); + final byte[] ippacket = + parserTCP.parse(theData).findFieldForNameAndType("Data", JBBPFieldArrayByte.class) + .getArray(); assertEquals(119, ippacket.length); - final byte[] optionsip = parserIP.parse(ippacket).findFieldForNameAndType("Options", JBBPFieldArrayByte.class).getArray(); + final byte[] optionsip = + parserIP.parse(ippacket).findFieldForNameAndType("Options", JBBPFieldArrayByte.class) + .getArray(); assertEquals(4, optionsip.length); parsingCounter.incrementAndGet(); } catch (Exception ex) { @@ -227,7 +308,8 @@ class Bits { byte[] bit; } - JBBPParser parser = JBBPParser.prepare(JBBPDslBuilder.Begin().AnnotatedClassFields(Bits.class).End()); + JBBPParser parser = + JBBPParser.prepare(JBBPDslBuilder.Begin().AnnotatedClassFields(Bits.class).End()); Bits parsed = parser.parse(new byte[] {73}).mapTo(new Bits()); @@ -244,18 +326,102 @@ class Bits { */ @Test public void testStringMsb0() throws Exception { - JBBPOut joparam = JBBPOut.BeginBin(JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.MSB0).String("zzzz").Int(12345); + JBBPOut joparam = + JBBPOut.BeginBin(JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.MSB0).String("zzzz").Int(12345); final byte[] array = joparam.End().toByteArray(); assertArrayEquals(new byte[] {32, 94, 94, 94, 94, 0, 0, 0x0C, (byte) 0x9C}, array); - final JBBPFieldStruct bitflds = JBBPParser.prepare("stringj fin; int i;", JBBPBitOrder.MSB0).parse(array); - assertEquals("zzzz", bitflds.findFieldForNameAndType("fin", JBBPFieldString.class).getAsString()); + final JBBPFieldStruct bitflds = + JBBPParser.prepare("stringj fin; int i;", JBBPBitOrder.MSB0).parse(array); + assertEquals("zzzz", + bitflds.findFieldForNameAndType("fin", JBBPFieldString.class).getAsString()); assertEquals(12345, bitflds.findFieldForNameAndType("i", JBBPFieldInt.class).getAsInt()); } + /** + * Case 18-feb-2020, #27 Strings in other codecs + * Example how to implement custom ASCII string format + * + * @throws Exception for any error + */ + @Test + public void testAscIIPascalString() throws Exception { + final class AscIIPascalString implements JBBPCustomFieldTypeProcessor { + private final String[] TYPES = new String[] {"asciistr"}; + + @Override + public String[] getCustomFieldTypes() { + return TYPES; + } + + @Override + public boolean isAllowed( + final JBBPFieldTypeParameterContainer fieldType, + final String fieldName, + final int extraData, + final boolean isArray + ) { + return extraData == 0; + } + + @Override + public JBBPAbstractField readCustomFieldType( + final JBBPBitInputStream in, + final JBBPBitOrder bitOrder, + final int parserFlags, + final JBBPFieldTypeParameterContainer customTypeFieldInfo, + final JBBPNamedFieldInfo fieldName, + final int extraData, + final boolean readWholeStream, + final int arrayLength, + final JBBPArraySizeLimiter arraySizeLimiter + ) throws IOException { + if (arrayLength < 0) { + return new JBBPFieldString(fieldName, readPascalAscIIString(in)); + } else { + final String[] loadedStrings; + if (readWholeStream) { + final List strings = new ArrayList<>(); + while (in.hasAvailableData()) { + strings.add(readPascalAscIIString(in)); + } + loadedStrings = strings.toArray(new String[0]); + } else { + loadedStrings = new String[arrayLength]; + for (int i = 0; i < arrayLength; i++) { + loadedStrings[i] = readPascalAscIIString(in); + } + } + return new JBBPFieldArrayString(fieldName, loadedStrings); + } + } + + private String readPascalAscIIString(final JBBPBitInputStream in) throws IOException { + final byte[] charArray = in.readByteArray(in.readByte()); + return new String(charArray, StandardCharsets.US_ASCII); + } + } + + final JBBPParser parserSingle = + JBBPParser.prepare("asciistr str1; asciistr str2;", new AscIIPascalString()); + final JBBPFieldStruct parsedSingle = parserSingle.parse(new byte[] {5, 65, 66, 67, 68, 69, 0}); + assertEquals("ABCDE", + parsedSingle.findFieldForNameAndType("str1", JBBPFieldString.class).getAsString()); + assertEquals("", + parsedSingle.findFieldForNameAndType("str2", JBBPFieldString.class).getAsString()); + + final JBBPParser parserArray = + JBBPParser.prepare("asciistr [2] str1; asciistr [_] str2;", new AscIIPascalString()); + final JBBPFieldStruct parsedArrays = + parserArray.parse(new byte[] {2, 65, 66, 1, 67, 3, 68, 69, 70, 2, 71, 72, 1, 73}); + assertArrayEquals(new String[] {"AB", "C"}, + parsedArrays.findFieldForNameAndType("str1", JBBPFieldArrayString.class).getArray()); + assertArrayEquals(new String[] {"DEF", "GH", "I"}, + parsedArrays.findFieldForNameAndType("str2", JBBPFieldArrayString.class).getArray()); + } + /** * Case 10-aug-2017 * NullPointer exception when referencing a JBBPCustomFieldTypeProcessor parsed field. - * * Issue #16, NullPointer exception when referencing a JBBPCustomFieldTypeProcessor parsed field * * @throws Exception for any error @@ -266,7 +432,8 @@ final class Uint32 implements JBBPCustomFieldTypeProcessor { private final String[] TYPES = new String[] {"uint32"}; - private long uint32_read(final JBBPBitInputStream in, final JBBPByteOrder byteOrder, final JBBPBitOrder bitOrder) throws IOException { + private long uint32_read(final JBBPBitInputStream in, final JBBPByteOrder byteOrder, + final JBBPBitOrder bitOrder) throws IOException { final int signedInt = in.readInt(byteOrder); return signedInt & 0xffffffffL; } @@ -277,7 +444,8 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final String fieldName, final int extraData, final boolean isArray) { + public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, + final String fieldName, final int extraData, final boolean isArray) { return extraData == 0; } @@ -291,10 +459,16 @@ private long[] convertLongs(List longs) { } @Override - public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final JBBPBitOrder bitOrder, - final int parserFlags, final JBBPFieldTypeParameterContainer customTypeFieldInfo, - final JBBPNamedFieldInfo fieldName, final int extraData, - final boolean readWholeStream, final int arrayLength) throws IOException { + public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, + final JBBPBitOrder bitOrder, + final int parserFlags, + final JBBPFieldTypeParameterContainer customTypeFieldInfo, + final JBBPNamedFieldInfo fieldName, + final int extraData, + final boolean readWholeStream, + final int arrayLength, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { if (arrayLength < 0) { final long uint32_val = uint32_read(in, customTypeFieldInfo.getByteOrder(), bitOrder); return new JBBPFieldLong(fieldName, uint32_val); @@ -339,4 +513,238 @@ public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final result = sasParser.parse(new byte[] {0, 0, 0, 2, 1, 2, 3, 4}); assertEquals(2, ((JBBPNumericField) result.findFieldForName("keycount")).getAsInt()); } + + /** + * Case 09-jun-2020 + * Example how to use external variable value provider. + * + * @throws Exception for any error + */ + @Test + public void testByteArrayWhichLengthProvidedExternally() throws Exception { + class BKlazz { + @Bin(order = 1, type = BinType.BYTE_ARRAY) + byte[] a; + @Bin(order = 2, type = BinType.BYTE_ARRAY) + byte[] b; + @Bin(order = 3, type = BinType.BYTE_ARRAY) + byte[] c; + } + + JBBPParser parser = JBBPParser.prepare("byte [$alen] a; byte [$blen] b; byte [$clen] c;"); + + BKlazz parsed = parser.parse(new byte[] {1, 2, 3}, null, + (fieldName, numericFieldMap, compiledBlock) -> { + if ("alen".equals(fieldName)) { + return 0; + } else if ("blen".equals(fieldName)) { + return 3; + } else if ("clen".equals(fieldName)) { + return 0; + } else { + throw new IllegalArgumentException("Unknown name: " + fieldName); + } + + }).mapTo(new BKlazz()); + + assertArrayEquals(new byte[0], parsed.a); + assertArrayEquals(new byte[] {1, 2, 3}, parsed.b); + assertArrayEquals(new byte[0], parsed.c); + } + + /** + * Case 09-jun-2020 + * Example how to write custom field type read-write-mapping processor for nullable byte array. + * + * @throws Exception for any error + */ + @Test + public void testNullableByteArrayField() throws Exception { + class NullableByteArrayProcessor + implements JBBPCustomFieldWriter, JBBPMapperCustomFieldProcessor, + JBBPCustomFieldTypeProcessor { + + private final String TYPE = "nullableByteArray"; + private final String[] CUSTOM_TYPE = new String[] {TYPE.toLowerCase(Locale.ENGLISH)}; + + @Override + public String[] getCustomFieldTypes() { + return CUSTOM_TYPE; + } + + @Override + public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, + int extraData, boolean isArray) { + return !isArray; + } + + private byte[] readFromStream(JBBPByteOrder byteOrder, JBBPBitInputStream in) + throws IOException { + final int len = in.readInt(byteOrder); + return len < 0 ? null : in.readByteArray(len); + } + + @Override + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + if (arrayLength < 0) { + return toStruct(fieldName, readFromStream(customTypeFieldInfo.getByteOrder(), in)); + } else { + throw new IllegalArgumentException("Array of nullable byte arrays is unsupported"); + } + } + + private void writeTo(final JBBPBitOutputStream outStream, final JBBPByteOrder order, + final byte[] data) throws IOException { + if (data == null) { + outStream.writeInt(-1, order); + } else { + outStream.writeInt(data.length, order); + outStream.write(data); + } + } + + @Override + public void writeCustomField(JBBPOut context, JBBPBitOutputStream outStream, + Object instanceToSave, Field instanceCustomField, + Bin fieldAnnotation, Object value) throws IOException { + if (fieldAnnotation.customType().equals(TYPE)) { + writeTo(outStream, fieldAnnotation.byteOrder(), (byte[]) value); + } else { + throw new IllegalArgumentException( + "Unsupported custom type: " + fieldAnnotation.customType()); + } + } + + private JBBPFieldStruct toStruct(JBBPNamedFieldInfo fieldName, final byte[] array) { + if (array == null) { + return new JBBPFieldStruct(fieldName, new JBBPAbstractField[0]); + } else { + return new JBBPFieldStruct(fieldName, + new JBBPAbstractField[] {new JBBPFieldArrayByte(null, array)}); + } + } + + private byte[] fromStruct(final JBBPFieldStruct struct) { + final JBBPAbstractField[] fields = struct.getArray(); + return fields.length == 0 ? null : ((JBBPFieldArrayByte) struct.getArray()[0]).getArray(); + } + + @Override + public Object prepareObjectForMapping(JBBPFieldStruct parsedBlock, + Bin annotation, + Field field) { + if (annotation.customType().equals(TYPE)) { + if (field.getType() == byte[][].class) { + final JBBPFieldArrayStruct structs = + parsedBlock.findFieldForNameAndType(field.getName(), JBBPFieldArrayStruct.class); + final byte[][] result = new byte[structs.size()][]; + for (int i = 0; i < structs.size(); i++) { + result[i] = fromStruct(structs.getElementAt(i)); + } + return result; + } else { + return fromStruct( + parsedBlock.findFieldForNameAndType(field.getName(), JBBPFieldStruct.class)); + } + } else { + throw new IllegalArgumentException("Unexpected custom type: " + annotation.customType()); + } + } + } + + final NullableByteArrayProcessor nullableByteArrayProcessor = new NullableByteArrayProcessor(); + + class Klazz { + @Bin + int a; + @Bin(custom = true, customType = "nullableByteArray") + byte[] b; + @Bin + int c; + } + + Klazz object = new Klazz(); + object.a = 12345; + object.b = null; + object.c = 7890; + + final byte[] withNullField = + JBBPOut.BeginBin().Bin(object, nullableByteArrayProcessor).End().toByteArray(); + + assertArrayEquals( + new byte[] {0, 0, 48, 57, (byte) -1, (byte) -1, (byte) -1, (byte) -1, 0, 0, 30, (byte) -46}, + withNullField); + + object = new Klazz(); + object.a = 12345; + object.b = new byte[] {1, 2, 3}; + object.c = 7890; + + final byte[] withContent = + JBBPOut.BeginBin().Bin(object, nullableByteArrayProcessor).End().toByteArray(); + assertArrayEquals(new byte[] {0, 0, 48, 57, 0, 0, 0, 3, 1, 2, 3, 0, 0, 30, (byte) -46}, + withContent); + + object = new Klazz(); + object.a = 12345; + object.b = new byte[0]; + object.c = 7890; + + final byte[] withZeroLength = + JBBPOut.BeginBin().Bin(object, nullableByteArrayProcessor).End().toByteArray(); + assertArrayEquals(new byte[] {0, 0, 48, 57, 0, 0, 0, 0, 0, 0, 30, (byte) -46}, withZeroLength); + + JBBPParser parser = + JBBPParser.prepare("int a; nullableByteArray b; int c;", nullableByteArrayProcessor); + + Klazz parsed = parser.parse(withNullField).mapTo(new Klazz(), nullableByteArrayProcessor); + + assertEquals(12345, parsed.a); + assertNull(parsed.b); + assertEquals(7890, parsed.c); + + parsed = parser.parse(withZeroLength).mapTo(new Klazz(), nullableByteArrayProcessor); + assertEquals(12345, parsed.a); + assertArrayEquals(new byte[0], parsed.b); + assertEquals(7890, parsed.c); + + parsed = parser.parse(withContent).mapTo(new Klazz(), nullableByteArrayProcessor); + assertEquals(12345, parsed.a); + assertArrayEquals(new byte[] {1, 2, 3}, parsed.b); + assertEquals(7890, parsed.c); + } + + /* + * Test for reported issue #42 https://github.com/raydac/java-binary-block-parser/issues/42 + */ + @Test + public void testCase_github_bug42_ThereIsNotAnyOpenedStruct() throws Exception { + byte[] data = new byte[] {0x12, 0x34, 0x20, 0x20}; + final JBBPParser parser = + JBBPParser.prepare(JBBPDslBuilder.Begin().AnnotatedClass(Child.class).End()); + JBBPFieldStruct parsed = parser.parse(data); + final Child parsedPackage = + parsed.findFieldForNameAndType("Child", JBBPFieldStruct.class).mapTo(new Child()); + assertEquals(0x1234, parsedPackage.headerSize); + assertEquals(" ", parsedPackage.body); + } + + @Bin + public class Parent { + @Bin(order = 1, type = BinType.USHORT, comment = "Size of package header") + public int headerSize; + } + + @Bin + public class Child extends Parent { + @Bin(order = 2, type = BinType.BYTE_ARRAY, arraySizeExpr = "2") + public String body; + } + } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/ClassParsingTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/ClassParsingTest.java index 55093fe2..02e52017 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/ClassParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/ClassParsingTest.java @@ -16,10 +16,15 @@ package com.igormaznitsa.jbbp.it; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import com.igormaznitsa.jbbp.JBBPNamedNumericFieldMap; import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.JBBPVarFieldProcessor; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPByteOrder; import com.igormaznitsa.jbbp.mapper.Bin; @@ -27,13 +32,10 @@ import com.igormaznitsa.jbbp.model.JBBPAbstractField; import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; import com.igormaznitsa.jbbp.utils.JBBPUtils; -import org.junit.jupiter.api.Test; - import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class ClassParsingTest extends AbstractParserIntegrationTest { @@ -88,7 +90,8 @@ public class ClassParsingTest extends AbstractParserIntegrationTest { + "ushort minor_version;" + "ushort major_version;" + "ushort constant_pool_count;" - + "constant_pool_item [constant_pool_count - 1] { var [1] cp_item; //we can make any array size because the field will be processed by a custom processor\n }" + + + "constant_pool_item [constant_pool_count - 1] { var [1] cp_item; //we can make any array size because the field will be processed by a custom processor\n }" + "ushort access_flags;" + "ushort this_class;" + "ushort super_class;" @@ -131,7 +134,11 @@ private JBBPVarFieldProcessor getVarFieldProcessor() { return new JBBPVarFieldProcessor() { @Override - public JBBPAbstractArrayField readVarArray(final JBBPBitInputStream inStream, final int arraySize, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { + public JBBPAbstractArrayField readVarArray( + final JBBPBitInputStream inStream, final int arraySize, + final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap, + final JBBPArraySizeLimiter arraySizeLimiter) throws IOException { if ("cp_item".equals(fieldName.getFieldName())) { final int tagItem = inStream.readByte(); final JBBPFieldArrayByte result; @@ -139,7 +146,9 @@ public JBBPAbstractArrayField readVarArray(final JB case CONSTANT_Class: case CONSTANT_String: case CONSTANT_MethodType: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte()}); + result = new JBBPFieldArrayByte(fieldName, + new byte[] {(byte) tagItem, (byte) inStream.readByte(), + (byte) inStream.readByte()}); } break; case CONSTANT_InterfaceMethodref: @@ -148,12 +157,20 @@ public JBBPAbstractArrayField readVarArray(final JB case CONSTANT_Float: case CONSTANT_Integer: case CONSTANT_NameAndType: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte()}); + result = new JBBPFieldArrayByte(fieldName, + new byte[] {(byte) tagItem, (byte) inStream.readByte(), + (byte) inStream.readByte(), (byte) inStream.readByte(), + (byte) inStream.readByte()}); } break; case CONSTANT_Double: case CONSTANT_Long: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte()}); + result = new JBBPFieldArrayByte(fieldName, + new byte[] {(byte) tagItem, (byte) inStream.readByte(), + (byte) inStream.readByte(), (byte) inStream.readByte(), + (byte) inStream.readByte(), (byte) inStream.readByte(), + (byte) inStream.readByte(), (byte) inStream.readByte(), + (byte) inStream.readByte()}); } break; case CONSTANT_Utf8: { @@ -171,7 +188,9 @@ public JBBPAbstractArrayField readVarArray(final JB break; case CONSTANT_MethodHandle: case CONSTANT_InvokeDynamic: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte()}); + result = new JBBPFieldArrayByte(fieldName, + new byte[] {(byte) tagItem, (byte) inStream.readByte(), + (byte) inStream.readByte(), (byte) inStream.readByte()}); } break; default: { @@ -186,20 +205,26 @@ public JBBPAbstractArrayField readVarArray(final JB } @Override - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { + public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, + final JBBPNamedFieldInfo fieldName, + final int extraValue, final JBBPByteOrder byteOrder, + final JBBPNamedNumericFieldMap numericFieldMap) + throws IOException { fail("Must not be called"); return null; } }; } - private String extractClassNameFromConstantPool(final ClassFile klazz, final int classInfoIndex) throws Exception { + private String extractClassNameFromConstantPool(final ClassFile klazz, final int classInfoIndex) + throws Exception { final byte[] constantClassInfo = klazz.constant_pool_item[classInfoIndex - 1].cp_item; final int utf8Index = (constantClassInfo[1] << 8) | (constantClassInfo[2] & 0xFF); return extractUtf8FromConstantPool(klazz, utf8Index); } - private String extractUtf8FromConstantPool(final ClassFile klazz, final int utf8Index) throws Exception { + private String extractUtf8FromConstantPool(final ClassFile klazz, final int utf8Index) + throws Exception { final byte[] utf8data = klazz.constant_pool_item[utf8Index - 1].cp_item; return new String(utf8data, 3, utf8data.length - 3, StandardCharsets.UTF_8); } @@ -214,7 +239,9 @@ private void assertAttribute(final ClassFile klass, final AttributeInfo attr) th fail("Disallowed attribute '" + attrName + '\''); } - private void assertClass(final ClassFile klazz, final int majorVersion, final String className, final String superclass, final int interfaces, final int fields, final int methods) throws Exception { + private void assertClass(final ClassFile klazz, final int majorVersion, final String className, + final String superclass, final int interfaces, final int fields, + final int methods) throws Exception { assertEquals(0xCAFEBABE, klazz.magic); assertEquals(0, klazz.minor_version); assertEquals(majorVersion, klazz.major_version); @@ -252,7 +279,8 @@ private void assertClass(final ClassFile klazz, final int majorVersion, final St public void testParseClassFile_TestClass() throws Exception { final InputStream in = getResourceAsInputStream("test.clazz"); try { - final ClassFile klazz = classParser.parse(in, getVarFieldProcessor(), null).mapTo(new ClassFile()); + final ClassFile klazz = + classParser.parse(in, getVarFieldProcessor(), null).mapTo(new ClassFile()); assertClass(klazz, FORMAT_J2SE7, "Test", "java/lang/Object", 0, 2, 4); assertEquals(831, classParser.getFinalStreamByteCounter()); } finally { @@ -264,8 +292,10 @@ public void testParseClassFile_TestClass() throws Exception { public void testParseClassFile_HexEngineClass() throws Exception { final InputStream in = getResourceAsInputStream("hexengine.clazz"); try { - final ClassFile klazz = classParser.parse(in, getVarFieldProcessor(), null).mapTo(new ClassFile()); - assertClass(klazz, FORMAT_J2SE5, "com/igormaznitsa/jhexed/engine/HexEngine", "java/lang/Object", 0, 22, 44); + final ClassFile klazz = + classParser.parse(in, getVarFieldProcessor(), null).mapTo(new ClassFile()); + assertClass(klazz, FORMAT_J2SE5, "com/igormaznitsa/jhexed/engine/HexEngine", + "java/lang/Object", 0, 22, 44); assertEquals(21364, classParser.getFinalStreamByteCounter()); } finally { JBBPUtils.closeQuietly(in); @@ -299,7 +329,7 @@ public static class AttributeInfo { } @Bin - public static class ClassFile { + public static class ClassFile { int magic; char minor_version; char major_version; diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/ConvertToJSONTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/ConvertToJSONTest.java index 75e7d17b..40ea816e 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/ConvertToJSONTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/ConvertToJSONTest.java @@ -16,6 +16,9 @@ package com.igormaznitsa.jbbp.it; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.model.JBBPAbstractArrayField; import com.igormaznitsa.jbbp.model.JBBPAbstractField; @@ -37,21 +40,18 @@ import com.igormaznitsa.jbbp.model.JBBPFieldStruct; import com.igormaznitsa.jbbp.model.JBBPFieldUByte; import com.igormaznitsa.jbbp.model.JBBPFieldUShort; +import java.io.InputStream; import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.JSONStyle; import org.junit.jupiter.api.Test; -import java.io.InputStream; - -import static org.junit.jupiter.api.Assertions.assertTrue; - public class ConvertToJSONTest extends AbstractParserIntegrationTest { public static JSONObject convertToJSon(final JSONObject jsn, final JBBPAbstractField field) { final JSONObject json = jsn == null ? new JSONObject() : jsn; - final String fieldName = field.getFieldName() == null ? "nonamed" : field.getFieldName(); + final String fieldName = field.getFieldName() == null ? "unnamed" : field.getFieldName(); if (field instanceof JBBPAbstractArrayField) { final JSONArray jsonArray = new JSONArray(); if (field instanceof JBBPFieldArrayBit) { @@ -135,19 +135,19 @@ public void testConvertToJSON() throws Exception { try (InputStream pngStream = getResourceAsInputStream("picture.png")) { final JBBPParser pngParser = JBBPParser.prepare( - "long header;" - + "// chunks\n" - + "chunk [_]{" - + " int length; " - + " int type; " - + " byte[length] data; " - + " int crc;" - + "}" + "long header;" + + "// chunks\n" + + "chunk [_]{" + + " int length; " + + " int type; " + + " byte[length] data; " + + " int crc;" + + "}" ); final JSONObject json = convertToJSon(null, pngParser.parse(pngStream)); final String jsonText = json.toJSONString(JSONStyle.MAX_COMPRESS); - assertTrue(jsonText.length() == 13917); + assertEquals(13917, jsonText.length()); assertTrue(jsonText.contains("header:")); assertTrue(jsonText.contains("chunk:{")); assertTrue(jsonText.contains("length:")); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/CustomThreeByteIntegerTypeTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/CustomThreeByteIntegerTypeTest.java index e433dc85..f6b71eb3 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/CustomThreeByteIntegerTypeTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/CustomThreeByteIntegerTypeTest.java @@ -16,11 +16,16 @@ package com.igormaznitsa.jbbp.it; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; import com.igormaznitsa.jbbp.exceptions.JBBPParsingException; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.io.JBBPByteOrder; @@ -29,14 +34,10 @@ import com.igormaznitsa.jbbp.model.JBBPFieldArrayInt; import com.igormaznitsa.jbbp.model.JBBPFieldInt; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Arrays; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * Example of three byte integer custom type processor to parse unsigned integer values represented by three bytes in data stream. @@ -46,24 +47,32 @@ public class CustomThreeByteIntegerTypeTest extends AbstractParserIntegrationTes @Test public void testCustomFieldAsAnonymousSingleField() throws Exception { final JBBPParser parser = JBBPParser.prepare("int24;", new Int24CustomTypeProcessor()); - assertEquals(5, parser.parse(new byte[] {0, 0, 5}).findFieldForType(JBBPFieldInt.class).getAsInt()); + assertEquals(5, + parser.parse(new byte[] {0, 0, 5}).findFieldForType(JBBPFieldInt.class).getAsInt()); } @Test public void testReadThreeByteInteger_AnonymousArray() throws Exception { final JBBPParser parser = JBBPParser.prepare("int24 [_];", new Int24CustomTypeProcessor()); - assertArrayEquals(new int[] {0x010203, 0x040506, 0x070809}, parser.parse(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}).findFieldForType(JBBPFieldArrayInt.class).getArray()); + assertArrayEquals(new int[] {0x010203, 0x040506, 0x070809}, + parser.parse(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}) + .findFieldForType(JBBPFieldArrayInt.class).getArray()); } @Test public void testReadThreeByte_NamedCustomFieldAsArrayLength() throws Exception { - final JBBPParser parser = JBBPParser.prepare("int24 value; byte [value];", new Int24CustomTypeProcessor()); - assertEquals(5, parser.parse(new byte[] {0, 0, 5, 1, 2, 3, 4, 5}).findFieldForType(JBBPFieldArrayByte.class).size()); + final JBBPParser parser = + JBBPParser.prepare("int24 value; byte [value];", new Int24CustomTypeProcessor()); + assertEquals(5, + parser.parse(new byte[] {0, 0, 5, 1, 2, 3, 4, 5}).findFieldForType(JBBPFieldArrayByte.class) + .size()); } @Test public void testReadThreeByteInteger_NamedCustomFieldInExpression() throws Exception { - final JBBPParser parser = JBBPParser.prepare("int24 value1; int24 value2; byte [value1+value2];", new Int24CustomTypeProcessor()); + final JBBPParser parser = JBBPParser + .prepare("int24 value1; int24 value2; byte [value1+value2];", + new Int24CustomTypeProcessor()); final JBBPFieldStruct struct = parser.parse(new byte[] {0, 0, 2, 0, 0, 3, 1, 2, 3, 4, 5}); assertEquals(5, struct.findFieldForType(JBBPFieldArrayByte.class).size()); assertEquals(2, struct.findFieldForNameAndType("value1", JBBPFieldInt.class).getAsInt()); @@ -73,11 +82,20 @@ public void testReadThreeByteInteger_NamedCustomFieldInExpression() throws Excep @Test public void testReadThreeByteInteger_OneValue() throws Exception { final JBBPParser parser = JBBPParser.prepare("int24 value;", new Int24CustomTypeProcessor()); - final JBBPParser inverseparser = JBBPParser.prepare(">> 8); } @@ -147,14 +174,23 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final String fieldName, final int extraData, final boolean isArray) { + public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, + final String fieldName, final int extraData, final boolean isArray) { return extraData == 0; } @Override - public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final JBBPBitOrder bitOrder, final int parserFlags, final JBBPFieldTypeParameterContainer customTypeFieldInfo, final JBBPNamedFieldInfo fieldName, final int extraData, final boolean readWholeStream, final int arrayLength) throws IOException { + public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, + final JBBPBitOrder bitOrder, final int parserFlags, + final JBBPFieldTypeParameterContainer customTypeFieldInfo, + final JBBPNamedFieldInfo fieldName, + final int extraData, final boolean readWholeStream, + final int arrayLength, + final JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { if (arrayLength < 0) { - return new JBBPFieldInt(fieldName, readThreeBytesAsInt(in, customTypeFieldInfo.getByteOrder(), bitOrder)); + return new JBBPFieldInt(fieldName, + readThreeBytesAsInt(in, customTypeFieldInfo.getByteOrder(), bitOrder)); } else { if (readWholeStream) { final IntBuffer intBuffer = new IntBuffer(1024); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/NetPacketParsingTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/NetPacketParsingTest.java index 4dca2c5e..2ff98ba0 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/NetPacketParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/NetPacketParsingTest.java @@ -43,7 +43,8 @@ public class NetPacketParsingTest extends AbstractParserIntegrationTest { @Test public void testParsingTCPFrameInsideNetworkFrame() throws Exception { - final JBBPBitInputStream netPacketStream = new JBBPBitInputStream(getResourceAsInputStream("tcppacket.bin")); + final JBBPBitInputStream netPacketStream = + new JBBPBitInputStream(getResourceAsInputStream("tcppacket.bin")); try { // Ethernet header Ethernet II @@ -67,7 +68,8 @@ public void testParsingTCPFrameInsideNetworkFrame() throws Exception { + "ushort HeaderChecksum;" + "int SourceAddress;" + "int DestinationAddress;" - + "byte [((InternetHeaderLength-5)*4)*((((InternetHeaderLength-5)&16)^16)>>4)] Options;" + + + "byte [((InternetHeaderLength-5)*4)*((((InternetHeaderLength-5)&16)^16)>>4)] Options;" ); // TCP header @@ -95,16 +97,26 @@ public void testParsingTCPFrameInsideNetworkFrame() throws Exception { // Check Ethernet header - final JBBPFieldStruct parsedEthernetHeader = ethernetParserHeaderWithout802_1QTag.parse(netPacketStream); - assertArrayEquals(new byte[] {(byte) 0x60, (byte) 0x67, (byte) 0x20, (byte) 0xE1, (byte) 0xF9, (byte) 0xF8}, parsedEthernetHeader.findFieldForNameAndType("MacDestination", JBBPFieldArrayByte.class).getArray(), "Destination MAC"); - assertArrayEquals(new byte[] {(byte) 0x00, (byte) 0x26, (byte) 0x44, (byte) 0x74, (byte) 0xFE, (byte) 0x66}, parsedEthernetHeader.findFieldForNameAndType("MacSource", JBBPFieldArrayByte.class).getArray(), "Source MAC"); - - final int etherTypeOrLength = parsedEthernetHeader.findFieldForNameAndType("EtherTypeOrLength", JBBPFieldUShort.class).getAsInt(); + final JBBPFieldStruct parsedEthernetHeader = + ethernetParserHeaderWithout802_1QTag.parse(netPacketStream); + assertArrayEquals( + new byte[] {(byte) 0x60, (byte) 0x67, (byte) 0x20, (byte) 0xE1, (byte) 0xF9, (byte) 0xF8}, + parsedEthernetHeader.findFieldForNameAndType("MacDestination", JBBPFieldArrayByte.class) + .getArray(), "Destination MAC"); + assertArrayEquals( + new byte[] {(byte) 0x00, (byte) 0x26, (byte) 0x44, (byte) 0x74, (byte) 0xFE, (byte) 0x66}, + parsedEthernetHeader.findFieldForNameAndType("MacSource", JBBPFieldArrayByte.class) + .getArray(), "Source MAC"); + + final int etherTypeOrLength = + parsedEthernetHeader.findFieldForNameAndType("EtherTypeOrLength", JBBPFieldUShort.class) + .getAsInt(); assertEquals(0x800, etherTypeOrLength, "Ethernet type or length"); if (etherTypeOrLength > 1500) { // list of protocols http://standards-oui.ieee.org/ethertype/eth.txt - System.out.println("Ethernet type is : 0x" + Integer.toHexString(etherTypeOrLength).toUpperCase()); + System.out.println( + "Ethernet type is : 0x" + Integer.toHexString(etherTypeOrLength).toUpperCase()); } else { System.out.println("Payload length : " + etherTypeOrLength); } @@ -114,39 +126,69 @@ public void testParsingTCPFrameInsideNetworkFrame() throws Exception { netPacketStream.resetCounter(); final JBBPFieldStruct parsedIPHeader = ipParserHeaderWithoutOptions.parse(netPacketStream); - assertEquals(4, parsedIPHeader.findFieldForNameAndType("Version", JBBPFieldBit.class).getAsInt(), "IP Version"); + assertEquals(4, + parsedIPHeader.findFieldForNameAndType("Version", JBBPFieldBit.class).getAsInt(), + "IP Version"); - final int internetHeaderLength = parsedIPHeader.findFieldForNameAndType("InternetHeaderLength", JBBPFieldBit.class).getAsInt(); + final int internetHeaderLength = + parsedIPHeader.findFieldForNameAndType("InternetHeaderLength", JBBPFieldBit.class) + .getAsInt(); assertEquals(5, internetHeaderLength, "Length of the IP header (in 4 byte items)"); - assertEquals(0, parsedIPHeader.findFieldForNameAndType("DSCP", JBBPFieldBit.class).getAsInt(), "Differentiated Services Code Point"); - assertEquals(0, parsedIPHeader.findFieldForNameAndType("ECN", JBBPFieldBit.class).getAsInt(), "Explicit Congestion Notification"); + assertEquals(0, parsedIPHeader.findFieldForNameAndType("DSCP", JBBPFieldBit.class).getAsInt(), + "Differentiated Services Code Point"); + assertEquals(0, parsedIPHeader.findFieldForNameAndType("ECN", JBBPFieldBit.class).getAsInt(), + "Explicit Congestion Notification"); - final int ipTotalPacketLength = parsedIPHeader.findFieldForNameAndType("TotalPacketLength", JBBPFieldUShort.class).getAsInt(); + final int ipTotalPacketLength = + parsedIPHeader.findFieldForNameAndType("TotalPacketLength", JBBPFieldUShort.class) + .getAsInt(); - assertEquals(159, ipTotalPacketLength, "Entire IP packet size, including header and data, in bytes"); - assertEquals(30810, parsedIPHeader.findFieldForNameAndType("Identification", JBBPFieldUShort.class).getAsInt(), "Identification"); + assertEquals(159, ipTotalPacketLength, + "Entire IP packet size, including header and data, in bytes"); + assertEquals(30810, + parsedIPHeader.findFieldForNameAndType("Identification", JBBPFieldUShort.class) + .getAsInt(), "Identification"); - final int ipFlagsAndFragmentOffset = parsedIPHeader.findFieldForNameAndType("IPFlagsAndFragmentOffset", JBBPFieldUShort.class).getAsInt(); + final int ipFlagsAndFragmentOffset = + parsedIPHeader.findFieldForNameAndType("IPFlagsAndFragmentOffset", JBBPFieldUShort.class) + .getAsInt(); assertEquals(0x2, ipFlagsAndFragmentOffset >>> 13, "Extracted IP flags"); assertEquals(0x00, ipFlagsAndFragmentOffset & 0x1FFF, "Extracted Fragment offset"); - assertEquals(0x39, parsedIPHeader.findFieldForNameAndType("TTL", JBBPFieldUByte.class).getAsInt(), "Time To Live"); - assertEquals(0x06, parsedIPHeader.findFieldForNameAndType("Protocol", JBBPFieldUByte.class).getAsInt(), "Protocol (RFC-790)"); - assertEquals(0x7DB6, parsedIPHeader.findFieldForNameAndType("HeaderChecksum", JBBPFieldUShort.class).getAsInt(), "IPv4 Header Checksum"); - assertEquals(0xD5C7B393, parsedIPHeader.findFieldForNameAndType("SourceAddress", JBBPFieldInt.class).getAsInt(), "Source IP address"); - assertEquals(0xC0A80145, parsedIPHeader.findFieldForNameAndType("DestinationAddress", JBBPFieldInt.class).getAsInt(), "Destination IP address"); - - assertEquals(0, parsedIPHeader.findFieldForNameAndType("Options", JBBPFieldArrayByte.class).getArray().length); + assertEquals(0x39, + parsedIPHeader.findFieldForNameAndType("TTL", JBBPFieldUByte.class).getAsInt(), + "Time To Live"); + assertEquals(0x06, + parsedIPHeader.findFieldForNameAndType("Protocol", JBBPFieldUByte.class).getAsInt(), + "Protocol (RFC-790)"); + assertEquals(0x7DB6, + parsedIPHeader.findFieldForNameAndType("HeaderChecksum", JBBPFieldUShort.class) + .getAsInt(), "IPv4 Header Checksum"); + assertEquals(0xD5C7B393, + parsedIPHeader.findFieldForNameAndType("SourceAddress", JBBPFieldInt.class).getAsInt(), + "Source IP address"); + assertEquals(0xC0A80145, + parsedIPHeader.findFieldForNameAndType("DestinationAddress", JBBPFieldInt.class) + .getAsInt(), "Destination IP address"); + + assertEquals(0, parsedIPHeader.findFieldForNameAndType("Options", JBBPFieldArrayByte.class) + .getArray().length); // Check TCP header netPacketStream.resetCounter(); final JBBPFieldStruct parsedTcpHeader = tcpHeader.parse(netPacketStream); - assertEquals(40018, parsedTcpHeader.findFieldForNameAndType("SourcePort", JBBPFieldUShort.class).getAsInt()); - assertEquals(56344, parsedTcpHeader.findFieldForNameAndType("DestinationPort", JBBPFieldUShort.class).getAsInt()); - assertEquals(0xE0084171, parsedTcpHeader.findFieldForNameAndType("SequenceNumber", JBBPFieldInt.class).getAsInt()); - assertEquals(0xAB616F71, parsedTcpHeader.findFieldForNameAndType("AcknowledgementNumber", JBBPFieldInt.class).getAsInt()); + assertEquals(40018, + parsedTcpHeader.findFieldForNameAndType("SourcePort", JBBPFieldUShort.class).getAsInt()); + assertEquals(56344, + parsedTcpHeader.findFieldForNameAndType("DestinationPort", JBBPFieldUShort.class) + .getAsInt()); + assertEquals(0xE0084171, + parsedTcpHeader.findFieldForNameAndType("SequenceNumber", JBBPFieldInt.class).getAsInt()); + assertEquals(0xAB616F71, + parsedTcpHeader.findFieldForNameAndType("AcknowledgementNumber", JBBPFieldInt.class) + .getAsInt()); assertFalse(parsedTcpHeader.findFieldForNameAndType("FIN", JBBPFieldBit.class).getAsBool()); assertFalse(parsedTcpHeader.findFieldForNameAndType("SYN", JBBPFieldBit.class).getAsBool()); @@ -154,25 +196,36 @@ public void testParsingTCPFrameInsideNetworkFrame() throws Exception { assertTrue(parsedTcpHeader.findFieldForNameAndType("PSH", JBBPFieldBit.class).getAsBool()); assertTrue(parsedTcpHeader.findFieldForNameAndType("ACK", JBBPFieldBit.class).getAsBool()); assertFalse(parsedTcpHeader.findFieldForNameAndType("URG", JBBPFieldBit.class).getAsBool()); - assertFalse(parsedTcpHeader.findFieldForNameAndType("ECNECHO", JBBPFieldBit.class).getAsBool()); + assertFalse( + parsedTcpHeader.findFieldForNameAndType("ECNECHO", JBBPFieldBit.class).getAsBool()); assertFalse(parsedTcpHeader.findFieldForNameAndType("CWR", JBBPFieldBit.class).getAsBool()); assertFalse(parsedTcpHeader.findFieldForNameAndType("NONCE", JBBPFieldBit.class).getAsBool()); - assertFalse(parsedTcpHeader.findFieldForNameAndType("RESERVED", JBBPFieldBit.class).getAsBool()); + assertFalse( + parsedTcpHeader.findFieldForNameAndType("RESERVED", JBBPFieldBit.class).getAsBool()); - assertEquals(5, parsedTcpHeader.findFieldForNameAndType("HLEN", JBBPFieldBit.class).getAsInt()); + assertEquals(5, + parsedTcpHeader.findFieldForNameAndType("HLEN", JBBPFieldBit.class).getAsInt()); - assertEquals(40880, parsedTcpHeader.findFieldForNameAndType("WindowSize", JBBPFieldUShort.class).getAsInt()); - assertEquals(0x8BB6, parsedTcpHeader.findFieldForNameAndType("TCPCheckSum", JBBPFieldUShort.class).getAsInt()); - assertEquals(0, parsedTcpHeader.findFieldForNameAndType("UrgentPointer", JBBPFieldUShort.class).getAsInt()); + assertEquals(40880, + parsedTcpHeader.findFieldForNameAndType("WindowSize", JBBPFieldUShort.class).getAsInt()); + assertEquals(0x8BB6, + parsedTcpHeader.findFieldForNameAndType("TCPCheckSum", JBBPFieldUShort.class).getAsInt()); + assertEquals(0, + parsedTcpHeader.findFieldForNameAndType("UrgentPointer", JBBPFieldUShort.class) + .getAsInt()); - assertEquals(0, parsedTcpHeader.findFieldForNameAndType("Option", JBBPFieldArrayByte.class).size()); + assertEquals(0, + parsedTcpHeader.findFieldForNameAndType("Option", JBBPFieldArrayByte.class).size()); // extract data - final int payloadDataLength = ipTotalPacketLength - (internetHeaderLength * 4) - (int) netPacketStream.getCounter(); + final int payloadDataLength = + ipTotalPacketLength - (internetHeaderLength * 4) - (int) netPacketStream.getCounter(); final byte[] data = netPacketStream.readByteArray(payloadDataLength); assertEquals(119, data.length); - System.out.println(new JBBPTextWriter(new StringWriter()).Comment("Payload data extracted from the TCP part").Byte(data).BR().toString()); + System.out.println( + new JBBPTextWriter(new StringWriter()).Comment("Payload data extracted from the TCP part") + .Byte(data).BR().toString()); final byte[] restOfFrame = netPacketStream.readByteArray(-1); assertEquals(0, restOfFrame.length); @@ -198,9 +251,11 @@ final class Parsed { int dataLength; } - final byte[] testArray = new byte[] {0x23, 0x21, (byte) 0x90, 0x23, 0x21, 0x22, 0x12, 0x00, (byte) 0xAA}; + final byte[] testArray = + new byte[] {0x23, 0x21, (byte) 0x90, 0x23, 0x21, 0x22, 0x12, 0x00, (byte) 0xAA}; - final Parsed parsed = JBBPParser.prepare("byte begin; bit:4 version; bit:4 returnType; byte [5] productCode; ushort dataLength;") + final Parsed parsed = JBBPParser.prepare( + "byte begin; bit:4 version; bit:4 returnType; byte [5] productCode; ushort dataLength;") .parse(testArray) .mapTo(new Parsed()); @@ -229,9 +284,15 @@ final class Parsed { byte[] data; } - final byte[] testArray = new byte[] {0x04, (byte) 0x89, 0x00, 0x35, 0x00, 0x2C, (byte) 0xAB, (byte) 0xB4, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x6F, 0x70, 0x64, 0x02, 0x69, 0x78, 0x06, 0x6E, 0x65, 0x74, 0x63, 0x6F, 0x6D, 0x03, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x01, 0x00, 0x01}; + final byte[] testArray = + new byte[] {0x04, (byte) 0x89, 0x00, 0x35, 0x00, 0x2C, (byte) 0xAB, (byte) 0xB4, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x6F, 0x70, + 0x64, 0x02, 0x69, 0x78, 0x06, 0x6E, 0x65, 0x74, 0x63, 0x6F, 0x6D, 0x03, 0x63, 0x6F, + 0x6D, 0x00, 0x00, 0x01, 0x00, 0x01}; - final Parsed parsed = JBBPParser.prepare("ushort source; ushort destination; ushort length; ushort checksum; byte [length-8] data;").parse(testArray).mapTo(new Parsed()); + final Parsed parsed = JBBPParser.prepare( + "ushort source; ushort destination; ushort length; ushort checksum; byte [length-8] data;") + .parse(testArray).mapTo(new Parsed()); assertEquals(0x0489, parsed.source); assertEquals(0x0035, parsed.destination); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PNGParsingTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PNGParsingTest.java index 47a3197f..2a9727c7 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PNGParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PNGParsingTest.java @@ -36,11 +36,15 @@ public class PNGParsingTest extends AbstractParserIntegrationTest { - private static void assertChunk(final String name, final int length, final JBBPFieldStruct chunk) { - final int chunkName = (name.charAt(0) << 24) | (name.charAt(1) << 16) | (name.charAt(2) << 8) | name.charAt(3); + private static void assertChunk(final String name, final int length, + final JBBPFieldStruct chunk) { + final int chunkName = + (name.charAt(0) << 24) | (name.charAt(1) << 16) | (name.charAt(2) << 8) | name.charAt(3); - assertEquals(chunkName, chunk.findFieldForNameAndType("type", JBBPFieldInt.class).getAsInt(), "Chunk must be " + name); - assertEquals(length, chunk.findFieldForNameAndType("length", JBBPFieldInt.class).getAsInt(), "Chunk length must be " + length); + assertEquals(chunkName, chunk.findFieldForNameAndType("type", JBBPFieldInt.class).getAsInt(), + "Chunk must be " + name); + assertEquals(length, chunk.findFieldForNameAndType("length", JBBPFieldInt.class).getAsInt(), + "Chunk length must be " + length); final PureJavaCrc32 crc32 = new PureJavaCrc32(); crc32.update(name.charAt(0)); @@ -57,7 +61,8 @@ private static void assertChunk(final String name, final int length, final JBBPF } final int crc = (int) crc32.getValue(); - assertEquals(crc, chunk.findLastFieldForType(JBBPFieldInt.class).getAsInt(), "CRC32 for " + name + " must be " + crc); + assertEquals(crc, chunk.findLastFieldForType(JBBPFieldInt.class).getAsInt(), + "CRC32 for " + name + " must be " + crc); } @@ -106,13 +111,15 @@ Chunk makeChunk() { assertEquals(0x89504E470D0A1A0AL, png.hEAder); - final String[] chunkNames = new String[] {"IHDR", "gAMA", "bKGD", "pHYs", "tIME", "tEXt", "IDAT", "IEND"}; + final String[] chunkNames = + new String[] {"IHDR", "gAMA", "bKGD", "pHYs", "tIME", "tEXt", "IDAT", "IEND"}; final int[] chunkSizes = new int[] {0x0D, 0x04, 0x06, 0x09, 0x07, 0x19, 0x0E5F, 0x00}; assertEquals(chunkNames.length, png.chuNK.length); for (int i = 0; i < png.chuNK.length; i++) { - assertPngChunk(chunkNames[i], chunkSizes[i], png.chuNK[i].type, png.chuNK[i].length, png.chuNK[i].crc, png.chuNK[i].data); + assertPngChunk(chunkNames[i], chunkSizes[i], png.chuNK[i].type, png.chuNK[i].length, + png.chuNK[i].crc, png.chuNK[i].data); } assertEquals(3847, pngParser.getFinalStreamByteCounter()); @@ -140,11 +147,14 @@ public void testPngParsing() throws Exception { final JBBPFieldStruct result = pngParser.parse(pngStream); - assertEquals(0x89504E470D0A1A0AL, result.findFieldForNameAndType("header", JBBPFieldLong.class).getAsLong()); + assertEquals(0x89504E470D0A1A0AL, + result.findFieldForNameAndType("header", JBBPFieldLong.class).getAsLong()); - final JBBPFieldArrayStruct chunks = result.findFieldForNameAndType("chunk", JBBPFieldArrayStruct.class); + final JBBPFieldArrayStruct chunks = + result.findFieldForNameAndType("chunk", JBBPFieldArrayStruct.class); - final String[] chunkNames = new String[] {"IHDR", "gAMA", "bKGD", "pHYs", "tIME", "tEXt", "IDAT", "IEND"}; + final String[] chunkNames = + new String[] {"IHDR", "gAMA", "bKGD", "pHYs", "tIME", "tEXt", "IDAT", "IEND"}; final int[] chunkSizes = new int[] {0x0D, 0x04, 0x06, 0x09, 0x07, 0x19, 0x0E5F, 0x00}; assertEquals(chunkNames.length, chunks.size()); @@ -175,19 +185,24 @@ public void testPngParsing_WithExternalValue() throws Exception { + "}" ); - final JBBPFieldStruct result = pngParser.parse(pngStream, null, (fieldName, numericFieldMap, compiledBlock) -> { - if ("value".equals(fieldName)) { - return numericFieldMap.findFieldForPathAndType("chunk.length", JBBPFieldInt.class).getAsInt(); - } - fail("Unexpected variable '" + fieldName + '\''); - return -1; - }); + final JBBPFieldStruct result = + pngParser.parse(pngStream, null, (fieldName, numericFieldMap, compiledBlock) -> { + if ("value".equals(fieldName)) { + return numericFieldMap.findFieldForPathAndType("chunk.length", JBBPFieldInt.class) + .getAsInt(); + } + fail("Unexpected variable '" + fieldName + '\''); + return -1; + }); - assertEquals(0x89504E470D0A1A0AL, result.findFieldForNameAndType("header", JBBPFieldLong.class).getAsLong()); + assertEquals(0x89504E470D0A1A0AL, + result.findFieldForNameAndType("header", JBBPFieldLong.class).getAsLong()); - final JBBPFieldArrayStruct chunks = result.findFieldForNameAndType("chunk", JBBPFieldArrayStruct.class); + final JBBPFieldArrayStruct chunks = + result.findFieldForNameAndType("chunk", JBBPFieldArrayStruct.class); - final String[] chunkNames = new String[] {"IHDR", "gAMA", "bKGD", "pHYs", "tIME", "tEXt", "IDAT", "IEND"}; + final String[] chunkNames = + new String[] {"IHDR", "gAMA", "bKGD", "pHYs", "tIME", "tEXt", "IDAT", "IEND"}; final int[] chunkSizes = new int[] {0x0D, 0x04, 0x06, 0x09, 0x07, 0x19, 0x0E5F, 0x00}; assertEquals(chunkNames.length, chunks.size()); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PackedBCDCustomFieldTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PackedBCDCustomFieldTest.java index f46ddfa5..3f252e0e 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PackedBCDCustomFieldTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PackedBCDCustomFieldTest.java @@ -16,11 +16,15 @@ package com.igormaznitsa.jbbp.it; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; import com.igormaznitsa.jbbp.exceptions.JBBPCompilationException; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.io.JBBPByteOrder; @@ -28,19 +32,15 @@ import com.igormaznitsa.jbbp.model.JBBPFieldArrayLong; import com.igormaznitsa.jbbp.model.JBBPFieldLong; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - import java.io.IOException; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; public class PackedBCDCustomFieldTest implements JBBPCustomFieldTypeProcessor { private static final String[] types = new String[] {"bcd", "sbcd"}; - public static long readValueFromPackedDecimal(final JBBPBitInputStream in, final int len, final boolean signed) throws IOException { + public static long readValueFromPackedDecimal(final JBBPBitInputStream in, final int len, + final boolean signed) throws IOException { final byte[] data = in.readByteArray(len); StringBuilder digitStr = new StringBuilder(); @@ -68,9 +68,11 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final String fieldName, final int extraData, final boolean isArray) { + public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final String fieldName, + final int extraData, final boolean isArray) { if (fieldType.getByteOrder() == JBBPByteOrder.LITTLE_ENDIAN) { - System.err.println("Packed Decimal does not support little endian...using big endian instead"); + System.err + .println("Packed Decimal does not support little endian...using big endian instead"); return false; } @@ -78,7 +80,13 @@ public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final } @Override - public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final JBBPBitOrder bitOrder, final int parserFlags, final JBBPFieldTypeParameterContainer customTypeFieldInfo, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException { + public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, + final JBBPBitOrder bitOrder, final int parserFlags, + final JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { final boolean signed = "sbcd".equals(customTypeFieldInfo.getTypeName()); if (readWholeStream) { @@ -111,7 +119,8 @@ public void testParse_SingleDefaultNonamedPackedDecimal_BigEndian() throws Excep } @Test - public void testParse_SingleDefaultNonamedPackedDecimal_LittleEndian_Exception() throws Exception { + public void testParse_SingleDefaultNonamedPackedDecimal_LittleEndian_Exception() + throws Exception { final PackedBCDCustomFieldTest theInstance = this; assertThrows(JBBPCompilationException.class, () -> JBBPParser.prepare("Remarkablepaper device + * Information about the format was found here + */ +public class RemarkableLinesParsingTest extends AbstractParserIntegrationTest { + + private static final String REMARKABLE_V5_LINES = "byte [43] header;" + + "", maxX, maxY)); + writer.println(); + writer.print(format("", maxX, maxY)); + writer.println(); + for (final Layer layer : layers) { + layer.printSvg(writer); + } + writer.print(""); + } + + public static class Layer { + @Bin(order = 1, byteOrder = LITTLE_ENDIAN) + public int nstrokes; + @Bin(order = 2, arraySizeExpr = "nstrokes") + public Stroke[] strokes; + + public void printSvg(final PrintWriter writer) { + for (final Stroke stroke : strokes) { + stroke.printSvg(writer); + } + writer.println(); + } + + public float findMaxX() { + float result = Float.MIN_VALUE; + for (final Stroke s : strokes) { + result = Math.max(result, s.findMaxX()); + } + return result; + } + + public float findMaxY() { + float result = Float.MIN_VALUE; + for (final Stroke s : strokes) { + result = Math.max(result, s.findMaxY()); + } + return result; + } + + public static class Stroke { + @Bin(order = 1, byteOrder = LITTLE_ENDIAN) + public int pen; + @Bin(order = 2, byteOrder = LITTLE_ENDIAN) + public int color; + @Bin(order = 3, byteOrder = LITTLE_ENDIAN) + public int unknown1; + @Bin(order = 4, byteOrder = LITTLE_ENDIAN) + public float width; + @Bin(order = 5, byteOrder = LITTLE_ENDIAN) + public int unknown2; + @Bin(order = 6, byteOrder = LITTLE_ENDIAN) + public int nsegments; + @Bin(order = 7, arraySizeExpr = "nsegments") + public Segment[] segments; + + private static String color2svg(final int index) { + switch (index) { + case 1: + return "grey"; + case 2: + return "white"; + default: + return "black"; + } + } + + private static float pen2opacity(final int index) { + switch (index) { + case 3: + case 7: + case 13: + case 16: + return 0.9f; + case 5: + case 18: + return 0.2f; + case 8: + return 0.0f; + default: + return 1.0f; + } + } + + public float findMaxX() { + float result = Float.MIN_VALUE; + for (final Segment s : segments) { + result = Math.max(result, s.x); + } + return result; + } + + public float findMaxY() { + float result = Float.MIN_VALUE; + for (final Segment s : segments) { + result = Math.max(result, s.y); + } + return result; + } + + public void printSvg(final PrintWriter writer) { + writer.print(format("", + UUID.randomUUID(), color2svg(this.color), pen2opacity(this.pen))); + writer.println(); + writer.print(format(""); + writer.println(); + writer.print(""); + writer.println(); + } + + public static class Segment { + @Bin(order = 1, byteOrder = LITTLE_ENDIAN) + public float x; + @Bin(order = 2, byteOrder = LITTLE_ENDIAN) + public float y; + @Bin(order = 3, byteOrder = LITTLE_ENDIAN) + public float pressure; + @Bin(order = 4, byteOrder = LITTLE_ENDIAN) + public float tilt; + @Bin(order = 5, byteOrder = LITTLE_ENDIAN) + public float unknown1; + @Bin(order = 6, byteOrder = LITTLE_ENDIAN) + public float unknown2; + + public void printSvg(final PrintWriter writer) { + writer.print(format("%f,%f", x, y)); + } + } + } + } + } + +} diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/SNAParsingTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/SNAParsingTest.java index 241a3765..ce3a34f2 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/SNAParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/SNAParsingTest.java @@ -82,14 +82,17 @@ public void testParseAndSave() throws Exception { final byte[] packed = JBBPOut.BeginBin(LITTLE_ENDIAN).Bin(sna).End().toByteArray(); assertResource("zexall.sna", packed); - final String text = new JBBPTextWriter().ByteOrder(LITTLE_ENDIAN).SetMaxValuesPerLine(32).Bin(sna).Close().toString(); + final String text = + new JBBPTextWriter().ByteOrder(LITTLE_ENDIAN).SetMaxValuesPerLine(32).Bin(sna).Close() + .toString(); assertTrue(text.length() > 10000); System.out.println(text); } @Test public void testParseAndSave_ThroughDslBuilder() throws Exception { - final JBBPParser parser = JBBPParser.prepare(JBBPDslBuilder.Begin().AnnotatedClass(SNA.class).End()); + final JBBPParser parser = + JBBPParser.prepare(JBBPDslBuilder.Begin().AnnotatedClass(SNA.class).End()); final InputStream in = getResourceAsInputStream("zexall.sna"); @@ -100,7 +103,8 @@ public void testParseAndSave_ThroughDslBuilder() throws Exception { JBBPUtils.closeQuietly(in); } - final SNA mapped = parsed.findFieldForNameAndType("SNA", JBBPFieldStruct.class).mapTo(new SNA()); + final SNA mapped = + parsed.findFieldForNameAndType("SNA", JBBPFieldStruct.class).mapTo(new SNA()); assertResource("zexall.sna", JBBPOut.BeginBin().Bin(mapped).End().toByteArray()); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/TAP_ParsingTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/TAP_ParsingTest.java index a1c804bc..164f8ec8 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/TAP_ParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/TAP_ParsingTest.java @@ -16,24 +16,26 @@ package com.igormaznitsa.jbbp.it; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + + import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.io.JBBPByteOrder; import com.igormaznitsa.jbbp.io.JBBPOut; import com.igormaznitsa.jbbp.mapper.Bin; import com.igormaznitsa.jbbp.mapper.BinType; import com.igormaznitsa.jbbp.utils.JBBPUtils; -import org.junit.jupiter.api.Test; - import java.io.IOException; import java.io.InputStream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; public class TAP_ParsingTest extends AbstractParserIntegrationTest { - public static final JBBPParser HEADER_PARSER = JBBPParser.prepare("byte type; byte [10] name; { - if (aClass == Tap.class) return new Tap(); - throw new Error("Unexpected class: "+aClass); + if (aClass == Tap.class) { + return new Tap(); + } + throw new Error("Unexpected class: " + aClass); }); assertEquals(89410, TAP_FILE_PARSER.getFinalStreamByteCounter()); @@ -116,12 +120,14 @@ static class Header extends TapData { @Override public String toString() { - return "HEADER: " + name + " (length=" + length + ", param1=" + param1 + ", param2=" + param2 + ')'; + return "HEADER: " + name + " (length=" + length + ", param1=" + param1 + ", param2=" + + param2 + ')'; } @Override void save(final JBBPOut ctx) throws IOException { - ctx.Short(19).Byte(0, type).ResetCounter().Byte(name).Align(10).Short(length).Short(param1).Short(param2).Byte(check); + ctx.Short(19).Byte(0, type).ResetCounter().Byte(name).Align(10).Short(length).Short(param1) + .Short(param2).Byte(check); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/TGAParsingTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/TGAParsingTest.java index 89936ac6..8c792a58 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/TGAParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/TGAParsingTest.java @@ -16,6 +16,8 @@ package com.igormaznitsa.jbbp.it; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct; @@ -24,11 +26,8 @@ import com.igormaznitsa.jbbp.model.JBBPFieldUByte; import com.igormaznitsa.jbbp.model.JBBPFieldUShort; import com.igormaznitsa.jbbp.utils.JBBPUtils; -import org.junit.jupiter.api.Test; - import java.io.InputStream; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class TGAParsingTest extends AbstractParserIntegrationTest { @@ -58,9 +57,12 @@ public class TGAParsingTest extends AbstractParserIntegrationTest { "byte [_] ImageData;" ); - private void assertTgaFile(final JBBPFieldStruct parsedTga, final String imageId, final int width, final int height, final int pixelDepth, final int colorTableItems, final int imageDataSize) { - final JBBPFieldArrayByte imageIdArray = parsedTga.findFieldForNameAndType("ImageID", JBBPFieldArrayByte.class); - if (imageId == null || imageId.length() == 0) { + private void assertTgaFile(final JBBPFieldStruct parsedTga, final String imageId, final int width, + final int height, final int pixelDepth, final int colorTableItems, + final int imageDataSize) { + final JBBPFieldArrayByte imageIdArray = + parsedTga.findFieldForNameAndType("ImageID", JBBPFieldArrayByte.class); + if (imageId == null || imageId.isEmpty()) { assertEquals(0, imageIdArray.size()); } else { assertEquals(imageId.length(), imageIdArray.size()); @@ -69,11 +71,16 @@ private void assertTgaFile(final JBBPFieldStruct parsedTga, final String imageId } } - assertEquals(width, parsedTga.findFieldForPathAndType("header.Width", JBBPFieldUShort.class).getAsInt()); - assertEquals(height, parsedTga.findFieldForPathAndType("header.Height", JBBPFieldUShort.class).getAsInt()); - assertEquals(pixelDepth, parsedTga.findFieldForPathAndType("header.PixelDepth", JBBPFieldUByte.class).getAsInt()); - assertEquals(colorTableItems, parsedTga.findFieldForNameAndType("ColorMap", JBBPFieldArrayStruct.class).size()); - assertEquals(imageDataSize, parsedTga.findFieldForNameAndType("ImageData", JBBPFieldArrayByte.class).size()); + assertEquals(width, + parsedTga.findFieldForPathAndType("header.Width", JBBPFieldUShort.class).getAsInt()); + assertEquals(height, + parsedTga.findFieldForPathAndType("header.Height", JBBPFieldUShort.class).getAsInt()); + assertEquals(pixelDepth, + parsedTga.findFieldForPathAndType("header.PixelDepth", JBBPFieldUByte.class).getAsInt()); + assertEquals(colorTableItems, + parsedTga.findFieldForNameAndType("ColorMap", JBBPFieldArrayStruct.class).size()); + assertEquals(imageDataSize, + parsedTga.findFieldForNameAndType("ImageData", JBBPFieldArrayByte.class).size()); } @Test @@ -104,8 +111,10 @@ public void testTgaParsing_Logo() throws Exception { try { final JBBPFieldStruct result = TGAParser.parse(tgaStream); assertTgaFile(result, "", 319, 165, 32, 0, 116944); - assertEquals(0, result.findFieldForPathAndType("Header.XOffset", JBBPFieldShort.class).getAsInt()); - assertEquals(165, result.findFieldForPathAndType("Header.YOffset", JBBPFieldShort.class).getAsInt()); + assertEquals(0, + result.findFieldForPathAndType("Header.XOffset", JBBPFieldShort.class).getAsInt()); + assertEquals(165, + result.findFieldForPathAndType("Header.YOffset", JBBPFieldShort.class).getAsInt()); } finally { JBBPUtils.closeQuietly(tgaStream); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/WAVParsingTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/WAVParsingTest.java index ad009c9f..a1e047d4 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/WAVParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/WAVParsingTest.java @@ -16,17 +16,17 @@ package com.igormaznitsa.jbbp.it; +import static org.junit.jupiter.api.Assertions.assertEquals; + + import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct; import com.igormaznitsa.jbbp.model.JBBPFieldInt; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; import com.igormaznitsa.jbbp.utils.JBBPUtils; -import org.junit.jupiter.api.Test; - import java.io.InputStream; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class WAVParsingTest extends AbstractParserIntegrationTest { @@ -43,29 +43,40 @@ public class WAVParsingTest extends AbstractParserIntegrationTest { ); private static String wavInt2Str(final int value) { - return new String(new char[] {(char) (value & 0xFF), (char) ((value >>> 8) & 0xFF), (char) ((value >>> 16) & 0xFF), (char) (value >>> 24)}); + return new String(new char[] {(char) (value & 0xFF), (char) ((value >>> 8) & 0xFF), + (char) ((value >>> 16) & 0xFF), (char) (value >>> 24)}); } private static void assertWavChunks(final JBBPFieldStruct parsedWav, final String... chunks) { - assertEquals(0x46464952, parsedWav.findFieldForNameAndType("ChunkID", JBBPFieldInt.class).getAsInt()); - assertEquals(0x45564157, parsedWav.findFieldForNameAndType("Format", JBBPFieldInt.class).getAsInt()); + assertEquals(0x46464952, + parsedWav.findFieldForNameAndType("ChunkID", JBBPFieldInt.class).getAsInt()); + assertEquals(0x45564157, + parsedWav.findFieldForNameAndType("Format", JBBPFieldInt.class).getAsInt()); int calculatedSize = 4; int index = 0; - assertEquals(chunks.length, parsedWav.findFieldForNameAndType("SubChunks", JBBPFieldArrayStruct.class).size(), "Number of parsed subchunks must be [" + chunks.length + ']'); + assertEquals(chunks.length, + parsedWav.findFieldForNameAndType("SubChunks", JBBPFieldArrayStruct.class).size(), + "Number of parsed subchunks must be [" + chunks.length + ']'); - for (final JBBPFieldStruct subchunk : parsedWav.findFieldForNameAndType("SubChunks", JBBPFieldArrayStruct.class)) { + for (final JBBPFieldStruct subchunk : parsedWav + .findFieldForNameAndType("SubChunks", JBBPFieldArrayStruct.class)) { final String strChunkId = chunks[index++]; - assertEquals(4, strChunkId.length(), "WAV subchunk must have 4 char length [" + strChunkId + ']'); - assertEquals(strChunkId, wavInt2Str(subchunk.findFieldForNameAndType("SubChunkID", JBBPFieldInt.class).getAsInt())); - final int subChunkSize = subchunk.findFieldForNameAndType("SubChunkSize", JBBPFieldInt.class).getAsInt(); - assertEquals(subChunkSize, subchunk.findFieldForNameAndType("data", JBBPFieldArrayByte.class).size()); + assertEquals(4, strChunkId.length(), + "WAV subchunk must have 4 char length [" + strChunkId + ']'); + assertEquals(strChunkId, wavInt2Str( + subchunk.findFieldForNameAndType("SubChunkID", JBBPFieldInt.class).getAsInt())); + final int subChunkSize = + subchunk.findFieldForNameAndType("SubChunkSize", JBBPFieldInt.class).getAsInt(); + assertEquals(subChunkSize, + subchunk.findFieldForNameAndType("data", JBBPFieldArrayByte.class).size()); calculatedSize += subChunkSize + 8 + (subChunkSize & 1); } - assertEquals(calculatedSize, parsedWav.findFieldForNameAndType("ChunkSize", JBBPFieldInt.class).getAsInt()); + assertEquals(calculatedSize, + parsedWav.findFieldForNameAndType("ChunkSize", JBBPFieldInt.class).getAsInt()); } @Test diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/Z80_v1_ParsingTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/Z80_v1_ParsingTest.java index 96a6e488..3c033237 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/Z80_v1_ParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/Z80_v1_ParsingTest.java @@ -54,20 +54,14 @@ public class Z80_v1_ParsingTest extends AbstractParserIntegrationTest { private static final JBBPParser z80Parser = JBBPParser.prepare( "byte reg_a; byte reg_f; , Object> INSTANTIATOR = aClass -> { if (aClass == Flags.class) { return new Flags(); @@ -78,6 +72,28 @@ public void testRLEEncoding() throws Exception { return null; }; + @Test + public void testRLEEncoding() throws Exception { + assertArrayEquals(new byte[] {(byte) 0xED, (byte) 0xED, 1, 2, 3}, JBBPOut.BeginBin() + .Var(new RLEDataEncoder(), 0, new byte[] {(byte) 0xED, (byte) 0xED, 1, 2, 3}).End() + .toByteArray()); + assertArrayEquals( + new byte[] {(byte) 0xED, (byte) 0xED, 2, (byte) 0xED, 1, 2, 3, 0x00, (byte) 0xED, + (byte) 0xED, 0x00}, JBBPOut.BeginBin() + .Var(new RLEDataEncoder(), 1, new byte[] {(byte) 0xED, (byte) 0xED, 1, 2, 3}).End() + .toByteArray()); + assertArrayEquals( + new byte[] {(byte) 0xED, 0x00, (byte) 0xED, (byte) 0xED, 0x05, 0x00, 0x00, (byte) 0xED, + (byte) 0xED, 0x00}, + JBBPOut.BeginBin().Var(new RLEDataEncoder(), 1, new byte[] {(byte) 0xED, 0, 0, 0, 0, 0, 0}) + .End().toByteArray()); + assertArrayEquals( + new byte[] {(byte) 0xED, (byte) 0xED, 8, 5, 1, 2, 3, 0x00, (byte) 0xED, (byte) 0xED, 0x00}, + JBBPOut.BeginBin() + .Var(new RLEDataEncoder(), 1, new byte[] {5, 5, 5, 5, 5, 5, 5, 5, 1, 2, 3}).End() + .toByteArray()); + } + @Test public void testParseAndWriteTestZ80WithoutCheckOfFields() throws Exception { assertParseAndPackBack("test1.z80", 16059); @@ -86,7 +102,8 @@ public void testParseAndWriteTestZ80WithoutCheckOfFields() throws Exception { assertParseAndPackBack("test4.z80", 9946); } - private Z80Snapshot assertParseAndPackBack(final String name, final long etalonLen) throws Exception { + private Z80Snapshot assertParseAndPackBack(final String name, final long etalonLen) + throws Exception { final Z80Snapshot z80sn; final InputStream resource = getResourceAsInputStream(name); @@ -128,19 +145,21 @@ private Z80Snapshot assertParseAndPackBack(final String name, final long etalonL public void testParseAndWriteTestZ80WithCheckOfFields() throws Exception { final Z80Snapshot z80sn = assertParseAndPackBack("test.z80", 12429); - final String text = new JBBPTextWriter().ByteOrder(LITTLE_ENDIAN).SetMaxValuesPerLine(32).AddExtras(new JBBPTextWriterExtraAdapter() { - - @Override - public String doConvertCustomField(JBBPTextWriter context, Object obj, Field field, Bin annotation) throws IOException { - try { - final byte[] data = (byte[]) field.get(obj); - return "byte array length [" + data.length + ']'; - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } + final String text = new JBBPTextWriter().ByteOrder(LITTLE_ENDIAN).SetMaxValuesPerLine(32) + .AddExtras(new JBBPTextWriterExtraAdapter() { + + @Override + public String doConvertCustomField(JBBPTextWriter context, Object obj, Field field, + Bin annotation) throws IOException { + try { + final byte[] data = (byte[]) field.get(obj); + return "byte array length [" + data.length + ']'; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } - }).Bin(z80sn).Close().toString(); + }).Bin(z80sn).Close().toString(); assertTrue(text.contains("byte array length [49152]")); System.out.println(text); @@ -197,7 +216,8 @@ public void testParseAndPackThrowMapping() throws Exception { JBBPUtils.closeQuietly(in); } - final byte[] saved = JBBPOut.BeginBin(LITTLE_ENDIAN).Bin(parsed, new DataProcessor()).End().toByteArray(); + final byte[] saved = + JBBPOut.BeginBin(LITTLE_ENDIAN).Bin(parsed, new DataProcessor()).End().toByteArray(); assertResource("test.z80", saved); } @@ -205,7 +225,8 @@ public void testParseAndPackThrowMapping() throws Exception { private static class RLEDataEncoder implements JBBPOutVarProcessor { @Override - public boolean processVarOut(final JBBPOut context, final JBBPBitOutputStream outStream, final Object... args) throws IOException { + public boolean processVarOut(final JBBPOut context, final JBBPBitOutputStream outStream, + final Object... args) throws IOException { final byte[] unpackedData = (byte[]) args[1]; if (((Number) args[0]).intValue() == 0) { context.Byte(unpackedData); @@ -263,14 +284,18 @@ public boolean processVarOut(final JBBPOut context, final JBBPBitOutputStream ou } } - private static class DataProcessor implements JBBPMapperCustomFieldProcessor, JBBPCustomFieldWriter { + private static class DataProcessor + implements JBBPMapperCustomFieldProcessor, JBBPCustomFieldWriter { @Override - public Object prepareObjectForMapping(JBBPFieldStruct parsedBlock, Bin annotation, Field field) { + public Object prepareObjectForMapping(JBBPFieldStruct parsedBlock, Bin annotation, + Field field) { if (field.getName().equals("data")) { - final byte[] data = parsedBlock.findFieldForNameAndType("data", JBBPFieldArrayByte.class).getArray(); + final byte[] data = + parsedBlock.findFieldForNameAndType("data", JBBPFieldArrayByte.class).getArray(); - if (parsedBlock.findFieldForPathAndType("flags.compressed", JBBPFieldBit.class).getAsBool()) { + if (parsedBlock.findFieldForPathAndType("flags.compressed", JBBPFieldBit.class) + .getAsBool()) { // RLE compressed final ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length << 1); int i = 0; @@ -314,7 +339,9 @@ public Object prepareObjectForMapping(JBBPFieldStruct parsedBlock, Bin annotatio } @Override - public void writeCustomField(final JBBPOut context, final JBBPBitOutputStream out, final Object instanceForSaving, final Field instanceCustomField, final Bin fieldAnnotation, final Object value) throws IOException { + public void writeCustomField(final JBBPOut context, final JBBPBitOutputStream out, + final Object instanceForSaving, final Field instanceCustomField, + final Bin fieldAnnotation, final Object value) throws IOException { try { final byte[] array = (byte[]) instanceCustomField.get(instanceForSaving); new RLEDataEncoder().processVarOut(context, out, 1, array); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/BinTypeTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/BinTypeTest.java index a56a8a07..0ba163cf 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/BinTypeTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/BinTypeTest.java @@ -16,14 +16,13 @@ package com.igormaznitsa.jbbp.mapper; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import java.math.BigInteger; import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; public class BinTypeTest { diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/JBBPMapperTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/JBBPMapperTest.java index dc77d35d..b3cb11ed 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/JBBPMapperTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/JBBPMapperTest.java @@ -16,7 +16,9 @@ package com.igormaznitsa.jbbp.mapper; + import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -26,10 +28,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; - import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.TestUtils; import com.igormaznitsa.jbbp.exceptions.JBBPMapperException; +import com.igormaznitsa.jbbp.exceptions.JBBPNumericFieldValueConversionException; import com.igormaznitsa.jbbp.io.JBBPBitNumber; import com.igormaznitsa.jbbp.io.JBBPOut; import com.igormaznitsa.jbbp.model.JBBPFieldInt; @@ -41,16 +43,30 @@ public class JBBPMapperTest { @Test void testMakeNewInstanceInLocalThroughDefaultConstructors() throws Exception { - final StaticTopNoInstanceMethod result = JBBPParser.prepare("levelOne { levelTwos[_]{byte a;}}").parse(new byte[] {1, 2, 3}).mapTo(new StaticTopNoInstanceMethod()); + final StaticTopNoInstanceMethod result = + JBBPParser.prepare("levelOne { levelTwos[_]{byte a;}}").parse(new byte[] {1, 2, 3}) + .mapTo(new StaticTopNoInstanceMethod()); assertNotNull(result.levelOne); assertNotNull(result.levelOne.levelTwos); assertEquals(3, result.levelOne.levelTwos.length); } + @Test + void testMakeNewInstanceInLocalThroughDefaultConstructors_WithFieldFilter() throws Exception { + final StaticTopNoInstanceMethod result = + JBBPParser.prepare("levelOne { levelTwos[_]{byte a;}}").parse(new byte[] {1, 2, 3, 4, 5, 6}) + .mapTo(new StaticTopNoInstanceMethod(), (b, f) -> !f.getName().equals("levelTwos")); + + assertNotNull(result.levelOne); + assertNull(result.levelOne.levelTwos); + } + @Test void testMakeNewInstanceInLocalStaticClasses() throws Exception { - final StaticTop result = JBBPParser.prepare("levelOne { levelTwos[_]{byte a;}}").parse(new byte[] {1, 2, 3}).mapTo(new StaticTop()); + final StaticTop result = + JBBPParser.prepare("levelOne { levelTwos[_]{byte a;}}").parse(new byte[] {1, 2, 3}) + .mapTo(new StaticTop()); assertNotNull(result.levelOne); assertNotNull(result.levelOne.levelTwos); @@ -88,7 +104,9 @@ class LevelTwo { } } - final Top result = JBBPParser.prepare("levelOne { levelTwos[_]{byte a;}}").parse(new byte[] {1, 2, 3}).mapTo(new Top()); + final Top result = + JBBPParser.prepare("levelOne { levelTwos[_]{byte a;}}").parse(new byte[] {1, 2, 3}) + .mapTo(new Top()); assertNotNull(result.levelOne); assertNotNull(result.levelOne.levelTwos); @@ -101,7 +119,8 @@ class Mapped { @Bin byte a; } - assertEquals(3, JBBPParser.prepare("byte a; some{struc {byte a;}}").parse(new byte[] {1, 3}).mapTo("some.struc", new Mapped()).a); + assertEquals(3, JBBPParser.prepare("byte a; some{struc {byte a;}}").parse(new byte[] {1, 3}) + .mapTo("some.struc", new Mapped()).a); } @Test @@ -110,7 +129,8 @@ class Mapped { @Bin byte a; } - assertEquals(3, JBBPMapper.map(JBBPParser.prepare("byte a;").parse(new byte[] {3}), new Mapped()).a); + assertEquals(3, + JBBPMapper.map(JBBPParser.prepare("byte a;").parse(new byte[] {3}), new Mapped()).a); } @Test @@ -128,7 +148,8 @@ class Mapped { @Bin short a; } - assertEquals(0x0304, JBBPParser.prepare("short a;").parse(new byte[] {3, 4}).mapTo(new Mapped()).a); + assertEquals(0x0304, + JBBPParser.prepare("short a;").parse(new byte[] {3, 4}).mapTo(new Mapped()).a); } @Test @@ -141,7 +162,9 @@ class Mapped { @Bin boolean c; } - final Mapped mapped = JBBPParser.prepare("bool a; bool b; bool c;").parse(new byte[] {23, 0, 12}).mapTo(new Mapped()); + final Mapped mapped = + JBBPParser.prepare("bool a; bool b; bool c;").parse(new byte[] {23, 0, 12}) + .mapTo(new Mapped()); assertTrue(mapped.a); assertFalse(mapped.b); assertTrue(mapped.c); @@ -155,24 +178,44 @@ class Mapped { @Bin String b; } - final Mapped mapped = JBBPParser.prepare("stringj a; stringj b;").parse(new byte[] {3, 65, 66, 67, 2, 68, 69}).mapTo(new Mapped()); + final Mapped mapped = + JBBPParser.prepare("stringj a; stringj b;").parse(new byte[] {3, 65, 66, 67, 2, 68, 69}) + .mapTo(new Mapped()); assertEquals("ABC", mapped.a); assertEquals("DE", mapped.b); } + @Test + void testMap_String_WithFilter() throws Exception { + class Mapped { + @Bin + String a; + @Bin + String b; + } + final Mapped mapped = + JBBPParser.prepare("stringj a; stringj b;").parse(new byte[] {3, 65, 66, 67, 2, 68, 69}) + .mapTo(new Mapped(), (b, f) -> !"b".equals(f.getName())); + assertEquals("ABC", mapped.a); + assertNull(mapped.b); + } + @Test void testMap_StringArrayToStringArray() throws Exception { class Mapped { @Bin String[] a; } - final Mapped mapped = JBBPParser.prepare("stringj [_] a;").parse(new byte[] {3, 65, 66, 67, 2, 68, 69}).mapTo(new Mapped()); + final Mapped mapped = + JBBPParser.prepare("stringj [_] a;").parse(new byte[] {3, 65, 66, 67, 2, 68, 69}) + .mapTo(new Mapped()); assertArrayEquals(new String[] {"ABC", "DE"}, mapped.a); } @Test void testMap_IgnoreStaticField() throws Exception { - final MappedWithStaticField mapped = JBBPParser.prepare("int a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new MappedWithStaticField()); + final MappedWithStaticField mapped = JBBPParser.prepare("int a;").parse(new byte[] {1, 2, 3, 4}) + .mapTo(new MappedWithStaticField()); assertEquals(0x01020304, mapped.a); assertEquals(111, MappedWithStaticField.ignored); } @@ -187,19 +230,76 @@ class Mapped { @Bin(type = BinType.BIT) byte c; } - final Mapped mapped = JBBPParser.prepare("bit:3 a; bit:2 b; bit:3 c; ").parse(new byte[] {(byte) 0xDD}).mapTo(new Mapped()); + final Mapped mapped = + JBBPParser.prepare("bit:3 a; bit:2 b; bit:3 c; ").parse(new byte[] {(byte) 0xDD}) + .mapTo(new Mapped()); assertEquals(5, mapped.a); assertEquals(3, mapped.b); assertEquals(6, mapped.c); } + @Test + void testMap_Bit_WithFilter() throws Exception { + class Mapped { + @Bin(type = BinType.BIT) + byte a; + @Bin(type = BinType.BIT) + byte b; + @Bin(type = BinType.BIT) + byte c; + } + final Mapped mapped = + JBBPParser.prepare("bit:3 a; bit:2 b; bit:3 c; ").parse(new byte[] {(byte) 0xDD}) + .mapTo(new Mapped(), (b, f) -> "c".equals(f.getName())); + assertEquals(0, mapped.a); + assertEquals(0, mapped.b); + assertEquals(6, mapped.c); + } + @Test void testMap_Int() throws Exception { class Mapped { @Bin int a; } - assertEquals(0x01020304, JBBPParser.prepare("int a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); + assertEquals(0x01020304, + JBBPParser.prepare("int a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); + } + + @Test + void testMap_UInt() throws Exception { + class Mapped { + @Bin(type = BinType.UINT) + long a; + } + assertEquals(0xFFA0B0C0L, + JBBPParser.prepare("uint a;") + .parse(new byte[] {(byte) 0xFF, (byte) 0xA0, (byte) 0xB0, (byte) 0xC0}) + .mapTo(new Mapped()).a); + } + + @Test + void testMap_UIntToInt() throws Exception { + class Mapped { + @Bin(type = BinType.UINT) + int a; + } + assertEquals(0x1FA0B0C0, + JBBPParser.prepare("uint a;") + .parse(new byte[] {(byte) 0x1F, (byte) 0xA0, (byte) 0xB0, (byte) 0xC0}) + .mapTo(new Mapped()).a); + } + + @Test + void testMap_UIntToInt_ErrorForTooBigValue() { + class Mapped { + @Bin(type = BinType.UINT) + int a; + } + assertThrows(JBBPNumericFieldValueConversionException.class, + () -> JBBPParser.prepare("uint a;") + .parse(new byte[] {(byte) 0xFF, (byte) 0xA0, (byte) 0xB0, (byte) 0xC0}) + .mapTo(new Mapped())); } @Test @@ -209,10 +309,14 @@ class Mapped { float a; } - final byte[] max = JBBPOut.BeginBin().Int(Float.floatToIntBits(Float.MAX_VALUE)).End().toByteArray(); - assertEquals(Float.MAX_VALUE, JBBPParser.prepare("int a;").parse(max).mapTo(new Mapped()).a, 0.005d); - final byte[] min = JBBPOut.BeginBin().Int(Float.floatToIntBits(Float.MIN_VALUE)).End().toByteArray(); - assertEquals(Float.MIN_VALUE, JBBPParser.prepare("int a;").parse(min).mapTo(new Mapped()).a, 0.005d); + final byte[] max = + JBBPOut.BeginBin().Int(Float.floatToIntBits(Float.MAX_VALUE)).End().toByteArray(); + assertEquals(Float.MAX_VALUE, JBBPParser.prepare("int a;").parse(max).mapTo(new Mapped()).a, + 0.005d); + final byte[] min = + JBBPOut.BeginBin().Int(Float.floatToIntBits(Float.MIN_VALUE)).End().toByteArray(); + assertEquals(Float.MIN_VALUE, JBBPParser.prepare("int a;").parse(min).mapTo(new Mapped()).a, + 0.005d); } @Test @@ -222,13 +326,76 @@ class Mapped { float[] a; } - final byte[] max = JBBPOut.BeginBin().Float(Float.MAX_VALUE, Float.MIN_VALUE).End().toByteArray(); + final byte[] max = + JBBPOut.BeginBin().Float(Float.MAX_VALUE, Float.MIN_VALUE).End().toByteArray(); final Mapped result = JBBPParser.prepare("int [_] a;").parse(max).mapTo(new Mapped()); assertEquals(2, result.a.length); assertEquals(Float.MAX_VALUE, result.a[0], TestUtils.FLOAT_DELTA); assertEquals(Float.MIN_VALUE, result.a[1], TestUtils.FLOAT_DELTA); } + @Test + void testMap_MapUIntArrayToLongArray() throws Exception { + class Mapped { + @Bin(type = BinType.UINT_ARRAY) + long[] a; + } + + final byte[] max = + JBBPOut.BeginBin().Byte(0xFF, 1, 2, 3, 0xFE, 4, 5, 6).End().toByteArray(); + final Mapped result = JBBPParser.prepare("uint [_] a;").parse(max).mapTo(new Mapped()); + assertEquals(2, result.a.length); + assertEquals(0xFF010203L, result.a[0]); + assertEquals(0xFE040506L, result.a[1]); + } + + @Test + void testMap_MapUIntArrayToIntArray() throws Exception { + class Mapped { + @Bin(type = BinType.UINT_ARRAY) + int[] a; + } + + final byte[] max = + JBBPOut.BeginBin().Byte(0xFF, 1, 2, 3, 0xFE, 4, 5, 6).End().toByteArray(); + final Mapped result = JBBPParser.prepare("uint [_] a;").parse(max).mapTo(new Mapped()); + assertEquals(2, result.a.length); + assertEquals(0xFF010203, result.a[0]); + assertEquals(0xFE040506, result.a[1]); + } + + @Test + void testMap_MapUIntArrayToFloatArray() throws Exception { + class Mapped { + @Bin(type = BinType.UINT_ARRAY) + float[] a; + } + + final byte[] max = + JBBPOut.BeginBin() + .Int(Float.floatToIntBits(Float.MIN_VALUE), Float.floatToIntBits(Float.MAX_VALUE)).End() + .toByteArray(); + final Mapped result = JBBPParser.prepare("uint [_] a;").parse(max).mapTo(new Mapped()); + assertEquals(2, result.a.length); + assertEquals(Float.MIN_VALUE, result.a[0], TestUtils.FLOAT_DELTA); + assertEquals(Float.MAX_VALUE, result.a[1], TestUtils.FLOAT_DELTA); + } + + @Test + void testMap_MapUIntArrayToDoubleArray() throws Exception { + class Mapped { + @Bin(type = BinType.UINT_ARRAY) + double[] a; + } + + final byte[] max = + JBBPOut.BeginBin().Int(0xFF0A0B0C, 0x01020304).End().toByteArray(); + final Mapped result = JBBPParser.prepare("uint [_] a;").parse(max).mapTo(new Mapped()); + assertEquals(2, result.a.length); + assertEquals(2.114031933E-314d, result.a[0], TestUtils.FLOAT_DELTA); + assertEquals(8.3541856E-317d, result.a[1], TestUtils.FLOAT_DELTA); + } + @Test void testMap_MapLongArrayToDoubleArray() throws Exception { class Mapped { @@ -237,7 +404,8 @@ class Mapped { double[] a; } - final byte[] max = JBBPOut.BeginBin().Double(Double.MAX_VALUE, Double.MIN_VALUE).End().toByteArray(); + final byte[] max = + JBBPOut.BeginBin().Double(Double.MAX_VALUE, Double.MIN_VALUE).End().toByteArray(); final Mapped result = JBBPParser.prepare("long [_] a;").parse(max).mapTo(new Mapped()); assertEquals(2, result.a.length); assertEquals(Double.MAX_VALUE, result.a[0], TestUtils.FLOAT_DELTA); @@ -252,7 +420,8 @@ class Mapped { } final byte[] max = JBBPOut.BeginBin().Float(-1.234567f).End().toByteArray(); - assertEquals(-1.234567f, JBBPParser.prepare("floatj a;").parse(max).mapTo(new Mapped()).a, TestUtils.FLOAT_DELTA); + assertEquals(-1.234567f, JBBPParser.prepare("floatj a;").parse(max).mapTo(new Mapped()).a, + TestUtils.FLOAT_DELTA); } @Test @@ -263,7 +432,21 @@ class Mapped { } final byte[] max = JBBPOut.BeginBin().Float(-1.234567f, 1.234567f).End().toByteArray(); - assertArrayEquals(new float[] {-1.234567f, 1.234567f}, JBBPParser.prepare("floatj [_] a;").parse(max).mapTo(new Mapped()).a, TestUtils.FLOAT_DELTA); + assertArrayEquals(new float[] {-1.234567f, 1.234567f}, + JBBPParser.prepare("floatj [_] a;").parse(max).mapTo(new Mapped()).a, + TestUtils.FLOAT_DELTA); + } + + @Test + void testMap_MapFloatArrayToFloatArray_WithFilter() throws Exception { + class Mapped { + @Bin + float[] a; + } + + final byte[] max = JBBPOut.BeginBin().Float(-1.234567f, 1.234567f).End().toByteArray(); + assertNull( + JBBPParser.prepare("floatj [_] a;").parse(max).mapTo(new Mapped(), (b, f) -> false).a); } @Test @@ -273,10 +456,14 @@ class Mapped { double a; } - final byte[] max = JBBPOut.BeginBin().Long(Double.doubleToLongBits(Double.MAX_VALUE)).End().toByteArray(); - assertEquals(Double.MAX_VALUE, JBBPParser.prepare("long a;").parse(max).mapTo(new Mapped()).a, TestUtils.FLOAT_DELTA); - final byte[] min = JBBPOut.BeginBin().Long(Double.doubleToLongBits(Double.MIN_VALUE)).End().toByteArray(); - assertEquals(Double.MIN_VALUE, JBBPParser.prepare("long a;").parse(min).mapTo(new Mapped()).a, TestUtils.FLOAT_DELTA); + final byte[] max = + JBBPOut.BeginBin().Long(Double.doubleToLongBits(Double.MAX_VALUE)).End().toByteArray(); + assertEquals(Double.MAX_VALUE, JBBPParser.prepare("long a;").parse(max).mapTo(new Mapped()).a, + TestUtils.FLOAT_DELTA); + final byte[] min = + JBBPOut.BeginBin().Long(Double.doubleToLongBits(Double.MIN_VALUE)).End().toByteArray(); + assertEquals(Double.MIN_VALUE, JBBPParser.prepare("long a;").parse(min).mapTo(new Mapped()).a, + TestUtils.FLOAT_DELTA); } @Test @@ -287,7 +474,8 @@ class Mapped { } final byte[] max = JBBPOut.BeginBin().Double(-1.2345678912345d).End().toByteArray(); - assertEquals(-1.2345678912345d, JBBPParser.prepare("doublej a;").parse(max).mapTo(new Mapped()).a, TestUtils.FLOAT_DELTA); + assertEquals(-1.2345678912345d, + JBBPParser.prepare("doublej a;").parse(max).mapTo(new Mapped()).a, TestUtils.FLOAT_DELTA); } @Test @@ -298,7 +486,9 @@ class Mapped { } final byte[] max = JBBPOut.BeginBin().Double(-1.2345678912345d, 45.3334d).End().toByteArray(); - assertArrayEquals(new double[] {-1.2345678912345d, 45.3334d}, JBBPParser.prepare("doublej [_] a;").parse(max).mapTo(new Mapped()).a, TestUtils.FLOAT_DELTA); + assertArrayEquals(new double[] {-1.2345678912345d, 45.3334d}, + JBBPParser.prepare("doublej [_] a;").parse(max).mapTo(new Mapped()).a, + TestUtils.FLOAT_DELTA); } @Test @@ -307,7 +497,9 @@ class Mapped { @Bin long a; } - assertEquals(0x0102030405060708L, JBBPParser.prepare("long a;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(new Mapped()).a); + assertEquals(0x0102030405060708L, + JBBPParser.prepare("long a;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}) + .mapTo(new Mapped()).a); } @Test @@ -316,7 +508,8 @@ class Mapped { @Bin(type = BinType.UBYTE) int a; } - assertEquals(0xFE, JBBPParser.prepare("ubyte a;").parse(new byte[] {(byte) 0xFE}).mapTo(new Mapped()).a); + assertEquals(0xFE, + JBBPParser.prepare("ubyte a;").parse(new byte[] {(byte) 0xFE}).mapTo(new Mapped()).a); } @Test @@ -325,7 +518,8 @@ class Mapped { @Bin char a; } - assertEquals(0x0102, JBBPParser.prepare("ushort a;").parse(new byte[] {1, 2}).mapTo(new Mapped()).a); + assertEquals(0x0102, + JBBPParser.prepare("ushort a;").parse(new byte[] {1, 2}).mapTo(new Mapped()).a); } @Test @@ -334,7 +528,8 @@ class Mapped { @Bin byte[] a; } - assertArrayEquals(new byte[] {1, 2, 3, 4}, JBBPParser.prepare("byte [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); + assertArrayEquals(new byte[] {1, 2, 3, 4}, + JBBPParser.prepare("byte [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); } @Test @@ -343,7 +538,9 @@ class Mapped { @Bin(type = BinType.UBYTE_ARRAY) String a; } - assertEquals("JFIF", JBBPParser.prepare("ubyte [_] a;").parse(new byte[] {(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46}).mapTo(new Mapped()).a); + assertEquals("JFIF", JBBPParser.prepare("ubyte [_] a;") + .parse(new byte[] {(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46}) + .mapTo(new Mapped()).a); } @Test @@ -352,7 +549,10 @@ class Mapped { @Bin(type = BinType.BIT_ARRAY) String a; } - assertEquals(new String(new char[] {0xA, 0x4, 0x6, 0x4, 0x9, 0x4, 0x6, 0x4}), JBBPParser.prepare("bit:4 [_] a;").parse(new byte[] {(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46}).mapTo(new Mapped()).a); + assertEquals(new String(new char[] {0xA, 0x4, 0x6, 0x4, 0x9, 0x4, 0x6, 0x4}), + JBBPParser.prepare("bit:4 [_] a;") + .parse(new byte[] {(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46}) + .mapTo(new Mapped()).a); } @Test @@ -361,7 +561,9 @@ class Mapped { @Bin(type = BinType.BIT_ARRAY) String a; } - assertEquals(new String(new char[] {0xFF, 0xED, 0x01, 0x36}), JBBPParser.prepare("bit:8 [_] a;").parse(new byte[] {(byte) 0xFF, (byte) 0xED, (byte) 0x01, (byte) 0x36}).mapTo(new Mapped()).a); + assertEquals(new String(new char[] {0xFF, 0xED, 0x01, 0x36}), JBBPParser.prepare("bit:8 [_] a;") + .parse(new byte[] {(byte) 0xFF, (byte) 0xED, (byte) 0x01, (byte) 0x36}) + .mapTo(new Mapped()).a); } @Test @@ -370,7 +572,9 @@ class Mapped { @Bin(type = BinType.BYTE_ARRAY) String a; } - assertEquals("JFIF", JBBPParser.prepare("byte [_] a;").parse(new byte[] {(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46}).mapTo(new Mapped()).a); + assertEquals("JFIF", JBBPParser.prepare("byte [_] a;") + .parse(new byte[] {(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46}) + .mapTo(new Mapped()).a); } @Test @@ -379,7 +583,9 @@ class Mapped { @Bin(type = BinType.SHORT_ARRAY) String a; } - assertEquals("JFIF", JBBPParser.prepare("short [_] a;").parse(new byte[] {0, (byte) 0x4A, 0, (byte) 0x46, 0, (byte) 0x49, 0, (byte) 0x46}).mapTo(new Mapped()).a); + assertEquals("JFIF", JBBPParser.prepare("short [_] a;") + .parse(new byte[] {0, (byte) 0x4A, 0, (byte) 0x46, 0, (byte) 0x49, 0, (byte) 0x46}) + .mapTo(new Mapped()).a); } @Test @@ -388,7 +594,9 @@ class Mapped { @Bin(type = BinType.INT_ARRAY) String a; } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int [_] a;").parse(new byte[] {0, (byte) 0x4A, 0, (byte) 0x46, 0, (byte) 0x49, 0, (byte) 0x46}).mapTo(new Mapped())); + assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int [_] a;") + .parse(new byte[] {0, (byte) 0x4A, 0, (byte) 0x46, 0, (byte) 0x49, 0, (byte) 0x46}) + .mapTo(new Mapped())); } @Test @@ -397,7 +605,9 @@ class Mapped { @Bin(type = BinType.USHORT_ARRAY) String a; } - assertEquals("JFIF", JBBPParser.prepare("ushort [_] a;").parse(new byte[] {0, (byte) 0x4A, 0, (byte) 0x46, 0, (byte) 0x49, 0, (byte) 0x46}).mapTo(new Mapped()).a); + assertEquals("JFIF", JBBPParser.prepare("ushort [_] a;") + .parse(new byte[] {0, (byte) 0x4A, 0, (byte) 0x46, 0, (byte) 0x49, 0, (byte) 0x46}) + .mapTo(new Mapped()).a); } @Test @@ -406,7 +616,8 @@ class Mapped { @Bin(type = BinType.BIT_ARRAY) byte[] a; } - assertArrayEquals(new byte[] {2, 0, 3, 2}, JBBPParser.prepare("bit:2 [_] a;").parse(new byte[] {(byte) 0xB2}).mapTo(new Mapped()).a); + assertArrayEquals(new byte[] {2, 0, 3, 2}, + JBBPParser.prepare("bit:2 [_] a;").parse(new byte[] {(byte) 0xB2}).mapTo(new Mapped()).a); } @Test @@ -415,7 +626,8 @@ class Mapped { @Bin short[] a; } - assertArrayEquals(new short[] {0x0102, 0x0304}, JBBPParser.prepare("short [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); + assertArrayEquals(new short[] {0x0102, 0x0304}, + JBBPParser.prepare("short [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); } @Test @@ -424,7 +636,8 @@ class Mapped { @Bin boolean[] a; } - final Mapped mapped = JBBPParser.prepare("bool [_] a;").parse(new byte[] {1, 0, 0, 4, 8, 0}).mapTo(new Mapped()); + final Mapped mapped = + JBBPParser.prepare("bool [_] a;").parse(new byte[] {1, 0, 0, 4, 8, 0}).mapTo(new Mapped()); assertEquals(6, mapped.a.length); assertTrue(mapped.a[0]); assertFalse(mapped.a[1]); @@ -440,7 +653,8 @@ class Mapped { @Bin char[] a; } - assertArrayEquals(new char[] {0x0102, 0x0304}, JBBPParser.prepare("ushort [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); + assertArrayEquals(new char[] {0x0102, 0x0304}, + JBBPParser.prepare("ushort [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); } @Test @@ -449,7 +663,9 @@ class Mapped { @Bin int[] a; } - assertArrayEquals(new int[] {0x01020304, 0x05060708}, JBBPParser.prepare("int [_] a;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(new Mapped()).a); + assertArrayEquals(new int[] {0x01020304, 0x05060708}, + JBBPParser.prepare("int [_] a;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}) + .mapTo(new Mapped()).a); } @Test @@ -466,15 +682,44 @@ class Mapped { @Bin Inside a; } - final Mapped mapped = JBBPParser.prepare("byte b; a{ int a; }").parse(new byte[] {1, 2, 3, 4, 5}).mapTo(new Mapped(), aClass -> { - if (aClass == Inside.class) { - return new Inside(); - } - return null; - }); + final Mapped mapped = + JBBPParser.prepare("byte b; a{ int a; }").parse(new byte[] {1, 2, 3, 4, 5}) + .mapTo(new Mapped(), aClass -> { + if (aClass == Inside.class) { + return new Inside(); + } + return null; + }); assertEquals(0x02030405, mapped.a.a); } + @Test + public void testMap_Struct_WithFilter() throws Exception { + class Inside { + + @Bin + int a; + } + class Mapped { + + @Bin + byte b; + @Bin + Inside a; + } + final Mapped mapped = + JBBPParser.prepare("byte b; a{ int a; }").parse(new byte[] {1, 2, 3, 4, 5}) + .mapTo(new Mapped(), + (b, f) -> !(f.getDeclaringClass().getSimpleName().equals("Inside") && + f.getName().equals("a")), aClass -> { + if (aClass == Inside.class) { + return new Inside(); + } + return null; + }); + assertEquals(0, mapped.a.a); + } + @Test void testMap_StructArray() throws Exception { class Inside { @@ -488,24 +733,65 @@ class Mapped { @Bin Inside[] a; } - final Mapped mapped = JBBPParser.prepare("byte b; a [_]{ int a; }").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}).mapTo(new Mapped(), aClass -> { - if (aClass == Inside.class) { - return new Inside(); - } - return null; - }); + final Mapped mapped = + JBBPParser.prepare("byte b; a [_]{ int a; }").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}) + .mapTo(new Mapped(), aClass -> { + if (aClass == Inside.class) { + return new Inside(); + } + return null; + }); assertEquals(2, mapped.a.length); assertEquals(0x02030405, mapped.a[0].a); assertEquals(0x06070809, mapped.a[1].a); } + @Test + void testMap_StructArray_WithFilter() throws Exception { + class Inside { + @Bin + int a; + } + class Mapped { + + @Bin + byte b; + @Bin + Inside[] a; + } + final Mapped mapped = + JBBPParser.prepare("byte b; a [_]{ int a; }").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}) + .mapTo(new Mapped(), (b, f) -> !f.getName().equals("a"), aClass -> { + if (aClass == Inside.class) { + return new Inside(); + } + return null; + }); + assertEquals(1, mapped.b); + assertNull(mapped.a); + } + @Test void testMap_LongArray() throws Exception { class Mapped { @Bin long[] a; } - assertArrayEquals(new long[] {0x0102030405060708L, 0x1112131415161718L}, JBBPParser.prepare("long [_] a;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}).mapTo(new Mapped()).a); + assertArrayEquals(new long[] {0x0102030405060708L, 0x1112131415161718L}, + JBBPParser.prepare("long [_] a;").parse( + new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}) + .mapTo(new Mapped()).a); + } + + @Test + void testMap_LongArray_WithFilter() throws Exception { + class Mapped { + @Bin + long[] a; + } + assertNull(JBBPParser.prepare("long [_] a;").parse( + new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}) + .mapTo(new Mapped(), (b, f) -> !f.getName().equals("a")).a); } @Test @@ -514,7 +800,20 @@ class Mapped { @Bin(name = "test", type = BinType.STRUCT) long a; } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("test { byte [_] a;}").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("test { byte [_] a;}").parse(new byte[] {1, 2, 3, 4}) + .mapTo(new Mapped())); + } + + @Test + void testMap_ErrorForMappingStructureToPrimitiveField_IgnoredByFilter() { + class Mapped { + @Bin(name = "test", type = BinType.STRUCT) + long a; + } + assertDoesNotThrow( + () -> JBBPParser.prepare("test { byte [_] a;}").parse(new byte[] {1, 2, 3, 4}) + .mapTo(new Mapped(), (b, f) -> !f.getName().equals("a"))); } @Test @@ -523,7 +822,8 @@ class Mapped { @Bin long a; } - final Mapped mapped = JBBPParser.prepare("byte f; test { inside {long a;} }").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}).mapTo("test.inside", new Mapped()); + final Mapped mapped = JBBPParser.prepare("byte f; test { inside {long a;} }") + .parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}).mapTo("test.inside", new Mapped()); assertEquals(0x0203040506070809L, mapped.a); } @@ -534,17 +834,23 @@ class Mapped { long a; } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("byte f; test { inside {long a;} }").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}).mapTo("f", new Mapped())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("byte f; test { inside {long a;} }") + .parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}).mapTo("f", new Mapped())); } @Test void testMap_privateFieldInPackagelevelClass() { - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int field;").parse(new byte[] {1, 2, 3, 4}).mapTo(new ClassWithPrivateFields())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int field;").parse(new byte[] {1, 2, 3, 4}) + .mapTo(new ClassWithPrivateFields())); } @Test void testMap_privateFieldWithSetterInPackagelevelClass() throws Exception { - final ClassWithPrivateFieldsAndSetterGetter instance = JBBPParser.prepare("int field;").parse(new byte[] {1, 2, 3, 4}).mapTo(new ClassWithPrivateFieldsAndSetterGetter()); + final ClassWithPrivateFieldsAndSetterGetter instance = + JBBPParser.prepare("int field;").parse(new byte[] {1, 2, 3, 4}) + .mapTo(new ClassWithPrivateFieldsAndSetterGetter()); assertEquals(0x1020304, instance.getField()); } @@ -559,7 +865,8 @@ public void testMap_classWithGettersSettersAndGenerator() throws Exception { assertEquals(3, instance.getI().getC()); assertEquals(4, instance.getI().getIi().getD()); - assertArrayEquals(new byte[] {1, 2, 3, 4}, JBBPOut.BeginBin().Bin(instance).End().toByteArray()); + assertArrayEquals(new byte[] {1, 2, 3, 4}, + JBBPOut.BeginBin().Bin(instance).End().toByteArray()); } @Test @@ -574,15 +881,20 @@ final class Mapped { int c; } - final Mapped mapped = JBBPParser.prepare("int a; int b; int c;").parse(new byte[] {1, 2, 3, 4, 0x4A, 0x46, 0x49, 0x46, 5, 6, 7, 8}).mapTo(new Mapped(), (parsedBlock, annotation, field) -> { - if ("b".equals(field.getName()) && "TEST_TEXT".equals(annotation.paramExpr())) { - final int bvalue = parsedBlock.findFieldForNameAndType("b", JBBPFieldInt.class).getAsInt(); - return String.valueOf((char) ((bvalue >>> 24) & 0xFF)) + (char) ((bvalue >>> 16) & 0xFF) + (char) ((bvalue >>> 8) & 0xFF) + (char) (bvalue & 0xFF); - } else { - fail("Unexpected state" + field); - return null; - } - }); + final Mapped mapped = JBBPParser.prepare("int a; int b; int c;") + .parse(new byte[] {1, 2, 3, 4, 0x4A, 0x46, 0x49, 0x46, 5, 6, 7, 8}) + .mapTo(new Mapped(), (parsedBlock, annotation, field) -> { + if ("b".equals(field.getName()) && "TEST_TEXT".equals(annotation.paramExpr())) { + final int bvalue = + parsedBlock.findFieldForNameAndType("b", JBBPFieldInt.class).getAsInt(); + return String.valueOf((char) ((bvalue >>> 24) & 0xFF)) + + (char) ((bvalue >>> 16) & 0xFF) + (char) ((bvalue >>> 8) & 0xFF) + + (char) (bvalue & 0xFF); + } else { + fail("Unexpected state" + field); + return null; + } + }); assertEquals(0x01020304, mapped.a); assertEquals("JFIF", mapped.b); @@ -602,15 +914,20 @@ final class Mapped { final Mapped mapped = new Mapped(); - final Mapped result = JBBPParser.prepare("int a; int b; int c;").parse(new byte[] {1, 2, 3, 4, 0x4A, 0x46, 0x49, 0x46, 5, 6, 7, 8}).mapTo(mapped, (parsedBlock, annotation, field) -> { - if ("b".equals(field.getName()) && "TEST_TEXT".equals(annotation.paramExpr())) { - final int bvalue = parsedBlock.findFieldForNameAndType("b", JBBPFieldInt.class).getAsInt(); - return String.valueOf((char) ((bvalue >>> 24) & 0xFF)) + (char) ((bvalue >>> 16) & 0xFF) + (char) ((bvalue >>> 8) & 0xFF) + (char) (bvalue & 0xFF); - } else { - fail("Unexpected state" + field); - return null; - } - }); + final Mapped result = JBBPParser.prepare("int a; int b; int c;") + .parse(new byte[] {1, 2, 3, 4, 0x4A, 0x46, 0x49, 0x46, 5, 6, 7, 8}) + .mapTo(mapped, (parsedBlock, annotation, field) -> { + if ("b".equals(field.getName()) && "TEST_TEXT".equals(annotation.paramExpr())) { + final int bvalue = + parsedBlock.findFieldForNameAndType("b", JBBPFieldInt.class).getAsInt(); + return String.valueOf((char) ((bvalue >>> 24) & 0xFF)) + + (char) ((bvalue >>> 16) & 0xFF) + (char) ((bvalue >>> 8) & 0xFF) + + (char) (bvalue & 0xFF); + } else { + fail("Unexpected state" + field); + return null; + } + }); assertSame(mapped, result); @@ -629,7 +946,9 @@ final class Parsed { String c; } - final Parsed parsed = JBBPParser.prepare("int a; int b; byte [_] c;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd'}).mapTo(new Parsed()); + final Parsed parsed = JBBPParser.prepare("int a; int b; byte [_] c;") + .parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd'}) + .mapTo(new Parsed()); assertEquals(0x01020304, parsed.a); assertEquals(0x05060708, parsed.b); assertEquals("abcd", parsed.c); @@ -659,7 +978,8 @@ final class Inner { final Outer oldouter = new Outer(); final Outer.Inner inner = oldouter.inner; - final Outer newouter = JBBPParser.prepare("int value; inner{ byte a; byte b;}").parse(new byte[] {1, 2, 3, 4, 5, 6}).mapTo(oldouter); + final Outer newouter = JBBPParser.prepare("int value; inner{ byte a; byte b;}") + .parse(new byte[] {1, 2, 3, 4, 5, 6}).mapTo(oldouter); assertSame(oldouter, newouter); assertSame(inner, newouter.inner); @@ -696,7 +1016,8 @@ final class Inner { final Outer.Inner inner0 = oldouter.inner[0]; final Outer.Inner inner1 = oldouter.inner[1]; - final Outer newouter = JBBPParser.prepare("int value; inner [2] { byte a; byte b;}").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(oldouter); + final Outer newouter = JBBPParser.prepare("int value; inner [2] { byte a; byte b;}") + .parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(oldouter); assertSame(oldouter, newouter); assertSame(inner, newouter.inner); @@ -740,12 +1061,13 @@ final class Inner { assertNull(inner[0]); assertNull(inner[1]); - final Outer newouter = JBBPParser.prepare("int value; inner [2] { byte a; byte b;}").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(oldouter, aClass -> { - if (aClass == Outer.Inner.class) { - return oldouter.makeInner(); - } - return null; - }); + final Outer newouter = JBBPParser.prepare("int value; inner [2] { byte a; byte b;}") + .parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(oldouter, aClass -> { + if (aClass == Outer.Inner.class) { + return oldouter.makeInner(); + } + return null; + }); assertSame(oldouter, newouter); assertSame(inner, newouter.inner); @@ -778,7 +1100,9 @@ final class Inner { } } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int value; inner [2] { byte a; byte b;}").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(new Outer())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int value; inner [2] { byte a; byte b;}") + .parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(new Outer())); } @Test @@ -794,7 +1118,9 @@ class Successor extends Ancestor { int b; } - final Successor successor = JBBPParser.prepare("int a; int b;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(new Successor()); + final Successor successor = + JBBPParser.prepare("int a; int b;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}) + .mapTo(new Successor()); assertEquals(0x01020304, successor.a); assertEquals(0x05060708, successor.b); @@ -810,7 +1136,9 @@ class Parsed { String str; } - final Parsed parsed = JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;").parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}).mapTo(new Parsed()); + final Parsed parsed = JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;") + .parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}) + .mapTo(new Parsed()); assertEquals(0x05, parsed.num); assertEquals("abc", parsed.str); } @@ -825,7 +1153,10 @@ class Parsed { String str; } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;").parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}).mapTo(new Parsed())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;") + .parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}) + .mapTo(new Parsed())); } @Test @@ -838,7 +1169,10 @@ class Parsed { String str; } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;").parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}).mapTo(new Parsed())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;") + .parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}) + .mapTo(new Parsed())); } @Test @@ -851,7 +1185,10 @@ class Parsed { String str; } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;").parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}).mapTo(new Parsed())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;") + .parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}) + .mapTo(new Parsed())); } @Test @@ -863,7 +1200,10 @@ class Parsed { byte str; } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;").parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}).mapTo(new Parsed())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;") + .parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}) + .mapTo(new Parsed())); } @Test @@ -877,7 +1217,9 @@ class Parsed { transient String ignored; } - final Parsed parsed = JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;").parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}).mapTo(new Parsed()); + final Parsed parsed = JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;") + .parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}) + .mapTo(new Parsed()); assertEquals(0x05, parsed.num); assertEquals("abc", parsed.str); } @@ -894,7 +1236,10 @@ class Parsed { transient String trans; } - final Parsed parsed = JBBPParser.prepare("int start; struct { byte a; byte [3] b; byte [3] c; } byte end;").parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', 9}).mapTo(new Parsed()); + final Parsed parsed = + JBBPParser.prepare("int start; struct { byte a; byte [3] b; byte [3] c; } byte end;").parse( + new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', + (byte) 'f', 9}).mapTo(new Parsed()); assertEquals(0x05, parsed.num); assertEquals("abc", parsed.str); assertEquals("def", parsed.trans); @@ -911,7 +1256,9 @@ class Parsed { String ignored; } - final Parsed parsed = JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;").parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}).mapTo(new Parsed()); + final Parsed parsed = JBBPParser.prepare("int start; struct { byte a; byte [3] b; } int end;") + .parse(new byte[] {1, 2, 3, 4, 5, (byte) 'a', (byte) 'b', (byte) 'c', 6, 7, 8, 9}) + .mapTo(new Parsed()); assertEquals(0x05, parsed.num); assertEquals("abc", parsed.str); } @@ -944,10 +1291,12 @@ class Parsed { final byte[] array = new byte[1024]; rnd.nextBytes(array); - final Parsed parsed = JBBPParser.prepare("struct [_] { byte a; byte b; }").parse(new ByteArrayInputStream(array)).mapTo(new Parsed(null), aClass -> { - fail("Must not be called"); - return null; - }); + final Parsed parsed = + JBBPParser.prepare("struct [_] { byte a; byte b; }").parse(new ByteArrayInputStream(array)) + .mapTo(new Parsed(null), aClass -> { + fail("Must not be called"); + return null; + }); assertNull(parsed.struct); } @@ -957,17 +1306,22 @@ class Parsed { @Bin(bitNumber = JBBPBitNumber.BITS_5) byte field; } - final Parsed parsed = JBBPParser.prepare("int fieldint; bit:5 field;").parse(new byte[] {1, 2, 3, 4, 0x35}).mapTo(new Parsed()); + final Parsed parsed = + JBBPParser.prepare("int fieldint; bit:5 field;").parse(new byte[] {1, 2, 3, 4, 0x35}) + .mapTo(new Parsed()); assertEquals(0x15, parsed.field); } @Test - void testMap_FieldWithDefinedBitNumberToBitField_FieldPresentedWithDifferentBitNumber() throws Exception { + void testMap_FieldWithDefinedBitNumberToBitField_FieldPresentedWithDifferentBitNumber() + throws Exception { class Parsed { @Bin(bitNumber = JBBPBitNumber.BITS_5) byte field; } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int fieldint; bit:6 field;").parse(new byte[] {1, 2, 3, 4, 0x35}).mapTo(new Parsed())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int fieldint; bit:6 field;").parse(new byte[] {1, 2, 3, 4, 0x35}) + .mapTo(new Parsed())); } @Test @@ -977,7 +1331,9 @@ class Parsed { byte[] field; } - final Parsed parsed = JBBPParser.prepare("int fieldint; bit:4 [2] field;").parse(new byte[] {1, 2, 3, 4, 0x35}).mapTo(new Parsed()); + final Parsed parsed = + JBBPParser.prepare("int fieldint; bit:4 [2] field;").parse(new byte[] {1, 2, 3, 4, 0x35}) + .mapTo(new Parsed()); assertArrayEquals(new byte[] {5, 3}, parsed.field); } @@ -987,18 +1343,23 @@ class Parsed { @Bin(type = BinType.INT_ARRAY, bitNumber = JBBPBitNumber.BITS_4) int[] field; } - final Parsed parsed = JBBPParser.prepare("int fieldint; int [2] field;").parse(new byte[] {1, 2, 3, 4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0A, 0x0B, 0x0C}).mapTo(new Parsed()); + final Parsed parsed = JBBPParser.prepare("int fieldint; int [2] field;") + .parse(new byte[] {1, 2, 3, 4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0A, 0x0B, 0x0C}) + .mapTo(new Parsed()); assertArrayEquals(new int[] {0x05060708, 0x090A0B0C}, parsed.field); } @Test - void testMap_ArrayFieldWithDefinedBitNumberToArrayBitField_FieldPresentedWithDifferentBitNumber() throws Exception { + void testMap_ArrayFieldWithDefinedBitNumberToArrayBitField_FieldPresentedWithDifferentBitNumber() + throws Exception { class Parsed { @Bin(bitNumber = JBBPBitNumber.BITS_4) byte field; } - assertThrows(JBBPMapperException.class, () -> JBBPParser.prepare("int fieldint; bit:3 [2] field;").parse(new byte[] {1, 2, 3, 4, 0x35}).mapTo(new Parsed())); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int fieldint; bit:3 [2] field;") + .parse(new byte[] {1, 2, 3, 4, 0x35}).mapTo(new Parsed())); } @Test @@ -1011,7 +1372,10 @@ class Parsed { int b; } - final Parsed parsed = JBBPParser.prepare("int a; int b;", JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF).parse(new byte[] {1, 2, 3, 4}).mapTo(new Parsed(), JBBPMapper.FLAG_IGNORE_MISSING_VALUES); + final Parsed parsed = + JBBPParser.prepare("int a; int b;", JBBPParser.FLAG_SKIP_REMAINING_FIELDS_IF_EOF) + .parse(new byte[] {1, 2, 3, 4}) + .mapTo(new Parsed(), JBBPMapper.FLAG_IGNORE_MISSING_VALUES); assertEquals(0x01020304, parsed.a); assertEquals(0, parsed.b); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBitTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBitTest.java index 4984adcf..19318fe7 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBitTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBitTest.java @@ -16,22 +16,29 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.io.JBBPBitNumber; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - import java.io.Serializable; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPFieldArrayBitTest { private final byte[] array = new byte[] {(byte) -1, 0, 1, 2, 3}; - private final JBBPFieldArrayBit test = new JBBPFieldArrayBit(new JBBPNamedFieldInfo("test.field", "field", 999), array, JBBPBitNumber.BITS_1); + private final JBBPFieldArrayBit test = + new JBBPFieldArrayBit(new JBBPNamedFieldInfo("test.field", "field", 999), array, + JBBPBitNumber.BITS_1); @Test public void testConstructor_NPEForNullBitNumber() { - assertThrows(NullPointerException.class, () -> new JBBPFieldArrayBit(new JBBPNamedFieldInfo("test.field", "field", 999), new byte[] {(byte) -1, 0, 1, 2, 3}, null)); + assertThrows(NullPointerException.class, + () -> new JBBPFieldArrayBit(new JBBPNamedFieldInfo("test.field", "field", 999), + new byte[] {(byte) -1, 0, 1, 2, 3}, null)); } @Test @@ -102,7 +109,9 @@ public void testIterable() { public void testGetValueArrayAsObject() { final byte[] array = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; - final JBBPFieldArrayBit test = new JBBPFieldArrayBit(new JBBPNamedFieldInfo("test.field", "field", 999), array, JBBPBitNumber.BITS_4); + final JBBPFieldArrayBit test = + new JBBPFieldArrayBit(new JBBPNamedFieldInfo("test.field", "field", 999), array, + JBBPBitNumber.BITS_4); assertArrayEquals(array, (byte[]) test.getValueArrayAsObject(false)); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBooleanTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBooleanTest.java index e5ffaa69..7d1338e7 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBooleanTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayBooleanTest.java @@ -16,17 +16,19 @@ package com.igormaznitsa.jbbp.model; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import java.io.Serializable; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPFieldArrayBooleanTest { private final boolean[] array = new boolean[] {true, false, true, true, false}; - private final JBBPFieldArrayBoolean test = new JBBPFieldArrayBoolean(new JBBPNamedFieldInfo("test.field", "field", 999), array); + private final JBBPFieldArrayBoolean test = + new JBBPFieldArrayBoolean(new JBBPNamedFieldInfo("test.field", "field", 999), array); @Test public void testNameAndOffset() { @@ -47,7 +49,7 @@ public void testGetArray() { final boolean[] array = test.getArray(); assertEquals(etalon.length, array.length); for (int i = 0; i < etalon.length; i++) { - assertTrue(etalon[i] == array[i]); + assertEquals(etalon[i], array[i]); } } @@ -92,7 +94,7 @@ public void testIterable() { final boolean[] etalon = new boolean[] {true, false, true, true, false}; int index = 0; for (final JBBPFieldBoolean f : test) { - assertTrue(etalon[index++] == f.getAsBool()); + assertEquals(etalon[index++], f.getAsBool()); } } @@ -101,7 +103,7 @@ public void testGetValueArrayAsObject() { final boolean[] noninverted = (boolean[]) test.getValueArrayAsObject(false); assertEquals(array.length, noninverted.length); for (int i = 0; i < array.length; i++) { - assertTrue(array[i] == noninverted[i]); + assertEquals(array[i], noninverted[i]); } final boolean[] inverted = (boolean[]) test.getValueArrayAsObject(true); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayByteTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayByteTest.java index d4ae7374..a6e75d72 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayByteTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayByteTest.java @@ -16,16 +16,20 @@ package com.igormaznitsa.jbbp.model; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; -import java.io.Serializable; -import static org.junit.jupiter.api.Assertions.*; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import java.io.Serializable; +import org.junit.jupiter.api.Test; public class JBBPFieldArrayByteTest { private final byte[] array = new byte[] {(byte) -1, 0, 1, 2, 3}; - private final JBBPFieldArrayByte test = new JBBPFieldArrayByte(new JBBPNamedFieldInfo("test.field", "field", 999), array); + private final JBBPFieldArrayByte test = + new JBBPFieldArrayByte(new JBBPNamedFieldInfo("test.field", "field", 999), array); @Test public void testNameAndOffset() { diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayIntTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayIntTest.java index 96f929ed..8981b44f 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayIntTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayIntTest.java @@ -16,16 +16,20 @@ package com.igormaznitsa.jbbp.model; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; -import java.io.Serializable; -import static org.junit.jupiter.api.Assertions.*; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import java.io.Serializable; +import org.junit.jupiter.api.Test; public class JBBPFieldArrayIntTest { private final int[] array = new int[] {-278349, 12223423, 0, -2, 3}; - private final JBBPFieldArrayInt test = new JBBPFieldArrayInt(new JBBPNamedFieldInfo("test.field", "field", 999), array); + private final JBBPFieldArrayInt test = + new JBBPFieldArrayInt(new JBBPNamedFieldInfo("test.field", "field", 999), array); @Test public void testNameAndOffset() { diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayLongTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayLongTest.java index 9520aa60..f9e806df 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayLongTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayLongTest.java @@ -16,16 +16,21 @@ package com.igormaznitsa.jbbp.model; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; -import java.io.Serializable; -import static org.junit.jupiter.api.Assertions.*; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import java.io.Serializable; +import org.junit.jupiter.api.Test; public class JBBPFieldArrayLongTest { - private final long[] array = new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}; - private final JBBPFieldArrayLong test = new JBBPFieldArrayLong(new JBBPNamedFieldInfo("test.field", "field", 999), array); + private final long[] array = + new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}; + private final JBBPFieldArrayLong test = + new JBBPFieldArrayLong(new JBBPNamedFieldInfo("test.field", "field", 999), array); @Test public void testNameAndOffset() { @@ -42,7 +47,9 @@ public void testSize() { @Test public void testGetArray() { - assertArrayEquals(new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}, test.getArray()); + assertArrayEquals( + new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}, + test.getArray()); } @Test @@ -55,7 +62,9 @@ public void testGetAsBool() { @Test public void testGetAsInt() { - final int[] etalon = new int[] {(int) -278349872364L, (int) 12223423987439324L, (int) 0L, (int) -2782346872343L, (int) 37238468273412L}; + final int[] etalon = + new int[] {(int) -278349872364L, (int) 12223423987439324L, (int) 0L, (int) -2782346872343L, + (int) 37238468273412L}; for (int i = 0; i < etalon.length; i++) { assertEquals(etalon[i], test.getAsInt(i)); } @@ -63,7 +72,8 @@ public void testGetAsInt() { @Test public void testGetAsLong() { - final long[] etalon = new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}; + final long[] etalon = + new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}; for (int i = 0; i < etalon.length; i++) { assertEquals(etalon[i], test.getAsLong(i)); } @@ -71,7 +81,8 @@ public void testGetAsLong() { @Test public void testGetElementAt() { - final long[] etalon = new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}; + final long[] etalon = + new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}; final Serializable payload = new FakePayload(); test.setPayload(payload); for (int i = 0; i < etalon.length; i++) { @@ -84,7 +95,8 @@ public void testGetElementAt() { @Test public void testIterable() { - final long[] etalon = new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}; + final long[] etalon = + new long[] {-278349872364L, 12223423987439324L, 0L, -2782346872343L, 37238468273412L}; int index = 0; for (final JBBPFieldLong f : test) { assertEquals(etalon[index++], f.getAsLong()); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayShortTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayShortTest.java index 71fa28ec..414b7c81 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayShortTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayShortTest.java @@ -16,17 +16,21 @@ package com.igormaznitsa.jbbp.model; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; -import java.io.Serializable; -import static org.junit.jupiter.api.Assertions.*; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import java.io.Serializable; +import org.junit.jupiter.api.Test; public class JBBPFieldArrayShortTest { private final short[] array = new short[] {(short) -27834, 23423, 0, -2, 3}; - private final JBBPFieldArrayShort test = new JBBPFieldArrayShort(new JBBPNamedFieldInfo("test.field", "field", 999), array); + private final JBBPFieldArrayShort test = + new JBBPFieldArrayShort(new JBBPNamedFieldInfo("test.field", "field", 999), array); @Test public void testNameAndOffset() { diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayStringTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayStringTest.java index bad4ec66..399d4562 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayStringTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayStringTest.java @@ -1,15 +1,19 @@ package com.igormaznitsa.jbbp.model; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; -import java.io.Serializable; -import static org.junit.jupiter.api.Assertions.*; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import java.io.Serializable; +import org.junit.jupiter.api.Test; public class JBBPFieldArrayStringTest { - private final String [] array = new String[] {"012",null,"ABC"}; - private final JBBPFieldArrayString test = new JBBPFieldArrayString(new JBBPNamedFieldInfo("test.field", "field", 999), array); + private final String[] array = new String[] {"012", null, "ABC"}; + private final JBBPFieldArrayString test = + new JBBPFieldArrayString(new JBBPNamedFieldInfo("test.field", "field", 999), array); @Test public void testNameAndOffset() { @@ -26,12 +30,12 @@ public void testSize() { @Test public void testGetArray() { - assertArrayEquals(new String[] {"012",null,"ABC"}, test.getArray()); + assertArrayEquals(new String[] {"012", null, "ABC"}, test.getArray()); } @Test public void testGetElementAt() { - final String[] etalon = new String[] {"012",null,"ABC"}; + final String[] etalon = new String[] {"012", null, "ABC"}; final Serializable payload = new FakePayload(); test.setPayload(payload); for (int i = 0; i < etalon.length; i++) { @@ -43,7 +47,7 @@ public void testGetElementAt() { @Test public void testIterable() { - final String[] etalon = new String[] {"012",null,"ABC"}; + final String[] etalon = new String[] {"012", null, "ABC"}; int index = 0; for (final JBBPFieldString f : test) { assertEquals(etalon[index++], f.getAsString()); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayStructTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayStructTest.java index d5f1381b..c758b8f3 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayStructTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayStructTest.java @@ -16,11 +16,15 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class JBBPFieldArrayStructTest { private final JBBPFieldArrayStruct test = new JBBPFieldArrayStruct( diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUByteTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUByteTest.java index 3d46cbf5..2aad908d 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUByteTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUByteTest.java @@ -16,16 +16,20 @@ package com.igormaznitsa.jbbp.model; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; -import java.io.Serializable; -import static org.junit.jupiter.api.Assertions.*; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import java.io.Serializable; +import org.junit.jupiter.api.Test; public class JBBPFieldArrayUByteTest { private final byte[] array = new byte[] {(byte) -1, 0, 1, 2, 3}; - private final JBBPFieldArrayUByte test = new JBBPFieldArrayUByte(new JBBPNamedFieldInfo("test.field", "field", 999), array); + private final JBBPFieldArrayUByte test = + new JBBPFieldArrayUByte(new JBBPNamedFieldInfo("test.field", "field", 999), array); @Test public void testNameAndOffset() { diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUIntTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUIntTest.java new file mode 100644 index 00000000..f5fc797b --- /dev/null +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUIntTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2017 Igor Maznitsa. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.igormaznitsa.jbbp.model; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import java.io.Serializable; +import org.junit.jupiter.api.Test; + +public class JBBPFieldArrayUIntTest { + private final int[] array = new int[] {-278349, 12223423, 0, -2, 3}; + private final long[] arrayLong = + new long[] {-278349 & 0xFFFFFFFFL, 12223423, 0, -2 & 0xFFFFFFFFL, 3}; + private final JBBPFieldArrayUInt test = + new JBBPFieldArrayUInt(new JBBPNamedFieldInfo("test.field", "field", 999), array); + + @Test + public void testNameAndOffset() { + assertEquals("test.field", test.getFieldPath()); + assertEquals("field", test.getFieldName()); + assertNotNull(test.getNameInfo()); + assertEquals(999, test.getNameInfo().getFieldOffsetInCompiledBlock()); + } + + @Test + public void testSize() { + assertEquals(5, test.size()); + } + + @Test + public void testGetArray() { + assertArrayEquals(new long[] {4294688947L, 12223423L, 0L, 4294967294L, 3L}, test.getArray()); + } + + @Test + public void testGetAsBool() { + final boolean[] etalon = new boolean[] {true, true, false, true, true}; + for (int i = 0; i < etalon.length; i++) { + assertEquals(etalon[i], test.getAsBool(i)); + } + } + + @Test + public void testGetAsInt() { + final int[] etalon = new int[] {-278349, 12223423, 0, -2, 3}; + for (int i = 0; i < etalon.length; i++) { + assertEquals(etalon[i], test.getAsInt(i)); + } + } + + @Test + public void testGetAsLong() { + final long[] etalon = new long[] {4294688947L, 12223423L, 0L, 4294967294L, 3L}; + for (int i = 0; i < etalon.length; i++) { + assertEquals(etalon[i], test.getAsLong(i)); + } + } + + @Test + public void testGetElementAt() { + final int[] etalon = new int[] {-278349, 12223423, 0, -2, 3}; + final Serializable payload = new FakePayload(); + test.setPayload(payload); + for (int i = 0; i < etalon.length; i++) { + final JBBPFieldUInt f = test.getElementAt(i); + assertSame(payload, f.getPayload()); + assertEquals(etalon[i], (int) f.getAsLong()); + assertEquals(etalon[i] & 0xFFFFFFFFL, f.getAsLong()); + } + } + + + @Test + public void testIterable() { + final int[] etalon = new int[] {-278349, 12223423, 0, -2, 3}; + int index = 0; + for (final JBBPFieldUInt f : test) { + assertEquals(etalon[index++], (int) f.getAsLong()); + } + } + + @Test + public void testGetValueArrayAsObject() { + assertArrayEquals(arrayLong, (long[]) test.getValueArrayAsObject(false)); + + final long[] inverted = (long[]) test.getValueArrayAsObject(true); + assertEquals(array.length, inverted.length); + for (int i = 0; i < array.length; i++) { + assertEquals(JBBPFieldUInt.reverseBits(array[i]), inverted[i]); + } + } + + +} diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUShortTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUShortTest.java index acb3cee9..cd99c992 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUShortTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldArrayUShortTest.java @@ -16,16 +16,21 @@ package com.igormaznitsa.jbbp.model; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; -import java.io.Serializable; -import static org.junit.jupiter.api.Assertions.*; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import java.io.Serializable; +import org.junit.jupiter.api.Test; public class JBBPFieldArrayUShortTest { - private final JBBPFieldArrayUShort test = new JBBPFieldArrayUShort(new JBBPNamedFieldInfo("test.field", "field", 999), new short[] {(short) -27834, 23423, 0, -2, 3}); + private final JBBPFieldArrayUShort test = + new JBBPFieldArrayUShort(new JBBPNamedFieldInfo("test.field", "field", 999), + new short[] {(short) -27834, 23423, 0, -2, 3}); @Test public void testNameAndOffset() { diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldBitTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldBitTest.java index 38e89bfe..24df0831 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldBitTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldBitTest.java @@ -16,23 +16,29 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.io.JBBPBitNumber; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - -import static org.junit.jupiter.api.Assertions.*; public class JBBPFieldBitTest { @Test public void testConstructor_NPEForNullBitNumber() { - assertThrows(NullPointerException.class, () -> new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 123, null)); + assertThrows(NullPointerException.class, + () -> new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 123, null)); } @Test public void testNameField() { - final JBBPFieldBit field = new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 123, JBBPBitNumber.BITS_4); + final JBBPFieldBit field = + new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 123, + JBBPBitNumber.BITS_4); final JBBPNamedFieldInfo namedField = field.getNameInfo(); assertEquals("test.field", namedField.getFieldPath()); assertEquals("field", namedField.getFieldName()); @@ -42,33 +48,46 @@ public void testNameField() { @Test public void testgetAsBool_True() { - assertTrue(new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 123, JBBPBitNumber.BITS_1).getAsBool()); + assertTrue(new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 123, + JBBPBitNumber.BITS_1).getAsBool()); } @Test public void testgetAsBool_False() { - assertFalse(new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 0, JBBPBitNumber.BITS_1).getAsBool()); + assertFalse(new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 0, + JBBPBitNumber.BITS_1).getAsBool()); } @Test public void testgetAsInt() { - assertEquals(12, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 12, JBBPBitNumber.BITS_3).getAsInt()); - assertEquals(-12 & 0xFF, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), -12, JBBPBitNumber.BITS_4).getAsInt()); + assertEquals(12, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 12, + JBBPBitNumber.BITS_3).getAsInt()); + assertEquals(-12 & 0xFF, + new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), -12, + JBBPBitNumber.BITS_4).getAsInt()); } @Test public void testgetAsLong() { - assertEquals(12L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 12, JBBPBitNumber.BITS_6).getAsLong()); - assertEquals(-12L & 0xFFL, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), -12, JBBPBitNumber.BITS_5).getAsLong()); + assertEquals(12L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 12, + JBBPBitNumber.BITS_6).getAsLong()); + assertEquals(-12L & 0xFFL, + new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), -12, + JBBPBitNumber.BITS_5).getAsLong()); } @Test public void testGetAsInvertedBitOrder() { - assertEquals(1L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 7, JBBPBitNumber.BITS_1).getAsInvertedBitOrder()); - assertEquals(4L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 1, JBBPBitNumber.BITS_3).getAsInvertedBitOrder()); - assertEquals(0xF0L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 0xF, JBBPBitNumber.BITS_8).getAsInvertedBitOrder()); - assertEquals(0x8FL, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 0xFF1, JBBPBitNumber.BITS_8).getAsInvertedBitOrder()); - assertEquals(0x8L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 0xFF1, JBBPBitNumber.BITS_4).getAsInvertedBitOrder()); + assertEquals(1L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 7, + JBBPBitNumber.BITS_1).getAsInvertedBitOrder()); + assertEquals(4L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 1, + JBBPBitNumber.BITS_3).getAsInvertedBitOrder()); + assertEquals(0xF0L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 0xF, + JBBPBitNumber.BITS_8).getAsInvertedBitOrder()); + assertEquals(0x8FL, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 0xFF1, + JBBPBitNumber.BITS_8).getAsInvertedBitOrder()); + assertEquals(0x8L, new JBBPFieldBit(new JBBPNamedFieldInfo("test.field", "field", 123), 0xFF1, + JBBPBitNumber.BITS_4).getAsInvertedBitOrder()); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldBooleanTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldBooleanTest.java index 497e19fb..1f933791 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldBooleanTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldBooleanTest.java @@ -16,16 +16,20 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class JBBPFieldBooleanTest { @Test public void testNameField() { - final JBBPFieldBoolean field = new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true); + final JBBPFieldBoolean field = + new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true); final JBBPNamedFieldInfo namedField = field.getNameInfo(); assertEquals("test.field", namedField.getFieldPath()); assertEquals("field", namedField.getFieldName()); @@ -34,30 +38,38 @@ public void testNameField() { @Test public void testgetAsBool_True() { - assertTrue(new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true).getAsBool()); + assertTrue( + new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true).getAsBool()); } @Test public void testgetAsBool_False() { - assertFalse(new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), false).getAsBool()); + assertFalse(new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), false) + .getAsBool()); } @Test public void testgetAsInt() { - assertEquals(1, new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true).getAsInt()); - assertEquals(0, new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), false).getAsInt()); + assertEquals(1, + new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true).getAsInt()); + assertEquals(0, + new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), false).getAsInt()); } @Test public void testgetAsLong() { - assertEquals(1L, new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true).getAsLong()); - assertEquals(0L, new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), false).getAsLong()); + assertEquals(1L, + new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true).getAsLong()); + assertEquals(0L, new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), false) + .getAsLong()); } @Test public void testGetAsInvertedBitOrder() { - assertEquals(0L, new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), false).getAsInvertedBitOrder()); - assertEquals(1L, new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true).getAsInvertedBitOrder()); + assertEquals(0L, new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), false) + .getAsInvertedBitOrder()); + assertEquals(1L, new JBBPFieldBoolean(new JBBPNamedFieldInfo("test.field", "field", 123), true) + .getAsInvertedBitOrder()); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldByteTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldByteTest.java index f74cfa64..4c59a477 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldByteTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldByteTest.java @@ -16,16 +16,20 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class JBBPFieldByteTest { @Test public void testNameField() { - final JBBPFieldByte field = new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 123); + final JBBPFieldByte field = + new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 123); final JBBPNamedFieldInfo namedField = field.getNameInfo(); assertEquals("test.field", namedField.getFieldPath()); assertEquals("field", namedField.getFieldName()); @@ -34,31 +38,47 @@ public void testNameField() { @Test public void testgetAsBool_True() { - assertTrue(new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 123).getAsBool()); + assertTrue(new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 123) + .getAsBool()); } @Test public void testgetAsBool_False() { - assertFalse(new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 0).getAsBool()); + assertFalse(new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 0) + .getAsBool()); } @Test public void testgetAsInt() { - assertEquals(12, new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 12).getAsInt()); - assertEquals(-12, new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) -12).getAsInt()); + assertEquals(12, + new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 12) + .getAsInt()); + assertEquals(-12, + new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) -12) + .getAsInt()); } @Test public void testgetAsLong() { - assertEquals(12L, new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 12).getAsLong()); - assertEquals(-12L, new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) -12).getAsLong()); + assertEquals(12L, + new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 12) + .getAsLong()); + assertEquals(-12L, + new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) -12) + .getAsLong()); } @Test public void testGetAsInvertedBitOrder() { - assertEquals(0xFFFFFFFFFFFFFF80L, new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 1).getAsInvertedBitOrder()); - assertEquals(0xFFFFFFFFFFFFFFE0L, new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 7).getAsInvertedBitOrder()); - assertEquals(0x0FL, new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 0xF0).getAsInvertedBitOrder()); + assertEquals(0xFFFFFFFFFFFFFF80L, + new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 1) + .getAsInvertedBitOrder()); + assertEquals(0xFFFFFFFFFFFFFFE0L, + new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 7) + .getAsInvertedBitOrder()); + assertEquals(0x0FL, + new JBBPFieldByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 0xF0) + .getAsInvertedBitOrder()); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldIntTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldIntTest.java index 3d88a66c..79cae952 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldIntTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldIntTest.java @@ -16,16 +16,20 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class JBBPFieldIntTest { @Test public void testNameField() { - final JBBPFieldInt field = new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 123456); + final JBBPFieldInt field = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 123456); final JBBPNamedFieldInfo namedField = field.getNameInfo(); assertEquals("test.field", namedField.getFieldPath()); assertEquals("field", namedField.getFieldName()); @@ -34,32 +38,44 @@ public void testNameField() { @Test public void testgetAsBool_True() { - assertTrue(new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 32423).getAsBool()); + assertTrue( + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 32423).getAsBool()); } @Test public void testgetAsBool_False() { - assertFalse(new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0).getAsBool()); + assertFalse( + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0).getAsBool()); } @Test public void testgetAsInt() { - assertEquals(234324, new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 234324).getAsInt()); - assertEquals(-234324, new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), -234324).getAsInt()); + assertEquals(234324, + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 234324).getAsInt()); + assertEquals(-234324, + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), -234324).getAsInt()); } @Test public void testgetAsLong() { - assertEquals(234324L, new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 234324).getAsLong()); - assertEquals(-234324L, new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), -234324).getAsLong()); + assertEquals(234324L, + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 234324).getAsLong()); + assertEquals(-234324L, + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), -234324).getAsLong()); } @Test public void testGetAsInvertedBitOrder() { - assertEquals(0x0000000020C04080L, new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0x01020304).getAsInvertedBitOrder()); - assertEquals(0x000000007FFFFFFFL, new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0xFFFFFFFE).getAsInvertedBitOrder()); - assertEquals(0xFFFFFFFF80000000L, new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0x00000001).getAsInvertedBitOrder()); + assertEquals(0x0000000020C04080L, + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0x01020304) + .getAsInvertedBitOrder()); + assertEquals(0x000000007FFFFFFFL, + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0xFFFFFFFE) + .getAsInvertedBitOrder()); + assertEquals(0xFFFFFFFF80000000L, + new JBBPFieldInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0x00000001) + .getAsInvertedBitOrder()); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldLongTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldLongTest.java index c0b86930..34df7ebb 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldLongTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldLongTest.java @@ -16,16 +16,20 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class JBBPFieldLongTest { @Test public void testNameField() { - final JBBPFieldLong field = new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 123456L); + final JBBPFieldLong field = + new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 123456L); final JBBPNamedFieldInfo namedField = field.getNameInfo(); assertEquals("test.field", namedField.getFieldPath()); assertEquals("field", namedField.getFieldName()); @@ -34,29 +38,41 @@ public void testNameField() { @Test public void testgetAsBool_True() { - assertTrue(new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 32423L).getAsBool()); + assertTrue( + new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 32423L).getAsBool()); } @Test public void testgetAsBool_False() { - assertFalse(new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 0L).getAsBool()); + assertFalse( + new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 0L).getAsBool()); } @Test public void testgetAsInt() { - assertEquals((int) 23432498237439L, new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 23432498237439L).getAsInt()); - assertEquals((int) -2343249987234L, new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), -2343249987234L).getAsInt()); + assertEquals((int) 23432498237439L, + new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 23432498237439L) + .getAsInt()); + assertEquals((int) -2343249987234L, + new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), -2343249987234L) + .getAsInt()); } @Test public void testgetAsLong() { - assertEquals(23432498237439L, new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 23432498237439L).getAsLong()); - assertEquals(-2343249987234L, new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), -2343249987234L).getAsLong()); + assertEquals(23432498237439L, + new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 23432498237439L) + .getAsLong()); + assertEquals(-2343249987234L, + new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), -2343249987234L) + .getAsLong()); } @Test public void testGetAsInvertedBitOrder() { - assertEquals(0x10E060A020C04080L, new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 0x0102030405060708L).getAsInvertedBitOrder()); + assertEquals(0x10E060A020C04080L, + new JBBPFieldLong(new JBBPNamedFieldInfo("test.field", "field", 123), 0x0102030405060708L) + .getAsInvertedBitOrder()); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldShortTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldShortTest.java index 5cddf8a2..e3b6b14d 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldShortTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldShortTest.java @@ -16,16 +16,20 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class JBBPFieldShortTest { @Test public void testNameField() { - final JBBPFieldShort field = new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23456); + final JBBPFieldShort field = + new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23456); final JBBPNamedFieldInfo namedField = field.getNameInfo(); assertEquals("test.field", namedField.getFieldPath()); assertEquals("field", namedField.getFieldName()); @@ -34,31 +38,47 @@ public void testNameField() { @Test public void testgetAsBool_True() { - assertTrue(new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 32423).getAsBool()); + assertTrue(new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 32423) + .getAsBool()); } @Test public void testgetAsBool_False() { - assertFalse(new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0).getAsBool()); + assertFalse(new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0) + .getAsBool()); } @Test public void testgetAsInt() { - assertEquals(23432, new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23432).getAsInt()); - assertEquals(-23432, new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) -23432).getAsInt()); + assertEquals(23432, + new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23432) + .getAsInt()); + assertEquals(-23432, + new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) -23432) + .getAsInt()); } @Test public void testgetAsLong() { - assertEquals(23432L, new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23432).getAsLong()); - assertEquals(-23432L, new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) -23432).getAsLong()); + assertEquals(23432L, + new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23432) + .getAsLong()); + assertEquals(-23432L, + new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) -23432) + .getAsLong()); } @Test public void testGetAsInvertedBitOrder() { - assertEquals(0xFFFFFFFFFFFF8000L, new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x1).getAsInvertedBitOrder()); - assertEquals(0x0L, new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x0).getAsInvertedBitOrder()); - assertEquals(0x0000000000004080L, new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x0102).getAsInvertedBitOrder()); + assertEquals(0xFFFFFFFFFFFF8000L, + new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x1) + .getAsInvertedBitOrder()); + assertEquals(0x0L, + new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x0) + .getAsInvertedBitOrder()); + assertEquals(0x0000000000004080L, + new JBBPFieldShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x0102) + .getAsInvertedBitOrder()); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldStringTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldStringTest.java index 7a7e0f67..f38978af 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldStringTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldStringTest.java @@ -1,16 +1,18 @@ package com.igormaznitsa.jbbp.model; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; + +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import org.junit.jupiter.api.Test; + public class JBBPFieldStringTest { @Test public void testNameField() { - final JBBPFieldString field = new JBBPFieldString(new JBBPNamedFieldInfo("test.field", "field", 123), "Huzzaa"); + final JBBPFieldString field = + new JBBPFieldString(new JBBPNamedFieldInfo("test.field", "field", 123), "Huzzaa"); final JBBPNamedFieldInfo namedField = field.getNameInfo(); assertEquals("test.field", namedField.getFieldPath()); assertEquals("field", namedField.getFieldName()); @@ -30,13 +32,15 @@ public void testReverseBits_Text() { @Test public void testGetAsString_NotNull() { - final JBBPFieldString field = new JBBPFieldString(new JBBPNamedFieldInfo("test.field", "field", 123), "Huzzaa"); + final JBBPFieldString field = + new JBBPFieldString(new JBBPNamedFieldInfo("test.field", "field", 123), "Huzzaa"); assertEquals("Huzzaa", field.getAsString()); } @Test public void testGetAsString_Null() { - final JBBPFieldString field = new JBBPFieldString(new JBBPNamedFieldInfo("test.field", "field", 123), null); + final JBBPFieldString field = + new JBBPFieldString(new JBBPNamedFieldInfo("test.field", "field", 123), null); assertNull(field.getAsString()); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldStructTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldStructTest.java index c236e718..92b047f4 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldStructTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldStructTest.java @@ -16,6 +16,16 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + + import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.exceptions.JBBPFinderException; @@ -24,20 +34,23 @@ import com.igormaznitsa.jbbp.utils.JBBPUtils; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class JBBPFieldStructTest { @Test public void testConstructor_Fields() { - final JBBPFieldStruct struct = new JBBPFieldStruct(null, new JBBPAbstractField[] {new JBBPFieldByte(null, (byte) 123), new JBBPFieldByte(null, (byte) -123)}); + final JBBPFieldStruct struct = new JBBPFieldStruct(null, + new JBBPAbstractField[] {new JBBPFieldByte(null, (byte) 123), + new JBBPFieldByte(null, (byte) -123)}); assertNull(struct.getNameInfo()); assertEquals(2, struct.getArray().length); } @Test public void testConstructor_Name_Fields() { - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), new JBBPAbstractField[] {new JBBPFieldByte(null, (byte) 123), new JBBPFieldByte(null, (byte) -123)}); + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), + new JBBPAbstractField[] {new JBBPFieldByte(null, (byte) 123), + new JBBPFieldByte(null, (byte) -123)}); assertNotNull(struct.getNameInfo()); assertEquals("test.struct", struct.getNameInfo().getFieldPath()); assertEquals("struct", struct.getNameInfo().getFieldName()); @@ -47,7 +60,10 @@ public void testConstructor_Name_Fields() { @Test public void testConstructor_Name_ListOfFields() { - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), JBBPUtils.fieldsAsList(new JBBPFieldByte(null, (byte) 123), new JBBPFieldByte(null, (byte) -123))); + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), JBBPUtils + .fieldsAsList(new JBBPFieldByte(null, (byte) 123), + new JBBPFieldByte(null, (byte) -123))); assertNotNull(struct.getNameInfo()); assertEquals("test.struct", struct.getNameInfo().getFieldPath()); assertEquals("struct", struct.getNameInfo().getFieldName()); @@ -57,11 +73,16 @@ public void testConstructor_Name_ListOfFields() { @Test public void testFindFieldForName() { - final JBBPFieldByte field1 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); - final JBBPFieldInt field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); - final JBBPFieldByte field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); - - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), new JBBPAbstractField[] {field1, field2, field3}); + final JBBPFieldByte field1 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); + final JBBPFieldInt field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); + final JBBPFieldByte field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); + + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), + new JBBPAbstractField[] {field1, field2, field3}); assertSame(field1, struct.findFieldForName("field1")); assertSame(field2, struct.findFieldForName("field2")); assertSame(field3, struct.findFieldForName("field3")); @@ -70,11 +91,16 @@ public void testFindFieldForName() { @Test public void testFindFieldForNameAndType() { - final JBBPFieldByte field1 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); - final JBBPFieldInt field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); - final JBBPFieldByte field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); - - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), new JBBPAbstractField[] {field1, field2, field3}); + final JBBPFieldByte field1 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); + final JBBPFieldInt field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); + final JBBPFieldByte field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); + + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), + new JBBPAbstractField[] {field1, field2, field3}); assertSame(field2, struct.findFieldForNameAndType("field2", JBBPFieldInt.class)); assertNull(struct.findFieldForNameAndType("field2", JBBPFieldByte.class)); assertNull(struct.findFieldForNameAndType("field1", JBBPFieldInt.class)); @@ -82,11 +108,16 @@ public void testFindFieldForNameAndType() { @Test public void testFindFieldForPathAndType() { - final JBBPFieldByte field1 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); - final JBBPFieldInt field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); - final JBBPFieldByte field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); - - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), new JBBPAbstractField[] {field1, field2, field3}); + final JBBPFieldByte field1 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); + final JBBPFieldInt field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); + final JBBPFieldByte field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); + + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), + new JBBPAbstractField[] {field1, field2, field3}); assertSame(field2, struct.findFieldForPathAndType("struct.field2", JBBPFieldInt.class)); assertNull(struct.findFieldForPathAndType("field2", JBBPFieldByte.class)); assertNull(struct.findFieldForPathAndType("field1", JBBPFieldInt.class)); @@ -94,9 +125,15 @@ public void testFindFieldForPathAndType() { @Test public void testFindFieldForPath() { - final JBBPFieldByte field = new JBBPFieldByte(new JBBPNamedFieldInfo("struct1.struct2.field3", "field3", 2048), (byte) 78); - final JBBPFieldStruct struct2 = new JBBPFieldStruct(new JBBPNamedFieldInfo("struct1.struct2", "struct2", 1024), new JBBPAbstractField[] {field}); - final JBBPFieldStruct struct1 = new JBBPFieldStruct(new JBBPNamedFieldInfo("struct1", "struct1", 1024), new JBBPAbstractField[] {struct2}); + final JBBPFieldByte field = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct1.struct2.field3", "field3", 2048), + (byte) 78); + final JBBPFieldStruct struct2 = + new JBBPFieldStruct(new JBBPNamedFieldInfo("struct1.struct2", "struct2", 1024), + new JBBPAbstractField[] {field}); + final JBBPFieldStruct struct1 = + new JBBPFieldStruct(new JBBPNamedFieldInfo("struct1", "struct1", 1024), + new JBBPAbstractField[] {struct2}); try { struct1.findFieldForPath(null); @@ -119,11 +156,16 @@ public void testFindFieldForPath() { @Test public void testFindFieldForType() { - final JBBPFieldByte field1 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); - final JBBPFieldInt field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); - final JBBPFieldByte field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); - - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), new JBBPAbstractField[] {field1, field2, field3}); + final JBBPFieldByte field1 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); + final JBBPFieldInt field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); + final JBBPFieldByte field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); + + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), + new JBBPAbstractField[] {field1, field2, field3}); try { struct.findFieldForType(JBBPFieldByte.class); fail("Must throw JBBPTooManyFieldsFoundException"); @@ -136,11 +178,16 @@ public void testFindFieldForType() { @Test public void testFindFirstFieldForType() { - final JBBPFieldByte field1 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); - final JBBPFieldInt field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); - final JBBPFieldByte field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); + final JBBPFieldByte field1 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); + final JBBPFieldInt field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); + final JBBPFieldByte field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), new JBBPAbstractField[] {field1, field2, field3}); + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), + new JBBPAbstractField[] {field1, field2, field3}); assertSame(field1, struct.findFirstFieldForType(JBBPFieldByte.class)); assertSame(field2, struct.findFirstFieldForType(JBBPFieldInt.class)); @@ -149,11 +196,16 @@ public void testFindFirstFieldForType() { @Test public void testFindLastFieldForType() { - final JBBPFieldByte field1 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); - final JBBPFieldInt field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); - final JBBPFieldByte field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); + final JBBPFieldByte field1 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); + final JBBPFieldInt field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); + final JBBPFieldByte field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), new JBBPAbstractField[] {field1, field2, field3}); + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), + new JBBPAbstractField[] {field1, field2, field3}); assertSame(field3, struct.findLastFieldForType(JBBPFieldByte.class)); assertSame(field2, struct.findLastFieldForType(JBBPFieldInt.class)); @@ -162,11 +214,16 @@ public void testFindLastFieldForType() { @Test public void testPathExists() { - final JBBPFieldByte field1 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); - final JBBPFieldInt field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); - final JBBPFieldByte field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); + final JBBPFieldByte field1 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); + final JBBPFieldInt field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); + final JBBPFieldByte field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), new JBBPAbstractField[] {field1, field2, field3}); + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), + new JBBPAbstractField[] {field1, field2, field3}); assertTrue(struct.pathExists("struct.field1")); assertFalse(struct.pathExists("field1")); @@ -175,11 +232,16 @@ public void testPathExists() { @Test public void testNameExists() { - final JBBPFieldByte field1 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); - final JBBPFieldInt field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); - final JBBPFieldByte field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); + final JBBPFieldByte field1 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field1", "field1", 1024), (byte) 23); + final JBBPFieldInt field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("struct.field2", "field2", 1960), 23432); + final JBBPFieldByte field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("struct.field3", "field3", 2048), (byte) 78); - final JBBPFieldStruct struct = new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), new JBBPAbstractField[] {field1, field2, field3}); + final JBBPFieldStruct struct = + new JBBPFieldStruct(new JBBPNamedFieldInfo("test.struct", "struct", 999), + new JBBPAbstractField[] {field1, field2, field3}); assertFalse(struct.nameExists("struct.field1")); assertTrue(struct.nameExists("field1")); @@ -189,7 +251,9 @@ public void testNameExists() { @Test public void testMapTo_Class() throws Exception { - final ClassTestMapToClass mapped = JBBPParser.prepare("byte a; byte b; byte c;").parse(new byte[] {1, 2, 3}).mapTo(new ClassTestMapToClass()); + final ClassTestMapToClass mapped = + JBBPParser.prepare("byte a; byte b; byte c;").parse(new byte[] {1, 2, 3}) + .mapTo(new ClassTestMapToClass()); assertEquals(1, mapped.a); assertEquals(2, mapped.b); @@ -199,7 +263,8 @@ public void testMapTo_Class() throws Exception { @Test public void testMapTo_Object() throws Exception { final ClassTestMapToClass mapped = new ClassTestMapToClass(); - assertSame(mapped, JBBPParser.prepare("byte a; byte b; byte c;").parse(new byte[] {1, 2, 3}).mapTo(mapped)); + assertSame(mapped, + JBBPParser.prepare("byte a; byte b; byte c;").parse(new byte[] {1, 2, 3}).mapTo(mapped)); assertEquals(1, mapped.a); assertEquals(2, mapped.b); @@ -208,12 +273,15 @@ public void testMapTo_Object() throws Exception { @Test public void testInterStructFieldReferences() throws Exception { - final JBBPParser parser = JBBPParser.prepare("header {ubyte sections; ubyte datalen;} sections [header.sections]{byte[header.datalen] data;}"); + final JBBPParser parser = JBBPParser.prepare( + "header {ubyte sections; ubyte datalen;} sections [header.sections]{byte[header.datalen] data;}"); - final JBBPFieldArrayStruct sections = parser.parse(new byte[] {3, 2, 1, 2, 3, 4, 5, 6}).findFieldForNameAndType("sections", JBBPFieldArrayStruct.class); + final JBBPFieldArrayStruct sections = parser.parse(new byte[] {3, 2, 1, 2, 3, 4, 5, 6}) + .findFieldForNameAndType("sections", JBBPFieldArrayStruct.class); assertEquals(3, sections.size()); for (int i = 0; i < 3; i++) { - JBBPFieldArrayByte data = sections.getElementAt(i).findFieldForNameAndType("data", JBBPFieldArrayByte.class); + JBBPFieldArrayByte data = + sections.getElementAt(i).findFieldForNameAndType("data", JBBPFieldArrayByte.class); final int base = i * 2; assertArrayEquals(new byte[] {(byte) (base + 1), (byte) (base + 2)}, data.getArray()); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUByteTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUByteTest.java index 9aa4ffec..38edb868 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUByteTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUByteTest.java @@ -16,15 +16,19 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class JBBPFieldUByteTest { @Test public void testNameField() { - final JBBPFieldUByte field = new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 10); + final JBBPFieldUByte field = + new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 10); final JBBPNamedFieldInfo namedField = field.getNameInfo(); assertEquals("test.field", namedField.getFieldPath()); assertEquals("field", namedField.getFieldName()); @@ -33,30 +37,46 @@ public void testNameField() { @Test public void testgetAsBool_True() { - assertTrue(new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 123).getAsBool()); + assertTrue(new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 123) + .getAsBool()); } @Test public void testgetAsBool_False() { - assertFalse(new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 0).getAsBool()); + assertFalse(new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 0) + .getAsBool()); } @Test public void testgetAsInt() { - assertEquals(12, new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 12).getAsInt()); - assertEquals(-12 & 0xFF, new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) -12).getAsInt()); + assertEquals(12, + new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 12) + .getAsInt()); + assertEquals(-12 & 0xFF, + new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) -12) + .getAsInt()); } @Test public void testgetAsLong() { - assertEquals(12L, new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 12).getAsLong()); - assertEquals(-12L & 0xFFL, new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) -12).getAsLong()); + assertEquals(12L, + new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 12) + .getAsLong()); + assertEquals(-12L & 0xFFL, + new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) -12) + .getAsLong()); } @Test public void testGetAsInvertedBitOrder() { - assertEquals(0x0000000000000080L, new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 1).getAsInvertedBitOrder()); - assertEquals(0x00000000000000E0L, new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 7).getAsInvertedBitOrder()); - assertEquals(0x0FL, new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 0xF0).getAsInvertedBitOrder()); + assertEquals(0x0000000000000080L, + new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 1) + .getAsInvertedBitOrder()); + assertEquals(0x00000000000000E0L, + new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 7) + .getAsInvertedBitOrder()); + assertEquals(0x0FL, + new JBBPFieldUByte(new JBBPNamedFieldInfo("test.field", "field", 123), (byte) 0xF0) + .getAsInvertedBitOrder()); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUIntTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUIntTest.java new file mode 100644 index 00000000..c3b5c641 --- /dev/null +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUIntTest.java @@ -0,0 +1,85 @@ +/* + * Copyright 2017 Igor Maznitsa. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.igormaznitsa.jbbp.model; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.exceptions.JBBPNumericFieldValueConversionException; +import org.junit.jupiter.api.Test; + +public class JBBPFieldUIntTest { + + @Test + public void testNameField() { + final JBBPFieldUInt field = + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), 123456); + final JBBPNamedFieldInfo namedField = field.getNameInfo(); + assertEquals("test.field", namedField.getFieldPath()); + assertEquals("field", namedField.getFieldName()); + assertEquals(123, namedField.getFieldOffsetInCompiledBlock()); + } + + @Test + public void testGetAsBool_True() { + assertTrue( + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), 32423).getAsBool()); + } + + @Test + public void testGetAsBool_False() { + assertFalse( + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0).getAsBool()); + } + + @Test + public void testGetAsInt() { + assertEquals(234324, + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), 234324).getAsInt()); + + assertThrows(JBBPNumericFieldValueConversionException.class, () -> + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), -234324).getAsInt()); + } + + @Test + public void testGetAsLong() { + assertEquals(234324L, + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), 234324).getAsLong()); + assertEquals(4294732972L, + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), + 4294732972L).getAsLong()); + } + + + @Test + public void testGetAsInvertedBitOrder() { + assertEquals(0x0000000020C04080L, + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0x01020304) + .getAsInvertedBitOrder()); + assertEquals(0x000000007FFFFFFFL, + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0xFFFFFFFE) + .getAsInvertedBitOrder()); + assertEquals(0x0000000080000000L, + new JBBPFieldUInt(new JBBPNamedFieldInfo("test.field", "field", 123), 0x00000001) + .getAsInvertedBitOrder()); + } + + +} diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUShortTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUShortTest.java index 9c451aaf..8aa10b3a 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUShortTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/model/JBBPFieldUShortTest.java @@ -16,16 +16,21 @@ package com.igormaznitsa.jbbp.model; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - public class JBBPFieldUShortTest { @Test public void testNameField() { - final JBBPFieldUShort field = new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23456); + final JBBPFieldUShort field = + new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23456); final JBBPNamedFieldInfo namedField = field.getNameInfo(); assertEquals("test.field", namedField.getFieldPath()); assertEquals("field", namedField.getFieldName()); @@ -34,37 +39,55 @@ public void testNameField() { @Test public void testgetAsBool_True() { - assertTrue(new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 32423).getAsBool()); + assertTrue( + new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 32423) + .getAsBool()); } @Test public void testgetAsBool_False() { - assertFalse(new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0).getAsBool()); + assertFalse(new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0) + .getAsBool()); } @Test public void testgetAsInt() { - assertEquals(23432, new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23432).getAsInt()); - assertEquals(-23432 & 0xFFFF, new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) -23432).getAsInt()); + assertEquals(23432, + new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23432) + .getAsInt()); + assertEquals(-23432 & 0xFFFF, + new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) -23432) + .getAsInt()); } @Test public void testgetAsLong() { - assertEquals(23432L, new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23432).getAsLong()); - assertEquals(-23432L & 0xFFFFL, new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) -23432).getAsLong()); + assertEquals(23432L, + new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 23432) + .getAsLong()); + assertEquals(-23432L & 0xFFFFL, + new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) -23432) + .getAsLong()); } @Test public void testGetAsInvertedBitOrder() { - assertEquals(0x0000000000008000L, new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x1).getAsInvertedBitOrder()); - assertEquals(0x0L, new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x0).getAsInvertedBitOrder()); - assertEquals(0x0000000000004080L, new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x0102).getAsInvertedBitOrder()); + assertEquals(0x0000000000008000L, + new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x1) + .getAsInvertedBitOrder()); + assertEquals(0x0L, + new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x0) + .getAsInvertedBitOrder()); + assertEquals(0x0000000000004080L, + new JBBPFieldUShort(new JBBPNamedFieldInfo("test.field", "field", 123), (short) 0x0102) + .getAsInvertedBitOrder()); } @Test public void testGetValueArrayAsObject() { final short[] array = new short[] {(short) -27834, 23423, 0, -2, 3}; - final JBBPFieldArrayUShort test = new JBBPFieldArrayUShort(new JBBPNamedFieldInfo("test.field", "field", 999), array); + final JBBPFieldArrayUShort test = + new JBBPFieldArrayUShort(new JBBPNamedFieldInfo("test.field", "field", 999), array); assertArrayEquals(array, (short[]) test.getValueArrayAsObject(false)); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJavaConverterTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJavaConverterTest.java index b6a511bb..47ca4b78 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJavaConverterTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJavaConverterTest.java @@ -55,9 +55,10 @@ public abstract class AbstractJBBPToJavaConverterTest { protected static final String PACKAGE_NAME = "com.igormaznitsa.test"; protected static final String CLASS_NAME = "TestClass"; + private static final List compilerOptions = + Arrays.asList("-Xlint:-options", "-proc:none"); protected static TemporaryFolder tempFolder = new TemporaryFolder(); protected final Random testRandomGen = new Random(123456); - protected boolean printGeneratedClassText = false; @BeforeAll @@ -72,11 +73,11 @@ public static void afterAll() { } } - protected static Map makeMap(final String... mapvalue) { + protected static Map makeMap(final String... values) { final Map result = new HashMap<>(); int i = 0; - while (i < mapvalue.length) { - result.put(mapvalue[i++], mapvalue[i++]); + while (i < values.length) { + result.put(values[i++], values[i++]); } return result; } @@ -93,7 +94,8 @@ protected Object callRead(final Object instance, final byte[] array) throws Exce } } - protected Object callRead(final Object instance, final JBBPBitInputStream inStream) throws Exception { + protected Object callRead(final Object instance, final JBBPBitInputStream inStream) + throws Exception { try { instance.getClass().getMethod("read", JBBPBitInputStream.class).invoke(instance, inStream); return instance; @@ -109,9 +111,9 @@ protected Object callRead(final Object instance, final JBBPBitInputStream inStre protected byte[] callWrite(final Object instance) throws Exception { try { final ByteArrayOutputStream bout = new ByteArrayOutputStream(); - final JBBPBitOutputStream bitout = new JBBPBitOutputStream(bout); - instance.getClass().getMethod("write", JBBPBitOutputStream.class).invoke(instance, bitout); - bitout.close(); + final JBBPBitOutputStream bitOut = new JBBPBitOutputStream(bout); + instance.getClass().getMethod("write", JBBPBitOutputStream.class).invoke(instance, bitOut); + bitOut.close(); return bout.toByteArray(); } catch (InvocationTargetException ex) { if (ex.getCause() != null) { @@ -122,52 +124,54 @@ protected byte[] callWrite(final Object instance) throws Exception { } } - protected void callWrite(final Object instance, final JBBPBitOutputStream outStream) throws Exception { + protected void callWrite(final Object instance, final JBBPBitOutputStream outStream) + throws Exception { instance.getClass().getMethod("write", JBBPBitOutputStream.class).invoke(instance, outStream); } - protected Object compileAndMakeInstanceSrc(final String script, final String classCustomText, final StringBuilder srcBuffer) throws Exception { - final String classBody = JBBPToJavaConverter.makeBuilder(JBBPParser.prepare(script)).setMainClassName(CLASS_NAME).setMainClassPackage(PACKAGE_NAME).setMainClassCustomText(classCustomText).build().convert(); + protected Object compileAndMakeInstanceSrc(final String script, final String classCustomText, + final StringBuilder srcBuffer) throws Exception { + final String classBody = + JBBPToJavaConverter.makeBuilder(JBBPParser.prepare(script)).setMainClassName(CLASS_NAME) + .setMainClassPackage(PACKAGE_NAME).setMainClassCustomText(classCustomText).build() + .convert(); if (srcBuffer != null) { srcBuffer.append(classBody); } - final ClassLoader cloader = saveAndCompile(new JavaClassContent(PACKAGE_NAME + '.' + CLASS_NAME, classBody)); - return ReflectUtils.newInstance(cloader.loadClass(PACKAGE_NAME + '.' + CLASS_NAME)); + final ClassLoader classLoader = + saveAndCompile(new JavaClassContent(PACKAGE_NAME + '.' + CLASS_NAME, classBody)); + return ReflectUtils.newInstance(classLoader.loadClass(PACKAGE_NAME + '.' + CLASS_NAME)); } protected Object compileAndMakeInstance(final String script) throws Exception { return this.compileAndMakeInstance(PACKAGE_NAME + '.' + CLASS_NAME, script, null); } - protected Object compileAndMakeInstance(final String script, final int parserFlags) throws Exception { + protected Object compileAndMakeInstance(final String script, final int parserFlags) + throws Exception { return this.compileAndMakeInstance(PACKAGE_NAME + '.' + CLASS_NAME, script, parserFlags, null); } - protected Object compileAndMakeInstance(final String instanceClassName, final String script, final JBBPCustomFieldTypeProcessor customFieldProcessor, final JavaClassContent... extraClasses) throws Exception { - return this.compileAndMakeInstance(instanceClassName, script, 0, customFieldProcessor, extraClasses); - } - - protected Object compileAndMakeInstance(final String instanceClassName, final String script, final int parserFlags, final JBBPCustomFieldTypeProcessor customFieldProcessor, final JavaClassContent... extraClasses) throws Exception { - final List klazzes = new ArrayList<>(Arrays.asList(extraClasses)); - final JavaClassContent klazzContent = new JavaClassContent(PACKAGE_NAME + '.' + CLASS_NAME, JBBPParser.prepare(script, JBBPBitOrder.LSB0, customFieldProcessor, parserFlags).convertToSrc(TargetSources.JAVA, PACKAGE_NAME + "." + CLASS_NAME).get(0).getResult().values().iterator().next()); - if (this.printGeneratedClassText) { - System.out.println(klazzContent.classText); - } - klazzes.add(0, klazzContent); - final ClassLoader cloader = saveAndCompile(klazzes.toArray(new JavaClassContent[0])); - return ReflectUtils.newInstance(cloader.loadClass(instanceClassName)); + protected Object compileAndMakeInstance(final String instanceClassName, final String script, + final JBBPCustomFieldTypeProcessor customFieldProcessor, + final JavaClassContent... extraClasses) throws Exception { + return this + .compileAndMakeInstance(instanceClassName, script, 0, customFieldProcessor, extraClasses); } - public ClassLoader saveAndCompile(final JavaClassContent... klasses) throws IOException { - return this.saveAndCompile(null, klasses); + public ClassLoader saveAndCompile(final JavaClassContent... javaClassContents) + throws IOException { + return this.saveAndCompile(null, javaClassContents); } - public ClassLoader saveAndCompile(final ClassLoader classLoader, final JavaClassContent... klasses) throws IOException { + public ClassLoader saveAndCompile(final ClassLoader classLoader, + final JavaClassContent... javaClassContents) + throws IOException { final File folder = tempFolder.newFolder(); final List classFiles = new ArrayList<>(); - for (final JavaClassContent c : klasses) { + for (final JavaClassContent c : javaClassContents) { final File classFile = c.makeFile(folder); final File pack = classFile.getParentFile(); if (!pack.isDirectory() && !pack.mkdirs()) { @@ -180,12 +184,16 @@ public ClassLoader saveAndCompile(final ClassLoader classLoader, final JavaClass final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); final DiagnosticCollector diagnostics = new DiagnosticCollector<>(); - final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); - final Iterable compilationUnits = fileManager.getJavaFileObjectsFromFiles(classFiles); + final StandardJavaFileManager fileManager = + compiler.getStandardFileManager(diagnostics, null, null); + final Iterable compilationUnits = + fileManager.getJavaFileObjectsFromFiles(classFiles); - if (!compiler.getTask(null, fileManager, null, null, null, compilationUnits).call()) { + if (!compiler.getTask(null, fileManager, null, compilerOptions, null, compilationUnits) + .call()) { for (final Diagnostic diagnostic : diagnostics.getDiagnostics()) { - System.err.format("Error on line %d in %s%n", diagnostic.getLineNumber(), diagnostic.getSource()); + System.err + .format("Error on line %d in %s%n", diagnostic.getLineNumber(), diagnostic.getSource()); } for (final File f : classFiles) { @@ -197,7 +205,26 @@ public ClassLoader saveAndCompile(final ClassLoader classLoader, final JavaClass throw new IOException("Error during compilation"); } - return classLoader == null ? new URLClassLoader(new URL[] {folder.toURI().toURL()}) : classLoader; + return classLoader == null ? new URLClassLoader(new URL[] {folder.toURI().toURL()}) : + classLoader; + } + + protected Object compileAndMakeInstance(final String instanceClassName, final String script, + final int parserFlags, + final JBBPCustomFieldTypeProcessor customFieldProcessor, + final JavaClassContent... extraClasses) throws Exception { + final List javaClassContents = new ArrayList<>(Arrays.asList(extraClasses)); + final JavaClassContent javaClassContent = new JavaClassContent(PACKAGE_NAME + '.' + CLASS_NAME, + JBBPParser.prepare(script, JBBPBitOrder.LSB0, customFieldProcessor, parserFlags) + .convertToSrc(TargetSources.JAVA, PACKAGE_NAME + "." + CLASS_NAME).get(0).getResult() + .values().iterator().next()); + if (this.printGeneratedClassText) { + System.out.println(javaClassContent.classText); + } + javaClassContents.add(0, javaClassContent); + final ClassLoader classLoader = + saveAndCompile(javaClassContents.toArray(new JavaClassContent[0])); + return ReflectUtils.newInstance(classLoader.loadClass(instanceClassName)); } protected static class TemporaryFolder { @@ -234,7 +261,8 @@ public File newFolder() { result.deleteOnExit(); return result; } catch (IOException ex) { - throw new Error("Can't make new sub-folder in temp folder : " + this.folder.getAbsolutePath(), ex); + throw new Error( + "Can't make new sub-folder in temp folder : " + this.folder.getAbsolutePath(), ex); } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/DynamicIntBuffer.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/DynamicIntBuffer.java index bd4de782..4a047238 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/DynamicIntBuffer.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/DynamicIntBuffer.java @@ -17,7 +17,6 @@ package com.igormaznitsa.jbbp.utils; import com.igormaznitsa.jbbp.compiler.conversion.JBBPToJavaConverterReadWriteTest; - import java.util.Arrays; /** diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPCustomFieldTypeProcessorAggregatorTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPCustomFieldTypeProcessorAggregatorTest.java index 3d20aa9e..6b8e5044 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPCustomFieldTypeProcessorAggregatorTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPCustomFieldTypeProcessorAggregatorTest.java @@ -16,23 +16,25 @@ package com.igormaznitsa.jbbp.utils; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.model.JBBPAbstractField; import com.igormaznitsa.jbbp.model.JBBPFieldByte; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPCustomFieldTypeProcessorAggregatorTest { @@ -47,13 +49,22 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, int extraData, boolean isArray) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, + int extraData, boolean isArray) { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override - public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, int parserFlags, JBBPFieldTypeParameterContainer customTypeFieldInfo, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. } }; @@ -65,13 +76,22 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, int extraData, boolean isArray) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, + int extraData, boolean isArray) { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override - public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, int parserFlags, JBBPFieldTypeParameterContainer customTypeFieldInfo, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. } }; @@ -89,13 +109,22 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, int extraData, boolean isArray) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, + int extraData, boolean isArray) { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override - public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, int parserFlags, JBBPFieldTypeParameterContainer customTypeFieldInfo, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. } }; @@ -107,17 +136,27 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, int extraData, boolean isArray) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, + int extraData, boolean isArray) { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override - public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, int parserFlags, JBBPFieldTypeParameterContainer customTypeFieldInfo, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { + throw new UnsupportedOperationException( + "Not supported yet."); //To change body of generated methods, choose Tools | Templates. } }; - final List types = Arrays.asList(new JBBPCustomFieldTypeProcessorAggregator(proc1, proc2).getCustomFieldTypes()); + final List types = Arrays + .asList(new JBBPCustomFieldTypeProcessorAggregator(proc1, proc2).getCustomFieldTypes()); assertEquals(6, types.size()); assertTrue(types.contains("type1")); @@ -142,13 +181,20 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, int extraData, boolean isArray) { + public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, + int extraData, boolean isArray) { allowed.add(new Record(fieldType.getTypeName(), this)); return true; } @Override - public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, int parserFlags, JBBPFieldTypeParameterContainer customTypeFieldInfo, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException { + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { read.add(new Record(customTypeFieldInfo.getTypeName(), this)); return new JBBPFieldByte(fieldName, (byte) in.readByte()); } @@ -162,19 +208,28 @@ public String[] getCustomFieldTypes() { } @Override - public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, int extraData, boolean isArray) { + public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, + int extraData, boolean isArray) { allowed.add(new Record(fieldType.getTypeName(), this)); return true; } @Override - public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, int parserFlags, JBBPFieldTypeParameterContainer customTypeFieldInfo, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException { + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) + throws IOException { read.add(new Record(customTypeFieldInfo.getTypeName(), this)); return new JBBPFieldByte(fieldName, (byte) in.readByte()); } }; - final JBBPParser parser = JBBPParser.prepare("type1; type2; type3; type4; type5; type6;", JBBPBitOrder.LSB0, new JBBPCustomFieldTypeProcessorAggregator(proc1, proc2), 0); + final JBBPParser parser = JBBPParser + .prepare("type1; type2; type3; type4; type5; type6;", JBBPBitOrder.LSB0, + new JBBPCustomFieldTypeProcessorAggregator(proc1, proc2), 0); assertEquals(6, allowed.size()); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilderTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilderTest.java index 1029ad3c..fd2c4199 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilderTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilderTest.java @@ -59,7 +59,8 @@ public void testCheckForDuplicatedNameInSameStructure() { final JBBPDslBuilder builder2 = JBBPDslBuilder.Begin().Int("test"); assertThrows(IllegalArgumentException.class, () -> builder2.Struct("test")); - final JBBPDslBuilder builder3 = JBBPDslBuilder.Begin().Struct("test").Int("a").CloseStruct().Bool("b"); + final JBBPDslBuilder builder3 = + JBBPDslBuilder.Begin().Struct("test").Int("a").CloseStruct().Bool("b"); assertThrows(IllegalArgumentException.class, () -> builder3.Struct("test")); } @@ -67,19 +68,23 @@ public void testCheckForDuplicatedNameInSameStructure() { @Test public void testCheckForDuplicatedNameInDifferentStructures() { JBBPDslBuilder.Begin().Int("test").Struct().Bool("test").CloseStruct().End(); - JBBPDslBuilder.Begin().Int("test").Struct().Int("test").Struct().Bool("test").CloseStruct().CloseStruct().End(); - JBBPDslBuilder.Begin().Struct().Int("test").Struct().Bool("test").CloseStruct().CloseStruct().Int("test").End(); + JBBPDslBuilder.Begin().Int("test").Struct().Int("test").Struct().Bool("test").CloseStruct() + .CloseStruct().End(); + JBBPDslBuilder.Begin().Struct().Int("test").Struct().Bool("test").CloseStruct().CloseStruct() + .Int("test").End(); JBBPDslBuilder.Begin().Struct("test").Int("test").CloseStruct().End(); } @Test public void testNonFormatted() { - assertEquals("bool test;{int field1;}", Begin().Bool("test").Struct().Int("field1").CloseStruct().End(false)); + assertEquals("bool test;{int field1;}", + Begin().Bool("test").Struct().Int("field1").CloseStruct().End(false)); } @Test public void testFormatted() { - assertEquals("bool test;\n{\n\tint field1;\n}\n", Begin().Bool("test").Struct().Int("field1").CloseStruct().End(true)); + assertEquals("bool test;\n{\n\tint field1;\n}\n", + Begin().Bool("test").Struct().Int("field1").CloseStruct().End(true)); } @Test @@ -103,9 +108,12 @@ public void testComment() { assertEquals("// Test\n", Begin().Comment("Test").End()); assertEquals("// //\n// Test\n", Begin().Comment("//").Comment("Test").End()); assertEquals("// Test\n// Test2\n", Begin().Comment("Test").Comment("Test2").End()); - assertEquals("int a;// Test\n// Test2\n", Begin().Int("a").Comment("Test").Comment("Test2").End()); - assertEquals("int a;\n// Test\n// Test2\n", Begin().Int("a").NewLineComment("Test").NewLineComment("Test2").End()); - assertEquals("int a;hello{// hello\n}// end hello\n", Begin().Int("a").Struct("hello").Comment("hello").CloseStruct().Comment("end hello").End()); + assertEquals("int a;// Test\n// Test2\n", + Begin().Int("a").Comment("Test").Comment("Test2").End()); + assertEquals("int a;\n// Test\n// Test2\n", + Begin().Int("a").NewLineComment("Test").NewLineComment("Test2").End()); + assertEquals("int a;hello{// hello\n}// end hello\n", + Begin().Int("a").Struct("hello").Comment("hello").CloseStruct().Comment("end hello").End()); } @Test @@ -125,7 +133,8 @@ public void testType_CustomArray() { assertEquals("some[1234] lupus;", Begin().CustomArray("some", "lupus", 1234).End()); assertEquals("some[a+1234] lupus;", Begin().CustomArray("some", "lupus", "a+1234").End()); assertEquals("some:(c/2)[_] huzzaa;", Begin().CustomArray("some", "huzzaa", -1, "c/2").End()); - assertEquals("some:(c/2)[a+b] huzzaa;", Begin().CustomArray("some", "huzzaa", "a+b", "c/2").End()); + assertEquals("some:(c/2)[a+b] huzzaa;", + Begin().CustomArray("some", "huzzaa", "a+b", "c/2").End()); } @Test @@ -368,13 +377,15 @@ public void testStructArray() { @Test public void testStruct_CloseStruct() { - assertEquals("{{{}}}", Begin().Struct().Struct().Struct().CloseStruct().CloseStruct().CloseStruct().End()); + assertEquals("{{{}}}", + Begin().Struct().Struct().Struct().CloseStruct().CloseStruct().CloseStruct().End()); assertEquals("{\n" + - "\t{\n" + - "\t\t{\n" + - "\t\t}\n" + - "\t}\n" + - "}\n", Begin().Struct().Struct().Struct().CloseStruct().CloseStruct().CloseStruct().End(true)); + "\t{\n" + + "\t\t{\n" + + "\t\t}\n" + + "\t}\n" + + "}\n", + Begin().Struct().Struct().Struct().CloseStruct().CloseStruct().CloseStruct().End(true)); assertThrows(IllegalStateException.class, () -> Begin().CloseStruct()); } @@ -419,7 +430,8 @@ class Internal { } } - assertEquals("Test{int a;,0x02", makeWriter().Byte(1).Str("Hello", "World", null).Byte(2).Close().toString()); + assertEquals(".0x01,Hello,World,,0x02", + makeWriter().Byte(1).Str("Hello", "World", null).Byte(2).Close().toString()); } @Test @@ -615,7 +671,8 @@ public void testAppend() throws Exception { @Test public void testSetValuePrefixPostfix() throws Exception { - assertEquals(".0x01,$02^", makeWriter().Byte(1).SetValuePrefix("$").SetValuePostfix("^").Byte(2).Close().toString()); + assertEquals(".0x01,$02^", + makeWriter().Byte(1).SetValuePrefix("$").SetValuePostfix("^").Byte(2).Close().toString()); } @Test @@ -640,7 +697,8 @@ public void testPrintNumericValueByExtras() throws Exception { final JBBPTextWriter writer = makeWriter(); writer.AddExtras(new JBBPTextWriterExtraAdapter() { @Override - public String doConvertObjToStr(JBBPTextWriter context, int id, Object obj) throws IOException { + public String doConvertObjToStr(JBBPTextWriter context, int id, Object obj) + throws IOException { assertEquals(234, id); return "obj" + obj; } @@ -677,9 +735,11 @@ public String doConvertByteToStr(JBBPTextWriter context, int value) throws IOExc }); - writer.SetValuePrefix("").Byte(1).Short(2).Int(3).Long(4).Obj(234, "Str").Float(Float.MIN_VALUE).Double(Double.MAX_VALUE); + writer.SetValuePrefix("").Byte(1).Short(2).Int(3).Long(4).Obj(234, "Str").Float(Float.MIN_VALUE) + .Double(Double.MAX_VALUE); - assertEquals(".byte1,short2,int3,long4,objStr,float1.4E-45,double1.7976931348623157E308", writer.Close().toString()); + assertEquals(".byte1,short2,int3,long4,objStr,float1.4E-45,double1.7976931348623157E308", + writer.Close().toString()); } @Test @@ -756,7 +816,9 @@ class Png { } final Png png = pngParser.parse(pngStream).mapTo(new Png(), aClass -> { - if (aClass == Chunk.class) return new Chunk(); + if (aClass == Chunk.class) { + return new Chunk(); + } return null; }); @@ -775,7 +837,8 @@ public void testBin_ParsedDoubleFloat() throws Exception { final JBBPTextWriter writer = makeWriter(); final InputStream pngStream = getResourceAsInputStream("picture.png"); - final JBBPParser parser = JBBPParser.prepare("floatj f; doublej d; floatj [2] fa; doublej [2] da;"); + final JBBPParser parser = + JBBPParser.prepare("floatj f; doublej d; floatj [2] fa; doublej [2] da;"); class Klazz { @@ -816,7 +879,8 @@ public void testBin_ParsedPng_NonMappedRawStruct() throws Exception { + "}" ); - final String text = makeWriter().SetMaxValuesPerLine(16).Bin(pngParser.parse(pngStream)).Close().toString(); + final String text = + makeWriter().SetMaxValuesPerLine(16).Bin(pngParser.parse(pngStream)).Close().toString(); System.out.println(text); assertFileContent("testwriterbin2b.txt", text); } finally { @@ -826,10 +890,16 @@ public void testBin_ParsedPng_NonMappedRawStruct() throws Exception { @Test public void testBin_AllEasyTypes_NonMappedRawStruct() throws Exception { - final JBBPParser parser = JBBPParser.prepare("bit:2 a1; bit:6 a2; byte a; ubyte b; short c; ushort d; int e; long f; bool g;"); - final byte[] testArray = new byte[] {(byte) 0xDE, (byte) 0x12, (byte) 0xFE, (byte) 0x23, (byte) 0x11, (byte) 0x45, (byte) 0xDA, (byte) 0x82, (byte) 0xA0, (byte) 0x33, (byte) 0x7F, (byte) 0x99, (byte) 0x04, (byte) 0x10, (byte) 0x45, (byte) 0xBD, (byte) 0xCA, (byte) 0xFE, (byte) 0x12, (byte) 0x11, (byte) 0xBA, (byte) 0xBE}; - - final String text = makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(testArray)).Close().toString(); + final JBBPParser parser = JBBPParser + .prepare("bit:2 a1; bit:6 a2; byte a; ubyte b; short c; ushort d; int e; long f; bool g;"); + final byte[] testArray = + new byte[] {(byte) 0xDE, (byte) 0x12, (byte) 0xFE, (byte) 0x23, (byte) 0x11, (byte) 0x45, + (byte) 0xDA, (byte) 0x82, (byte) 0xA0, (byte) 0x33, (byte) 0x7F, (byte) 0x99, + (byte) 0x04, (byte) 0x10, (byte) 0x45, (byte) 0xBD, (byte) 0xCA, (byte) 0xFE, + (byte) 0x12, (byte) 0x11, (byte) 0xBA, (byte) 0xBE}; + + final String text = + makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(testArray)).Close().toString(); System.out.println(text); assertFileContent("txtwrtrjbbpobj1.txt", text); } @@ -837,19 +907,23 @@ public void testBin_AllEasyTypes_NonMappedRawStruct() throws Exception { @Test public void testBin_ValField() throws Exception { final JBBPParser parser = JBBPParser.prepare("val:123 a;"); - final String text = makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(new byte[0])).Close().toString(); - assertEquals("~--------------------------------------------------------------------------------\n" + - "; Start {} \n" + + final String text = + makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(new byte[0])).Close().toString(); + assertEquals( "~--------------------------------------------------------------------------------\n" + - " .0x0000007B; int a\n" + - "~--------------------------------------------------------------------------------\n" + - "; End {} \n" + - "~--------------------------------------------------------------------------------\n", text); + "; Start {} \n" + + "~--------------------------------------------------------------------------------\n" + + " .0x0000007B; int a\n" + + "~--------------------------------------------------------------------------------\n" + + "; End {} \n" + + "~--------------------------------------------------------------------------------\n", + text); } @Test public void testBin_AllEasyTypes_Anonymous_NonMappedRawStruct() throws Exception { - final JBBPParser parser = JBBPParser.prepare("bit:2; bit:6; byte; ubyte; short; ushort; int; long; bool; stringj;"); + final JBBPParser parser = + JBBPParser.prepare("bit:2; bit:6; byte; ubyte; short; ushort; int; long; bool; stringj;"); final byte[] testArray = new byte[] { (byte) 0xDE, (byte) 0x12, (byte) 0xFE, (byte) 0x23, (byte) 0x11, (byte) 0x45, (byte) 0xDA, (byte) 0x82, (byte) 0xA0, (byte) 0x33, @@ -858,7 +932,8 @@ public void testBin_AllEasyTypes_Anonymous_NonMappedRawStruct() throws Exception 3, 65, 66, 67 }; - final String text = makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(testArray)).Close().toString(); + final String text = + makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(testArray)).Close().toString(); System.out.println(text); assertFileContent("txtwrtrjbbpobj2.txt", text); } @@ -872,7 +947,8 @@ public void testBin_StringFieldAndStringArray() throws Exception { 3, 71, 72, 73 }; - final String text = makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(testArray)).Close().toString(); + final String text = + makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(testArray)).Close().toString(); System.out.println(text); assertFileContent("txtwrtrjbbpobj3.txt", text); } @@ -880,9 +956,14 @@ public void testBin_StringFieldAndStringArray() throws Exception { @Test public void testBin_BooleanArray_NonMappedRawStruct() throws Exception { final JBBPParser parser = JBBPParser.prepare("bool [_] array;"); - final byte[] testArray = new byte[] {(byte) 0xDE, (byte) 0x00, (byte) 0xFE, (byte) 0x00, (byte) 0x11, (byte) 0x45, (byte) 0xDA, (byte) 0x82, (byte) 0xA0, (byte) 0x33, (byte) 0x7F, (byte) 0x99, (byte) 0x04, (byte) 0x10, (byte) 0x45, (byte) 0xBD, (byte) 0xCA, (byte) 0xFE, (byte) 0x12, (byte) 0x11, (byte) 0x00, (byte) 0xBE}; - - final String text = makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(testArray)).Close().toString(); + final byte[] testArray = + new byte[] {(byte) 0xDE, (byte) 0x00, (byte) 0xFE, (byte) 0x00, (byte) 0x11, (byte) 0x45, + (byte) 0xDA, (byte) 0x82, (byte) 0xA0, (byte) 0x33, (byte) 0x7F, (byte) 0x99, + (byte) 0x04, (byte) 0x10, (byte) 0x45, (byte) 0xBD, (byte) 0xCA, (byte) 0xFE, + (byte) 0x12, (byte) 0x11, (byte) 0x00, (byte) 0xBE}; + + final String text = + makeWriter().SetMaxValuesPerLine(16).Bin(parser.parse(testArray)).Close().toString(); System.out.println(text); assertFileContent("boolarrayraw.txt", text); } @@ -896,7 +977,8 @@ class Parsed { String str2; } - final Parsed parsed = JBBPParser.prepare("byte [5] str1; ubyte [4] str2;").parse(new byte[] {49, 50, 51, 52, 53, 54, 55, 56, 57}).mapTo(new Parsed()); + final Parsed parsed = JBBPParser.prepare("byte [5] str1; ubyte [4] str2;") + .parse(new byte[] {49, 50, 51, 52, 53, 54, 55, 56, 57}).mapTo(new Parsed()); final String text = makeWriter().Bin(parsed).Close().toString(); System.out.println(text); @@ -919,19 +1001,23 @@ class TestClass { writer.AddExtras(new JBBPTextWriterExtraAdapter() { @Override - public String doConvertObjToStr(JBBPTextWriter context, int id, Object obj) throws IOException { + public String doConvertObjToStr(JBBPTextWriter context, int id, Object obj) + throws IOException { fail("Must not be called"); return null; } @Override - public String doConvertCustomField(final JBBPTextWriter context, final Object obj, final Field field, final Bin annotation) throws IOException { + public String doConvertCustomField(final JBBPTextWriter context, final Object obj, + final Field field, final Bin annotation) + throws IOException { return "test" + field.getName(); } }); - final String text = writer.SetHR("~", 3, '-').SetValuePrefix("").Bin(new TestClass()).Close().toString(); + final String text = + writer.SetHR("~", 3, '-').SetValuePrefix("").Bin(new TestClass()).Close().toString(); System.out.println(text); assertFileContent("testwriterbin3.txt", text); } @@ -951,20 +1037,24 @@ class TestClass { writer.AddExtras(new JBBPTextWriterExtraAdapter() { @Override - public String doConvertObjToStr(JBBPTextWriter context, int id, Object obj) throws IOException { + public String doConvertObjToStr(JBBPTextWriter context, int id, Object obj) + throws IOException { fail("Must not be called"); return null; } @Override - public String doConvertCustomField(JBBPTextWriter context, Object obj, Field field, Bin annotation) throws IOException { - context.HR().Str(field.getType().isArray() ? "See on array" : "Error").Comment("Line one", "Line two").HR(); + public String doConvertCustomField(JBBPTextWriter context, Object obj, Field field, + Bin annotation) throws IOException { + context.HR().Str(field.getType().isArray() ? "See on array" : "Error") + .Comment("Line one", "Line two").HR(); return null; } }); - final String text = writer.SetHR("~", 3, '-').SetValuePrefix("").Bin(new TestClass()).Close().toString(); + final String text = + writer.SetHR("~", 3, '-').SetValuePrefix("").Bin(new TestClass()).Close().toString(); System.out.println(text); assertFileContent("testwriterbin4.txt", text); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPUtilsTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPUtilsTest.java index bd5412ce..afb0494c 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPUtilsTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPUtilsTest.java @@ -16,22 +16,133 @@ package com.igormaznitsa.jbbp.utils; +import static com.igormaznitsa.jbbp.utils.JBBPUtils.findMaxStaticArraySize; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPArraySizeLimiter; +import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitNumber; import com.igormaznitsa.jbbp.io.JBBPBitOrder; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - +import com.igormaznitsa.jbbp.model.JBBPAbstractField; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.InputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; import java.util.Random; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPUtilsTest { + @Test + public void testFindMaxStaticArraySize_CustomDefaultSize() { + assertEquals(0L, findMaxStaticArraySize("byte [_] a;", null, (name, whole) -> 1000)); + assertEquals(1L, findMaxStaticArraySize("byte [1] a;", null, (name, whole) -> 1000)); + assertEquals(0L, findMaxStaticArraySize("byte a; byte [a] b;", null, (name, whole) -> 1000)); + assertEquals(112L, + findMaxStaticArraySize("byte a; byte [a] b; int [112];", null, (name, whole) -> 1000)); + assertEquals(1120L, + findMaxStaticArraySize("byte a; byte [a] b; some [10] { int [112]; }", null, + (name, whole) -> { + assertNotNull(name); + assertFalse(whole); + return 1000; + })); + assertEquals(112000L, + findMaxStaticArraySize("byte a; byte [a] b; some [_] { int [112]; }", null, + (name, whole) -> { + assertNotNull(name); + assertTrue(whole); + return 1000; + })); + assertEquals(112000L, + findMaxStaticArraySize("byte a; byte [a] b; [_] { int [112]; }", null, (name, whole) -> { + assertNull(name); + assertTrue(whole); + return 1000; + })); + } + + @Test + public void testFindMaxStaticArraySize() { + assertEquals(0L, findMaxStaticArraySize("byte [_] a;", null)); + assertEquals(1L, findMaxStaticArraySize("byte [1] a;", null)); + assertEquals(0L, findMaxStaticArraySize("byte a; byte [a] b;", null)); + assertEquals(112L, findMaxStaticArraySize("byte a; byte [a] b; int [112];", null)); + assertEquals(1120L, + findMaxStaticArraySize("byte a; byte [a] b; some [10] { int [112]; }", null)); + assertEquals(10230L, + findMaxStaticArraySize("byte a; byte [a] b; some [10] { int [112]; byte [1023] d;}", + null)); + assertEquals(10230L, findMaxStaticArraySize( + "byte a; byte [a] b; some [10] { int [112]; j [_] {byte [1023] d;}}", null)); + assertEquals(65535L, findMaxStaticArraySize("a [1]{ b[1]{ c[_]{byte[65535] a;}}}", null)); + assertEquals(65535L, + findMaxStaticArraySize("a [1]{ b[1]{ c[_]{int [128] l; var[65535] a;}}}", null)); + assertEquals(65535L, + findMaxStaticArraySize("a [1]{ b[1]{ c[_]{int [128] l; var[65535] a;}}}", null)); + assertEquals(65535L, + findMaxStaticArraySize("a [1]{ b[1]{ c[_]{int [128] l; stringj[65535] a;}}}", null)); + assertEquals(65535L, + findMaxStaticArraySize("a [1]{ b[1]{ c[_]{int [128] l; floatj[65535] a;}}}", null)); + assertEquals(273948L, + findMaxStaticArraySize( + "a [1]{ b[1]{ c[_]{int [128] l; str [222] { ubyte [1234] p; } doublej[65535] a;}}}", + null)); + assertEquals(273948L, + findMaxStaticArraySize( + "a [1]{ b[1]{ c[_]{int [128] l; str [222] { bit:3 [1234] p; } doublej[65535] a;}}}", + null)); + assertEquals(65535L, + findMaxStaticArraySize( + "a [1]{ b[1]{ c[_]{int [128] l; str [222] { val:3 p; } doublej[65535] a;}}}", null)); + assertEquals(288217182213504000L, + findMaxStaticArraySize( + "a [65535] { b [65535] { c [65535] { byte [1024]d; }}}", null)); + assertEquals(65535, findMaxStaticArraySize( + "a [1]{ b[1]{ lala [65534] { long s; } c[1]{int [128] l; cus[65535] a;}}}", + new JBBPCustomFieldTypeProcessor() { + @Override + public String[] getCustomFieldTypes() { + return new String[] {"cus"}; + } + + @Override + public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName, + int extraData, boolean isArray) { + return "cus".equals(fieldType.getTypeName()); + } + + @Override + public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder, + int parserFlags, + JBBPFieldTypeParameterContainer customTypeFieldInfo, + JBBPNamedFieldInfo fieldName, int extraData, + boolean readWholeStream, int arrayLength, + JBBPArraySizeLimiter arraySizeLimiter) { + throw new UnsupportedOperationException(); + } + })); + assertThrows(ArithmeticException.class, + () -> findMaxStaticArraySize( + "a [_]{ b[65535]{ c[65535]{byte[65535] { byte [10000000] d;}}}}", null)); + } + @Test public void testUtf8EncdeDecode() { - assertEquals("78634двлфодйукйДЛОД wdf", JBBPUtils.utf8ToStr(JBBPUtils.strToUtf8("78634двлфодйукйДЛОД wdf"))); + assertEquals("78634двлфодйукйДЛОД wdf", + JBBPUtils.utf8ToStr(JBBPUtils.strToUtf8("78634двлфодйукйДЛОД wdf"))); } @Test @@ -150,7 +261,8 @@ public void testUnpackInt_NPEForArrayIsNull() { @Test public void testUnpackInt_IAEForWrongPrefix() { - assertThrows(IllegalArgumentException.class, () -> JBBPUtils.unpackInt(new byte[] {(byte) 0xAA, 0, 0, 0, 0, 0}, new JBBPIntCounter())); + assertThrows(IllegalArgumentException.class, + () -> JBBPUtils.unpackInt(new byte[] {(byte) 0xAA, 0, 0, 0, 0, 0}, new JBBPIntCounter())); } @Test @@ -163,7 +275,8 @@ public void testPackUnpackIntFromByteArray() { int counter2 = 0; int counter3 = 0; - final int[] etalons = new int[] {0, -1, -89, 234, 123124, 1223112, 34323, Integer.MIN_VALUE, Integer.MAX_VALUE}; + final int[] etalons = + new int[] {0, -1, -89, 234, 123124, 1223112, 34323, Integer.MIN_VALUE, Integer.MAX_VALUE}; for (final int generated : etalons) { pos.set(0); @@ -195,19 +308,22 @@ public void testPackUnpackIntFromByteArray() { @Test public void testArray2Hex() { assertNull(JBBPUtils.array2hex(null)); - assertEquals("[0x01, 0x02, 0x03, 0xFF]", JBBPUtils.array2hex(new byte[] {1, 2, 3, (byte) 0xFF})); + assertEquals("[0x01, 0x02, 0x03, 0xFF]", + JBBPUtils.array2hex(new byte[] {1, 2, 3, (byte) 0xFF})); } @Test public void testArray2Oct() { assertNull(JBBPUtils.array2hex(null)); - assertEquals("[0o001, 0o002, 0o003, 0o377]", JBBPUtils.array2oct(new byte[] {1, 2, 3, (byte) 0xFF})); + assertEquals("[0o001, 0o002, 0o003, 0o377]", + JBBPUtils.array2oct(new byte[] {1, 2, 3, (byte) 0xFF})); } @Test public void testArray2Bin() { assertNull(JBBPUtils.array2bin(null)); - assertEquals("[0b00000001, 0b00000010, 0b00000011, 0b11111111]", JBBPUtils.array2bin(new byte[] {1, 2, 3, (byte) 0xFF})); + assertEquals("[0b00000001, 0b00000010, 0b00000011, 0b11111111]", + JBBPUtils.array2bin(new byte[] {1, 2, 3, (byte) 0xFF})); } @Test @@ -240,7 +356,8 @@ public void testBin2Str() { assertEquals("01010101 10101010", JBBPUtils.bin2str(new byte[] {0x55, (byte) 0xAA}, true)); assertEquals("0101010110101010", JBBPUtils.bin2str(new byte[] {0x55, (byte) 0xAA}, false)); assertEquals("00001001", JBBPUtils.bin2str(new byte[] {0x9}, false)); - assertEquals("1010101001010101", JBBPUtils.bin2str(new byte[] {0x55, (byte) 0xAA}, JBBPBitOrder.MSB0, false)); + assertEquals("1010101001010101", + JBBPUtils.bin2str(new byte[] {0x55, (byte) 0xAA}, JBBPBitOrder.MSB0, false)); assertEquals("0101010110101010", JBBPUtils.bin2str(new byte[] {0x55, (byte) 0xAA})); } @@ -251,8 +368,10 @@ public void testStr2Bin_Default() { assertArrayEquals(new byte[] {(byte) 0x80}, JBBPUtils.str2bin("10000000")); assertArrayEquals(new byte[] {(byte) 0x01}, JBBPUtils.str2bin("1")); assertArrayEquals(new byte[] {(byte) 0x80, 0x01}, JBBPUtils.str2bin("10000000X00x0Zz1")); - assertArrayEquals(new byte[] {(byte) 0x80, 0x01, 0x07}, JBBPUtils.str2bin("10000000000000010111")); - assertArrayEquals(new byte[] {(byte) 0x80, 0x01, 0x07}, JBBPUtils.str2bin("10000000_00000001_0111")); + assertArrayEquals(new byte[] {(byte) 0x80, 0x01, 0x07}, + JBBPUtils.str2bin("10000000000000010111")); + assertArrayEquals(new byte[] {(byte) 0x80, 0x01, 0x07}, + JBBPUtils.str2bin("10000000_00000001_0111")); try { JBBPUtils.str2bin("10001021"); @@ -269,9 +388,12 @@ public void testStr2Bin_LSB0() { assertArrayEquals(new byte[] {(byte) 0x80}, JBBPUtils.str2bin("10000000", JBBPBitOrder.LSB0)); assertArrayEquals(new byte[] {(byte) 0x01}, JBBPUtils.str2bin("1", JBBPBitOrder.LSB0)); assertArrayEquals(new byte[] {(byte) 0x01}, JBBPUtils.str2bin("00000001", JBBPBitOrder.LSB0)); - assertArrayEquals(new byte[] {(byte) 0x80, (byte) 0x01}, JBBPUtils.str2bin("10000000X00x0Zz1", JBBPBitOrder.LSB0)); - assertArrayEquals(new byte[] {(byte) 0x80, (byte) 0x01, (byte) 0x07}, JBBPUtils.str2bin("10000000000000010111", JBBPBitOrder.LSB0)); - assertArrayEquals(new byte[] {(byte) 0x80, (byte) 0x01, (byte) 0x07}, JBBPUtils.str2bin("10000000_00000001_0111", JBBPBitOrder.LSB0)); + assertArrayEquals(new byte[] {(byte) 0x80, (byte) 0x01}, + JBBPUtils.str2bin("10000000X00x0Zz1", JBBPBitOrder.LSB0)); + assertArrayEquals(new byte[] {(byte) 0x80, (byte) 0x01, (byte) 0x07}, + JBBPUtils.str2bin("10000000000000010111", JBBPBitOrder.LSB0)); + assertArrayEquals(new byte[] {(byte) 0x80, (byte) 0x01, (byte) 0x07}, + JBBPUtils.str2bin("10000000_00000001_0111", JBBPBitOrder.LSB0)); try { JBBPUtils.str2bin("10001021", JBBPBitOrder.MSB0); @@ -283,9 +405,11 @@ public void testStr2Bin_LSB0() { @Test public void testStr2Bin_LSB0_1bitShift() { - final byte[] array = JBBPUtils.str2bin("0 11111111 01010101 00011000 00000001", JBBPBitOrder.LSB0); + final byte[] array = + JBBPUtils.str2bin("0 11111111 01010101 00011000 00000001", JBBPBitOrder.LSB0); - assertArrayEquals(new byte[] {(byte) 0x7F, (byte) 0xAA, (byte) 0x8C, (byte) 0x0, (byte) 0x01}, array); + assertArrayEquals(new byte[] {(byte) 0x7F, (byte) 0xAA, (byte) 0x8C, (byte) 0x0, (byte) 0x01}, + array); } @@ -297,10 +421,14 @@ public void testStr2Bin_MSB() { assertArrayEquals(new byte[] {(byte) 0x80}, JBBPUtils.str2bin("00000001", JBBPBitOrder.MSB0)); assertArrayEquals(new byte[] {(byte) 0x01}, JBBPUtils.str2bin("10000000", JBBPBitOrder.MSB0)); assertArrayEquals(new byte[] {(byte) 0xA9}, JBBPUtils.str2bin("10010101", JBBPBitOrder.MSB0)); - assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0x80}, JBBPUtils.str2bin("10000000X00x0Zz1", JBBPBitOrder.MSB0)); - assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0x80, (byte) 0x0E}, JBBPUtils.str2bin("1000000000000001 0111", JBBPBitOrder.MSB0)); - assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0x80, (byte) 0x0E}, JBBPUtils.str2bin("10000000_00000001_0111", JBBPBitOrder.MSB0)); - assertArrayEquals(new byte[] {(byte) 0x03, (byte) 0x00, (byte) 0x01, (byte) 0x01}, JBBPUtils.str2bin("1_10000000_00000001_00000001", JBBPBitOrder.MSB0)); + assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0x80}, + JBBPUtils.str2bin("10000000X00x0Zz1", JBBPBitOrder.MSB0)); + assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0x80, (byte) 0x0E}, + JBBPUtils.str2bin("1000000000000001 0111", JBBPBitOrder.MSB0)); + assertArrayEquals(new byte[] {(byte) 0x01, (byte) 0x80, (byte) 0x0E}, + JBBPUtils.str2bin("10000000_00000001_0111", JBBPBitOrder.MSB0)); + assertArrayEquals(new byte[] {(byte) 0x03, (byte) 0x00, (byte) 0x01, (byte) 0x01}, + JBBPUtils.str2bin("1_10000000_00000001_00000001", JBBPBitOrder.MSB0)); try { JBBPUtils.str2bin("10001021", JBBPBitOrder.MSB0); @@ -347,8 +475,10 @@ public void testReverseArray() { assertArrayEquals(new byte[] {1}, JBBPUtils.reverseArray(new byte[] {1})); assertArrayEquals(new byte[] {2, 1}, JBBPUtils.reverseArray(new byte[] {1, 2})); - assertArrayEquals(new byte[] {5, 4, 3, 2, 1}, JBBPUtils.reverseArray(new byte[] {1, 2, 3, 4, 5})); - assertArrayEquals(new byte[] {6, 5, 4, 3, 2, 1}, JBBPUtils.reverseArray(new byte[] {1, 2, 3, 4, 5, 6})); + assertArrayEquals(new byte[] {5, 4, 3, 2, 1}, + JBBPUtils.reverseArray(new byte[] {1, 2, 3, 4, 5})); + assertArrayEquals(new byte[] {6, 5, 4, 3, 2, 1}, + JBBPUtils.reverseArray(new byte[] {1, 2, 3, 4, 5, 6})); } @Test @@ -363,7 +493,8 @@ public void testSplitInteger() { assertArrayEquals(new byte[] {1, 2, 3, 4}, JBBPUtils.splitInteger(0x01020304, false, buff)); buff = new byte[8]; - assertArrayEquals(new byte[] {1, 2, 3, 4, 0, 0, 0, 0}, JBBPUtils.splitInteger(0x01020304, false, buff)); + assertArrayEquals(new byte[] {1, 2, 3, 4, 0, 0, 0, 0}, + JBBPUtils.splitInteger(0x01020304, false, buff)); buff = null; assertArrayEquals(new byte[] {4, 3, 2, 1}, JBBPUtils.splitInteger(0x01020304, true, buff)); @@ -375,54 +506,65 @@ public void testSplitInteger() { assertArrayEquals(new byte[] {4, 3, 2, 1}, JBBPUtils.splitInteger(0x01020304, true, buff)); buff = new byte[8]; - assertArrayEquals(new byte[] {4, 3, 2, 1, 0, 0, 0, 0}, JBBPUtils.splitInteger(0x01020304, true, buff)); + assertArrayEquals(new byte[] {4, 3, 2, 1, 0, 0, 0, 0}, + JBBPUtils.splitInteger(0x01020304, true, buff)); } @Test public void testSplitLong() { byte[] buff = null; - assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, JBBPUtils.splitLong(0x0102030405060708L, false, buff)); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, + JBBPUtils.splitLong(0x0102030405060708L, false, buff)); buff = new byte[2]; - assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, JBBPUtils.splitLong(0x0102030405060708L, false, buff)); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, + JBBPUtils.splitLong(0x0102030405060708L, false, buff)); buff = new byte[8]; - assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, JBBPUtils.splitLong(0x0102030405060708L, false, buff)); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}, + JBBPUtils.splitLong(0x0102030405060708L, false, buff)); buff = new byte[10]; - assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 0, 0}, JBBPUtils.splitLong(0x0102030405060708L, false, buff)); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 0, 0}, + JBBPUtils.splitLong(0x0102030405060708L, false, buff)); buff = null; - assertArrayEquals(new byte[] {8, 7, 6, 5, 4, 3, 2, 1}, JBBPUtils.splitLong(0x0102030405060708L, true, buff)); + assertArrayEquals(new byte[] {8, 7, 6, 5, 4, 3, 2, 1}, + JBBPUtils.splitLong(0x0102030405060708L, true, buff)); buff = new byte[2]; - assertArrayEquals(new byte[] {8, 7, 6, 5, 4, 3, 2, 1}, JBBPUtils.splitLong(0x0102030405060708L, true, buff)); + assertArrayEquals(new byte[] {8, 7, 6, 5, 4, 3, 2, 1}, + JBBPUtils.splitLong(0x0102030405060708L, true, buff)); buff = new byte[8]; - assertArrayEquals(new byte[] {8, 7, 6, 5, 4, 3, 2, 1}, JBBPUtils.splitLong(0x0102030405060708L, true, buff)); + assertArrayEquals(new byte[] {8, 7, 6, 5, 4, 3, 2, 1}, + JBBPUtils.splitLong(0x0102030405060708L, true, buff)); buff = new byte[10]; - assertArrayEquals(new byte[] {8, 7, 6, 5, 4, 3, 2, 1, 0, 0}, JBBPUtils.splitLong(0x0102030405060708L, true, buff)); + assertArrayEquals(new byte[] {8, 7, 6, 5, 4, 3, 2, 1, 0, 0}, + JBBPUtils.splitLong(0x0102030405060708L, true, buff)); } @Test public void testConcat() { - assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, JBBPUtils.concat(new byte[] {1, 2, 3, 4}, new byte[] {5}, new byte[] {6, 7, 8, 9}, new byte[0], new byte[] {10})); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, JBBPUtils + .concat(new byte[] {1, 2, 3, 4}, new byte[] {5}, new byte[] {6, 7, 8, 9}, new byte[0], + new byte[] {10})); } @Test - public void testReverdeByteOrder_ErrorForZeroByteNumber() { + public void testReverseByteOrder_ErrorForZeroByteNumber() { assertThrows(IllegalArgumentException.class, () -> JBBPUtils.reverseByteOrder(1234, 0)); } @Test - public void testReverdeByteOrder_ErrorForTooBigByteNumber() { + public void testReverseByteOrder_ErrorForTooBigByteNumber() { assertThrows(IllegalArgumentException.class, () -> JBBPUtils.reverseByteOrder(1234, 9)); } @Test - public void testReverdeByteOrder() { + public void testReverseByteOrder() { assertEquals(0x0000000000000012L, JBBPUtils.reverseByteOrder(0x0000000000000012L, 1)); assertEquals(0x0000000000003412L, JBBPUtils.reverseByteOrder(0x0000000000001234L, 2)); assertEquals(0x0000000000563412L, JBBPUtils.reverseByteOrder(0x0000000000123456L, 3)); @@ -544,4 +686,97 @@ public void testGenerateMask() { assertEquals(0x7F, JBBPUtils.makeMask(100)); assertEquals(0xFFFF, JBBPUtils.makeMask(65535)); } + + @Test + public void testTraceData_Defaults() throws Exception { + final byte[] testData = new byte[211]; + for (int i = 0; i < 111; i++) { + testData[i] = (byte) i; + } + final InputStream stream = new ByteArrayInputStream(testData); + final ByteArrayOutputStream outArray = new ByteArrayOutputStream(); + final PrintStream out = new PrintStream(outArray, true, StandardCharsets.UTF_8); + JBBPUtils.traceData(stream, out); + out.close(); + final String asString = + outArray.toString(StandardCharsets.UTF_8).replace("\r\n", "\n") + .replace("\r", "\n"); + assertEquals( + "00000000 00 01 02 03 | 04 05 06 07 | 08 09 0A 0B | 0C 0D 0E 0F | 10 11 12 13 | 14 15 16 17 | 18 19 1A 1B | 1C 1D 1E 1F ................................\n" + + + "00000020 20 21 22 23 | 24 25 26 27 | 28 29 2A 2B | 2C 2D 2E 2F | 30 31 32 33 | 34 35 36 37 | 38 39 3A 3B | 3C 3D 3E 3F !\"#$%&'()*+,-./0123456789:;<=>?\n" + + + "00000040 40 41 42 43 | 44 45 46 47 | 48 49 4A 4B | 4C 4D 4E 4F | 50 51 52 53 | 54 55 56 57 | 58 59 5A 5B | 5C 5D 5E 5F @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n" + + + "00000060 60 61 62 63 | 64 65 66 67 | 68 69 6A 6B | 6C 6D 6E 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 `abcdefghijklmn.................\n" + + + "00000080 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 ................................\n" + + + "000000A0 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 ................................\n" + + + "000000C0 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 -- | -- -- -- -- | -- -- -- -- | -- -- -- -- ................................\n", + asString); + } + + @Test + public void testTraceData_CustomWithChars() throws Exception { + final byte[] testData = new byte[211]; + for (int i = 0; i < 111; i++) { + testData[i] = (byte) i; + } + final InputStream stream = new ByteArrayInputStream(testData); + final ByteArrayOutputStream outArray = new ByteArrayOutputStream(); + final PrintStream out = new PrintStream(outArray, true, StandardCharsets.UTF_8); + JBBPUtils.traceData(stream, 8, 4, "#", "_", "$", "Z", '&', true, out); + out.close(); + final String asString = + new String(outArray.toByteArray(), StandardCharsets.UTF_8).replace("\r\n", "\n") + .replace("\r", "\n"); + assertEquals( + "00000000#00_01_02_03_04_05_06_07$08_09_0A_0B_0C_0D_0E_0F$10_11_12_13_14_15_16_17$18_19_1A_1B_1C_1D_1E_1FZ&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n" + + + "00000020#20_21_22_23_24_25_26_27$28_29_2A_2B_2C_2D_2E_2F$30_31_32_33_34_35_36_37$38_39_3A_3B_3C_3D_3E_3FZ !\"#$%&'()*+,-./0123456789:;<=>?\n" + + + "00000040#40_41_42_43_44_45_46_47$48_49_4A_4B_4C_4D_4E_4F$50_51_52_53_54_55_56_57$58_59_5A_5B_5C_5D_5E_5FZ@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n" + + + "00000060#60_61_62_63_64_65_66_67$68_69_6A_6B_6C_6D_6E_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00Z`abcdefghijklmn&&&&&&&&&&&&&&&&&\n" + + + "00000080#00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00Z&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n" + + + "000000A0#00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00Z&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n" + + + "000000C0#00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_--_--_--_--_--$--_--_--_--_--_--_--_--Z&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n", + asString); + } + + @Test + public void testTraceData_CustomNoChars() throws Exception { + final byte[] testData = new byte[211]; + for (int i = 0; i < 111; i++) { + testData[i] = (byte) i; + } + final InputStream stream = new ByteArrayInputStream(testData); + final ByteArrayOutputStream outArray = new ByteArrayOutputStream(); + final PrintStream out = new PrintStream(outArray, true, StandardCharsets.UTF_8); + JBBPUtils.traceData(stream, 8, 4, "#", "_", "$", "Z", '&', false, out); + out.close(); + final String asString = + new String(outArray.toByteArray(), StandardCharsets.UTF_8).replace("\r\n", "\n") + .replace("\r", "\n"); + assertEquals( + "00000000#00_01_02_03_04_05_06_07$08_09_0A_0B_0C_0D_0E_0F$10_11_12_13_14_15_16_17$18_19_1A_1B_1C_1D_1E_1F\n" + + + "00000020#20_21_22_23_24_25_26_27$28_29_2A_2B_2C_2D_2E_2F$30_31_32_33_34_35_36_37$38_39_3A_3B_3C_3D_3E_3F\n" + + + "00000040#40_41_42_43_44_45_46_47$48_49_4A_4B_4C_4D_4E_4F$50_51_52_53_54_55_56_57$58_59_5A_5B_5C_5D_5E_5F\n" + + + "00000060#60_61_62_63_64_65_66_67$68_69_6A_6B_6C_6D_6E_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00\n" + + + "00000080#00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00\n" + + + "000000A0#00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00\n" + + + "000000C0#00_00_00_00_00_00_00_00$00_00_00_00_00_00_00_00$00_00_00_--_--_--_--_--$--_--_--_--_--_--_--_--\n", + asString); + } } diff --git a/jbbp/src/test/jmh/com/igormaznitsa/jbbp/benchmarks/JBBP_Benchmark.java b/jbbp/src/test/jmh/com/igormaznitsa/jbbp/benchmarks/JBBP_Benchmark.java index 91908231..82ed5c4b 100644 --- a/jbbp/src/test/jmh/com/igormaznitsa/jbbp/benchmarks/JBBP_Benchmark.java +++ b/jbbp/src/test/jmh/com/igormaznitsa/jbbp/benchmarks/JBBP_Benchmark.java @@ -32,7 +32,8 @@ */ public class JBBP_Benchmark { - private static final JBBPParser parser = JBBPParser.prepare("ubyte value; data [(value>>1)*(value+3)]{ bit:3 a; bit:3 b; bit:2 c; skip:1; }"); + private static final JBBPParser parser = JBBPParser + .prepare("ubyte value; data [(value>>1)*(value+3)]{ bit:3 a; bit:3 b; bit:2 c; skip:1; }"); private static final Random RND = new Random(12345); diff --git a/jbbp/src/test/resources/com/igormaznitsa/jbbp/it/remarkable1.rm b/jbbp/src/test/resources/com/igormaznitsa/jbbp/it/remarkable1.rm new file mode 100644 index 00000000..f00b92b0 Binary files /dev/null and b/jbbp/src/test/resources/com/igormaznitsa/jbbp/it/remarkable1.rm differ diff --git a/logo.svg b/logo.svg index 88966259..6ed51689 100644 --- a/logo.svg +++ b/logo.svg @@ -25,13223 +25,13244 @@ inkscape:export-ydpi="671.93872">image/svg+xml + + + + + + + + + + + + + - + + + + + + + + + + + + + + com.igormaznitsa jbbp-main-pom - 2.0.1 + 3.0.2-SNAPSHOT pom jbbp - jbbp-plugins https://github.com/raydac/java-binary-block-parser + 3.0.2-SNAPSHOT + ${jbbp.version} UTF-8 UTF-8 ${maven.build.timestamp} yyyyMMddHHmm 3.0 - 1.1.2 - 2.0.1 - ${jbbp.version} - 1.8 - 1.8 - 5.5.1 - 1.21 + 1.2.1 + 11 + 11 + 11 + 5.13.3 + 4.13.2 + 2.17.0 + 1.36 @@ -74,6 +76,11 @@ + + org.apache.maven.shared + maven-verifier + 2.0.0-M1 + org.junit.jupiter junit-jupiter-engine @@ -89,10 +96,30 @@ junit-jupiter-params ${junit5.version} + + org.junit.platform + junit-platform-launcher + 1.13.4 + commons-io commons-io - 2.6 + ${commonsio.version} + + + commons-codec + commons-codec + 1.18.0 + + + net.minidev + json-smart + 2.5.2 + + + org.codehaus.mojo + exec-maven-plugin + 3.5.0 @@ -113,9 +140,20 @@ junit-jupiter-params test + + org.junit.platform + junit-platform-launcher + test + + + plugins + + jbbp-plugins + + bundle @@ -154,7 +192,7 @@ org.codehaus.mojo properties-maven-plugin - 1.0.0 + 1.2.1 org.apache.maven @@ -164,27 +202,37 @@ org.codehaus.mojo animal-sniffer-maven-plugin - 1.18 + 1.24 org.apache.maven.plugins maven-assembly-plugin - 3.1.1 + 3.7.1 org.apache.maven.plugins maven-gpg-plugin - 1.6 + 3.2.7 + + + net.nicoulaj.maven.plugins + checksum-maven-plugin + 1.11 org.apache.maven.plugins maven-javadoc-plugin - 3.1.1 + 3.10.1 + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.5.0 org.apache.maven.plugins maven-source-plugin - 3.1.0 + 3.3.1 com.igormaznitsa @@ -194,20 +242,21 @@ org.apache.maven.plugins maven-jar-plugin - 3.1.2 + 3.4.2 org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.14.0 org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M3 + 3.5.3 + org.apache.maven.plugins @@ -219,6 +268,64 @@ true + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforcer-verify + validate + + enforce + + true + + + + true + + + + test + provided + runtime + + + org.codehaus.* + org.apache.maven.* + + + + + com.plexus.* + javax.* + org.codehaus.* + + + test + provided + + true + true + + + + ${maven.compiler.target} + + test + provided + + + + + + + org.codehaus.mojo + extra-enforcer-rules + 1.10.0 + + + org.apache.maven.plugins maven-surefire-plugin