diff --git a/.gitignore b/.gitignore index f5c88ff1..cb2f51b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,30 @@ -/jbbp/target +/**/target/ /target/ /nbproject/ -/.idea/ +/**/.idea/ *.iml /jbbp-plugins/jbbp-gradle/.gradle/ /jbbp-plugins/jbbp-gradle/build/ /jbbp/BenchmarkList /jbbp/CompilerHints -/jbbp/nb-configuration.xml \ No newline at end of file +/jbbp/nb-configuration.xml +/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/ +/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 58740543..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 1\.4\.0 +# 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 6\+ +### Java 11\+ > fillColor=`#3399FF`,textColor=`#FFFFCC` -### Android 2\.0\+ +### Android 12\+ > fillColor=`#3399FF`,textColor=`#FFFFCC` @@ -92,7 +92,7 @@ Mind Map generated by NB MindMap plugin - TOPIC
152926734C4A
-### conversion of script into
Java classes \(1\.6\+\) +### conversion of script into
Java classes > fillColor=`#AAFF82`,topicLinkUID=`15E33F334A5A` - TOPIC @@ -102,11 +102,11 @@ Mind Map generated by NB MindMap plugin > fillColor=`#00FFFF`,leftSide=`true` -### Java 6 source generator +### Java source generator > fillColor=`#D1FF9C`,topicLinkUID=`15E33F384B4A` - FILE -
jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJava6Converter.java
+
jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverter.java
#### Maven plugin > fillColor=`#D1FF9C` diff --git a/.projectKnowledge/JBBP_Types.mmd b/.projectKnowledge/JBBP_Types.mmd index 834a3ae5..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` @@ -90,11 +106,35 @@ Mind Map generated by NB MindMap plugin > fillColor=`#99FFFF` +#### floatj +> fillColor=`#FFFE9F` + + +##### 32 bit signed field
\(Java float format\) +> fillColor=`#99FFFF` + + +#### doublej +> fillColor=`#FFFE9F` + + +##### 64 bit signed field
\(Java double format\) +> fillColor=`#99FFFF` + + +#### stringj +> fillColor=`#FFFE9F` + + +##### UTF\-8 string with length info, NULL value is allowed +> fillColor=`#99FFFF` + + #### var > fillColor=`#00FAFF` -##### such field must be processed by
special external var field processor +##### custom field to be processed by specific code > fillColor=`#00FAFF` @@ -132,6 +172,14 @@ Mind Map generated by NB MindMap plugin > fillColor=`#99FF99` +##### bit:3 bits; +> fillColor=`#99FF99` + + +##### bit:\(a\+1\) b; +> fillColor=`#99FF99` + + ## Complex types ### Arrays @@ -162,7 +210,7 @@ Mind Map generated by NB MindMap plugin > fillColor=`#6666FF`,textColor=`#CCFFCC` -###### It can be placed only
for the end item in script +###### it is impossible to have fields after > fillColor=`#FF3300`,textColor=`#FFFFFF` @@ -196,7 +244,7 @@ Mind Map generated by NB MindMap plugin > fillColor=`#9999FF` -#### align\[:number\_of\_bytes|\(expression\_in\_parentheses\)\] +#### align\[:number\_of\_bytes|:\(expression\_in\_parentheses\)\] > fillColor=`#FFCC00` diff --git a/README.md b/README.md index 10ba7c8c..8523e1c2 100644 --- a/README.md +++ b/README.md @@ -1,136 +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|1.4.0|jar) -[![Codacy Badge](https://api.codacy.com/project/badge/grade/50b0281430a94eb6abe417409f99ed58)](https://www.codacy.com/app/rrg4400/java-binary-block-parser) -[![Java 6.0+](https://img.shields.io/badge/java-6.0%2b-green.svg)](http://www.oracle.com/technetwork/java/javase/downloads/index.html) -[![Android 2.0+](https://img.shields.io/badge/android-2.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 I wanted to work with separated bits and describe binary structure in some strong DSL(domain specific language). I was very impressed by the [the Python Struct package](https://docs.python.org/2/library/struct.html) package so that I decided to make something like that. So JBBP was born.
-p.s.
-For instance I have been very actively using the framework in [the ZX-Poly emulator](https://github.com/raydac/zxpoly) to parse snapshot files and save results. + +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 -- **1.4.0 (29-jul-2018)** - - added type `val` which allows to create virtual field with calculated value, can play role of variable in scripts - - `val` and `var` have been added into reserved words and can't be used as field names - - added field `outByteOrder` attribute to `Bin` annotation, it affects logic of `JBBPOut#Bin` for output of annotated objects which fields should be saved with different byte order - - removed deprecated method `JBBPFinderException#getNameOrPath` - - added [auxiliary class to build JBBP script](https://github.com/raydac/java-binary-block-parser/blob/master/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilder.java) - - added flag `JBBPParser#FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO` to recognize negative expression result as zero - - improved Java 6 class source generator to process FLAG_SKIP_REMAINING_FIELDS_IF_EOF for structure fields - - added stable automatic module name `igormaznitsa.jbbp` into manifest file - - added support of float, double and string java types, as `floatj`,`doublej` and `stringj` - -- **1.3.0 (02-sep-2017)** - - __Fixed issue [#16 NullPointerException when referencing a JBBPCustomFieldTypeProcessor parsed field"](https://github.com/raydac/java-binary-block-parser/issues/16), many thanks to @use-sparingly for the bug report__ - - [added Maven plugin to generate sources from JBBP scripts](https://search.maven.org/#artifactdetails%7Ccom.igormaznitsa%7Cjbbp-maven-plugin%7C1.3.0%7Cmaven-plugin) - - [added Gradle plugin to generate sources from JBBP scripts](https://plugins.gradle.org/plugin/com.igormaznitsa.gradle.jbbp) - - added extra byte array reading writing methods with byte order support into JBBPBitInputStream and JBBPBitOutputStream - - 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 - - Minor refactoring - -- **1.2.1 (28-JUL-2016)** - - __Fixed issue [#10 "assertArrayLength throws exception in multi-thread"](https://github.com/raydac/java-binary-block-parser/issues/10), many thanks to @sky4star for the bug report.__ - - minor refactoring - -[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 - 1.4.0 + 3.0.1 ``` -the precompiled library jar, javadoc and sources also can be downloaded directly from [the Maven central.](http://search.maven.org/#browse|808871750) + +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 Framework is very easy in use because it has only two main classes for its functionality com.igormaznitsa.jbbp.JBBPParser (for data parsing) and com.igormaznitsa.jbbp.io.JBBPOut (for binary block writing), both of them work over low-level IO classes com.igormaznitsa.jbbp.io.JBBPBitInputStream and com.igormaznitsa.jbbp.io.JBBPBitOutputStream which are the core for the framework. -The Easiest case below shows how to parse 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(); ``` -Of course sometime it is not a comfortable way to look for parsed fields in the result, so you can use mapping of parsed data to class fields. + +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(Parsed.class); +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 -On the start the framework was created to provide comfortable way to parse data, it was not developed for hight speed. But since 1.3.0 version there has been added way to generate Java class sources from JBBP parsers and it allows to increase parsing speed dramatically (keep in mind that JBBP generates Java class sources but not compile it automaticaly). I have made some microbenchmark testing of all parsing approaches to show relative productivity of each one -![JMH results](https://github.com/raydac/java-binary-block-parser/blob/master/docs/jmh_results.png) -The Chart shows three standard ways to parse data with JBBP -* __Dynamic__ - parsing into inside structures through interpretation of script written in DSL. It is not very fast way but you can generate parsers on fly even from dynamically formed strings. -* __Dynamic + map to class__ - Parsing into inside structures through interpretation of script and mapping parsed data into class instance fields. the way is very slow (because it uses reflections to fill fields) and recommended only if comfortable parsing is much more preffered than speed. -* __Static class__ - parsing with Java sources generated from a JBBP parser. It is the fastest way because Java compiler and JIT can make optimizations. The Approach can be used in High-Load systems. It is possible to compile generated Java sources on fly, [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/AbstractJBBPToJava6ConverterTest.java). +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) + . # Generate sources from JBBP scripts -Since 1.3.0 version, the framework can convert JBBP scripts into sources __(the sources anyway need JBBP framework for work)__. -For instance you can use such simple snippet to generate Java classes from JBBP script, potentially it can generate many classes but usually only one class + +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_1_6,"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 special plugins for Maven and Gradle to generate sources from JBBP scripts during source generate phase -in Maven you should just add such plugin execution + +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 - 1.4.0 - - - gen-jbbp-src - - generate - - - + + + com.igormaznitsa + jbbp-maven-plugin + 3.0.1 + + + gen-jbbp-src + + generate + + + ``` -By default the maven plugin looks for files with `jbbp` extension in `src/jbbp` folder of project (it can be changed in options) and produces result java classes in `target/generated-sources/jbbp` folder. [I use such approach in 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 -The Example shows how to parse a byte written in non-standard MSB0 order (Java has LSB0 bit order) to bit fields, 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(outOrder = 1, name = "f1", type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_1, comment = "It's flag one") byte flag1; - @Bin(outOrder = 2, name = "f2", type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_2, comment = "It's second flag") byte flag2; - @Bin(outOrder = 3, name = "f3", type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_1, comment = "It's 3th flag") byte flag3; - @Bin(outOrder = 4, name = "f4", type = BinType.BIT, outBitNumber = 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(Flags.class); - assertEquals(1,parsed.flag1); - assertEquals(2,parsed.flag2); - assertEquals(0,parsed.flag3); - assertEquals(5,parsed.flag4); + @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); 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 @@ -143,65 +190,96 @@ The Example will print in console the text below ; END : Flags ;-------------------------------------------------------------------------------- ``` + # Fields -Every field can have case insensitive name which should not contain '.' (because it is reserved for links to structure field values) and '#'(because it is also reserved for inside usage). -Field name must not be started by a number or chars '$' and '_'. *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 -The Framework supports full set of Java numeric primitives with extra types like ubyte and bit. + +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 -The Framework provides support for arrays and structures. Just keep in mind that in expressions you can make links to field values only defined before expression. + +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 own 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/src/test/java/com/igormaznitsa/jbbp/it/CustomThreeByteIntegerTypeTest.java). -### Float and Double types -The Parser does not support Java float and double types out of the box. But it can be implemented through custom type processor. [there is written example and test and the code can be copy pasted](https://github.com/raydac/java-binary-block-parser/blob/master/src/test/java/com/igormaznitsa/jbbp/it/FloatAndDoubleTypesTest.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`. ## Variable fields -If you have some data which structure is variable then you can use the `var` type for defined field and process reading of the data manually with custom [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(); final JBBPFieldStruct struct = parser.parse(new byte[]{9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - 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(JBBPBitInputStream inStream, int arraySize, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { fail("Must not be called"); return null; } - public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final JBBPNamedFieldInfo fieldName, final int extraValue, final JBBPByteOrder byteOrder, final JBBPNamedNumericFieldMap numericFieldMap) throws IOException { + public JBBPAbstractField readVarField(JBBPBitInputStream inStream, JBBPNamedFieldInfo fieldName, int extraValue, JBBPByteOrder byteOrder, JBBPNamedNumericFieldMap numericFieldMap) throws IOException { final int value = inStream.readByte(); return new JBBPFieldByte(fieldName, (byte) value); } }, null); ``` -*NB! Some programmers trying to use only parser for complex data, it is 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 -Every multi-byte type can be read with different 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 { @@ -211,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 @@ -219,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 -The Example below shows how to parse a PNG file with the JBBP parser (the example taken from tests) + +Example below shows how to parse a PNG file through JBBP parser: + ```Java final InputStream pngStream = getResourceAsInputStream("picture.png"); try { @@ -241,15 +332,14 @@ final InputStream pngStream = getResourceAsInputStream("picture.png"); + "}" ); - final JBBPFieldStruct result = pngParser.parse(pngStream); + JBBPFieldStruct result = pngParser.parse(pngStream); assertEquals(0x89504E470D0A1A0AL,result.findFieldForNameAndType("header",JBBPFieldLong.class).getAsLong()); - final JBBPFieldArrayStruct chunks = result.findFieldForNameAndType("chunk", JBBPFieldArrayStruct.class); + JBBPFieldArrayStruct chunks = result.findFieldForNameAndType("chunk", JBBPFieldArrayStruct.class); - - 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}; + String [] chunkNames = new String[]{"IHDR","gAMA","bKGD","pHYs","tIME","tEXt","IDAT","IEND"}; + int [] chunkSizes = new int[]{0x0D, 0x04, 0x06, 0x09, 0x07, 0x19, 0x0E5F, 0x00}; assertEquals(chunkNames.length,chunks.size()); @@ -261,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;" @@ -284,11 +376,17 @@ final JBBPParser pngParser = JBBPParser.prepare( class Png { long header; Chunk [] chunk; + + public Object newInstance(Class klazz){ + return klazz == Chunk.class ? new Chunk() : null; + } } - final Png png = pngParser.parse(pngStream).mapTo(Png.class); + final Png png = pngParser.parse(pngStream).mapTo(new Png()); ``` -The Example from tests shows how to parse a tcp frame wrapped in a network frame + +Example shows how to parse TCP frame: + ```Java final JBBPParser tcpParser = JBBPParser.prepare( "skip:34; // skip bytes till the frame\n" @@ -319,15 +417,32 @@ final JBBPParser tcpParser = JBBPParser.prepare( final JBBPFieldStruct result = pngParser.parse(tcpFrameStream); ``` + # F.A.Q. + ## Is it possible to use `@Bin` annotations for parsing and not only mapping? -No, `@Bin` annotations in classes are used only for mapping and data writing, but there is [the code snippet](https://gist.github.com/raydac/28d770307bd33683aa17ea3c39d5e2c4) allows to generate JBBP DSL based on detected @Bin annotations in class. + +`@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! The Parser works over [com.igormaznitsa.jbbp.io.JBBPBitInputStream](https://github.com/raydac/java-binary-block-parser/blob/master/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 from a stream (for output 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 bin block instead of parsing! -The Framework contains a special helper as the class com.igormaznitsa.jbbp.io.JBBPOut which allows to build bin blocks with some kind of DSL +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 + ```Java import static com.igormaznitsa.jbbp.io.JBBPOut.*; ... diff --git a/changelog.txt b/changelog.txt index cbd94dce..143fa08b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,63 @@ -Change log --------------------------- +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 + +2.0.0 + - __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 + - 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) + 1.4.0 - added type `val` which allows to create virtual field with calculated value, can play role of variable in scripts - `val` and `var` have been added into reserved words and can't be used as field names @@ -19,7 +77,7 @@ Change log - 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_complex_types.png b/docs/jbbp_complex_types.png index 7e06d271..155d5f70 100644 Binary files a/docs/jbbp_complex_types.png and b/docs/jbbp_complex_types.png differ diff --git a/docs/jbbp_fields.png b/docs/jbbp_fields.png index d8894995..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 7977f40f..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 5ee09acc..32bf5efe 100644 Binary files a/docs/jbbp_primitives.png and b/docs/jbbp_primitives.png differ diff --git a/docs/jbbp_special_fields.png b/docs/jbbp_special_fields.png index 7c8ac349..d87e07aa 100644 Binary files a/docs/jbbp_special_fields.png and b/docs/jbbp_special_fields.png differ diff --git a/docs/jmh_results.ods b/docs/jmh_results.ods index a981a9fd..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 6efb18f9..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-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/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 similarity index 100% rename from jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp rename to jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.WholeStreamByteArray.jbbp b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.WholeStreamByteArray.jbbp new file mode 100644 index 00000000..32cfce5b --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/jbbp/com.igormaznitsa.mvn.test.jbbp.WholeStreamByteArray.jbbp @@ -0,0 +1,2 @@ +// some easy JBBP script to test +byte [_] array; \ No newline at end of file diff --git a/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java new file mode 100644 index 00000000..3d1b935d --- /dev/null +++ b/jbbp-plugins/jbbp-gradle-tests/jbbp-gradle5-plugin-test/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java @@ -0,0 +1,93 @@ +package com.igormaznitsa.mvn.tst; + +import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; +import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; +import com.igormaznitsa.jbbp.io.JBBPBitInputStream; +import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; +import com.igormaznitsa.jbbp.io.JBBPByteOrder; +import com.igormaznitsa.jbbp.model.JBBPAbstractArrayField; +import com.igormaznitsa.jbbp.model.JBBPAbstractField; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayLong; +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())); + } + + @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()); + } + + @Override + 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 { + 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 6758bad5..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', '1.4.1-SNAPSHOT') -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.6 -targetCompatibility = 1.6 +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 2bfeee9e..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 - 1.4.1-SNAPSHOT + 3.0.2-SNAPSHOT jbbp-gradle-plugin @@ -22,12 +22,13 @@ - install + gradle8 + publishToMavenLocal - publishGradle + publish-gradle publishPlugins @@ -38,7 +39,6 @@ maven-clean-plugin - 3.0.0 @@ -71,7 +71,6 @@ org.codehaus.mojo properties-maven-plugin - 1.0.0 @@ -81,7 +80,7 @@ gradle.prop.jbbp_plugin_version - ${project.version} + ${jbbp.plugin.version} gradle.prop.meta_lib_version @@ -93,29 +92,29 @@ - org.fortasoft - gradle-maven-plugin - 1.0.8 - - - org.gradle - gradle-tooling-api - 4.2.1 - - - - - 4.2.1 - - 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/JBBPExtension.java b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPExtension.java index fdd4aefa..ff2a6832 100644 --- a/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPExtension.java +++ b/jbbp-plugins/jbbp-gradle/src/main/java/com/igormaznitsa/jbbp/plugin/gradle/JBBPExtension.java @@ -2,15 +2,14 @@ import com.igormaznitsa.jbbp.plugin.common.converters.ParserFlags; import com.igormaznitsa.jbbp.plugin.common.converters.Target; -import org.gradle.api.Project; -import org.gradle.api.file.ConfigurableFileTree; - -import javax.annotation.Nonnull; import java.io.File; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.annotation.Nonnull; +import org.gradle.api.Project; +import org.gradle.api.file.ConfigurableFileTree; /** * JBBP extension settings. @@ -27,7 +26,7 @@ public class JBBPExtension { /** * Target of translation. */ - public Target target = Target.JAVA_1_6; + public Target target = Target.JAVA; /** * Flag to generate getters and setters in result class, all fields will be @@ -134,6 +133,16 @@ public class JBBPExtension { */ public ConfigurableFileTree source; + /** + * Generate methods newInstance in generated classes. + */ + public boolean addNewInstanceMethods; + + /** + * Generate Bin annotations for fields + */ + public boolean addBinAnnotations; + public JBBPExtension(@Nonnull final Project project) { this.source = project.fileTree("src/jbbp"); } 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 e9b5fc31..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 @@ -1,8 +1,11 @@ package com.igormaznitsa.jbbp.plugin.gradle; +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; @@ -13,20 +16,18 @@ import com.igormaznitsa.meta.annotation.MustNotContainNull; import com.igormaznitsa.meta.common.utils.Assertions; import com.igormaznitsa.meta.common.utils.GetUtils; -import org.gradle.api.GradleException; -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; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.util.HashSet; import java.util.Locale; import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.gradle.api.GradleException; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.SourceSet; /** * Task to translate found JBBP scripts in source files. @@ -39,12 +40,15 @@ 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_1_6); + final Target target = GetUtils.ensureNonNull(ext.target, Target.JAVA); final Set normalizedCustomTypeNames = new HashSet(); if (ext.customTypes != null) { @@ -52,13 +56,14 @@ 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); } getLogger().debug("Defined normalized custom types : " + normalizedCustomTypeNames); } - final String[] customTypesArray = normalizedCustomTypeNames.toArray(new String[normalizedCustomTypeNames.size()]); + final String[] customTypesArray = normalizedCustomTypeNames.toArray(ARRAY_STRING_EMPTY); final JBBPCustomFieldTypeProcessor customFieldProcessor = new JBBPCustomFieldTypeProcessor() { @Override @@ -69,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()); @@ -79,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"); } }; @@ -97,6 +113,8 @@ public JBBPAbstractField readCustomFieldType(@Nonnull final JBBPBitInputStream i .setEncodingOut(CommonUtils.ensureEncodingName(ext.outEncoding)) .setCustomFieldTypeProcessor(customFieldProcessor) .setSuperClass(ext.superClass) + .setAddNewInstanceMethods(ext.addNewInstanceMethods) + .setAddBinAnnotations(ext.addBinAnnotations) .setClassImplements(ext.interfaces) .setSubClassInterfaces(ext.mapSubClassInterfaces) .setSubClassSuperclasses(ext.mapSubClassSuperclasses) @@ -113,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-getterssetters/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java deleted file mode 100644 index 312bda2f..00000000 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/src/main/java/com/igormaznitsa/mvn/tst/VarCustomImpl.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.mvn.tst; - -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer; -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; -import com.igormaznitsa.jbbp.io.JBBPByteOrder; -import com.igormaznitsa.jbbp.model.JBBPAbstractArrayField; -import com.igormaznitsa.jbbp.model.JBBPAbstractField; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayLong; -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())); - } - - @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()); - } - - @Override - 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 { - 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-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/pom.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/pom.xml index 2630d1f7..e138b327 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/pom.xml +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-customvars/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-maven-plugin-tests - 1.4.1-SNAPSHOT + 0.0.0-SNAPSHOT jbbp-mvn-test-customvars @@ -16,7 +16,7 @@ ${project.groupId} jbbp-maven-plugin - ${project.version} + ${jbbp.plugin.version} 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/pom.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/pom.xml new file mode 100644 index 00000000..99d152bb --- /dev/null +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + com.igormaznitsa + jbbp-maven-plugin-tests + 0.0.0-SNAPSHOT + + + jbbp-mvn-test-genannotations-nonstatic + jar + + + + + ${project.groupId} + jbbp-maven-plugin + ${jbbp.plugin.version} + + + + generate + + + + + Generated with annotations + true + true + true + true + + + + + \ No newline at end of file diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/src/jbbp/com.igormaznitsa.mvn.test.jbbp.GenAnnotationsNonStatic.jbbp new file mode 100644 index 00000000..58f5edc9 --- /dev/null +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/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-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 new file mode 100644 index 00000000..ed031763 --- /dev/null +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations-nonstatic/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsNonStaticTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2019 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.mvn.test.jbbp; + +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 java.io.ByteArrayInputStream; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class GenAnnotationsNonStaticTest { + + @Test + 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))); + 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()); + } +} diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/pom.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/pom.xml new file mode 100644 index 00000000..aec17ea0 --- /dev/null +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + com.igormaznitsa + jbbp-maven-plugin-tests + 0.0.0-SNAPSHOT + + + jbbp-mvn-test-genannotations + jar + + + + + ${project.groupId} + jbbp-maven-plugin + ${jbbp.plugin.version} + + + + generate + + + + + Generated with annotations + true + true + true + + + + + \ No newline at end of file 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 new file mode 100644 index 00000000..b1f6c18f --- /dev/null +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/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-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 new file mode 100644 index 00000000..f137c3a1 --- /dev/null +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-genannotations/src/test/java/com/igormaznitsa/mvn/test/jbbp/GenAnnotationsTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2019 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.mvn.test.jbbp; + +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 java.io.ByteArrayInputStream; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class GenAnnotationsTest { + + @Test + void testReadWrite() 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()); + } +} diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/pom.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/pom.xml similarity index 93% rename from jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/pom.xml rename to jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/pom.xml index 53b361a2..b79d321b 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/pom.xml +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-maven-plugin-tests - 1.4.1-SNAPSHOT + 0.0.0-SNAPSHOT jbbp-mvn-test-getterssetters @@ -16,7 +16,7 @@ ${project.groupId} jbbp-maven-plugin - ${project.version} + ${jbbp.plugin.version} diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/src/jbbp/com.igormaznitsa.mvn.test.jbbp.VarCustom.jbbp new file mode 100644 index 00000000..39d99c87 --- /dev/null +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/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-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java similarity index 100% rename from jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java rename to jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java index a5059ae1..0eccb1b7 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-getterssetters/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-getterssetters/src/test/java/com/igormaznitsa/mvn/test/jbbp/VarCustomTest.java @@ -16,17 +16,17 @@ package com.igormaznitsa.mvn.test.jbbp; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + + 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 static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class VarCustomTest { diff --git a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-primitives/pom.xml b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-primitives/pom.xml index bfbffd35..530f888e 100644 --- a/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-primitives/pom.xml +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin-tests/jbbp-mvn-test-primitives/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-maven-plugin-tests - 1.4.1-SNAPSHOT + 0.0.0-SNAPSHOT jbbp-mvn-test-primitives @@ -16,7 +16,7 @@ ${project.groupId} jbbp-maven-plugin - ${project.version} + ${jbbp.plugin.version} 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 2c538dd6..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,18 +5,21 @@ com.igormaznitsa jbbp-maven-plugin-pom - 1.4.1-SNAPSHOT + 3.0.2-SNAPSHOT jbbp-maven-plugin-tests pom + 0.0.0-SNAPSHOT Integration tests for JBBP Maven plugin jbbp-mvn-test-primitives jbbp-mvn-test-customvars - jbbp-mvn-getterssetters + jbbp-mvn-test-getterssetters + jbbp-mvn-test-genannotations + jbbp-mvn-test-genannotations-nonstatic @@ -28,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 a96a7f1f..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 - 1.4.1-SNAPSHOT + 3.0.2-SNAPSHOT jbbp-maven-plugin @@ -22,7 +22,6 @@ com.igormaznitsa uber-pom - 1.0.1
parent
@@ -42,7 +41,6 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 generate-sources @@ -56,7 +54,6 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0 generate-javadoc @@ -64,13 +61,15 @@ jar + + 1.8 + org.apache.maven.plugins maven-gpg-plugin - 1.6 sign-artifacts @@ -81,6 +80,33 @@ + + net.nicoulaj.maven.plugins + checksum-maven-plugin + + + verify + + files + + + + + ${project.build.directory} + + *.jar + *.pom + + + + + SHA-1 + MD5 + + + + +
@@ -164,7 +190,7 @@ com.igormaznitsa uber-pom - 1.0.1 + 1.0.3
parent
@@ -181,31 +207,10 @@
- - org.codehaus.mojo - animal-sniffer-maven-plugin - 1.16 - - - 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 64cd1226..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 @@ -60,7 +59,7 @@ public abstract class AbstractJBBPMojo extends AbstractMojo { * * @see Target */ - @Parameter(alias = "target", defaultValue = "JAVA_1_6") + @Parameter(alias = "target", defaultValue = "JAVA") protected String target; /** * Flag to skip processing of the plug-in. @@ -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 1df44d58..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 @@ -16,25 +16,21 @@ package com.igormaznitsa.jbbp.plugin.mvn; +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; import com.igormaznitsa.jbbp.model.JBBPAbstractField; import com.igormaznitsa.jbbp.plugin.common.converters.JBBPScriptTranslator; import com.igormaznitsa.jbbp.plugin.common.converters.ParserFlags; import com.igormaznitsa.jbbp.plugin.common.converters.Target; import com.igormaznitsa.meta.annotation.MustNotContainNull; -import org.apache.commons.io.FileUtils; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.util.HashMap; @@ -42,8 +38,14 @@ import java.util.Locale; import java.util.Map; import java.util.Set; - -import static com.igormaznitsa.jbbp.plugin.common.utils.CommonUtils.ensureEncodingName; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.apache.commons.io.FileUtils; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; /** * The Mojo looks for all JBBP scripts in source and generate sources. @@ -162,6 +164,23 @@ public class JBBPGenerateMojo extends AbstractJBBPMojo { @Parameter(alias = "addToTestSourceFolders") private boolean addToTestSourceFolders; + /** + * Turn on generate of newInstance methods inside generated classes. + * + * @since 2.0.0 + */ + @Parameter(alias = "addNewInstanceMethods", defaultValue = "false") + private boolean addNewInstanceMethods; + + /** + * Add Bin annotations + * + * @see Bin + * @since 2.0.0 + */ + @Parameter(alias = "addBinAnnotations", defaultValue = "false") + private boolean addBinAnnotations; + public boolean isAddToSourceFolders() { return this.addToSourceFolders; } @@ -183,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; @@ -261,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; @@ -324,13 +343,14 @@ 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); } getLog().debug("Defined normalized custom types : " + normalizedCustomTypeNames); - final String[] customTypesArray = normalizedCustomTypeNames.toArray(new String[normalizedCustomTypeNames.size()]); + final String[] customTypesArray = normalizedCustomTypeNames.toArray(ARRAY_STRING_EMPTY); final JBBPCustomFieldTypeProcessor customFieldProcessor = new JBBPCustomFieldTypeProcessor() { @Override @@ -341,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()); @@ -351,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"); } }; @@ -377,7 +409,9 @@ public JBBPAbstractField readCustomFieldType(@Nonnull final JBBPBitInputStream i .setSubClassSuperclasses(this.getMapStructToSuperclasses()) .setAddGettersSetters(this.getAddGettersSetters()) .setDoAbstract(this.isDoAbstract()) - .setDisableGenerateFields(this.isDisableGenerateFields()); + .setDisableGenerateFields(this.isDisableGenerateFields()) + .setAddBinAnnotations(this.isAddBinAnnotations()) + .setAddNewInstanceMethods(this.isAddNewInstanceMethods()); for (final File aScript : foundJBBPScripts) { parameters.setScriptFile(aScript).assertAllOk(); @@ -386,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()); } } @@ -407,4 +445,19 @@ public JBBPAbstractField readCustomFieldType(@Nonnull final JBBPBitInputStream i registerSourceRoot(this.output); } + public boolean isAddNewInstanceMethods() { + return this.addNewInstanceMethods; + } + + public void setAddNewInstanceMethods(final boolean addNewInstanceMethods) { + this.addNewInstanceMethods = addNewInstanceMethods; + } + + public boolean isAddBinAnnotations() { + return addBinAnnotations; + } + + public void setAddBinAnnotations(boolean addBinAnnotations) { + this.addBinAnnotations = addBinAnnotations; + } } 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 new file mode 100644 index 00000000..430d4962 --- /dev/null +++ b/jbbp-plugins/jbbp-maven/jbbp-maven-plugin/src/test/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverterTest.java @@ -0,0 +1,50 @@ +package com.igormaznitsa.jbbp.plugin.common.converters; + +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 java.io.File; +import org.junit.jupiter.api.Test; + +class JavaConverterTest { + + @Test + void testTranslateParameters() { + final JBBPScriptTranslator.Parameters parameters = new JBBPScriptTranslator.Parameters(); + + assertTrue(parameters.setAddNewInstanceMethods(true).isAddNewInstanceMethods()); + assertFalse(parameters.setAddNewInstanceMethods(false).isAddNewInstanceMethods()); + + assertTrue(parameters.setAddBinAnnotations(true).isAddBinAnnotations()); + assertFalse(parameters.setAddBinAnnotations(false).isAddBinAnnotations()); + + assertTrue(parameters.setAddGettersSetters(true).isAddGettersSetters()); + assertFalse(parameters.setAddGettersSetters(false).isAddGettersSetters()); + + assertTrue(parameters.setDisableGenerateFields(true).isDisableGenerateFields()); + assertFalse(parameters.setDisableGenerateFields(false).isDisableGenerateFields()); + + assertTrue(parameters.setDoAbstract(true).isDoAbstract()); + assertFalse(parameters.setDoAbstract(false).isDoAbstract()); + + 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("bit a;", parameters.setScriptText("bit a;").getScriptText()); + assertEquals("SomeSuperClass", parameters.setSuperClass("SomeSuperClass").getSuperClass()); + assertEquals(1234, parameters.setParserFlags(1234).getParserFlags()); + assertEquals("UTF-8", parameters.setEncodingIn("UTF-8").getEncodingIn()); + assertEquals("UTF-8", parameters.setEncodingOut("UTF-8").getEncodingOut()); + + parameters.setScriptFile(null); + } + +} \ No newline at end of file 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 7df92da4..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 @@ -16,6 +16,13 @@ package com.igormaznitsa.jbbp.plugin.mvn; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + + +import java.io.File; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; import org.apache.maven.execution.DefaultMavenExecutionRequest; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.plugin.testing.AbstractMojoTestCase; @@ -26,13 +33,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.File; -import java.util.Arrays; -import java.util.Map; -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; - public class JBBPGenerateMojoTest extends AbstractMojoTestCase { private JBBPGenerateMojo findMojo(final String pomName, final String goal) throws Exception { @@ -62,6 +62,17 @@ private String[] set2array(final Set set) { return arr; } + private void assertPath(final String expected, final String check) { + final String normalized = expected.replace('/', File.separatorChar); + if (check.endsWith(normalized)) { + final String start = check.substring(0, check.length() - expected.length()); + if (start.length() == 0 || start.endsWith(":")) { + return; + } + } + fail(String.format("Expected %s but detected %s", expected, check)); + } + @Test public void testConfig() throws Exception { final JBBPGenerateMojo mojo = findMojo("mojoConfig.xml", "generate"); @@ -70,13 +81,13 @@ public void testConfig() throws Exception { assertTrue(mojo.getGenerateTestSources()); assertTrue(mojo.getSkip()); assertTrue(mojo.getVerbose()); - assertEquals("/some/custom/file", mojo.getCustomTextFile().getPath()); + assertPath("/some/custom/file", mojo.getCustomTextFile().getPath()); assertEquals("public void test(){}", mojo.getCustomText()); assertEquals("uber.package", mojo.getPackageName()); - assertEquals("/some/cap/file", mojo.getHeadCommentFile().getPath()); + assertPath("/some/cap/file", mojo.getHeadCommentFile().getPath()); assertEquals("some cap text", mojo.getHeadComment()); - assertEquals("/some/source", mojo.getSource().getPath()); - assertEquals("/some/output", mojo.getOutput().getPath()); + assertPath("/some/source", mojo.getSource().getPath()); + assertPath("/some/output", mojo.getOutput().getPath()); assertEquals("IN-8", mojo.getInputEncoding()); assertEquals("OUT-8", mojo.getOutputEncoding()); assertEquals("com.igormaznitsa.Super", mojo.getSuperClass()); @@ -87,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 7980b5b8..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 - 1.4.1-SNAPSHOT + 2.0.4-SNAPSHOT generate diff --git a/jbbp-plugins/jbbp-maven/pom.xml b/jbbp-plugins/jbbp-maven/pom.xml index a2acf2db..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 - 1.4.1-SNAPSHOT + 3.0.2-SNAPSHOT jbbp-maven-plugin-pom @@ -23,22 +23,12 @@ org.apache.maven.plugins maven-jar-plugin - 3.0.2 **/.netbeans_automatic_build - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.1 - - 1.6 - 1.6 - - diff --git a/jbbp-plugins/jbbp-plugin-common/pom.xml b/jbbp-plugins/jbbp-plugin-common/pom.xml index 87d54352..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 - 1.4.1-SNAPSHOT + 3.0.2-SNAPSHOT jbbp-plugin-common @@ -18,7 +18,7 @@ ${project.groupId} jbbp - ${project.version} + ${jbbp.version} 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 a5a8767d..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 @@ -2,9 +2,6 @@ import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.meta.common.utils.Assertions; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.util.Collections; @@ -12,6 +9,8 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; /** * Interface for auxiliary class to process found JBBP script and translate them into set of files. @@ -35,7 +34,7 @@ public interface JBBPScriptTranslator { * * @since 1.3.0 */ - final class Parameters { + public final class Parameters { /** * Map of interface names to be implemented by subclasses. */ @@ -48,28 +47,34 @@ 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 - protected String superClass = null; + private String superClass = null; /** - * Processor for custom types. + * Destination file name. + * + * @since 2.0.0 */ @Nullable - JBBPCustomFieldTypeProcessor customFieldTypeProcessor = null; + private String destFileName = null; /** * Disable generate class fields. * @@ -89,6 +94,12 @@ final class Parameters { */ @Nullable private File scriptFile = null; + /** + * Script text, it will be used only if {@link #scriptFile} is null + * + * @since 2.0.0 + */ + private String scriptText = null; /** * Package name for main class. */ @@ -123,6 +134,18 @@ final class Parameters { * Parser flags. */ private int parserFlags; + /** + * Turn on generate Bin annotations for fields. + * + * @since 2.0.0 + */ + private boolean addBinAnnotations; + /** + * Generate newInstance methods in classes. + * + * @since 2.0.0 + */ + private boolean addNewInstanceMethods; @Nullable public String getPackageName() { @@ -135,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; } @@ -151,6 +168,17 @@ public Parameters setAddGettersSetters(final boolean value) { return this; } + @Nullable + public String getDestFileName() { + return this.destFileName; + } + + @Nonnull + public Parameters setDestFileName(@Nullable final String name) { + this.destFileName = name; + return this; + } + public boolean isDisableGenerateFields() { return this.disableGenerateFields; } @@ -178,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; } @@ -194,16 +230,28 @@ public boolean isDoInternalClassesNonStatic() { } @Nonnull - public Parameters setSubClassSuperclasses(@Nonnull final Map value) { - this.subClassSuperclasses.clear(); - this.subClassSuperclasses.putAll(value); + public Parameters setDoInternalClassesNonStatic(final boolean flag) { + this.doInternalClassesNonStatic = flag; return this; } + public boolean isAddNewInstanceMethods() { + return this.addNewInstanceMethods; + } + @Nonnull - public Parameters setSubClassInterfaces(@Nonnull final Map value) { - this.subClassInterfaces.clear(); - this.subClassInterfaces.putAll(value); + public Parameters setAddNewInstanceMethods(final boolean flag) { + this.addNewInstanceMethods = flag; + return this; + } + + public boolean isAddBinAnnotations() { + return this.addBinAnnotations; + } + + @Nonnull + public Parameters setAddBinAnnotations(final boolean flag) { + this.addBinAnnotations = flag; return this; } @@ -238,14 +286,25 @@ public Parameters setOutputDir(@Nullable final File dir) { return this; } - @Nonnull + @Nullable public File getScriptFile() { - return Assertions.assertNotNull(this.scriptFile); + return this.scriptFile; } @Nonnull - public Parameters setScriptFile(@Nonnull final File file) { - this.scriptFile = Assertions.assertNotNull(file); + public Parameters setScriptFile(@Nullable final File file) { + this.scriptFile = file; + return this; + } + + @Nullable + public String getScriptText() { + return this.scriptText; + } + + @Nonnull + public Parameters setScriptText(@Nonnull final String text) { + this.scriptText = Assertions.assertNotNull(text); return this; } @@ -299,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; } @@ -311,5 +371,16 @@ public Parameters assertAllOk() { } return this; } + + @Nullable + 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/Java16Converter.java b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverter.java similarity index 52% rename from jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/Java16Converter.java rename to jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverter.java index aa3053ef..28595c4a 100644 --- a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/Java16Converter.java +++ b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/JavaConverter.java @@ -1,42 +1,59 @@ package com.igormaznitsa.jbbp.plugin.common.converters; +import static com.igormaznitsa.jbbp.utils.JBBPUtils.ARRAY_STRING_EMPTY; + + import com.igormaznitsa.jbbp.JBBPParser; -import com.igormaznitsa.jbbp.compiler.conversion.JBBPToJava6Converter; +import com.igormaznitsa.jbbp.compiler.conversion.JBBPToJavaConverter; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.plugin.common.utils.CommonUtils; import com.igormaznitsa.meta.common.utils.Assertions; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; - -import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Set; +import javax.annotation.Nonnull; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; -public class Java16Converter implements JBBPScriptTranslator { +public class JavaConverter implements JBBPScriptTranslator { @Override @Nonnull - public Set translate(@Nonnull final Parameters parameters, final boolean dryRun) throws IOException { - final File scriptToProcess = Assertions.assertNotNull(parameters.getScriptFile()); - - final String text = FileUtils.readFileToString(scriptToProcess, parameters.getEncodingIn()); - final String rawFileName = FilenameUtils.getBaseName(scriptToProcess.getName()); + 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()); + } 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(new String[parameters.getClassImplements().size()]); + final String[] implementsSorted = parameters.getClassImplements().toArray(ARRAY_STRING_EMPTY); Arrays.sort(implementsSorted); - final JBBPToJava6Converter.Builder builder = JBBPToJava6Converter.makeBuilder(parser) + final JBBPToJavaConverter.Builder builder = JBBPToJavaConverter.makeBuilder(parser) .setMapSubClassesInterfaces(parameters.getSubClassInterfaces()) .setMapSubClassesSuperclasses(parameters.getSubClassSuperclasses()) .setMainClassName(className) @@ -47,7 +64,15 @@ public Set translate(@Nonnull final Parameters parameters, final boolean d .setDoMainClassAbstract(parameters.isDoAbstract()) .setMainClassImplements(implementsSorted) .setParserFlags(parameters.getParserFlags()) - .setSuperClass(parameters.superClass); + .setSuperClass(parameters.getSuperClass()); + + if (parameters.isAddBinAnnotations()) { + builder.addBinAnnotations(); + } + + if (parameters.isAddNewInstanceMethods()) { + builder.addNewInstanceMethods(); + } if (parameters.isDoInternalClassesNonStatic()) { builder.doInternalClassesNonStatic(); @@ -56,7 +81,7 @@ public Set translate(@Nonnull final Parameters parameters, final boolean d if (parameters.isDisableGenerateFields()) { builder.disableGenerateFields(); } - + FileUtils.write(resultJavaFile, builder.build().convert(), parameters.getEncodingOut()); } return resultFiles; 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/converters/Target.java b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/Target.java index dc4d8099..9747899e 100644 --- a/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/Target.java +++ b/jbbp-plugins/jbbp-plugin-common/src/main/java/com/igormaznitsa/jbbp/plugin/common/converters/Target.java @@ -3,7 +3,7 @@ import javax.annotation.Nonnull; public enum Target { - JAVA_1_6(new Java16Converter()); + JAVA(new JavaConverter()); private final JBBPScriptTranslator JBBPScriptTranslator; 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 e6d6d5d5..f1cc9863 100644 --- a/jbbp-plugins/pom.xml +++ b/jbbp-plugins/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-main-pom - 1.4.1-SNAPSHOT + 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 00f8f55f..9f031e0f 100644 --- a/jbbp/pom.xml +++ b/jbbp/pom.xml @@ -5,7 +5,7 @@ com.igormaznitsa jbbp-main-pom - 1.4.1-SNAPSHOT + 3.0.2-SNAPSHOT jbbp @@ -17,7 +17,8 @@ - 1.21 + 1.8 + 1.8 @@ -36,19 +37,22 @@ org.apache.commons commons-lang3 - 3.7 + 3.18.0 test net.minidev json-smart - 2.3 test - org.apache.commons + commons-io commons-io - 1.3.2 + test + + + commons-codec + commons-codec test @@ -111,7 +115,7 @@ test - java + java8 -classpath @@ -137,7 +141,6 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 generate-sources @@ -151,8 +154,8 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0 + false true protected UTF-8 @@ -164,13 +167,15 @@ jar + + 8 + org.apache.maven.plugins maven-gpg-plugin - 1.6 sign-artifacts @@ -181,6 +186,33 @@ + + net.nicoulaj.maven.plugins + checksum-maven-plugin + + + verify + + files + + + + + ${project.build.directory} + + *.jar + *.pom + + + + + SHA-1 + MD5 + + + + + @@ -191,7 +223,6 @@ com.igormaznitsa uber-pom - 1.0.1
parent
@@ -211,7 +242,6 @@ org.apache.maven.plugins maven-jar-plugin - 3.0.2 @@ -223,33 +253,18 @@ org.codehaus.mojo animal-sniffer-maven-plugin - 1.16 - ensure-java-1.6-class-library - test - - check - - - - org.codehaus.mojo.signature - java16-sun - 1.0 - - - - - ensure-android-2.0-class-library + ensure-android-api-32-class-library test check - net.sf.androidscents.signature - android-api-level-5 - 2.0_r1 + 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 d0fd4c70..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} - / + /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 48264658..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; @@ -59,7 +58,7 @@ public JBBPNamedNumericFieldMap() { * @param externalValueProvider an external value provider, it can be null */ public JBBPNamedNumericFieldMap(final JBBPExternalValueProvider externalValueProvider) { - this.fieldMap = new LinkedHashMap(); + this.fieldMap = new LinkedHashMap<>(); this.externalValueProvider = externalValueProvider; } @@ -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 e7644f8b..da3c2ce9 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParser.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParser.java @@ -16,13 +16,18 @@ 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; -import com.igormaznitsa.jbbp.compiler.conversion.JBBPToJava6Converter; +import com.igormaznitsa.jbbp.compiler.conversion.JBBPToJavaConverter; 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; @@ -40,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; @@ -52,12 +58,12 @@ 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; import com.igormaznitsa.jbbp.utils.JBBPUtils; import com.igormaznitsa.jbbp.utils.TargetSources; - import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.IOException; @@ -74,7 +80,7 @@ * * @since 1.0 */ -@SuppressWarnings( {"WeakerAccess", "ConstantConditions"}) +@SuppressWarnings({"WeakerAccess"}) public final class JBBPParser { /** @@ -87,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 */ @@ -107,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; @@ -143,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) + + ']'); } } @@ -161,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 @@ -173,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 @@ -191,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); } @@ -216,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); } @@ -235,34 +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 */ - @SuppressWarnings("ConstantConditions") - 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 { - final List structureFields = skipStructureFields ? null : new ArrayList(); + 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; } @@ -273,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); } @@ -298,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); @@ -313,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; } @@ -348,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); @@ -363,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)"); } } } @@ -371,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); } @@ -407,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) { @@ -424,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))); } } } @@ -436,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))); } } } @@ -444,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)) ); } } @@ -457,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)) ); } } @@ -470,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)) ); } } @@ -486,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))); } } } @@ -497,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(new JBBPAbstractField[structFields.size()]))); + structureFields + .add(new JBBPFieldStruct(name, structFields.toArray(ARRAY_FIELD_EMPTY))); } } else { final int nameFieldCurrent = positionAtNamedFieldList.get(); @@ -518,14 +661,23 @@ private List parseStruct(final JBBPBitInputStream inStream, f if (resultNotIgnored) { if (wholeStreamArray) { // read till the stream end - final List list = new ArrayList(); + final List list = new ArrayList<>(); while (inStream.hasAvailableData()) { 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()) { @@ -533,20 +685,26 @@ private List parseStruct(final JBBPBitInputStream inStream, f } } - result = list.isEmpty() ? EMPTY_STRUCT_ARRAY : list.toArray(new JBBPFieldStruct[list.size()]); + result = list.isEmpty() ? EMPTY_STRUCT_ARRAY : list.toArray(EMPTY_STRUCT_ARRAY); } else { // read number of items 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); @@ -554,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)); } } } @@ -564,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); } } @@ -582,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); } } @@ -621,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; @@ -633,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(); } @@ -677,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); } @@ -711,50 +914,49 @@ public JBBPCompiledBlock getCompiledBlock() { * @param name name of result, depends on target, must not be null, for instance class name (example 'com.test.jbbp.Parser') * @return list of source items generated during operation, must not be null and must not be empty * @throws IllegalArgumentException if target is unsupported - * @see JBBPToJava6Converter - * @see JBBPToJava6Converter.Builder + * @see JBBPToJavaConverter + * @see JBBPToJavaConverter.Builder * @since 1.3.0 */ public List convertToSrc(final TargetSources target, final String name) { JBBPUtils.assertNotNull(name, "Name must not be null"); - switch (target) { - case JAVA_1_6: { - final Properties metadata = new Properties(); - metadata.setProperty("script", this.compiledBlock.getSource()); - metadata.setProperty("name", name); - metadata.setProperty("target", target.name()); - metadata.setProperty("converter", JBBPToJava6Converter.class.getCanonicalName()); - - final int nameStart = name.lastIndexOf('.'); - final String packageName; - final String className; - if (nameStart < 0) { - packageName = ""; - className = name; - } else { - packageName = name.substring(0, nameStart); - className = name.substring(nameStart + 1); - } + if (target == TargetSources.JAVA) { + final Properties metadata = new Properties(); + metadata.setProperty("script", this.compiledBlock.getSource()); + metadata.setProperty("name", name); + metadata.setProperty("target", target.name()); + metadata.setProperty("converter", JBBPToJavaConverter.class.getCanonicalName()); + + final int nameStart = name.lastIndexOf('.'); + final String packageName; + final String className; + if (nameStart < 0) { + packageName = ""; + className = name; + } else { + packageName = name.substring(0, nameStart); + className = name.substring(nameStart + 1); + } - final String resultSources = JBBPToJava6Converter.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 - public Properties getMetadata() { - return metadata; - } + return Collections.singletonList(new ResultSrcItem() { + @Override + public Properties getMetadata() { + return metadata; + } - @Override - public Map getResult() { - return resultMap; - } - }); - } - default: { - throw new IllegalArgumentException("Unsupported target : " + target); - } + @Override + public Map getResult() { + return resultMap; + } + }); } + throw new IllegalArgumentException("Unsupported target : " + target); } } 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 9b9c2ad4..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; @@ -33,6 +32,12 @@ */ 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]; + /** * The Array of named field info items. */ @@ -70,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; @@ -193,9 +201,9 @@ public int findFieldOffsetForPath(final String fieldPath) { */ public final static class Builder { - private final List namedFields = new ArrayList(); - private final List varLenProcessors = new ArrayList(); - private final List customTypeFields = new ArrayList(); + private final List namedFields = new ArrayList<>(); + private final List varLenProcessors = new ArrayList<>(); + private final List customTypeFields = new ArrayList<>(); private String source; private byte[] compiledData; private boolean hasVarFields; @@ -211,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(new JBBPNamedFieldInfo[this.namedFields.size()]), this.varLenProcessors.isEmpty() ? null : this.varLenProcessors.toArray(new JBBPIntegerValueEvaluator[this.varLenProcessors.size()]), this.compiledData, this.hasVarFields, this.customTypeFields.toArray(new JBBPFieldTypeParameterContainer[this.customTypeFields.size()])); + 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 d89e2b77..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,33 +157,27 @@ 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); } } private static void assertTokenNamed(final String fieldType, final JBBPToken token) { if (token.getFieldName() == null) { - final String fieldName = token.getFieldName() == null ? "" : token.getFieldName(); - throw new JBBPCompilationException('\'' + fieldType + "' must be named (" + fieldName + ')', token); + throw new JBBPCompilationException('\'' + fieldType + "' must be named", token); } } private static void assertTokenNotNamed(final String fieldType, final JBBPToken token) { if (token.getFieldName() != null) { - final String fieldName = token.getFieldName() == null ? "" : token.getFieldName(); - throw new JBBPCompilationException('\'' + fieldType + "' must not be named (" + fieldName + ')', 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); } } @@ -198,19 +192,21 @@ 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); - final List namedFields = new ArrayList(); - final List customTypeFields = new ArrayList(); - final List varLengthEvaluators = new ArrayList(); + final List namedFields = new ArrayList<>(); + final List customTypeFields = new ArrayList<>(); + final List varLengthEvaluators = new ArrayList<>(); final ByteArrayOutputStream out = new ByteArrayOutputStream(); int offset = 0; - final List structureStack = new ArrayList(); + final List structureStack = new ArrayList<>(); final JBBPTokenizer parser = new JBBPTokenizer(script, customTypeFieldProcessor); int fieldUnrestrictedArrayOffset = -1; @@ -240,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) { @@ -254,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) { @@ -263,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 { @@ -287,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; @@ -311,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; @@ -325,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); } } } @@ -333,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; @@ -347,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); } } } @@ -356,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; @@ -366,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); } } } @@ -375,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); } } @@ -400,30 +423,35 @@ 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, token.getArraySizeAsInt()); + offset += writePackedInt(out, fixedArraySize); } } @@ -438,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 @@ -474,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. * @@ -483,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); } } @@ -496,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); } } @@ -510,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)); @@ -542,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: { @@ -552,50 +601,72 @@ 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); - if ("skip".equals(name) || "val".equals(name)) { - result |= CODE_SKIP; - } else if ("align".equals(name)) { - result |= CODE_ALIGN; - } else if ("bit".equals(name)) { - result |= CODE_BIT; - } else if ("var".equals(name)) { - result |= CODE_VAR; - } else if ("bool".equals(name) || JBBPFieldString.TYPE_NAME.equals(name)) { - result |= CODE_BOOL; - } else if ("ubyte".equals(name)) { - result |= CODE_UBYTE; - } else if ("byte".equals(name)) { - result |= CODE_BYTE; - } else if ("ushort".equals(name)) { - result |= CODE_USHORT; - } else if ("short".equals(name)) { - result |= CODE_SHORT; - } else if ("int".equals(name) || JBBPFieldFloat.TYPE_NAME.equals(name)) { - result |= CODE_INT; - } else if ("long".equals(name) || JBBPFieldDouble.TYPE_NAME.equals(name)) { - result |= CODE_LONG; - } else if ("reset$$".equals(name)) { - result |= CODE_RESET_COUNTER; - } else { - boolean unsupportedType = true; - if (customTypeFieldProcessor != null) { - for (final String s : customTypeFieldProcessor.getCustomFieldTypes()) { - if (name.equals(s)) { - result |= CODE_CUSTOMTYPE; - unsupportedType = false; - break; + switch (name) { + case "skip": + case "val": + result |= CODE_SKIP; + break; + case "align": + result |= CODE_ALIGN; + break; + case "bit": + result |= CODE_BIT; + break; + case "var": + result |= CODE_VAR; + break; + case "bool": + case JBBPFieldString.TYPE_NAME: + result |= CODE_BOOL; + break; + case "ubyte": + result |= CODE_UBYTE; + break; + case "byte": + case JBBPFieldUInt.TYPE_NAME: + result |= CODE_BYTE; + break; + case "ushort": + result |= CODE_USHORT; + break; + case "short": + result |= CODE_SHORT; + break; + case "int": + case JBBPFieldFloat.TYPE_NAME: + result |= CODE_INT; + break; + case "long": + case JBBPFieldDouble.TYPE_NAME: + result |= CODE_LONG; + break; + case "reset$$": + result |= CODE_RESET_COUNTER; + break; + default: + boolean unsupportedType = true; + if (customTypeFieldProcessor != null) { + for (final String s : customTypeFieldProcessor.getCustomFieldTypes()) { + if (name.equals(s)) { + result |= CODE_CUSTOMTYPE; + unsupportedType = false; + break; + } } } - } - if (unsupportedType) { - throw new JBBPCompilationException("Unsupported type [" + descriptor.getTypeName() + ']', token); - } + if (unsupportedType) { + throw new JBBPCompilationException( + "Unsupported type [" + descriptor.getTypeName() + ']', token); + } + break; } } break; @@ -604,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; } @@ -643,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; @@ -654,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 aac9508c..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 @@ -68,7 +68,6 @@ protected boolean isFlagSkipRemainingFieldsIfEOF() { * * @return the instance of the visitor, must not be null */ - @SuppressWarnings("unchecked") public final CompiledBlockVisitor visit() { this.visitStart(); @@ -89,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; } @@ -103,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): { @@ -114,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: { @@ -133,10 +139,12 @@ 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, name, evaluator); + visitValField(theOffset, byteOrder, name, evaluator); } else { throw new Error("Unexpected code:" + theCode); } @@ -147,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, name, numberOfBits, arraySizeEvaluator); + final JBBPIntegerValueEvaluator numberOfBits = + extraFieldNumAsExpr ? extraFieldValueEvaluator : new IntConstValueEvaluator( + JBBPUtils.unpackInt(compiledData, positionAtCompiledBlock)); + visitBitField(theOffset, byteOrder, name, readWholeStream, numberOfBits, + arraySizeEvaluator); } break; @@ -159,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, name, arraySizeEvaluator); + visitStructureStart(theOffset, byteOrder, readWholeStream, name, arraySizeEvaluator); } break; @@ -175,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: @@ -206,18 +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 nameFieldInfo name of the field, must not be null * @param expression expression to calculate value * @since 1.4.0 */ - public void visitValField(int offsetInCompiledBlock, JBBPNamedFieldInfo nameFieldInfo, JBBPIntegerValueEvaluator expression) { + public void visitValField(int offsetInCompiledBlock, + JBBPByteOrder byteOrder, + JBBPNamedFieldInfo nameFieldInfo, + JBBPIntegerValueEvaluator expression) { } /** @@ -227,7 +252,7 @@ public void visitValField(int offsetInCompiledBlock, JBBPNamedFieldInfo nameFiel * @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, JBBPNamedFieldInfo nameFiel * @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, 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, 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/JBBPToJava6Converter.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJava6Converter.java deleted file mode 100644 index cc216e93..00000000 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJava6Converter.java +++ /dev/null @@ -1,1392 +0,0 @@ -/* - * 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.compiler.conversion; - -import com.igormaznitsa.jbbp.JBBPParser; -import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo; -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.JBBPByteOrder; -import com.igormaznitsa.jbbp.utils.JavaSrcTextBuffer; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.*; - -/** - * Converter to produce Java class sources (1.6+) from JBBPParser. If a parser contains variable field, custom fields or external - * values in expressions then the result class will be abstract one and its - * abstract methods must be implemented in successor. - * - * @since 1.3.0 - */ -@SuppressWarnings("SpellCheckingInspection") -public final class JBBPToJava6Converter extends CompiledBlockVisitor { - - private static final int FLAG_DETECTED_CUSTOM_FIELDS = 1; - private static final int FLAG_DETECTED_EXTERNAL_FIELDS = 2; - private static final int FLAG_DETECTED_VAR_FIELDS = 4; - private static final int FLAG_ADD_ASSERT_NOT_NEGATIVE_EXPR = 8; - - /** - * Name of the field to be used as link to the root structure instance in - * child structures. - */ - private static final String NAME_ROOT_STRUCT = "_Root_"; - /** - * Name of the field to keep information about parser flags. - */ - private static final String NAME_PARSER_FLAGS = "_ParserFlags_"; - /** - * Name of the input stream argument. - */ - private static final String NAME_INPUT_STREAM = "In"; - /** - * Name of the output stream argument. - */ - private static final String NAME_OUTPUT_STREAM = "Out"; - /** - * Detected flags. - */ - private final AtomicInteger flagSet = new AtomicInteger(); - - /** - * Map of detected named fields to their name field info object. - */ - private final Map foundNamedFields = new HashMap(); - /** - * Counter of anonymous fields to generate unique names. - */ - private final AtomicInteger anonymousFieldCounter = new AtomicInteger(); - /** - * Counter of special fields to generate their unique names. - */ - private final AtomicInteger specialFieldsCounter = new AtomicInteger(); - /** - * The List implements stack of current processing structures. The 0 contains - * the root. - */ - private final List structStack = new ArrayList(); - /** - * Text buffer for the special section. - */ - private final JavaSrcTextBuffer specialSection = new JavaSrcTextBuffer(); - /** - * Text buffer for the special methods. - */ - private final JavaSrcTextBuffer specialMethods = new JavaSrcTextBuffer(); - /** - * The Builder instance to be used as the data source for the parser. It must - * not be null. - */ - private final Builder builder; - /** - * The Field contains conversion result after process end. - */ - private String result; - - /** - * The Only Constructor based on a builder instance. - * - * @param builder a builder instance, must not be null - */ - private JBBPToJava6Converter(final Builder builder) { - super(builder.parserFlags, builder.srcParser.getCompiledBlock()); - this.builder = builder; - } - - /** - * Make new builder. - * - * @param parser parser instance to be used as the base for translation, must not be - * null - * @return the new builder instance, must not be null. - */ - public static Builder makeBuilder(final JBBPParser parser) { - return new Builder(parser); - } - - /** - * Do conversion. - * - * @return generated class with needed parameters as text, must not be null. - */ - public String convert() { - return JBBPToJava6Converter.class.cast(this.visit()).getResult(); - } - - private void registerNamedField(final JBBPNamedFieldInfo fieldInfo, final FieldType fieldType) { - if (fieldInfo != null) { - if (this.foundNamedFields.containsKey(fieldInfo)) { - throw new Error("Detected duplication of named field : " + fieldInfo); - } - this.foundNamedFields.put(fieldInfo, new NamedFieldInfo(fieldInfo, this.getCurrentStruct(), fieldType)); - } - } - - private Struct getCurrentStruct() { - return this.structStack.get(0); - } - - @Override - public void visitStart() { - this.flagSet.set(0); - this.foundNamedFields.clear(); - this.anonymousFieldCounter.set(1234); - this.specialFieldsCounter.set(1); - this.specialSection.clean(); - this.structStack.clear(); - this.specialMethods.clean(); - - this.structStack.add(new Struct(null, this.builder.mainClassName, "public")); - } - - /** - * Get result of the conversion process. - * - * @return the result, it will not be null if the process completed without - * errors. - */ - public String getResult() { - return this.result; - } - - @Override - public void visitEnd() { - final JavaSrcTextBuffer buffer = new JavaSrcTextBuffer(); - - if (this.builder.headComment != null) { - buffer.printCommentMultiLinesWithIndent(this.builder.headComment); - } - - if (this.builder.mainClassPackage != null && this.builder.mainClassPackage.length() != 0) { - buffer.print("package ").print(this.builder.mainClassPackage).println(";"); - } - - buffer.println(); - - buffer.println("import com.igormaznitsa.jbbp.model.*;"); - buffer.println("import com.igormaznitsa.jbbp.io.*;"); - buffer.println("import com.igormaznitsa.jbbp.compiler.*;"); - buffer.println("import com.igormaznitsa.jbbp.compiler.tokenizer.*;"); - buffer.println("import java.io.IOException;"); - buffer.println("import java.util.*;"); - - 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); - - 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.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;"); - } - - 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);"); - } - - 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.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.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.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;"); - } - - 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; }"); - } - - 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; - - buffer.printJavaDocLinesWithIndent("Generated from JBBP script by internal JBBP Class Source Generator"); - - this.structStack.get(0).write(buffer, - hasAbstractMethods ? "abstract" : null, - this.builder.superClass, - this.builder.mainClassImplements, - this.builder.mapSubClassesInterfaces, - this.builder.mapSubClassesSuperclasses, - this.specialSection.toString(), - specialMethodsText.length() == 0 ? null : specialMethodsText, - this.builder.mainClassCustomText, - true - ); - - this.result = buffer.toString(); - } - - @Override - public void visitStructureStart(final int offsetInCompiledBlock, final JBBPNamedFieldInfo nullableNameFieldInfo, final JBBPIntegerValueEvaluator nullableArraySize) { - final String structName = (nullableNameFieldInfo == null ? makeAnonymousStructName() : 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 fieldModifier = makeModifier(nullableNameFieldInfo); - - final String toType; - if (this.builder.generateFields) { - toType = ""; - } else { - toType = '(' + structBaseTypeName + ')'; - } - - final String structType; - if (nullableArraySize == null) { - structType = structBaseTypeName; - if (this.builder.generateFields) { - this.getCurrentStruct().getFields().indent().print(fieldModifier).printf(" %s %s;", structType, structName).println(); - } - - processSkipRemainingFlag(); - processSkipRemainingFlagForWriting("this." + structName); - - this.getCurrentStruct().getReadFunc().indent() - .printf("if ( this.%1$s == null) { this.%1$s = new %2$s(%3$s);}", structName, structType, this.structStack.size() == 1 ? "this" : "this." + NAME_ROOT_STRUCT) - .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);"); - } else { - structType = structBaseTypeName + " []"; - if (this.builder.generateFields) { - this.getCurrentStruct().getFields().indent().print(fieldModifier).printf(" %s %s;", structType, structName).println(); - } - processSkipRemainingFlag(); - processSkipRemainingFlagForWriting("this." + structName); - if ("-1".equals(arraySizeIn)) { - 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", - structName, - arraySizeIn, - structBaseTypeName, - (this.structStack.size() == 1 ? "this" : NAME_ROOT_STRUCT), - NAME_INPUT_STREAM); - this.getCurrentStruct().getWriteFunc().indent().printf("for (int I=0;I stack = new ArrayList(); - - @Override - public ExpressionEvaluatorVisitor visitStart() { - this.stack.clear(); - return this; - } - - @Override - public ExpressionEvaluatorVisitor visitSpecial(final Special specialField) { - this.stack.add(specialField); - return this; - } - - @Override - public ExpressionEvaluatorVisitor visitField(final JBBPNamedFieldInfo nullableNameFieldInfo, final String nullableExternalFieldName) { - if (nullableNameFieldInfo != null) { - this.stack.add(nullableNameFieldInfo); - } else if (nullableExternalFieldName != null) { - detectedFlagsSet.set(detectedFlagsSet.get() | FLAG_DETECTED_EXTERNAL_FIELDS); - this.stack.add(nullableExternalFieldName); - } - return this; - } - - @Override - public ExpressionEvaluatorVisitor visitOperator(final Operator operator) { - this.stack.add(operator); - return this; - } - - @Override - public ExpressionEvaluatorVisitor visitConstant(final int value) { - this.stack.add(value); - return this; - } - - private String arg2str(final Object obj) { - if (obj instanceof ExprTreeItem) { - return obj.toString(); - } else if (obj instanceof Special) { - switch ((Special) obj) { - case STREAM_COUNTER: - return "(int)" + streamName + ".getCounter()"; - default: - throw new Error("Unexpected special"); - } - } else if (obj instanceof Integer) { - if ((Integer) obj < 0) { - return '(' + obj.toString() + ')'; - } else { - return obj.toString(); - } - } else if (obj instanceof String) { - return String.format("%s.getNamedValue(this, \"%s\")", (getCurrentStruct().isRoot() ? "this" : "this." + NAME_ROOT_STRUCT), obj.toString()); - } else if (obj instanceof JBBPNamedFieldInfo) { - final NamedFieldInfo namedFieldInfo = foundNamedFields.get(obj); - final String fieldPath = namedFieldInfo.makeSrcPath(getCurrentStruct()); - - String result; - switch (namedFieldInfo.fieldType) { - case BOOL: { - result = '(' + fieldPath + "?1:0)"; - } - break; - case CUSTOM: - case VAR: { - result = "((JBBPNumericField)" + fieldPath + ").getAsInt()"; - } - break; - default: { - result = "(int)" + fieldPath; - } - break; - } - - return result; - } else { - return null; - } - } - - @Override - public ExpressionEvaluatorVisitor visitEnd() { - buffer.setLength(0); - - for (int i = 0; i < this.stack.size(); i++) { - if (this.stack.get(i) instanceof Operator) { - final Operator op = (Operator) this.stack.remove(i); - i--; - ExprTreeItem newItem = new ExprTreeItem(op); - for (int j = 0; j < op.argsNumber; j++) { - final Object val = this.stack.remove(i); - i--; - if (newItem.right == null) { - newItem.right = val; - } else { - newItem.left = val; - } - } - i++; - this.stack.add(i, newItem); - } - } - - if (this.stack.size() != 1) { - throw new IllegalStateException("Stack must have only element"); - } - - final Object result = this.stack.remove(0); - if (result instanceof ExprTreeItem) { - buffer.append('(').append(result.toString()).append(')'); - } else { - buffer.append(arg2str(result)); - } - - return this; - } - - class ExprTreeItem { - - Operator op; - Object left; - Object right; - - ExprTreeItem(Operator op) { - this.op = op; - } - - boolean doesNeedBrackets(Object obj) { - if (!(obj instanceof ExprTreeItem)) { - return false; - } - final ExprTreeItem that = (ExprTreeItem) obj; - - return that.op.priority <= this.op.priority || ((that.op == Operator.LSHIFT || that.op == Operator.RSHIFT || that.op == Operator.URSHIFT) && (this.op == Operator.LSHIFT || this.op == Operator.RSHIFT || this.op == Operator.URSHIFT)); - } - - @Override - public String toString() { - String leftStr = arg2str(this.left); - String rightStr = arg2str(this.right); - if (doesNeedBrackets(this.left)) { - leftStr = '(' + leftStr + ')'; - } - if (doesNeedBrackets(this.right)) { - rightStr = '(' + rightStr + ')'; - } - return (leftStr == null ? "" : leftStr) + this.op.text + (rightStr == null ? "" : rightStr); - } - } - }; - - evaluator.visitItems(this.compiledBlock, offsetInBlock, visitor); - - String result = buffer.toString(); - if (result.startsWith("(") && result.endsWith(")")) { - try { - result = Integer.toString(Integer.parseInt(result.substring(1, result.length() - 1).trim())); - } catch (NumberFormatException ex) { - // ignore the excepton because it is checking exception - } - } - - if (!(evaluator instanceof IntConstValueEvaluator)) { - if (doResultPostprocessing) { - if ((this.parserFlags & JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO) != 0) { - result = "java.lang.Math.max(0," + result + ')'; - } else { - detectedFlagsSet.set(detectedFlagsSet.get() | FLAG_ADD_ASSERT_NOT_NEGATIVE_EXPR); - result = "assrtExprNotNeg(" + result + ')'; - } - } - } - - return result; - } - - @Override - public void visitActionItem(final int offsetInCompiledBlock, final int actionType, final JBBPIntegerValueEvaluator nullableArgument) { - final String valueTxtIn = nullableArgument == null ? "1" : evaluatorToString(NAME_INPUT_STREAM, offsetInCompiledBlock, nullableArgument, this.flagSet, true); - final String valueTxtOut = nullableArgument == null ? "1" : evaluatorToString(NAME_OUTPUT_STREAM, offsetInCompiledBlock, nullableArgument, this.flagSet, true); - - switch (actionType) { - case CODE_RESET_COUNTER: { - getCurrentStruct().getReadFunc().println(NAME_INPUT_STREAM + ".resetCounter();"); - getCurrentStruct().getWriteFunc().println(NAME_OUTPUT_STREAM + ".resetCounter();"); - } - break; - case CODE_ALIGN: { - getCurrentStruct().getReadFunc().indent().print(NAME_INPUT_STREAM + ".align(").print(valueTxtIn).println(");"); - getCurrentStruct().getWriteFunc().indent().print(NAME_OUTPUT_STREAM + ".align(").print(valueTxtOut).println(");"); - } - break; - case CODE_SKIP: { - getCurrentStruct().getReadFunc().indent().print(NAME_INPUT_STREAM + ".skip(").print(valueTxtIn).println(");"); - getCurrentStruct().getWriteFunc().indent().printf("for(int I=0; I<%s; I++) %s.write(0);%n", valueTxtOut, NAME_OUTPUT_STREAM); - } - break; - default: { - throw new Error("Detected unknown action, contact developer!"); - } - } - } - - private enum FieldType { - BOOL(CODE_BOOL, "boolean", "boolean", "%s.readBoolean()", "%s.readBoolArray(%s)", "%s.write(%s ? 1 : 0)", "for(int I=0;I<%3$s;I++){%1$s.write(%2$s[I] ? 1 : 0);}", "for(int I=0;I<%2$s.length;I++){%1$s.write(%2$s[I] ? 1 : 0);}"), - BYTE(CODE_BYTE, "byte", "byte", "(byte)%s.readByte()", "%s.readByteArray(%s, %s)", "%s.write(%s)", "%1$s.writeBytes(%2$s, %3$s, %4$s)", "%1$s.writeBytes(%2$s, %2$s.length, %3$s)"), - UBYTE(CODE_UBYTE, "char", "byte", "(char)(%s.readByte() & 0xFF)", "%s.readByteArray(%s, %s)", "%s.write(%s)", "%1$s.writeBytes(%2$s, %3$s, %4$s)", "%1$s.writeBytes(%2$s, %2$s.length, %3$s)"), - SHORT(CODE_SHORT, "short", "short", "(short)%s.readUnsignedShort(%s)", "%s.readShortArray(%s,%s)", "%s.writeShort(%s,%s)", "for(int I=0;I<%3$s;I++){%1$s.writeShort(%2$s[I],%4$s);}", "for(int I=0;I<%2$s.length;I++){%1$s.writeShort(%2$s[I],%3$s);}"), - USHORT(CODE_USHORT, "char", "char", "(char)%s.readUnsignedShort(%s)", "%s.readUShortArray(%s,%s)", "%s.writeShort(%s,%s)", "for(int I=0;I<%3$s;I++){%1$s.writeShort(%2$s[I],%4$s);}", "for(int I=0;I<%2$s.length;I++){%1$s.writeShort(%2$s[I],%3$s);}"), - INT(CODE_INT, "int", "int", "%s.readInt(%s)", "%s.readIntArray(%s,%s)", "%s.writeInt(%s,%s)", "for(int I=0;I<%3$s;I++){%1$s.writeInt(%2$s[I],%4$s);}", "for(int I=0;I<%2$s.length;I++){%1$s.writeInt(%2$s[I],%3$s);}"), - LONG(CODE_LONG, "long", "long", "%s.readLong(%s)", "%s.readLongArray(%s,%s)", "%s.writeLong(%s,%s)", "for(int I=0;I<%3$s;I++){%1$s.writeLong(%2$s[I],%4$s);}", "for(int I=0;I<%2$s.length;I++){%1$s.writeLong(%2$s[I],%3$s);}"), - CUSTOM(-1, "", "", "", "", "", "", ""), - VAR(-2, "", "", "", "", "", "", ""), - VAL(-3, "int", "", "", "", "", "", ""), - BIT(-4, "", "", "", "", "", "", ""), - FLOAT(-5, "float", "float", "%s.readFloat(%s)", "%s.readFloatArray(%s,%s)", "%s.writeFloat(%s,%s)", "for(int I=0;I<%3$s;I++){%1$s.writeFloat(%2$s[I],%4$s);}", "for(int I=0;I<%2$s.length;I++){%1$s.writeFloat(%2$s[I],%3$s);}"), - DOUBLE(-6, "double", "double", "%s.readDouble(%s)", "%s.readDoubleArray(%s,%s)", "%s.writeDouble(%s,%s)", "for(int I=0;I<%3$s;I++){%1$s.writeDouble(%2$s[I],%4$s);}", "for(int I=0;I<%2$s.length;I++){%1$s.writeDouble(%2$s[I],%3$s);}"), - STRING(-7, "String", "String", "%s.readString(%s)", "%s.readStringArray(%s,%s)", "%s.writeString(%s,%s)", "for(int I=0;I<%3$s;I++){%1$s.writeString(%2$s[I],%4$s);}", "%1$s.writeStringArray(%2$s,%3$s)"), - UNKNOWN(Integer.MIN_VALUE, "", "", "", "", "", "", ""); - - private final int code; - private final String javaSingleType; - private final String javaArrayType; - private final String methodReadOne; - private final String methodReadArray; - private final String methodWriteOne; - private final String methodWriteArray; - private final String methodWriteArrayWithUnknownSize; - - FieldType(final int code, final String javaSingleType, final String javaArrayType, final String readOne, final String readArray, final String writeOne, final String writeArray, final String writeArrayWithUnknownSize) { - this.code = code; - this.methodWriteArrayWithUnknownSize = writeArrayWithUnknownSize; - this.javaSingleType = javaSingleType; - this.javaArrayType = javaArrayType; - this.methodReadArray = readArray; - this.methodReadOne = readOne; - this.methodWriteArray = writeArray; - this.methodWriteOne = writeOne; - } - - static FieldType findForCode(final int code) { - for (final FieldType t : values()) { - if (t.code == code) { - return t; - } - } - return UNKNOWN; - } - - void assertNotUnknown() { - if (this == UNKNOWN) { - throw new Error("Call method for unknown type"); - } - } - - String asJavaSingleFieldType() { - assertNotUnknown(); - return this.javaSingleType; - } - - String asJavaArrayFieldType() { - assertNotUnknown(); - return this.javaArrayType; - } - - String makeReaderForSingleField(final String streamName, final JBBPByteOrder byteOrder) { - assertNotUnknown(); - return String.format(this.methodReadOne, streamName, "JBBPByteOrder." + byteOrder.name()); - } - - String makeWriterForSingleField(final String streamName, final String fieldName, final JBBPByteOrder byteOrder) { - assertNotUnknown(); - return String.format(this.methodWriteOne, streamName, fieldName, "JBBPByteOrder." + byteOrder.name()); - } - - String makeReaderForArray(final String streamName, final String arraySize, final JBBPByteOrder byteOrder) { - assertNotUnknown(); - return String.format(this.methodReadArray, streamName, arraySize, "JBBPByteOrder." + byteOrder.name()); - } - - String makeWriterForArray(final String streamName, final String fieldName, final String arraySize, final JBBPByteOrder byteOrder) { - assertNotUnknown(); - return String.format(this.methodWriteArray, streamName, fieldName, arraySize, "JBBPByteOrder." + byteOrder.name()); - } - - String makeWriterForArrayWithUnknownSize(final String streamName, final String fieldName, final JBBPByteOrder byteOrder) { - assertNotUnknown(); - return String.format(this.methodWriteArrayWithUnknownSize, streamName, fieldName, "JBBPByteOrder." + byteOrder.name()); - } - } - - /** - * Builder to build instance of converter. - */ - public static final class Builder { - - /** - * Set of interfaces to be implemented by the main result class. - */ - private final Set mainClassImplements = new HashSet(); - /** - * The Parser to provide compiled data. - */ - private final JBBPParser srcParser; - /** - * Interfaces to be implemented by generated subclasses, also getters return the interface type. - */ - private final Map mapSubClassesInterfaces = new HashMap(); - /** - * Superclasses to be extended by generated subclasses. - */ - private final Map mapSubClassesSuperclasses = new HashMap(); - - /** - * Imternal classes must not be static. - */ - public boolean internalClassesNotStatic; - /** - * The Package name for the result class. - */ - private String mainClassPackage; - /** - * The Result class name for the result class. - */ - private String mainClassName; - /** - * The Flag to force the result class as abstract one. - */ - private boolean doMainClassAbstract; - /** - * The Name of class to be extended by the result class. - */ - private String superClass; - /** - * The Comment to be placed before package info. - */ - private String headComment; - /** - * Flag to lockBuilder the builder. - */ - private boolean lockBuilder; - /** - * Parser flags. - */ - private int parserFlags; - /** - * Generate getters and setters. - */ - private boolean addGettersSetters; - /** - * Text to be inserted into custom section of the resut class. - */ - private String mainClassCustomText; - /** - * Flag to generate fields in result class file. - * - * @since 1.4.0 - */ - private boolean generateFields; - - private Builder(final JBBPParser parser) { - this.srcParser = parser; - this.parserFlags = parser.getFlags(); - this.generateFields = true; - } - - private void assertNonLocked() { - if (this.lockBuilder) { - throw new IllegalStateException("Builder already locked"); - } - } - - /** - * Map inside structures to mainClassImplements, a structure class will implement mapped interface and getter of the structure object will return interface object as result. - * - * @param mapClassNameToInterface map with structure path as the key and the interface name as value, it can be null. Names of structures should be in the lower case form amd dot separated for their hierarchy. (example: "a.b.c") - * @return the builder instance, must not be null - */ - public Builder setMapSubClassesInterfaces(final Map mapClassNameToInterface) { - assertNonLocked(); - this.mapSubClassesInterfaces.clear(); - if (mapClassNameToInterface != null) { - this.mapSubClassesInterfaces.putAll(mapClassNameToInterface); - } - return this; - } - - /** - * Add superclasses to classes generated for inside structures, a structure class will extend mapped class. - * - * @param mapClassNameToSuperclasses map with structure path as the key and the interface name as value, it can be null. Names of structures should be in the lower case form amd dot separated for their hierarchy. (example: "a.b.c") - * @return the builder instance, must not be null - * @since 1.4.0 - */ - public Builder setMapSubClassesSuperclasses(final Map mapClassNameToSuperclasses) { - assertNonLocked(); - this.mapSubClassesSuperclasses.clear(); - if (mapClassNameToSuperclasses != null) { - this.mapSubClassesSuperclasses.putAll(mapClassNameToSuperclasses); - } - return this; - } - - /** - * Set custom text, the text will be added into the end of the result class. - * - * @param value text value, it can be null - * @return the builder instance, must not be null - */ - public Builder setMainClassCustomText(final String value) { - assertNonLocked(); - this.mainClassCustomText = value; - return this; - } - - /** - * Set flag to generate getters setters. NB! All fields will be private ones in the case. - * - * @param value flag, if true then generate getters setters, false otherwise - * @return the builder instance, must not be null - */ - public Builder setAddGettersSetters(final boolean value) { - assertNonLocked(); - this.addGettersSetters = value; - return this; - } - - /** - * Set the parser flags for the generated class, by default the flags are imported from the base parser. - * - * @param value parser flags. - * @return the builder instance, must not be null - */ - public Builder setParserFlags(final int value) { - assertNonLocked(); - this.parserFlags = value; - return this; - } - - /** - * Set the package for the generated class. - * - * @param value name of the package, it can be empty or null in the case the class will be in the default package - * @return the builder instance, must not be null - */ - public Builder setMainClassPackage(final String value) { - assertNonLocked(); - this.mainClassPackage = value; - return this; - } - - /** - * Set flag to force abstract modifier for the generated class, by default the class is abstract one only if it contains abstract methods. - * - * @param value true if to force the abstract modifier, false otherwise - * @return the builder instance, must not be null - */ - public Builder setDoMainClassAbstract(final boolean value) { - assertNonLocked(); - this.doMainClassAbstract = value; - return this; - } - - /** - * The Name of the generated class. Must be provided. - * - * @param value the class name for the generated class, must not be null - * @return the builder instance, must not be null - */ - public Builder setMainClassName(final String value) { - assertNonLocked(); - this.mainClassName = value; - return this; - } - - /** - * Don't make insternal generated classes as static ones - * - * @return the builder instance, must not be null - * @since 1.4.0 - */ - public Builder doInternalClassesNonStatic() { - assertNonLocked(); - this.internalClassesNotStatic = true; - return this; - } - - /** - * Set the superclass for the main generated class. NB! Also it affects read and write methods of the main class, the class will be used as the return type. - * - * @param value the superclass name, it can be null - * @return the builder instance, must not be null - */ - public Builder setSuperClass(final String value) { - assertNonLocked(); - this.superClass = value; - return this; - } - - /** - * Set interfaces to be added into 'implements' for the generated class. - * - * @param values interface names - * @return the builder instance, must not be null - */ - public Builder setMainClassImplements(final String... values) { - assertNonLocked(); - Collections.addAll(this.mainClassImplements, values); - return this; - } - - /** - * Set commentaries placed just before first package directive of the generated class. - * - * @param text text to be used as comment, it can be null - * @return the builder instance, must not be null - */ - public Builder setHeadComment(final String text) { - assertNonLocked(); - this.headComment = text; - return this; - } - - /** - * 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 enabled. - * - * @return the builder instance, must not be null - * @since 1.4.0 - */ - public Builder disableGenerateFields() { - this.generateFields = false; - return this; - } - - /** - * Build converter with provided parameters. NB! It locks builder parameters and they can't be changed in future. - * - * @return a converter instance. - */ - public JBBPToJava6Converter build() { - this.lockBuilder = true; - if (this.mainClassName == null) { - throw new NullPointerException("Class name must not be null"); - } - return new JBBPToJava6Converter(this); - } - } - - private static class Struct { - - private final String classModifiers; - private final String className; - private final Struct parent; - private final List children = new ArrayList(); - private final JavaSrcTextBuffer fields = new JavaSrcTextBuffer(); - private final JavaSrcTextBuffer readFunc = new JavaSrcTextBuffer(); - private final JavaSrcTextBuffer writeFunc = new JavaSrcTextBuffer(); - private final JavaSrcTextBuffer gettersSetters = new JavaSrcTextBuffer(); - 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.classModifiers = classModifiers; - this.className = className; - this.parent = parent; - if (this.parent != null) { - this.parent.children.add(this); - } - } - - private static String interfaces2str(final Set set) { - final StringBuilder buffer = new StringBuilder(); - for (final String s : set) { - if (buffer.length() > 0) { - buffer.append(','); - } - buffer.append(s); - } - return buffer.toString(); - } - - boolean isRoot() { - return this.parent == null; - } - - String getPath() { - return this.path; - } - - Struct findRoot() { - if (this.parent == null) { - return this; - } - return this.parent.findRoot(); - } - - void write( - final JavaSrcTextBuffer buffer, - final String extraModifier, - final String superClass, - final Set implementedInterfaces, - final Map mapStructInterfaces, - final Map mapStructSuperclasses, - final String commonSectionText, - final String specialMethods, - final String customText, - final boolean useSuperclassForReadWrite) { - final String interfaceForGetSet = mapStructInterfaces == null ? null : mapStructInterfaces.get(this.getPath()); - - buffer.indent().printf( - "%s%sclass %s%s%s {%n", - this.classModifiers, - extraModifier == null ? " " : ' ' + extraModifier + ' ', - this.className, - superClass != null ? " extends " + superClass + ' ' : "", - interfaceForGetSet == null ? implementedInterfaces != null && !implementedInterfaces.isEmpty() ? " implements " + interfaces2str(implementedInterfaces) + ' ' : "" : " implements " + interfaceForGetSet - ); - buffer.incIndent(); - - if (commonSectionText != null) { - buffer.printLinesWithIndent(commonSectionText); - } - - for (final Struct c : this.children) { - 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.println(); - - buffer.indent().print("public ").print(this.className).print(" (") - .print(this.parent == null ? "" : (findRoot().className + " root")) - .println(") {"); - - buffer.incIndent(); - if (this.parent != null) { - buffer.indent().print(NAME_ROOT_STRUCT).print(" = ").println("root;"); - } - buffer.decIndent(); - - buffer.indent().println("}"); - - buffer.println(); - - 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;"); - buffer.decIndent(); - buffer.indent().println("}"); - - buffer.println(); - - 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;"); - buffer.decIndent(); - buffer.indent().println("}"); - - if (specialMethods != null) { - buffer.println(); - buffer.printLinesWithIndent(specialMethods); - buffer.println(); - } - - if (!this.gettersSetters.isEmpty()) { - buffer.println(); - buffer.printLinesWithIndent(this.gettersSetters.toString()); - buffer.println(); - } - - if (customText != null && customText.length() != 0) { - buffer.printCommentLinesWithIndent("------ Custom section START"); - buffer.printLinesWithIndent(customText); - buffer.printCommentLinesWithIndent("------ Custom section END"); - } - - buffer.decIndent(); - buffer.indent().println("}"); - - } - - JavaSrcTextBuffer getWriteFunc() { - return this.writeFunc; - } - - JavaSrcTextBuffer getReadFunc() { - return this.readFunc; - } - - JavaSrcTextBuffer getFields() { - return this.fields; - } - - JavaSrcTextBuffer getGettersSetters() { - return this.gettersSetters; - } - } - - private static final class NamedFieldInfo { - - final JBBPNamedFieldInfo info; - final Struct struct; - final FieldType fieldType; - - NamedFieldInfo(final JBBPNamedFieldInfo info, final Struct struct, final FieldType fieldType) { - this.info = info; - this.struct = struct; - this.fieldType = fieldType; - } - - String makeSrcPath(final Struct currentStruct) { - if (this.struct == currentStruct) { - return "this." + info.getFieldName(); - } else { - final String structPath = this.struct.getPath(); - if (currentStruct.isRoot()) { - return "this." + (structPath.length() == 0 ? "" : structPath + ".") + info.getFieldName(); - } else { - return "this." + NAME_ROOT_STRUCT + '.' + (structPath.length() == 0 ? "" : structPath + ".") + info.getFieldName(); - } - } - } - } -} 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 new file mode 100644 index 00000000..7b7cb043 --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverter.java @@ -0,0 +1,1925 @@ +/* + * 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.compiler.conversion; + +import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_ALIGN; +import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_BOOL; +import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_BYTE; +import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_INT; +import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_LONG; +import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_RESET_COUNTER; +import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_SHORT; +import static com.igormaznitsa.jbbp.compiler.JBBPCompiler.CODE_SKIP; +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; +import com.igormaznitsa.jbbp.compiler.varlen.JBBPIntegerValueEvaluator; +import com.igormaznitsa.jbbp.io.JBBPBitNumber; +import com.igormaznitsa.jbbp.io.JBBPByteOrder; +import com.igormaznitsa.jbbp.mapper.BinType; +import com.igormaznitsa.jbbp.mapper.JBBPMapper; +import com.igormaznitsa.jbbp.utils.JavaSrcTextBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Converter to produce Java class sources (1.6+) from JBBPParser. If a parser + * contains variable field, custom fields or external values in expressions then + * the result class will be abstract one and its abstract methods must be + * implemented in successor. + * + * @since 1.3.0 + */ +@SuppressWarnings("SpellCheckingInspection") +public class JBBPToJavaConverter extends CompiledBlockVisitor { + + private static final int FLAG_DETECTED_CUSTOM_FIELDS = 1; + private static final int FLAG_DETECTED_EXTERNAL_FIELDS = 2; + private static final int FLAG_DETECTED_VAR_FIELDS = 4; + private static final int FLAG_ADD_ASSERT_NOT_NEGATIVE_EXPR = 8; + + private static final Set RESERVED_JAVA_KEYWORDS; + /** + * Name of the field to be used as link to the root structure instance in + * child structures. + */ + private static final String NAME_ROOT_STRUCT = "_Root_"; + /** + * Name of the field to keep information about parser flags. + */ + private static final String NAME_PARSER_FLAGS = "_ParserFlags_"; + /** + * Name of the input stream argument. + */ + private static final String NAME_INPUT_STREAM = "In"; + /** + * 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. + */ + private final AtomicInteger flagSet = new AtomicInteger(); + + /** + * Map of detected named fields to their name field info object. + */ + private final Map foundNamedFields = new HashMap<>(); + /** + * Counter of anonymous fields to generate unique names. + */ + private final AtomicInteger anonymousFieldCounter = new AtomicInteger(); + /** + * Counter of special fields to generate their unique names. + */ + private final AtomicInteger specialFieldsCounter = new AtomicInteger(); + /** + * The List implements stack of current processing structures. The 0 contains + * the root. + */ + private final List structStack = new ArrayList<>(); + /** + * Text buffer for the special section. + */ + private final JavaSrcTextBuffer specialSection = new JavaSrcTextBuffer(); + /** + * Text buffer for the special methods. + */ + private final JavaSrcTextBuffer specialMethods = new JavaSrcTextBuffer(); + /** + * The Builder instance to be used as the data source for the parser. It must + * not be null. + */ + private final Builder builder; + /** + * The Field contains conversion result after process end. + */ + private String result; + + /** + * The Only Constructor based on a builder instance. + * + * @param builder a builder instance, must not be null + */ + private JBBPToJavaConverter(final Builder builder) { + super(builder.parserFlags, builder.srcParser.getCompiledBlock()); + this.builder = builder; + } + + /** + * Make new builder. + * + * @param parser parser instance to be used as the base for translation, must + * not be null + * @return the new builder instance, must not be null. + */ + public static Builder makeBuilder(final JBBPParser parser) { + return new Builder(parser); + } + + /** + * Do conversion. + * + * @return generated class with needed parameters as text, must not be null. + */ + public String convert() { + return ((JBBPToJavaConverter) this.visit()).getResult(); + } + + private void registerNamedField(final JBBPNamedFieldInfo fieldInfo, final FieldType fieldType) { + if (fieldInfo != null) { + if (this.foundNamedFields.containsKey(fieldInfo)) { + throw new Error("Detected duplication of named field : " + fieldInfo); + } + this.foundNamedFields + .put(fieldInfo, new NamedFieldInfo(fieldInfo, this.getCurrentStruct(), fieldType)); + } + } + + private Struct getCurrentStruct() { + return this.structStack.get(0); + } + + @Override + public void visitStart() { + this.flagSet.set(0); + this.foundNamedFields.clear(); + this.anonymousFieldCounter.set(1234); + this.specialFieldsCounter.set(1); + this.specialSection.clean(); + this.structStack.clear(); + this.specialMethods.clean(); + + final Struct rootStruct = new Struct(null, this.builder.mainClassName, "public"); + this.structStack.add(rootStruct); + } + + /** + * Get result of the conversion process. + * + * @return the result, it will not be null if the process completed without + * errors. + */ + public String getResult() { + return this.result; + } + + @Override + public void visitEnd() { + final JavaSrcTextBuffer buffer = new JavaSrcTextBuffer(); + + if (this.builder.headComment != null) { + buffer.printCommentMultiLinesWithIndent(this.builder.headComment); + } + + if (this.builder.mainClassPackage != null && !this.builder.mainClassPackage.isEmpty()) { + buffer.print("package ").print(this.builder.mainClassPackage).println(";"); + } + + buffer.println(); + + buffer.println("import com.igormaznitsa.jbbp.model.*;"); + buffer.println("import com.igormaznitsa.jbbp.io.*;"); + buffer.println("import com.igormaznitsa.jbbp.compiler.*;"); + buffer.println("import com.igormaznitsa.jbbp.compiler.tokenizer.*;"); + buffer.println("import java.io.IOException;"); + buffer.println("import java.util.*;"); + + if (this.builder.addBinAnnotations) { + buffer.println("import com.igormaznitsa.jbbp.mapper.Bin;"); + buffer.println("import com.igormaznitsa.jbbp.mapper.BinType;"); + } + + 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); + + 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.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;"); + } + + 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);"); + } + + 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.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.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.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;"); + } + + 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; }"); + } + + 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; + + 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.incIndent(); + + for (final Struct c : rootStruct.children) { + rootStruct.misc.indent().println(String.format("if (aClass == %s.class) {", c.className)); + rootStruct.misc.incIndent(); + rootStruct.misc.indent().println(String.format("return new %s(this);", c.className)); + rootStruct.misc.decIndent(); + rootStruct.misc.indent().println("}"); + } + + rootStruct.misc.indent().println("return null;"); + rootStruct.misc.decIndent(); + rootStruct.misc.println("}"); + } + + rootStruct.write(buffer, + hasAbstractMethods ? "abstract" : null, + this.builder.superClass, + this.builder.mainClassImplements, + this.builder.mapSubClassesInterfaces, + this.builder.mapSubClassesSuperclasses, + this.specialSection.toString(), + specialMethodsText.isEmpty() ? null : specialMethodsText, + this.builder.mainClassCustomText, + true + ); + + this.result = buffer.toString(); + } + + @Override + 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 fieldModifier = makeModifier(nullableNameFieldInfo); + + final String toType; + if (this.builder.generateFields) { + toType = ""; + } else { + toType = '(' + structBaseTypeName + ')'; + } + + final String structType; + + final String pathToRootObject = this.structStack.size() == 1 ? "this" : NAME_ROOT_STRUCT; + + if (nullableArraySize == null) { + structType = structBaseTypeName; + if (this.builder.generateFields) { + 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.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); + } + processSkipRemainingFlag(); + processSkipRemainingFlagForWriting("this." + structName); + 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", + structName, + arraySizeIn, + structBaseTypeName, + pathToRootObject, + NAME_INPUT_STREAM); + this.getCurrentStruct().getWriteFunc().indent() + .printf("for (int I=0;I stack = new ArrayList<>(); + + @Override + public ExpressionEvaluatorVisitor visitStart() { + this.stack.clear(); + return this; + } + + @Override + public ExpressionEvaluatorVisitor visitSpecial(final Special specialField) { + this.stack.add(specialField); + return this; + } + + @Override + public ExpressionEvaluatorVisitor visitField(final JBBPNamedFieldInfo nullableNameFieldInfo, + final String nullableExternalFieldName) { + if (nullableNameFieldInfo != null) { + this.stack.add(nullableNameFieldInfo); + } else if (nullableExternalFieldName != null) { + detectedFlagsSet.set(detectedFlagsSet.get() | FLAG_DETECTED_EXTERNAL_FIELDS); + this.stack.add(nullableExternalFieldName); + } + return this; + } + + @Override + public ExpressionEvaluatorVisitor visitOperator(final Operator operator) { + this.stack.add(operator); + return this; + } + + @Override + public ExpressionEvaluatorVisitor visitConstant(final int value) { + this.stack.add(value); + return this; + } + + private String arg2str(final Object obj) { + if (obj instanceof ExprTreeItem) { + return obj.toString(); + } else if (obj instanceof Special) { + if (obj == Special.STREAM_COUNTER) { + return "(int)" + streamName + ".getCounter()"; + } + throw new Error("Unexpected special"); + } else if (obj instanceof Integer) { + if ((Integer) obj < 0) { + return '(' + obj.toString() + ')'; + } else { + return obj.toString(); + } + } else if (obj instanceof String) { + return String.format("%s.getNamedValue(this, \"%s\")", + (getCurrentStruct().isRoot() ? "this" : "this." + NAME_ROOT_STRUCT), obj); + } else if (obj instanceof JBBPNamedFieldInfo) { + final NamedFieldInfo namedFieldInfo = foundNamedFields.get(obj); + final String fieldPath = namedFieldInfo.makeSrcPath(getCurrentStruct()); + + String result; + switch (namedFieldInfo.fieldType) { + case BOOL: { + result = '(' + fieldPath + "?1:0)"; + } + break; + case CUSTOM: + case VAR: { + result = "((JBBPNumericField)" + fieldPath + ").getAsInt()"; + } + break; + default: { + result = "(int)" + fieldPath; + } + break; + } + + return result; + } else { + return null; + } + } + + @Override + public ExpressionEvaluatorVisitor visitEnd() { + buffer.setLength(0); + + for (int i = 0; i < this.stack.size(); i++) { + if (this.stack.get(i) instanceof Operator) { + final Operator op = (Operator) this.stack.remove(i); + i--; + ExprTreeItem newItem = new ExprTreeItem(op); + for (int j = 0; j < op.argsNumber; j++) { + final Object val = this.stack.remove(i); + i--; + if (newItem.right == null) { + newItem.right = val; + } else { + newItem.left = val; + } + } + i++; + this.stack.add(i, newItem); + } + } + + if (this.stack.size() != 1) { + throw new IllegalStateException("Stack must have only element"); + } + + final Object result = this.stack.remove(0); + if (result instanceof ExprTreeItem) { + buffer.append('(').append(result).append(')'); + } else { + buffer.append(arg2str(result)); + } + + return this; + } + + class ExprTreeItem { + + final Operator op; + Object left; + Object right; + + ExprTreeItem(Operator op) { + this.op = op; + } + + boolean doesNeedBrackets(Object obj) { + if (!(obj instanceof ExprTreeItem)) { + return false; + } + final ExprTreeItem that = (ExprTreeItem) obj; + + return that.op.priority <= this.op.priority || + ((that.op == Operator.LSHIFT || that.op == Operator.RSHIFT || + that.op == Operator.URSHIFT) && + (this.op == Operator.LSHIFT || this.op == Operator.RSHIFT || + this.op == Operator.URSHIFT)); + } + + @Override + public String toString() { + String leftStr = arg2str(this.left); + String rightStr = arg2str(this.right); + if (doesNeedBrackets(this.left)) { + leftStr = '(' + leftStr + ')'; + } + if (doesNeedBrackets(this.right)) { + rightStr = '(' + rightStr + ')'; + } + return (leftStr == null ? "" : leftStr) + this.op.text + + (rightStr == null ? "" : rightStr); + } + } + }; + + evaluator.visitItems(this.compiledBlock, offsetInBlock, visitor); + + String result = buffer.toString(); + if (result.startsWith("(") && result.endsWith(")")) { + try { + result = + Integer.toString(Integer.parseInt(result.substring(1, result.length() - 1).trim())); + } catch (NumberFormatException ex) { + // ignore the excepton because it is checking exception + } + } + + if (!(evaluator instanceof IntConstValueEvaluator)) { + if (doResultPostprocessing) { + if ((this.parserFlags & JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO) != 0) { + result = "java.lang.Math.max(0," + result + ')'; + } else { + detectedFlagsSet.set(detectedFlagsSet.get() | FLAG_ADD_ASSERT_NOT_NEGATIVE_EXPR); + result = "assrtExprNotNeg(" + result + ')'; + } + } + } + + return result; + } + + @Override + public void visitActionItem(final int offsetInCompiledBlock, final int actionType, + final JBBPIntegerValueEvaluator nullableArgument) { + final String valueTxtIn = nullableArgument == null ? "1" : + evaluatorToString(NAME_INPUT_STREAM, offsetInCompiledBlock, nullableArgument, this.flagSet, + true); + final String valueTxtOut = nullableArgument == null ? "1" : + evaluatorToString(NAME_OUTPUT_STREAM, offsetInCompiledBlock, nullableArgument, this.flagSet, + true); + + switch (actionType) { + case CODE_RESET_COUNTER: { + getCurrentStruct().getReadFunc().println(NAME_INPUT_STREAM + ".resetCounter();"); + getCurrentStruct().getWriteFunc().println(NAME_OUTPUT_STREAM + ".resetCounter();"); + } + break; + case CODE_ALIGN: { + getCurrentStruct().getReadFunc().indent().print(NAME_INPUT_STREAM + ".align(") + .print(valueTxtIn).println(");"); + getCurrentStruct().getWriteFunc().indent().print(NAME_OUTPUT_STREAM + ".align(") + .print(valueTxtOut).println(");"); + } + break; + case CODE_SKIP: { + getCurrentStruct().getReadFunc().indent().print(NAME_INPUT_STREAM + ".skip(") + .print(valueTxtIn).println(");"); + getCurrentStruct().getWriteFunc().indent() + .printf("for(int I=0; I<%s; I++) %s.write(0);%n", valueTxtOut, NAME_OUTPUT_STREAM); + } + break; + default: { + throw new Error("Detected unknown action, contact developer!"); + } + } + } + + private enum FieldType { + BOOL(BinType.BOOL, BinType.BOOL_ARRAY, CODE_BOOL, "boolean", "boolean", "%s.readBoolean()", + "%s.readBoolArray(%s)", "%s.write(%s ? 1 : 0)", + "for(int I=0;I<%3$s;I++){%1$s.write(%2$s[I] ? 1 : 0);}", + "for(int I=0;I<%2$s.length;I++){%1$s.write(%2$s[I] ? 1 : 0);}"), + BYTE(BinType.BYTE, BinType.BYTE_ARRAY, CODE_BYTE, "byte", "byte", "(byte)%s.readByte()", + "%s.readByteArray(%s, %s)", "%s.write(%s)", "%1$s.writeBytes(%2$s, %3$s, %4$s)", + "%1$s.writeBytes(%2$s, %2$s.length, %3$s)"), + UBYTE(BinType.UBYTE, BinType.UBYTE_ARRAY, CODE_UBYTE, "char", "byte", + "(char)(%s.readByte() & 0xFF)", "%s.readByteArray(%s, %s)", "%s.write(%s)", + "%1$s.writeBytes(%2$s, %3$s, %4$s)", "%1$s.writeBytes(%2$s, %2$s.length, %3$s)"), + SHORT(BinType.SHORT, BinType.SHORT_ARRAY, CODE_SHORT, "short", "short", + "(short)%s.readUnsignedShort(%s)", "%s.readShortArray(%s,%s)", "%s.writeShort(%s,%s)", + "for(int I=0;I<%3$s;I++){%1$s.writeShort(%2$s[I],%4$s);}", + "for(int I=0;I<%2$s.length;I++){%1$s.writeShort(%2$s[I],%3$s);}"), + USHORT(BinType.USHORT, BinType.USHORT_ARRAY, CODE_USHORT, "char", "char", + "(char)%s.readUnsignedShort(%s)", "%s.readUShortArray(%s,%s)", "%s.writeShort(%s,%s)", + "for(int I=0;I<%3$s;I++){%1$s.writeShort(%2$s[I],%4$s);}", + "for(int I=0;I<%2$s.length;I++){%1$s.writeShort(%2$s[I],%3$s);}"), + INT(BinType.INT, BinType.INT_ARRAY, CODE_INT, "int", "int", "%s.readInt(%s)", + "%s.readIntArray(%s,%s)", "%s.writeInt(%s,%s)", + "for(int I=0;I<%3$s;I++){%1$s.writeInt(%2$s[I],%4$s);}", + "for(int I=0;I<%2$s.length;I++){%1$s.writeInt(%2$s[I],%3$s);}"), + LONG(BinType.LONG, BinType.LONG_ARRAY, CODE_LONG, "long", "long", "%s.readLong(%s)", + "%s.readLongArray(%s,%s)", "%s.writeLong(%s,%s)", + "for(int I=0;I<%3$s;I++){%1$s.writeLong(%2$s[I],%4$s);}", + "for(int I=0;I<%2$s.length;I++){%1$s.writeLong(%2$s[I],%3$s);}"), + CUSTOM(BinType.UNDEFINED, BinType.UNDEFINED, -1, "", "", "", "", "", "", ""), + VAR(BinType.UNDEFINED, BinType.UNDEFINED, -2, "", "", "", "", "", "", ""), + VAL(BinType.UNDEFINED, BinType.UNDEFINED, -3, "int", "", "", "", "", "", ""), + BIT(BinType.BIT, BinType.BIT_ARRAY, -4, "", "", "", "", "", "", ""), + FLOAT(BinType.FLOAT, BinType.FLOAT_ARRAY, -5, "float", "float", "%s.readFloat(%s)", + "%s.readFloatArray(%s,%s)", "%s.writeFloat(%s,%s)", + "for(int I=0;I<%3$s;I++){%1$s.writeFloat(%2$s[I],%4$s);}", + "for(int I=0;I<%2$s.length;I++){%1$s.writeFloat(%2$s[I],%3$s);}"), + DOUBLE(BinType.DOUBLE, BinType.DOUBLE_ARRAY, -6, "double", "double", "%s.readDouble(%s)", + "%s.readDoubleArray(%s,%s)", "%s.writeDouble(%s,%s)", + "for(int I=0;I<%3$s;I++){%1$s.writeDouble(%2$s[I],%4$s);}", + "for(int I=0;I<%2$s.length;I++){%1$s.writeDouble(%2$s[I],%3$s);}"), + STRING(BinType.UNDEFINED, BinType.UNDEFINED, -7, "String", "String", "%s.readString(%s)", + "%s.readStringArray(%s,%s)", "%s.writeString(%s,%s)", + "for(int I=0;I<%3$s;I++){%1$s.writeString(%2$s[I],%4$s);}", + "%1$s.writeStringArray(%2$s,%3$s)"), + UINT(BinType.UINT, BinType.UINT_ARRAY, -8, "long", "long", "%s.readUInt(%s)", + "%s.readUIntArray(%s,%s)", "%s.writeUInt(%s,%s)", + "for(int I=0;I<%3$s;I++){%1$s.writeUInt(%2$s[I],%4$s);}", + "for(int I=0;I<%2$s.length;I++){%1$s.writeUInt(%2$s[I],%3$s);}"), + UNKNOWN(BinType.UNDEFINED, BinType.UNDEFINED, Integer.MIN_VALUE, "", "", "", "", "", "", ""); + + private final BinType binType; + private final BinType binTypeArray; + private final int code; + private final String javaSingleType; + private final String javaArrayType; + private final String methodReadOne; + private final String methodReadArray; + private final String methodWriteOne; + private final String methodWriteArray; + private final String methodWriteArrayWithUnknownSize; + + FieldType( + final BinType binType, + final BinType binTypeArray, + final int code, + final String javaSingleType, + final String javaArrayType, + final String readOne, + final String readArray, + final String writeOne, + final String writeArray, + final String writeArrayWithUnknownSize + ) { + this.binTypeArray = binTypeArray; + this.binType = binType; + this.code = code; + this.methodWriteArrayWithUnknownSize = writeArrayWithUnknownSize; + this.javaSingleType = javaSingleType; + this.javaArrayType = javaArrayType; + this.methodReadArray = readArray; + this.methodReadOne = readOne; + this.methodWriteArray = writeArray; + this.methodWriteOne = writeOne; + } + + static FieldType findForCode(final int code) { + for (final FieldType t : values()) { + if (t.code == code) { + return t; + } + } + return UNKNOWN; + } + + void assertNotUnknown() { + if (this == UNKNOWN) { + throw new Error("Call method for unknown type"); + } + } + + String asJavaSingleFieldType() { + assertNotUnknown(); + return this.javaSingleType; + } + + String asJavaArrayFieldType() { + assertNotUnknown(); + return this.javaArrayType; + } + + String makeReaderForSingleField(final String streamName, final JBBPByteOrder byteOrder) { + assertNotUnknown(); + return String.format(this.methodReadOne, streamName, "JBBPByteOrder." + byteOrder.name()); + } + + String makeWriterForSingleField(final String streamName, final String fieldName, + final JBBPByteOrder byteOrder) { + assertNotUnknown(); + return String + .format(this.methodWriteOne, streamName, fieldName, "JBBPByteOrder." + byteOrder.name()); + } + + String makeReaderForArray(final String streamName, final String arraySize, + final JBBPByteOrder byteOrder) { + assertNotUnknown(); + return String + .format(this.methodReadArray, streamName, arraySize, "JBBPByteOrder." + byteOrder.name()); + } + + String makeWriterForArray(final String streamName, final String fieldName, + final String arraySize, final JBBPByteOrder byteOrder) { + assertNotUnknown(); + return String.format(this.methodWriteArray, streamName, fieldName, arraySize, + "JBBPByteOrder." + byteOrder.name()); + } + + String makeWriterForArrayWithUnknownSize(final String streamName, final String fieldName, + final JBBPByteOrder byteOrder) { + assertNotUnknown(); + return String.format(this.methodWriteArrayWithUnknownSize, streamName, fieldName, + "JBBPByteOrder." + byteOrder.name()); + } + + BinType getBinType() { + return this.binType; + } + + BinType getBinTypeArray() { + return this.binTypeArray; + } + } + + /** + * Builder to build instance of converter. + */ + public static final class Builder { + + /** + * Set of interfaces to be implemented by the main result class. + */ + private final Set mainClassImplements = new HashSet<>(); + /** + * The Parser to provide compiled data. + */ + private final JBBPParser srcParser; + /** + * Interfaces to be implemented by generated subclasses, also getters return + * the interface type. + */ + private final Map mapSubClassesInterfaces = new HashMap<>(); + /** + * Superclasses to be extended by generated subclasses. + */ + private final Map mapSubClassesSuperclasses = new HashMap<>(); + + /** + * Imternal classes must not be static. + */ + private boolean internalClassesNotStatic; + + /** + * Flag to add Bin annotations to fields. + * + * @since 2.0.0 + */ + private boolean addBinAnnotations; + + /** + * Flage to add newInstance methods into generated classes. + * + * @since 2.0.0 + */ + private boolean addNewInstanceMethods; + + /** + * The Package name for the result class. + */ + private String mainClassPackage; + /** + * The Result class name for the result class. + */ + private String mainClassName; + /** + * The Flag to force the result class as abstract one. + */ + private boolean doMainClassAbstract; + /** + * The Name of class to be extended by the result class. + */ + private String superClass; + /** + * The Comment to be placed before package info. + */ + private String headComment; + /** + * Flag to lockBuilder the builder. + */ + private boolean lockBuilder; + /** + * Parser flags. + */ + private int parserFlags; + /** + * Generate getters and setters. + */ + private boolean addGettersSetters; + /** + * Text to be inserted into custom section of the resut class. + */ + private String mainClassCustomText; + /** + * Flag to generate fields in result class file. + * + * @since 1.4.0 + */ + private boolean generateFields; + + private Builder(final JBBPParser parser) { + this.srcParser = parser; + this.parserFlags = parser.getFlags(); + this.generateFields = true; + } + + private void assertNonLocked() { + if (this.lockBuilder) { + throw new IllegalStateException("Builder already locked"); + } + } + + /** + * Map inside structures to mainClassImplements, a structure class will + * implement mapped interface and getter of the structure object will return + * interface object as result. + * + * @param mapClassNameToInterface map with structure path as the key and the + * interface name as value, it can be null. Names of structures should be + * in the lower case form amd dot separated for their hierarchy. (example: + * "a.b.c") + * @return the builder instance, must not be null + */ + public Builder setMapSubClassesInterfaces(final Map mapClassNameToInterface) { + assertNonLocked(); + this.mapSubClassesInterfaces.clear(); + if (mapClassNameToInterface != null) { + this.mapSubClassesInterfaces.putAll(mapClassNameToInterface); + } + return this; + } + + /** + * Add superclasses to classes generated for inside structures, a structure + * class will extend mapped class. + * + * @param mapClassNameToSuperclasses map with structure path as the key and + * the interface name as value, it can be null. Names of structures + * should be in the lower case form amd dot separated for their hierarchy. + * (example: "a.b.c") + * @return the builder instance, must not be null + * @since 1.4.0 + */ + public Builder setMapSubClassesSuperclasses( + final Map mapClassNameToSuperclasses) { + assertNonLocked(); + this.mapSubClassesSuperclasses.clear(); + if (mapClassNameToSuperclasses != null) { + this.mapSubClassesSuperclasses.putAll(mapClassNameToSuperclasses); + } + return this; + } + + /** + * Set custom text, the text will be added into the end of the result class. + * + * @param value text value, it can be null + * @return the builder instance, must not be null + */ + public Builder setMainClassCustomText(final String value) { + assertNonLocked(); + this.mainClassCustomText = value; + return this; + } + + /** + * Set flag to generate getters setters. NB! All fields will be private + * ones in the case. + * + * @param value flag, if true then generate getters setters, false otherwise + * @return the builder instance, must not be null + */ + public Builder setAddGettersSetters(final boolean value) { + assertNonLocked(); + this.addGettersSetters = value; + return this; + } + + /** + * Set the parser flags for the generated class, by default the flags are + * imported from the base parser. + * + * @param value parser flags. + * @return the builder instance, must not be null + */ + public Builder setParserFlags(final int value) { + assertNonLocked(); + this.parserFlags = value; + return this; + } + + /** + * Turn on adding of Bin annotations to generated fields. + * + * @return the builder instance, must not be null + * @since 2.0.0 + */ + public Builder addBinAnnotations() { + assertNonLocked(); + this.addBinAnnotations = true; + return this; + } + + /** + * Turn on generate newInstance methods compatible with JBBPMapper. + * + * @return the builder instance, must not be null + * @since 2.0.0 + */ + public Builder addNewInstanceMethods() { + assertNonLocked(); + this.addNewInstanceMethods = true; + return this; + } + + /** + * Set the package for the generated class. + * + * @param value name of the package, it can be empty or null in the case the + * class will be in the default package + * @return the builder instance, must not be null + */ + public Builder setMainClassPackage(final String value) { + assertNonLocked(); + this.mainClassPackage = value; + return this; + } + + /** + * Set flag to force abstract modifier for the generated class, by default + * the class is abstract one only if it contains abstract methods. + * + * @param value true if to force the abstract modifier, false otherwise + * @return the builder instance, must not be null + */ + public Builder setDoMainClassAbstract(final boolean value) { + assertNonLocked(); + this.doMainClassAbstract = value; + return this; + } + + /** + * The Name of the generated class. Must be provided. + * + * @param value the class name for the generated class, must not be null + * @return the builder instance, must not be null + */ + public Builder setMainClassName(final String value) { + assertNonLocked(); + this.mainClassName = value; + return this; + } + + /** + * Don't make insternal generated classes as static ones + * + * @return the builder instance, must not be null + * @since 1.4.0 + */ + public Builder doInternalClassesNonStatic() { + assertNonLocked(); + this.internalClassesNotStatic = true; + return this; + } + + /** + * Set the superclass for the main generated class. NB! Also it affects + * read and write methods of the main class, the class will be used as the + * return type. + * + * @param value the superclass name, it can be null + * @return the builder instance, must not be null + */ + public Builder setSuperClass(final String value) { + assertNonLocked(); + this.superClass = value; + return this; + } + + /** + * Set interfaces to be added into 'implements' for the generated class. + * + * @param values interface names + * @return the builder instance, must not be null + */ + public Builder setMainClassImplements(final String... values) { + assertNonLocked(); + Collections.addAll(this.mainClassImplements, values); + return this; + } + + /** + * Set commentaries placed just before first package directive of the + * generated class. + * + * @param text text to be used as comment, it can be null + * @return the builder instance, must not be null + */ + public Builder setHeadComment(final String text) { + assertNonLocked(); + this.headComment = text; + return this; + } + + /** + * 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 + * enabled. + * + * @return the builder instance, must not be null + * @since 1.4.0 + */ + public Builder disableGenerateFields() { + this.generateFields = false; + return this; + } + + /** + * Build converter with provided parameters. NB! It locks builder parameters, + * and they can't be changed in future. + * + * @return a converter instance. + */ + public JBBPToJavaConverter build() { + this.lockBuilder = true; + if (this.mainClassName == null) { + throw new NullPointerException("Class name must not be null"); + } + return new JBBPToJavaConverter(this); + } + } + + private static class Struct { + + private final String classModifiers; + private final String className; + private final Struct parent; + private final List children = new ArrayList<>(); + private final JavaSrcTextBuffer fields = new JavaSrcTextBuffer(); + private final JavaSrcTextBuffer readFunc = new JavaSrcTextBuffer(); + private final JavaSrcTextBuffer writeFunc = new JavaSrcTextBuffer(); + private final JavaSrcTextBuffer gettersSetters = new JavaSrcTextBuffer(); + private final JavaSrcTextBuffer misc = new JavaSrcTextBuffer(); + private final String path; + + private Struct(final Struct parent, final String className, final String classModifiers) { + this.path = parent == null ? "" : parent.path + (parent.path.isEmpty() ? "" : ".") + + className.toLowerCase(Locale.ENGLISH); + this.classModifiers = classModifiers; + this.className = className; + this.parent = parent; + if (this.parent != null) { + this.parent.children.add(this); + } + } + + private static String interfaces2str(final Set set) { + final StringBuilder buffer = new StringBuilder(); + for (final String s : set) { + if (buffer.length() > 0) { + buffer.append(','); + } + buffer.append(s); + } + return buffer.toString(); + } + + boolean isRoot() { + return this.parent == null; + } + + String getPath() { + return this.path; + } + + Struct findRoot() { + if (this.parent == null) { + return this; + } + return this.parent.findRoot(); + } + + void write( + final JavaSrcTextBuffer buffer, + final String extraModifier, + final String superClass, + final Set implementedInterfaces, + final Map mapStructInterfaces, + final Map mapStructSuperclasses, + final String commonSectionText, + final String specialMethods, + final String customText, + final boolean useSuperclassForReadWrite) { + final String interfaceForGetSet = + mapStructInterfaces == null ? null : mapStructInterfaces.get(this.getPath()); + + buffer.indent().printf( + "%s%sclass %s%s%s {%n", + this.classModifiers, + extraModifier == null ? " " : ' ' + extraModifier + ' ', + this.className, + superClass != null ? " extends " + superClass + ' ' : "", + interfaceForGetSet == null ? + implementedInterfaces != null && !implementedInterfaces.isEmpty() ? + " implements " + interfaces2str(implementedInterfaces) + ' ' : "" : + " implements " + interfaceForGetSet + ); + buffer.incIndent(); + + if (commonSectionText != null) { + buffer.printLinesWithIndent(commonSectionText); + } + + for (final Struct c : this.children) { + 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.println(); + + buffer.indent().print("public ").print(this.className).print(" (") + .print(this.parent == null ? "" : (findRoot().className + " root")) + .println(") {"); + + buffer.incIndent(); + if (this.parent != null) { + buffer.indent().print(NAME_ROOT_STRUCT).print(" = ").println("root;"); + } + buffer.decIndent(); + + buffer.indent().println("}"); + + buffer.println(); + + 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;"); + buffer.decIndent(); + buffer.indent().println("}"); + + buffer.println(); + + 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;"); + buffer.decIndent(); + buffer.indent().println("}"); + + if (specialMethods != null) { + buffer.println(); + buffer.printLinesWithIndent(specialMethods); + buffer.println(); + } + + if (!this.gettersSetters.isEmpty()) { + buffer.println(); + buffer.printLinesWithIndent(this.gettersSetters.toString()); + buffer.println(); + } + + if (!this.misc.isEmpty()) { + buffer.println(); + buffer.printLinesWithIndent(this.misc.toString()); + buffer.println(); + } + + if (customText != null && !customText.isEmpty()) { + buffer.printCommentLinesWithIndent("------ Custom section START"); + buffer.printLinesWithIndent(customText); + buffer.printCommentLinesWithIndent("------ Custom section END"); + } + + buffer.decIndent(); + buffer.indent().println("}"); + + } + + JavaSrcTextBuffer getMisc() { + return this.misc; + } + + JavaSrcTextBuffer getWriteFunc() { + return this.writeFunc; + } + + JavaSrcTextBuffer getReadFunc() { + return this.readFunc; + } + + JavaSrcTextBuffer getFields() { + return this.fields; + } + + JavaSrcTextBuffer getGettersSetters() { + return this.gettersSetters; + } + } + + private final class NamedFieldInfo { + + final JBBPNamedFieldInfo info; + final Struct struct; + final FieldType fieldType; + + NamedFieldInfo(final JBBPNamedFieldInfo info, final Struct struct, final FieldType fieldType) { + this.info = info; + this.struct = struct; + this.fieldType = fieldType; + } + + private String toFieldIfNotEmpty(final String structPath) { + return structPath.isEmpty() ? "" : structPath + "."; + } + + String makeSrcPath(final Struct currentStruct) { + final String fieldName = prepFldName(info.getFieldName()); + if (this.struct == currentStruct) { + return "this." + fieldName; + } else { + final String structPath = this.struct.getPath(); + if (currentStruct.isRoot()) { + return "this." + toFieldIfNotEmpty(structPath) + fieldName; + } else { + return "this." + NAME_ROOT_STRUCT + '.' + toFieldIfNotEmpty(structPath) + fieldName; + } + } + } + } +} 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 393d9e2f..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; @@ -42,22 +42,27 @@ 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. */ private static final Set GLOBAL_RESERVED_TYPE_NAMES; static { - GLOBAL_RESERVED_TYPE_NAMES = new HashSet(); + GLOBAL_RESERVED_TYPE_NAMES = new HashSet<>(); GLOBAL_RESERVED_TYPE_NAMES.add(JBBPFieldFloat.TYPE_NAME); GLOBAL_RESERVED_TYPE_NAMES.add(JBBPFieldDouble.TYPE_NAME); GLOBAL_RESERVED_TYPE_NAMES.add(JBBPFieldString.TYPE_NAME); + GLOBAL_RESERVED_TYPE_NAMES.add(JBBPFieldUInt.TYPE_NAME); GLOBAL_RESERVED_TYPE_NAMES.add("bit"); GLOBAL_RESERVED_TYPE_NAMES.add("bool"); GLOBAL_RESERVED_TYPE_NAMES.add("byte"); @@ -101,13 +106,14 @@ public JBBPTokenizer(final String str) { * @param str a string to be parsed, must not be null. * @param customFieldTypeProcessor custom field type processor, it can be null */ - public JBBPTokenizer(final String str, final JBBPCustomFieldTypeProcessor customFieldTypeProcessor) { + public JBBPTokenizer(final String str, + final JBBPCustomFieldTypeProcessor customFieldTypeProcessor) { JBBPUtils.assertNotNull(str, "String must not be null"); if (customFieldTypeProcessor == null) { this.reservedTypeNames = GLOBAL_RESERVED_TYPE_NAMES; } else { - this.reservedTypeNames = new HashSet(GLOBAL_RESERVED_TYPE_NAMES); + this.reservedTypeNames = new HashSet<>(GLOBAL_RESERVED_TYPE_NAMES); for (final String customType : customFieldTypeProcessor.getCustomFieldTypes()) { JBBPUtils.assertNotNull(customType, "Type must not be null"); this.reservedTypeNames.add(customType); @@ -120,15 +126,33 @@ public JBBPTokenizer(final String str, final JBBPCustomFieldTypeProcessor custom } /** - * Case sensitive check that the name is among global reserved ones. + * Case-sensitive check that the name is among global reserved ones. * * @param name the name to check, must not be null - * @return true if the name is global reserved one, false otherwise. + * @return true if the name is globally reserved one, false otherwise. */ public static boolean isGlobalReservedName(final String name) { return GLOBAL_RESERVED_TYPE_NAMES.contains(name); } + private static JBBPByteOrder getJbbpByteOrder(String groupTypeByteOrder, String fieldType) { + 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; + } + return byteOrder; + } + /** * Inside method to read the next token from the string and place it into * inside storage. @@ -144,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; @@ -156,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; } @@ -205,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; } } @@ -232,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; @@ -255,16 +287,32 @@ 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 (this.reservedTypeNames.contains(normalized) || normalized.startsWith("$")) { - return new JBBPTokenizerException("'" + name + "' can't be used as field name", position); + + if (!normalized.isEmpty()) { + if (normalized.equals("_") + || normalized.equals("$$") + || normalized.startsWith("$") + || Character.isDigit(normalized.charAt(0)) + ) { + 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", + this.processingString, position); + } + } } } 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. */ @@ -160,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); @@ -168,7 +177,7 @@ public JBBPExpressionEvaluator(final String expression, final List operationStack = new ArrayList(); + final List operationStack = new ArrayList<>(); boolean prevoperator = false; @@ -178,14 +187,15 @@ public JBBPExpressionEvaluator(final String expression, final List externalValueNameList = new ArrayList(); + final List externalValueNameList = new ArrayList<>(); while (matcher.find()) { if (lastFound >= 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 + ']'); } } @@ -213,7 +223,8 @@ public JBBPExpressionEvaluator(final String expression, final List>".equals(operator)) { - code = CODE_RSHIFT; - } else if (">>>".equals(operator)) { - code = CODE_RSIGNSHIFT; - } else { - throw new Error("Detected unsupported operator, contact developer [" + operator + ']'); + switch (operator) { + case "+": + code = CODE_ADD; + break; + case "-": + code = CODE_MINUS; + break; + case "*": + code = CODE_MUL; + break; + case "%": + code = CODE_MOD; + break; + case "/": + code = CODE_DIV; + break; + case "&": + code = CODE_AND; + break; + case "|": + code = CODE_OR; + break; + case "^": + code = CODE_XOR; + break; + case "~": + code = CODE_NOT; + break; + case "<<": + code = CODE_LSHIFT; + break; + case ">>": + code = CODE_RSHIFT; + break; + case ">>>": + code = CODE_RSIGNSHIFT; + break; + default: + throw new Error("Detected unsupported operator, contact developer [" + operator + ']'); } if (theFirstInTheSubExpression) { @@ -326,39 +350,19 @@ 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); @@ -368,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) { @@ -389,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; @@ -499,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 + ']'); } } @@ -532,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--; @@ -543,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; @@ -552,8 +593,10 @@ private int calculateMaxStackDepth() { } } - if (stackPosition != 1 || stackPosition > stackMaxPosition) { - throw new JBBPEvalException("Wrong expression [" + this.expressionSource + "] (" + stackPosition + ':' + stackMaxPosition + ')', this); + if (stackPosition != 1) { + throw new JBBPEvalException( + "Wrong expression [" + this.expressionSource + "] (" + stackPosition + ':' + + stackMaxPosition + ')', this); } return stackMaxPosition; } @@ -579,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; @@ -595,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(); } @@ -688,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 98275576..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,22 +19,20 @@ 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; import com.igormaznitsa.jbbp.model.JBBPFieldInt; 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 com.igormaznitsa.jbbp.utils.ReflectUtils; - import java.lang.reflect.Array; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * Abstract class to collect, order and process all fields in a mapped class. @@ -42,26 +40,24 @@ */ public abstract class AbstractMappedClassFieldObserver { - /** - * Inside cache to keep outOrder of fields for classes for data output. It is - * lazy initialized field. - */ - private static volatile Map, Field[]> cachedClasses; - /** * Inside auxiliary method to read object field value. * - * @param obj an object which field is read - * @param field a field to be read + * @param obj an object which field is read + * @param record field record, must not be null * @return a value from the field of the object * @throws JBBPException if the field can't be read - * @since 1.1 + * @since 2.0 */ - private static Object readFieldValue(final Object obj, final Field field) { + private static Object readFieldValue(final Object obj, final MappedFieldRecord record) { try { - return field.get(obj); + if (record.getter == null) { + return record.mappingField.get(obj); + } else { + return record.getter.invoke(obj); + } } catch (Exception ex) { - throw new JBBPException("Can't get value from field [" + field + ']', ex); + throw new JBBPException("Can't get value from field [" + record + ']', ex); } } @@ -73,119 +69,127 @@ private static Object readFieldValue(final Object obj, final Field field) { */ 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 + ']'); } } /** - * Process an object. + * 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 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) { - JBBPUtils.assertNotNull(obj, "Object must not be null"); - - Field[] orderedFields = null; + protected void processObject( + final Object obj, + final Field field, + final BinAnnotationWrapper binAnnotationWrapper, + final Object customFieldProcessor + ) { + this.processObject(obj, field, binAnnotationWrapper, null, customFieldProcessor); + } - final Map, Field[]> fieldz; - if (cachedClasses == null) { - fieldz = new HashMap, Field[]>(); - cachedClasses = fieldz; - } else { - fieldz = cachedClasses; - synchronized (cachedClasses) { - orderedFields = fieldz.get(obj.getClass()); - } - } + /** + * 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"); - if (orderedFields == null) { - // find out the outOrder of fields and fields which should be serialized - final List> listOfClassHierarchy = new ArrayList>(); - final List fields = new ArrayList(); + final List orderedFields = JBBPMapper.findAffectedFields(obj, binFieldFilter); - Class current = obj.getClass(); - while (current != java.lang.Object.class) { - listOfClassHierarchy.add(current); - current = current.getSuperclass(); - } + final Bin clazzAnno = obj.getClass().getAnnotation(Bin.class); + final Bin fieldAnno = field == null ? null : field.getAnnotation(Bin.class); - for (int i = listOfClassHierarchy.size() - 1; i >= 0; i--) { - final Class clazzToProcess = listOfClassHierarchy.get(i); - final Bin clazzAnno = clazzToProcess.getAnnotation(Bin.class); + final Bin binAnno = clazzAnno == null ? fieldAnno : clazzAnno; - for (Field f : clazzToProcess.getDeclaredFields()) { - f = ReflectUtils.makeAccessible(f); + if (binFieldFilter == null || binFieldFilter.isAllowed(binAnno, field)) { + this.onStructStart(obj, field, binAnno); - final int modifiers = f.getModifiers(); - if (Modifier.isTransient(modifiers) || Modifier.isStatic(modifiers) || f.getName().indexOf('$') >= 0) { - continue; - } + for (final MappedFieldRecord rec : orderedFields) { + final Bin annotation = binAnnotationWrapper == null ? rec.binAnnotation : + binAnnotationWrapper.setWrapped(rec.binAnnotation); - Bin fieldAnno = f.getAnnotation(Bin.class); - fieldAnno = fieldAnno == null ? clazzAnno : fieldAnno; - if (fieldAnno == null) { - continue; + 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."); } - - fields.add(new OrderedField(fieldAnno.outOrder(), f)); + processObjectField(obj, rec, annotation, customFieldProcessor, binFieldFilter); } } - Collections.sort(fields); - - orderedFields = new Field[fields.size()]; - for (int i = 0; i < fields.size(); i++) { - orderedFields[i] = fields.get(i).field; - } - - synchronized (fieldz) { - fieldz.put(obj.getClass(), orderedFields); - } - } - - field = ReflectUtils.makeAccessible(field); - - 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); - - for (final Field f : orderedFields) { - Bin binAnno = f.getAnnotation(Bin.class); - if (binAnno == null) { - binAnno = f.getDeclaringClass().getAnnotation(Bin.class); - if (binAnno == null) { - throw new JBBPIllegalArgumentException("Can't find any Bin annotation to use for " + f + " field"); - } - } - - if (binAnno.custom() && customFieldProcessor == null) { - throw new JBBPIllegalArgumentException("The Class '" + obj.getClass().getName() + "' contains the field '" + f.getName() + "\' which is a custom one, you must provide a JBBPCustomFieldWriter instance to save the field."); - } - - processObjectField(obj, f, 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); } /** * Inside auxiliary method to process a field of an object. * * @param obj the object which field under processing, must not be null - * @param field the field to be written, 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 + * @param binFieldFilter filter allows to exclude some fields from process, can be null + * @since 2.0.4 */ - protected void processObjectField(final Object obj, final Field field, 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, field)); + 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) { @@ -198,11 +202,12 @@ protected void processObjectField(final Object obj, final Field field, final Bin switch (type) { case BIT: { - final JBBPBitNumber bitNumber = annotation.outBitNumber(); + final JBBPBitNumber bitNumber = annotation.bitNumber(); if (fieldType == boolean.class) { - this.onFieldBits(obj, field, annotation, bitNumber, ((Boolean) readFieldValue(obj, field)) ? 0xFF : 0x00); + this.onFieldBits(obj, field, annotation, bitNumber, + ((Boolean) readFieldValue(obj, fieldRecord)) ? 0xFF : 0x00); } else { - byte value = ((Number) readFieldValue(obj, field)).byteValue(); + byte value = ((Number) readFieldValue(obj, fieldRecord)).byteValue(); if (reverseBits) { value = JBBPUtils.reverseBitsInByte(bitNumber, value); } @@ -212,15 +217,16 @@ protected void processObjectField(final Object obj, final Field field, final Bin break; case BOOL: { if (fieldType == boolean.class) { - onFieldBool(obj, field, annotation, (Boolean) readFieldValue(obj, field)); + onFieldBool(obj, field, annotation, (Boolean) readFieldValue(obj, fieldRecord)); } else { - onFieldBool(obj, field, annotation, ((Number) readFieldValue(obj, field)).longValue() != 0); + onFieldBool(obj, field, annotation, + ((Number) readFieldValue(obj, fieldRecord)).longValue() != 0); } } break; case BYTE: case UBYTE: { - byte value = ((Number) readFieldValue(obj, field)).byteValue(); + byte value = ((Number) readFieldValue(obj, fieldRecord)).byteValue(); if (reverseBits) { value = JBBPUtils.reverseBitsInByte(value); } @@ -231,9 +237,9 @@ protected void processObjectField(final Object obj, final Field field, final Bin case USHORT: { short value; if (fieldType == char.class) { - value = (short) ((Character) readFieldValue(obj, field)).charValue(); + value = (short) ((Character) readFieldValue(obj, fieldRecord)).charValue(); } else { - value = ((Number) readFieldValue(obj, field)).shortValue(); + value = ((Number) readFieldValue(obj, fieldRecord)).shortValue(); } if (reverseBits) { value = (short) JBBPFieldShort.reverseBits(value); @@ -243,29 +249,39 @@ protected void processObjectField(final Object obj, final Field field, final Bin break; case INT: { int value; - value = ((Number) readFieldValue(obj, field)).intValue(); + value = ((Number) readFieldValue(obj, fieldRecord)).intValue(); if (reverseBits) { value = (int) JBBPFieldInt.reverseBits(value); } 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) { - value = (Float) readFieldValue(obj, field); + value = (Float) readFieldValue(obj, fieldRecord); } else { - value = ((Number) readFieldValue(obj, field)).floatValue(); + 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); } break; case STRING: { String value; - final Object valueAsObject = readFieldValue(obj, field); + final Object valueAsObject = readFieldValue(obj, fieldRecord); if (valueAsObject != null) { value = String.valueOf(valueAsObject); if (reverseBits) { @@ -278,7 +294,7 @@ protected void processObjectField(final Object obj, final Field field, final Bin } break; case LONG: { - long value = ((Number) readFieldValue(obj, field)).longValue(); + long value = ((Number) readFieldValue(obj, fieldRecord)).longValue(); if (reverseBits) { value = JBBPFieldLong.reverseBits(value); } @@ -288,25 +304,26 @@ protected void processObjectField(final Object obj, final Field field, final Bin case DOUBLE: { double value; if (float.class == fieldType) { - value = (Float) readFieldValue(obj, field); + value = (Float) readFieldValue(obj, fieldRecord); } else if (double.class == fieldType) { - value = (Double) readFieldValue(obj, field); + value = (Double) readFieldValue(obj, fieldRecord); } else { - value = ((Number) readFieldValue(obj, field)).doubleValue(); + value = ((Number) readFieldValue(obj, fieldRecord)).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); } break; case STRUCT: { - processObject(readFieldValue(obj, field), field, customFieldProcessor); + processObject(readFieldValue(obj, fieldRecord), field, wrapper, binFieldFilter, customFieldProcessor); } break; default: { - final Object array = readFieldValue(obj, field); + final Object array = readFieldValue(obj, fieldRecord); switch (type) { case BIT_ARRAY: { assertFieldArray(field); @@ -314,11 +331,12 @@ protected void processObjectField(final Object obj, final Field field, final Bin final int len = Array.getLength(array); this.onArrayStart(obj, field, annotation, len); - final JBBPBitNumber bitNumber = annotation.outBitNumber(); + final JBBPBitNumber bitNumber = annotation.bitNumber(); 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++) { @@ -351,7 +369,7 @@ protected void processObjectField(final Object obj, final Field field, final Bin final boolean signed = type == BinType.BYTE_ARRAY; if (fieldType == String.class) { - final String strValue = (String) readFieldValue(obj, field); + final String strValue = (String) readFieldValue(obj, fieldRecord); this.onArrayStart(obj, field, annotation, strValue.length()); for (int i = 0; i < strValue.length(); i++) { @@ -382,7 +400,7 @@ protected void processObjectField(final Object obj, final Field field, final Bin final boolean signed = type == BinType.SHORT_ARRAY; if (fieldType == String.class) { - final String str = (String) readFieldValue(obj, field); + final String str = (String) readFieldValue(obj, fieldRecord); this.onArrayStart(obj, field, annotation, str.length()); for (int i = 0; i < str.length(); i++) { @@ -427,13 +445,29 @@ protected void processObjectField(final Object obj, final Field field, final Bin 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); @@ -469,7 +503,7 @@ protected void processObjectField(final Object obj, final Field field, final Bin this.onArrayStart(obj, field, annotation, len); for (int i = 0; i < len; i++) { final Object value = Array.get(array, i); - String nullableStrValue = value == null ? null : String.valueOf (value); + String nullableStrValue = value == null ? null : String.valueOf(value); if (nullableStrValue != null && reverseBits) { nullableStrValue = JBBPFieldString.reverseBits(nullableStrValue); } @@ -485,7 +519,8 @@ protected void processObjectField(final Object obj, final Field field, final Bin 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); } @@ -497,13 +532,14 @@ protected void processObjectField(final Object obj, final Field field, final Bin 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 + ']'); } } } @@ -521,7 +557,8 @@ protected void processObjectField(final Object obj, final Field field, final Bin * @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) { } @@ -534,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) { } @@ -546,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) { } @@ -559,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) { } @@ -572,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) { } @@ -584,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) { } @@ -597,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) { } @@ -610,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) { } @@ -623,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) { } @@ -635,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) { } @@ -669,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) { } @@ -684,52 +745,4 @@ protected void onArrayEnd(final Object obj, final Field field, final Bin annotat } - /** - * Inside JBBPOut.Bin command creates cached list of fields of a saved class, - * the method allows to reset the inside cache. - */ - public void resetInsideClassCache() { - final Map, Field[]> fieldz = cachedClasses; - if (fieldz != null) { - synchronized (fieldz) { - fieldz.clear(); - } - } - } - - /** - * An Auxiliary class to be used for class field ordering in save operations. - */ - private static final class OrderedField implements Comparable { - - final int order; - final Field field; - - OrderedField(final int order, final Field field) { - this.order = order; - this.field = field; - } - - @Override - public boolean equals(final Object obj) { - return obj != null && (obj == this || (obj instanceof OrderedField && this.field.equals(((OrderedField) obj).field))); - } - - @Override - public int hashCode() { - return this.order; - } - - @Override - public int compareTo(final OrderedField o) { - final int result; - if (this.order == o.order) { - result = this.field.getName().compareTo(o.field.getName()); - } else { - result = this.order < o.order ? -1 : 1; - } - return result; - } - } - } 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 fbb47a58..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,8 +16,9 @@ package com.igormaznitsa.jbbp.io; -import com.igormaznitsa.jbbp.utils.JBBPUtils; +import static java.util.Objects.requireNonNull; +import com.igormaznitsa.jbbp.utils.JBBPUtils; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -29,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; /** @@ -47,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. */ @@ -58,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"); } /** @@ -77,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; } /** @@ -119,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. @@ -190,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() { @@ -200,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 */ @@ -227,23 +248,21 @@ 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.bitBufferCount == 0) { - out.write(b, off, len); - this.byteCounter += len; - } else { + if (this.bitOrderMode == JBBPBitOrder.MSB0 || this.bitBufferCount != 0) { int i = off; int cnt = len; while (cnt > 0) { - this.write((int) b[i++]); + this.write(b[i++]); cnt--; } + } else { + out.write(b, off, len); + this.byteCounter += len; } } - @SuppressWarnings("NullableProblems") @Override public void write(final byte[] b) throws IOException { this.write(b, 0, b.length); @@ -259,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; + } } } } @@ -309,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); @@ -331,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); } } @@ -347,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) { @@ -359,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() { @@ -381,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); @@ -418,6 +456,7 @@ public void writeString(final String value, final JBBPByteOrder order) throws IO * the byte order in saved char data will be BIG_ENDIAN * * @param value array to be written, must not be null but can contain null values + * @param order byte order to write char data, must not be null * @throws IOException it will be thrown for transport errors * @see #writeString(String, JBBPByteOrder) * @since 1.4.0 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 48b2342a..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,11 +16,15 @@ 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; import java.io.OutputStream; @@ -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"); } /** @@ -258,11 +268,10 @@ public JBBPOut Skip(int numberOfBytes) throws IOException { * * @param value the byte outOrder to be used in next operations, must not be null * @return the DSL session - * @throws IOException it will be thrown for transport errors */ - public JBBPOut ByteOrder(final JBBPByteOrder value) 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; } @@ -301,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 @@ -320,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 @@ -342,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 */ @@ -379,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); } @@ -397,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); @@ -417,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); @@ -731,7 +740,7 @@ public JBBPOut Short(final char[] value) throws IOException { assertArrayNotNull(value); if (this.processCommands) { for (final char v : value) { - this._writeShort((int) v); + this._writeShort(v); } } return this; @@ -800,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. * @@ -937,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); } @@ -996,49 +1019,159 @@ protected void assertNotEnded() { /** * Save fields of an object marked by Bin annotation. Fields will be ordered - * through {@link Bin#outOrder()} 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 #resetInsideClassCache()} + * 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 #resetInsideClassCache() + * @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 + * 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#outOrder()} 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 #resetInsideClassCache()} + * 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 * @return the context - * @throws IOException it will be thrown for any transport error - * @see #resetInsideClassCache() + * @see JBBPMapper#clearFieldCache() * @see Bin + * @see #BinForceByteOrder(Object, JBBPCustomFieldWriter) * @since 1.1 */ - public JBBPOut Bin(final Object object, final JBBPCustomFieldWriter customFieldWriter) throws IOException { + 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.outByteOrder(); + this.byteOrder = annotation.byteOrder(); this.Float(value); } catch (IOException ex) { throw new JBBPIOException("Can't write float value", ex); @@ -1048,10 +1181,11 @@ 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.outByteOrder(); + this.byteOrder = annotation.byteOrder(); this.String(value); } catch (IOException ex) { throw new JBBPIOException("Can't write string value", ex); @@ -1061,10 +1195,11 @@ 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.outByteOrder(); + this.byteOrder = annotation.byteOrder(); this.Double(value); } catch (IOException ex) { throw new JBBPIOException("Can't write double value", ex); @@ -1074,10 +1209,11 @@ 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.outByteOrder(); + this.byteOrder = annotation.byteOrder(); this.Long(value); } catch (IOException ex) { throw new JBBPIOException("Can't write long value", ex); @@ -1087,10 +1223,11 @@ 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.outByteOrder(); + this.byteOrder = annotation.byteOrder(); this.Int(value); } catch (IOException ex) { throw new JBBPIOException("Can't write int value", ex); @@ -1099,11 +1236,31 @@ 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.outByteOrder(); + this.byteOrder = annotation.byteOrder(); this.Short(value); } catch (IOException ex) { throw new JBBPIOException("Can't write short value", ex); @@ -1113,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) { @@ -1122,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) { @@ -1131,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) { @@ -1140,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 2a99cebc..37a4fb1e 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/Bin.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/Bin.java @@ -22,7 +22,6 @@ import com.igormaznitsa.jbbp.io.JBBPCustomFieldWriter; import com.igormaznitsa.jbbp.io.JBBPOut; import com.igormaznitsa.jbbp.utils.JBBPTextWriter; - import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; @@ -31,31 +30,52 @@ /** * 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 { /** * Name of a structure element to be mapped to the field. * - * @return string name, if it is empty then the name of a field will be used + * @return string name, if it is empty then field name will be used * as name */ String name() default ""; /** - * Path inside structure to an element to be mapped to the field. + * Structure path inside to be mapped to the field. * * @return string path, if it is empty then the path is not used */ String path() default ""; + /** + * Custom type. It plays role only if {@link #type()} is UNDEFINED + * Keep attention! The value plays role only in build of script and it is not used in mapping! + * + * @return type of the field, if empty then undefined + * @see com.igormaznitsa.jbbp.utils.JBBPDslBuilder + * @since 2.0.0 + */ + String customType() default ""; + + /** + * Expression to represent array size of the field. + * Keep attention! The value plays role only in build of script and it is not used in mapping! + * + * @return array size of the field, if empty then not defined + * @see com.igormaznitsa.jbbp.utils.JBBPDslBuilder + * @since 2.0.0 + */ + String arraySizeExpr() default ""; + /** * Type of mapped parsed structure element. * @@ -85,43 +105,46 @@ boolean custom() default false; /** - * The Field is used by custom field processor and as expression to calculate array length. + * Expression as extra part of type. It means take part in type[:extra] + * Keep attention! The value plays role only in build of script and it is not used in mapping! * - * @return the extra field as String - * @see JBBPMapperCustomFieldProcessor + * @return extra value, if empty then undefined + * @see com.igormaznitsa.jbbp.utils.JBBPDslBuilder + * @since 2.0.0 */ - String extra() default ""; + String paramExpr() default ""; /** - * The Value defines how many bytes are actual ones in the field, works for numeric field and arrays and allows make mapping to bit fields.The Property - * works only for save and logging. + * The Value defines how many bytes are actual ones in the field, works for numeric field and arrays and allows make mapping to bit fields. * * @return the number of lower bits, by default 8 bits * @see JBBPTextWriter#Bin(java.lang.Object...) * @see JBBPOut#Bin(java.lang.Object) * @see JBBPOut#Bin(java.lang.Object, com.igormaznitsa.jbbp.io.JBBPCustomFieldWriter) - * @since 1.1 + * @see JBBPBitNumber + * @since 2.0.0 */ - JBBPBitNumber outBitNumber() default JBBPBitNumber.BITS_8; + JBBPBitNumber bitNumber() default JBBPBitNumber.BITS_8; /** - * Byte order to be used for write of the value. + * Byte order to be used for operations. * - * @return order of bytes to be used for field value write - * @since 1.4.0 + * @return order of bytes to be used + * @see JBBPByteOrder + * @since 2.0.0 */ - JBBPByteOrder outByteOrder() default JBBPByteOrder.BIG_ENDIAN; + JBBPByteOrder byteOrder() default JBBPByteOrder.BIG_ENDIAN; /** - * The Value defines the field order to sort fields of the class for save or logging. + * The Value defines the field order to show relative position in data stream. If -1then it is undefined. * * @return the outOrder of the field as number (the mapping will make ascending sorting) * @see JBBPTextWriter#Bin(java.lang.Object...) * @see JBBPOut#Bin(java.lang.Object) * @see JBBPOut#Bin(java.lang.Object, com.igormaznitsa.jbbp.io.JBBPCustomFieldWriter) - * @since 1.1 + * @since 2.0.0 */ - int outOrder() default 0; + int order() default -1; /** * Just either description of the field or some remark. 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 a62ec5cd..adb58652 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapper.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapper.java @@ -18,91 +18,81 @@ import com.igormaznitsa.jbbp.exceptions.JBBPMapperException; import com.igormaznitsa.jbbp.io.JBBPBitNumber; -import com.igormaznitsa.jbbp.io.JBBPBitOrder; -import com.igormaznitsa.jbbp.mapper.instantiators.JBBPClassInstantiator; -import com.igormaznitsa.jbbp.mapper.instantiators.JBBPClassInstantiatorFactory; import com.igormaznitsa.jbbp.model.BitEntity; -import com.igormaznitsa.jbbp.model.JBBPAbstractArrayField; import com.igormaznitsa.jbbp.model.JBBPAbstractField; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayBit; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayInt; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayLong; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayShort; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayUByte; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayUShort; -import com.igormaznitsa.jbbp.model.JBBPFieldInt; -import com.igormaznitsa.jbbp.model.JBBPFieldLong; -import com.igormaznitsa.jbbp.model.JBBPFieldString; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; -import com.igormaznitsa.jbbp.model.JBBPNumericField; +import com.igormaznitsa.jbbp.utils.Function; import com.igormaznitsa.jbbp.utils.JBBPUtils; +import com.igormaznitsa.jbbp.utils.NullableTriple; import com.igormaznitsa.jbbp.utils.ReflectUtils; - -import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** - * The Class processes mapping of a parsed binary data to class fields. The - * Class uses sun.misc.Unsafe which creates class instances without any - * constructor call. + * The Class processes mapping of a parsed binary data to class fields. * - * @see sun.misc.Unsafe * @since 1.0 */ public final class JBBPMapper { + public static final String MAKE_CLASS_INSTANCE_METHOD_NAME = "newInstance"; /** * Flag to not throw exception if structure doesn't have value for a field. * * @since 1.1 */ public static final int FLAG_IGNORE_MISSING_VALUES = 1; - - /** - * The Special auxiliary object to generate class instances. - */ - private static final JBBPClassInstantiator CLASS_INSTANTIATOR = JBBPClassInstantiatorFactory.getInstance().make(); + private static final Map, List> CACHED_FIELDS = + new ConcurrentHashMap<>(); /** * Create a class instance, map binary data of a structure for its path to its * fields and return the instance. * - * @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 - * to the class, must not be null - * @param mappingClass the mapping class, must not be null and must have the - * default constructor + * @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 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 * @return the created and mapped instance of the mapping class * @throws JBBPMapperException for any error + * @since 2.0.0 */ - public static T map(final JBBPFieldStruct root, final String structPath, final Class mappingClass) { - return map(root, structPath, mappingClass, null); + @SafeVarargs + public static T map(final JBBPFieldStruct root, final String structPath, final T instance, + final Function, Object>... instantiators) { + return map(root, structPath, instance, null, instantiators); } /** * Create a class instance, map binary data of a structure for its path to its * fields and return the instance. * - * @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 - * to the class, must not be null - * @param mappingClass the mapping class, must not be null and must have the - * default constructor - * @param flags special flags to tune mapping process + * @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 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 + * @param instantiators functions to produce class instance by request, + * must not be null * @return the created and mapped instance of the mapping class * @throws JBBPMapperException for any error * @see #FLAG_IGNORE_MISSING_VALUES - * @since 1.1 + * @since 2.0.0 */ - public static T map(final JBBPFieldStruct root, final String structPath, final Class mappingClass, final int flags) { - return map(root, structPath, mappingClass, null, flags); + @SafeVarargs + 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); } /** @@ -111,18 +101,23 @@ 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 mappingClass the mapping class, must not be null and must have the - * default constructor + * @param instance instance to be filled by values, 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 instantiators functions produce class instance by request, + * must not be null * @return the created and mapped instance of the mapping class * @throws JBBPMapperException for any error + * @since 2.0.0 */ - public static T map(final JBBPFieldStruct root, final String structPath, final Class mappingClass, final JBBPMapperCustomFieldProcessor customFieldProcessor) { - return map(root, structPath, mappingClass, customFieldProcessor, 0); + @SafeVarargs + 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); } /** @@ -131,26 +126,32 @@ 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 mappingClass the mapping class, must not be null and must have the - * default constructor + * @param instance object to be filled by values, 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 to tune mapping + * @param instantiators functions produce class instance by request, + * must not be null * @return the created and mapped instance of the mapping class * @throws JBBPMapperException for any error * @see #FLAG_IGNORE_MISSING_VALUES - * @since 1.1 + * @since 2.0.0 */ - public static T map(final JBBPFieldStruct root, final String structPath, final Class mappingClass, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags) { + @SafeVarargs + 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, mappingClass, null, null); + throw new JBBPMapperException( + "Can't find a structure field for its path [" + structPath + ']', null, + instance.getClass(), null, null); } - return map(struct, mappingClass, customFieldProcessor); + return map(struct, instance, customFieldProcessor, flags, instantiators); } /** @@ -158,16 +159,20 @@ public static T map(final JBBPFieldStruct root, final String structPath, fin * return it. It will create a class instance through a hack method and its * constructor will not be called, thus use the method carefully. * - * @param the mapping class type - * @param root a parsed structure to be mapped to the class instance, must not - * be null - * @param mappingClass the class to be instantiated and mapped, must not be - * null + * @param the mapping class type + * @param root a parsed structure to be mapped to the class instance, must not + * be null + * @param instance object instance to be filled by values, must not be null + * @param instantiators functions produce class instance by request, + * must not be null * @return the created and mapped instance of the class * @throws JBBPMapperException for any error + * @since 2.0.0 */ - public static T map(final JBBPFieldStruct root, final Class mappingClass) { - return mappingClass.cast(map(root, allocateMemoryForClass(root, mappingClass), null)); + @SafeVarargs + public static T map(final JBBPFieldStruct root, final T instance, + final Function, Object>... instantiators) { + return map(root, instance, null, instantiators); } /** @@ -175,434 +180,331 @@ public static T map(final JBBPFieldStruct root, final Class mappingClass) * return it. It will create a class instance through a hack method and its * constructor will not be called, thus use the method carefully. * - * @param the mapping class type - * @param root a parsed structure to be mapped to the class instance, must not - * be null - * @param mappingClass the class to be instantiated and mapped, must not be - * null - * @param flags special flags to tune mapping process + * @param the mapping class type + * @param root a parsed structure to be mapped to the class instance, must not + * be null + * @param instance the class to be instantiated and mapped, must not be + * null + * @param flags special flags to tune mapping process + * @param instantiators functions produce class instance by request, + * must not be null * @return the created and mapped instance of the class * @throws JBBPMapperException for any error * @see #FLAG_IGNORE_MISSING_VALUES - * @since 1.1 + * @since 2.0.0 */ - public static T map(final JBBPFieldStruct root, final Class mappingClass, final int flags) { - return mappingClass.cast(map(root, allocateMemoryForClass(root, mappingClass), null, flags)); + @SafeVarargs + public static T map(final JBBPFieldStruct root, final T instance, final int flags, + final Function, Object>... instantiators) { + return map(root, instance, null, flags, instantiators); } /** - * Create a class instance, map binary data of a structure to the instance and - * return it. It will create a class instance through a hack method and its - * constructor will not be called, thus use the method carefully. + * Map a structure to a class instance. * * @param the mapping class type - * @param root a parsed structure to be mapped to the class instance, must not - * be null - * @param mappingClass the class to be instantiated and mapped, must not be - * null + * @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 - * @return the created and mapped instance of the class + * @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 */ - public static T map(final JBBPFieldStruct root, final Class mappingClass, final JBBPMapperCustomFieldProcessor customFieldProcessor) { - return mappingClass.cast(map(root, allocateMemoryForClass(root, mappingClass), customFieldProcessor)); + @SafeVarargs + public static T map(final JBBPFieldStruct rootStructure, final T instance, + final JBBPMapperCustomFieldProcessor customFieldProcessor, + final Function, Object>... instantiators) { + return map(rootStructure, instance, customFieldProcessor, 0, instantiators); } - /** - * Create a class instance, map binary data of a structure to the instance and - * return it. It will create a class instance through a hack method and its - * constructor will not be called, thus use the method carefully. - * - * @param the mapping class type - * @param root a parsed structure to be mapped to the class instance, must not - * be null - * @param mappingClass the class to be instantiated and mapped, 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 to tune mapping process - * @return the created and mapped instance of the class - * @throws JBBPMapperException for any error - * @see #FLAG_IGNORE_MISSING_VALUES - * @since 1.1 - */ - public static T map(final JBBPFieldStruct root, final Class mappingClass, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags) { - return mappingClass.cast(map(root, allocateMemoryForClass(root, mappingClass), customFieldProcessor, flags)); + @SafeVarargs + @SuppressWarnings("varargs") + private static void processFieldOfMappedClass( + 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); + MappedFieldRecord.setFieldValue(instance, record.setter, record.mappingField, null, value); + } else { + final JBBPAbstractField binField; + + 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()); + } + + 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); + } + + 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, + binFieldFilter, 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 mappingClassInstance a class instance to be destination for map + * @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 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 1.1 */ - public static Object map(final JBBPFieldStruct rootStructure, final Object mappingClassInstance, final JBBPMapperCustomFieldProcessor customFieldProcessor) { - return map(rootStructure, mappingClassInstance, customFieldProcessor, 0); + @SafeVarargs + @SuppressWarnings("varargs") + 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 mappingClassInstance a class instance to be destination for map + * @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 1.1 + * @since 2.0.4 */ - public static Object map(final JBBPFieldStruct rootStructure, final Object mappingClassInstance, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags) { + @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(mappingClassInstance, "The Mapping class instance must not be null"); - - final Class mappingClass = mappingClassInstance.getClass(); + JBBPUtils.assertNotNull(instance, "The Mapping class instance must not be null"); + + // Don't use forEach() for Android compatibility! + for (final MappedFieldRecord record : findAffectedFields(instance, binFieldFilter)) { + processFieldOfMappedClass( + record, + rootStructure, + instance, + customFieldProcessor, + flags, + binFieldFilter, + instantiators + ); + } + return instance; + } - final Bin defaultAnno = mappingClass.getAnnotation(Bin.class); + /** + * Get current number of classes which fields are cached in internal field cache. + * + * @return number of classes + * @since 2.0.0 + */ + public static int getFieldCacheSize() { + return CACHED_FIELDS.size(); + } - // make chain of ancestors till java.lang.Object - final List> listOfClassHierarchy = new ArrayList>(); - Class current = mappingClassInstance.getClass(); - while (current != java.lang.Object.class) { - listOfClassHierarchy.add(current); - current = current.getSuperclass(); - } + /** + * Clear internal class field cache. + * + * @since 2.0.0 + */ + public static void clearFieldCache() { + CACHED_FIELDS.clear(); + } - for (final Class processingClazz : listOfClassHierarchy) { - for (Field mappingField : processingClazz.getDeclaredFields()) { - final int modifiers = mappingField.getModifiers(); - if (Modifier.isTransient(modifiers) || Modifier.isStatic(modifiers)) { - continue; + public static List findAffectedFields(final Object instance, final BinFieldFilter binFieldFilter) { + final Class mappingClass = instance.getClass(); + + List result = CACHED_FIELDS.get(mappingClass); + if (result == null) { + result = new ArrayList<>(); + + final Bin defaultAnno = mappingClass.getAnnotation(Bin.class); + + // make chain of ancestors till java.lang.Object + final List> listOfClassHierarchy = new ArrayList<>(); + Class current = instance.getClass(); + while (current != null) { + final String packageName = current.getPackage().getName(); + if (packageName.startsWith("java.") + || packageName.startsWith("javax.") + || packageName.startsWith("android.") + ) { + break; } + listOfClassHierarchy.add(current); + current = current.getSuperclass(); + } - mappingField = ReflectUtils.makeAccessible(mappingField); + for (final Class processingClazz : listOfClassHierarchy) { + for (Field mappingField : processingClazz.getDeclaredFields()) { + final int fieldModifiers = mappingField.getModifiers(); - final Bin fieldAnno = mappingField.getAnnotation(Bin.class); - final Bin mappedAnno; - if ((fieldAnno == null && defaultAnno == null) || mappingField.getName().indexOf('$') >= 0) { - continue; - } - mappedAnno = fieldAnno == null ? defaultAnno : fieldAnno; - - if (mappedAnno.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, mappedAnno, mappingField); - setFieldValue(mappingClassInstance, mappingField, null, value); - } else { - final BinType fieldType; - - final JBBPBitNumber mappedBitNumber = mappedAnno.outBitNumber(); - - if (mappedAnno.type() == BinType.UNDEFINED) { - BinType thetype = BinType.findCompatible(mappingField.getType()); - if (thetype == null) { - throw new JBBPMapperException("Can't find compatible type for a mapping field", rootStructure, mappingClass, mappingField, null); - } else if (mappedBitNumber.getBitNumber() < 8 && !(thetype == BinType.STRUCT || thetype == BinType.STRUCT_ARRAY)) { - thetype = thetype.isArray() ? BinType.BIT_ARRAY : BinType.BIT; + final Bin fieldAnno = mappingField.getAnnotation(Bin.class); + final Bin mappedAnno; + 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)) { + continue; } - fieldType = thetype; } else { - fieldType = mappedAnno.type(); + final String disallowedModifier; + if (Modifier.isStatic(fieldModifiers)) { + disallowedModifier = "STATIC"; + } else if (Modifier.isFinal(fieldModifiers)) { + disallowedModifier = "FINAL"; + } else { + disallowedModifier = null; + } + if (disallowedModifier != null) { + throw new JBBPMapperException("Detected @Bin marked " + disallowedModifier + " field", + null, processingClazz, mappingField, null); + } } - final boolean bitWideField = fieldType == BinType.BIT || fieldType == BinType.BIT_ARRAY; - final String fieldName = mappedAnno.name().length() == 0 ? mappingField.getName() : mappedAnno.name(); - final String fieldPath = mappedAnno.path(); + final NullableTriple auxMethods = + findAuxFieldMethods(processingClazz, mappingField); - final JBBPAbstractField binField; + final Method fieldGenerator = auxMethods.getA(); + final Method fieldGetter = auxMethods.getB(); + final Method fieldSetter = auxMethods.getC(); - if (fieldPath.length() == 0) { - binField = fieldName.length() == 0 ? rootStructure.findFieldForType(fieldType.getFieldClass()) : rootStructure.findFieldForNameAndType(fieldName, fieldType.getFieldClass()); - } else { - binField = rootStructure.findFieldForPathAndType(fieldPath, fieldType.getFieldClass()); + 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 (binField == null) { - if ((flags & FLAG_IGNORE_MISSING_VALUES) != 0) { - continue; - } - throw new JBBPMapperException("Can't find value to be mapped to a mapping field [" + mappingField + ']', null, mappingClass, mappingField, null); - } - - if (bitWideField && mappedBitNumber != JBBPBitNumber.BITS_8 && ((BitEntity) binField).getBitWidth() != mappedBitNumber) { - throw new JBBPMapperException("Can't map value to a mapping field for different field bit width [" + mappedBitNumber + "!=" + ((BitEntity) binField).getBitWidth().getBitNumber() + ']', null, mappingClass, mappingField, null); + if (fieldGetter == null && fieldGenerator == null && + !ReflectUtils.isPotentiallyAccessibleField(mappingField)) { + mappingField = ReflectUtils.makeAccessible(mappingField); } - if (mappingField.getType().isArray()) { - if (binField instanceof JBBPAbstractArrayField) { - if (binField instanceof JBBPFieldArrayStruct) { - // structure - final JBBPFieldArrayStruct structArray = (JBBPFieldArrayStruct) binField; - final Class componentType = mappingField.getType().getComponentType(); - - Object valueArray = getFieldValue(mappingClassInstance, mappingField); - - 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, mappingClass, mappingField, null); - } - - for (int i = 0; i < structArray.size(); i++) { - final Object curInstance = Array.get(valueArray, i); - if (curInstance == null) { - Array.set(valueArray, i, map(structArray.getElementAt(i), componentType, customFieldProcessor)); - } else { - Array.set(valueArray, i, map(structArray.getElementAt(i), curInstance, customFieldProcessor)); - } - } - setFieldValue(mappingClassInstance, mappingField, binField, valueArray); - } else { - // primitive - mapArrayField(mappingClassInstance, mappingField, (JBBPAbstractArrayField) binField, mappedAnno.bitOrder() == JBBPBitOrder.MSB0); - } - } else { - throw new JBBPMapperException("Can't map a non-array value to an array mapping field", binField, mappingClass, mappingField, null); - } - } else { - if (binField instanceof JBBPNumericField) { - mapNumericField(mappingClassInstance, mappingField, (JBBPNumericField) binField, mappedAnno.bitOrder() == JBBPBitOrder.MSB0); - } else if (binField instanceof JBBPFieldString) { - if (mappingField.getType().isPrimitive()) { - throw new JBBPMapperException("Can't map a string to a primitive mapping field", binField, mappingClass, mappingField, null); - } else { - setFieldValue(mappingClassInstance, mappingField, binField, ((JBBPFieldString)binField).getAsString()); - } - } else if (binField instanceof JBBPFieldStruct) { - if (mappingField.getType().isPrimitive()) { - throw new JBBPMapperException("Can't map a structure to a primitive mapping field", binField, mappingClass, mappingField, null); - } else { - final Object curValue = getFieldValue(mappingClassInstance, mappingField); - if (curValue == null) { - setFieldValue(mappingClassInstance, mappingField, binField, map((JBBPFieldStruct) binField, mappingField.getType(), customFieldProcessor)); - } else { - setFieldValue(mappingClassInstance, mappingField, binField, map((JBBPFieldStruct) binField, curValue, customFieldProcessor)); - } - } - } else { - boolean processed = false; - if (mappingField.getType() == String.class && binField instanceof JBBPAbstractArrayField) { - final String convertedValue = convertFieldValueToString((JBBPAbstractArrayField) binField); - if (convertedValue != null) { - setFieldValue(mappingClassInstance, mappingField, binField, convertedValue); - processed = true; - } - } - if (!processed) { - throw new JBBPMapperException("Can't map a field for its value incompatibility", binField, mappingClass, mappingField, null); - } - } + try { + result.add(new MappedFieldRecord(mappingField, fieldGenerator, fieldSetter, fieldGetter, + mappingClass, mappedAnno)); + } catch (IllegalStateException ex) { + throw new JBBPMapperException(ex.getMessage(), null, mappingClass, mappingField, ex); } } } + + Collections.sort(result); + + CACHED_FIELDS.put(mappingClass, result); } - return mappingClassInstance; - } - /** - * Convert an array field into its string representation. - * - * @param field an array field to be converted, must not be null - * @return the string representation of the array or null if the field can't - * be converted - */ - private static String convertFieldValueToString(final JBBPAbstractArrayField field) { - final StringBuilder result; - if (field instanceof JBBPFieldArrayBit) { - final JBBPFieldArrayBit array = (JBBPFieldArrayBit) field; - result = new StringBuilder(array.size()); - for (final byte b : array.getArray()) { - result.append((char) (b & 0xFF)); - } - } else if (field instanceof JBBPFieldArrayByte) { - final JBBPFieldArrayByte array = (JBBPFieldArrayByte) field; - result = new StringBuilder(array.size()); - for (final byte b : array.getArray()) { - result.append((char) (b & 0xFF)); - } - } else if (field instanceof JBBPFieldArrayUByte) { - final JBBPFieldArrayUByte array = (JBBPFieldArrayUByte) field; - result = new StringBuilder(array.size()); - for (final byte b : array.getArray()) { - result.append((char) (b & 0xFF)); - } - } else if (field instanceof JBBPFieldArrayShort) { - final JBBPFieldArrayShort array = (JBBPFieldArrayShort) field; - result = new StringBuilder(array.size()); - for (final short b : array.getArray()) { - result.append((char) b); - } - } else if (field instanceof JBBPFieldArrayUShort) { - final JBBPFieldArrayUShort array = (JBBPFieldArrayUShort) field; - result = new StringBuilder(array.size()); - for (final short b : array.getArray()) { - result.append((char) b); + if (binFieldFilter != null) { + final List filteredRecords = new ArrayList<>(); + for (final MappedFieldRecord r : result) { + if (binFieldFilter.isAllowed(r.binAnnotation, r.mappingField)) { + filteredRecords.add(r); + } } - } else { - result = null; + result = filteredRecords; } - return result == null ? null : result.toString(); - } - /** - * Set a value to a field of a class instance. Can't be used for static - * fields! - * - * @param classInstance a class instance - * @param classField a mapping class field which should be set by the value, - * must not be null - * @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 - */ - private static void setFieldValue(final Object classInstance, final Field classField, final JBBPAbstractField binField, final Object value) { - try { - classField.set(classInstance, value); - } catch (IllegalArgumentException 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); - } + return result; } - /** - * Get a value of a field from a class instance. - * - * @param classInstance a class instance object - * @param classField a class field which value must be returned, must not be - * null - * @return the field value for the class instance - */ - private static Object getFieldValue(final Object classInstance, final Field classField) { - try { - return classField.get(classInstance); - } catch (IllegalArgumentException 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); - } - } + 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; + final String setterName = "set" + lowerCasedFieldName; - /** - * Map a parsed primitive numeric field to a primitive field in a mapping - * class. - * - * @param mappingClassInstance the mapping class instance, must not be null - * @param mappingField a mapping field to set the value, must not be null - * @param numericField a parsed numeric field which value should be used, must - * not be null - * @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 Field mappingField, final JBBPNumericField numericField, final boolean invertBitOrder) { - final Class fieldClass = mappingField.getType(); - try { - if (fieldClass == byte.class) { - mappingField.setByte(mappingClassInstance, (byte) (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsInt())); - } else if (fieldClass == boolean.class) { - mappingField.setBoolean(mappingClassInstance, numericField.getAsBool()); - } else if (fieldClass == char.class) { - mappingField.setChar(mappingClassInstance, (char) (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsInt())); - } else if (fieldClass == short.class) { - mappingField.setShort(mappingClassInstance, (short) (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsInt())); - } else if (fieldClass == int.class) { - mappingField.setInt(mappingClassInstance, (int) (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsInt())); - } else if (fieldClass == long.class) { - mappingField.setLong(mappingClassInstance, (invertBitOrder ? numericField.getAsInvertedBitOrder() : numericField.getAsLong())); - } else if (fieldClass == float.class) { - if (numericField instanceof JBBPFieldInt) { - mappingField.setFloat(mappingClassInstance, invertBitOrder ? Float.intBitsToFloat((int) numericField.getAsInvertedBitOrder()) : Float.intBitsToFloat(numericField.getAsInt())); - } else { - mappingField.setFloat(mappingClassInstance, invertBitOrder ? Float.intBitsToFloat((int) numericField.getAsInvertedBitOrder()) : numericField.getAsFloat()); - } - } else if (fieldClass == double.class) { - if (numericField instanceof JBBPFieldLong) { - mappingField.setDouble(mappingClassInstance, invertBitOrder ? Double.longBitsToDouble(numericField.getAsInvertedBitOrder()) : Double.longBitsToDouble(numericField.getAsLong())); - } else { - mappingField.setDouble(mappingClassInstance, invertBitOrder ? Double.longBitsToDouble(numericField.getAsInvertedBitOrder()) : numericField.getAsDouble()); - } - } else { - throw new JBBPMapperException("Unsupported mapping class field type to be mapped for binary parsed data", (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, null); + Method generator = null; + Method setter = null; + Method getter = null; + + for (final Method m : klazz.getMethods()) { + final Class[] args = m.getParameterTypes(); + final String lcMethodName = m.getName().toLowerCase(Locale.ENGLISH); + + if (!Modifier.isPublic(m.getModifiers()) || Modifier.isStatic(m.getModifiers())) { + continue; } - } catch (IllegalAccessException 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); - } - } - /** - * Map a parsed array to an array field in mapping class. - * - * @param mappingClassInstance a mapping class instance, must not be null - * @param mappingField a field in the mapping class to be set, must not be - * null - * @param arrayField a binary parsed array field, must not be null - * @param invertBitOrder flag shows that values of an array must be bit - * reversed before set - */ - private static void mapArrayField(final Object mappingClassInstance, final Field mappingField, final JBBPAbstractArrayField arrayField, final boolean invertBitOrder) { - try { - 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 (args.length == 0) { + if (generator == null && lcMethodName.equals(generatorName) + ) { + generator = m; } - mappingField.set(mappingClassInstance, 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]); + if (getter == null && lcMethodName.equals(getterName)) { + getter = m; } - mappingField.set(mappingClassInstance, 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]; - } - mappingField.set(mappingClassInstance, chararray); - } else { - mappingField.set(mappingClassInstance, arrayField.getValueArrayAsObject(invertBitOrder)); } - } catch (IllegalAccessException 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); - } - } - /** - * Makes an instance of a class without call of its constructor, just allocate - * memory - * - * @param a class which instance is needed - * @param root the structure to be mapped, it is needed as info for exception - * @param klazz the class which instance is needed - * @return an instance of the class without called constructor - * @throws JBBPMapperException it will be thrown if it is impossible to make - * an instance - */ - private static T allocateMemoryForClass(final JBBPFieldStruct root, final Class klazz) { - try { - return CLASS_INSTANTIATOR.makeClassInstance(klazz); - } catch (InstantiationException ex) { - throw new JBBPMapperException("Can't make an instance of a class", root, klazz, null, ex); + if (args.length == 1 && setter == null && lcMethodName.equals(setterName) && + field.getType().isAssignableFrom(args[0])) { + setter = m; + } + + if (generator != null && setter != null && getter != null) { + break; + } } + return new NullableTriple<>(generator, getter, setter); } } 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 new file mode 100644 index 00000000..07084e8c --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/MappedFieldRecord.java @@ -0,0 +1,625 @@ +package com.igormaznitsa.jbbp.mapper; + +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; +import com.igormaznitsa.jbbp.model.JBBPAbstractArrayField; +import com.igormaznitsa.jbbp.model.JBBPAbstractField; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayBit; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayInt; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayLong; +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; +import com.igormaznitsa.jbbp.model.JBBPFieldString; +import com.igormaznitsa.jbbp.model.JBBPFieldStruct; +import com.igormaznitsa.jbbp.model.JBBPNumericField; +import com.igormaznitsa.jbbp.utils.Function; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +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; + } + } 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, binFieldFilter, instantiators) -> { + + 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); + + 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); + } + + 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 { + // 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, 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 { + 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 { + 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); + } + } + }; + + public final Field mappingField; + public final Class mappingClass; + public final Method setter; + public final Method getter; + public final Method instanceMaker; + public final Bin binAnnotation; + public final boolean bitWideField; + public final String fieldName; + public final String fieldPath; + public final JBBPBitNumber mappedBitNumber; + public final BinType fieldType; + public final FieldProcessor proc; + + MappedFieldRecord(final Field mappingField, + final Method instanceMaker, + final Method setter, + final Method getter, + final Class mappingClass, + final Bin binAnnotation) { + this.instanceMaker = instanceMaker; + this.setter = setter; + this.getter = getter; + + this.mappingField = mappingField; + this.mappingClass = mappingClass; + this.binAnnotation = binAnnotation; + + this.mappedBitNumber = binAnnotation.bitNumber(); + + if (binAnnotation.type() == BinType.UNDEFINED) { + 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 && + !(compatibleBinType == BinType.STRUCT || compatibleBinType == BinType.STRUCT_ARRAY)) { + compatibleBinType = compatibleBinType.isArray() ? BinType.BIT_ARRAY : BinType.BIT; + } + this.fieldType = compatibleBinType; + } else { + this.fieldType = binAnnotation.type(); + } + this.bitWideField = this.fieldType == BinType.BIT || fieldType == BinType.BIT_ARRAY; + + this.fieldName = + binAnnotation.name().isEmpty() ? mappingField.getName() : binAnnotation.name(); + this.fieldPath = binAnnotation.path(); + + if (this.mappingField.getType().isArray()) { + this.proc = PROC_ARRAYS; + } else { + this.proc = PROC_NUM; + } + } + + /** + * Map a parsed array to an array field in mapping class. + * + * @param mappingClassInstance a mapping class instance, must not be null + * @param setter detected setter for the field, can be null + * @param mappingField a field in the mapping class to be set, must not be + * null + * @param arrayField a binary parsed array field, must not be null + * @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) { + 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]); + } + 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 = 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 = 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; + } else { + value = arrayField.getValueArrayAsObject(invertBitOrder); + } + if (setter == null) { + mappingField.set(mappingClassInstance, value); + } else { + setter.invoke(mappingClassInstance, value); + } + } catch (IllegalAccessException 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); + } catch (InvocationTargetException ex) { + throw new JBBPMapperException("Can't set argument to field through setter", arrayField, + mappingClassInstance.getClass(), mappingField, ex); + } + } + + /** + * Convert an array field into its string representation. + * + * @param field an array field to be converted, must not be null + * @return the string representation of the array or null if the field can't + * be converted + */ + private static String convertFieldValueToString(final JBBPAbstractArrayField field) { + final StringBuilder result; + if (field instanceof JBBPFieldArrayBit) { + final JBBPFieldArrayBit array = (JBBPFieldArrayBit) field; + result = new StringBuilder(array.size()); + for (final byte b : array.getArray()) { + result.append((char) (b & 0xFF)); + } + } else if (field instanceof JBBPFieldArrayByte) { + final JBBPFieldArrayByte array = (JBBPFieldArrayByte) field; + result = new StringBuilder(array.size()); + for (final byte b : array.getArray()) { + result.append((char) (b & 0xFF)); + } + } else if (field instanceof JBBPFieldArrayUByte) { + final JBBPFieldArrayUByte array = (JBBPFieldArrayUByte) field; + result = new StringBuilder(array.size()); + for (final byte b : array.getArray()) { + result.append((char) (b & 0xFF)); + } + } else if (field instanceof JBBPFieldArrayShort) { + final JBBPFieldArrayShort array = (JBBPFieldArrayShort) field; + result = new StringBuilder(array.size()); + for (final short b : array.getArray()) { + result.append((char) b); + } + } else if (field instanceof JBBPFieldArrayUShort) { + final JBBPFieldArrayUShort array = (JBBPFieldArrayUShort) field; + result = new StringBuilder(array.size()); + for (final short b : array.getArray()) { + result.append((char) b); + } + } else { + result = null; + } + return result == null ? null : result.toString(); + } + + /** + * Map a parsed primitive numeric field to a primitive field in a mapping + * class. + * + * @param mappingClassInstance the mapping class instance, must not be null + * @param setter detected setter for field, can be null + * @param mappingField a mapping field to set the value, must not be null + * @param numericField a parsed numeric field which value should be used, must + * not be null + * @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) { + final Class fieldClass = mappingField.getType(); + try { + if (fieldClass == byte.class) { + final byte value = (byte) (invertBitOrder ? numericField.getAsInvertedBitOrder() : + numericField.getAsInt()); + if (setter == null) { + mappingField.setByte(mappingClassInstance, value); + } else { + setter.invoke(mappingClassInstance, value); + } + } else if (fieldClass == boolean.class) { + if (setter == null) { + mappingField.setBoolean(mappingClassInstance, numericField.getAsBool()); + } else { + setter.invoke(mappingClassInstance, numericField.getAsBool()); + } + } else if (fieldClass == char.class) { + 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()); + 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()); + 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()); + if (setter == null) { + mappingField.setLong(mappingClassInstance, value); + } else { + setter.invoke(mappingClassInstance, value); + } + } else if (fieldClass == float.class) { + final float value; + if (numericField instanceof JBBPFieldInt) { + value = + invertBitOrder ? Float.intBitsToFloat((int) numericField.getAsInvertedBitOrder()) : + Float.intBitsToFloat(numericField.getAsInt()); + } else { + value = + invertBitOrder ? Float.intBitsToFloat((int) numericField.getAsInvertedBitOrder()) : + numericField.getAsFloat(); + } + if (setter == null) { + mappingField.setFloat(mappingClassInstance, value); + } else { + setter.invoke(mappingClassInstance, value); + } + } else if (fieldClass == double.class) { + final double value; + if (numericField instanceof JBBPFieldLong) { + value = invertBitOrder ? Double.longBitsToDouble(numericField.getAsInvertedBitOrder()) : + Double.longBitsToDouble(numericField.getAsLong()); + } else { + value = invertBitOrder ? Double.longBitsToDouble(numericField.getAsInvertedBitOrder()) : + numericField.getAsDouble(); + } + if (setter == null) { + mappingField.setDouble(mappingClassInstance, value); + } else { + 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); + } + } catch (IllegalAccessException 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); + } catch (InvocationTargetException ex) { + throw new JBBPMapperException("Can't set argument to a mapping field through setter", + (JBBPAbstractField) numericField, mappingClassInstance.getClass(), mappingField, ex); + } + } + + /** + * Get a value of a field from a class instance. + * + * @param classInstance a class instance object + * @param getter method to get field value, can be null + * @param classField a class field which value must be returned, must not be + * null + * @return the field value for the class instance + */ + private static Object getFieldValue(final Object classInstance, final Method getter, + final Field classField) { + try { + if (getter == null) { + return classField.get(classInstance); + } else { + return getter.invoke(classInstance); + } + } catch (IllegalArgumentException 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); + } catch (InvocationTargetException ex) { + throw new JBBPMapperException("Can't get field value through getter", null, + classInstance.getClass(), classField, ex); + } + } + + /** + * Set a value to a field of a class instance. Can't be used for static + * fields! + * + * @param classInstance a class instance + * @param setter setter for the field, can be null + * @param classField a mapping class field which should be set by the value, + * must not be null + * @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) { + try { + if (setter == null) { + classField.set(classInstance, value); + } else { + setter.invoke(classInstance, value); + } + } catch (IllegalArgumentException 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); + } catch (InvocationTargetException ex) { + throw new JBBPMapperException("Can't set field value through setter", binField, + classInstance.getClass(), classField, ex); + } + } + + private static T tryMakeInstance( + 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) { + result = type.cast(instantiator.apply(type)); + if (result != null) { + break; + } + } + + if (result == null) { + Exception detectedException = null; + try { + 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)); + } + } catch (NoSuchMethodException ex) { + // do nothing + } catch (IllegalAccessException ex) { + // 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); + } + + if (result == null) { + result = type.cast(STATIC_MAKE_CLASS_INSTANCE_INSTANTIATOR.apply(type)); + if (result == null) { + result = type.cast(DEFAULT_CONSTRUCTOR_INSTANTIATOR.apply(type)); + } + } + + if (result == null) { + throw new JBBPMapperException(String.format("Can't create instance of %s", type), binField, + mappingObject.getClass(), mappingField, null); + } + } + return result; + } + + @Override + public int compareTo(final MappedFieldRecord o) { + final int thisOrder = this.binAnnotation.order(); + final int thatOrder = o.binAnnotation.order(); + + final int result; + if (thisOrder == thatOrder) { + result = this.mappingField.getName().compareTo(o.mappingField.getName()); + } else { + result = thisOrder < thatOrder ? -1 : 1; + } + 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/mapper/instantiators/JBBPClassInstantiatorFactory.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorFactory.java deleted file mode 100644 index 7813d5f9..00000000 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorFactory.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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.mapper.instantiators; - -import com.igormaznitsa.jbbp.utils.JBBPSystemProperty; -import com.igormaznitsa.jbbp.utils.JBBPUtils; -import com.igormaznitsa.jbbp.utils.ReflectUtils; - -/** - * The Factory produces a class instantiator which is compatible with the - * current platform. - * - * @since 1.0 - */ -@SuppressWarnings("LiteralClassName") -public final class JBBPClassInstantiatorFactory { - - /** - * The Factory INSTANCE. - */ - private static final JBBPClassInstantiatorFactory INSTANCE = new JBBPClassInstantiatorFactory(); - - /** - * The Hidden constructor. - */ - private JBBPClassInstantiatorFactory() { - - } - - /** - * Get the factory INSTANCE. - * - * @return the factory INSTANCE, must not be null - */ - public static JBBPClassInstantiatorFactory getInstance() { - return INSTANCE; - } - - /** - * Make an instantiator automatically for the current platform. - * - * @return the class instantiator INSTANCE which is compatible with the - * current platform - * @see JBBPClassInstantiator - */ - public JBBPClassInstantiator make() { - return this.make(JBBPClassInstantiatorType.AUTO); - } - - /** - * Make an instantiator for defined type. - * - * @param type the type of needed instantiator, must not be null - * @return the class instantiator INSTANCE which is compatible with the - * current platform - */ - public JBBPClassInstantiator make(final JBBPClassInstantiatorType type) { - JBBPUtils.assertNotNull(type, "Type must not be null"); - - String className = "com.igormaznitsa.jbbp.mapper.instantiators.JBBPSafeInstantiator"; - - switch (type) { - case AUTO: { - final String customClassName = JBBPSystemProperty.PROPERTY_INSTANTIATOR_CLASS.getAsString(null); - if (customClassName == null) { - try { - final Class unsafeclazz = Class.forName("sun.misc.Unsafe"); - unsafeclazz.getDeclaredField("theUnsafe"); - className = "com.igormaznitsa.jbbp.mapper.instantiators.JBBPUnsafeInstantiator"; - } catch (ClassNotFoundException ex) { - // do nothing - } catch (NoSuchFieldException ex) { - // do nothing - } catch (SecurityException ex) { - // do nothing - } - } else { - className = customClassName; - } - } - break; - case SAFE: { - className = "com.igormaznitsa.jbbp.mapper.instantiators.JBBPSafeInstantiator"; - } - break; - case UNSAFE: { - className = "com.igormaznitsa.jbbp.mapper.instantiators.JBBPUnsafeInstantiator"; - } - break; - default: - throw new Error("Unexpected type, contact developer! [" + type + ']'); - } - - return JBBPClassInstantiator.class.cast(ReflectUtils.newInstanceForClassName(className)); - } -} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPSafeInstantiator.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPSafeInstantiator.java deleted file mode 100644 index 508730d2..00000000 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPSafeInstantiator.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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.mapper.instantiators; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; - -/** - * Class creates instances of classes through call of their default - * constructors, it works without any magic but through reflection thus inner - * class instances will be with null instead of instance of enclosing class. - * - * @since 1.0 - */ -public final class JBBPSafeInstantiator implements JBBPClassInstantiator { - - /** - * Predefined empty object array. - */ - private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; - - /** - * Check that a class is an inner one. - * - * @param klazz a class to be checked, must not be null - * @return true if the class is inner one, false otherwise - */ - private static boolean isInnerClass(final Class klazz) { - return klazz.isMemberClass() && !Modifier.isStatic(klazz.getModifiers()); - } - - /** - * Make stub arguments for a constructor. - * - * @param constructorParamTypes types of constructor arguments, must not be - * null - * @return generated Object array contains stub values for the constructor, - * must not be null - */ - private static Object[] makeStubForConstructor(final Class[] constructorParamTypes) { - if (constructorParamTypes.length == 0) { - return EMPTY_OBJECT_ARRAY; - } - final Object[] result = new Object[constructorParamTypes.length]; - for (int i = 0; i < constructorParamTypes.length; i++) { - final Class arg = constructorParamTypes[i]; - final Object obj; - if (arg.isArray()) { - obj = null; - } else { - if (arg == byte.class) { - obj = (byte) 0; - } else if (arg == char.class) { - obj = 'a'; - } else if (arg == short.class) { - obj = (short) 0; - } else if (arg == boolean.class) { - obj = Boolean.FALSE; - } else if (arg == int.class) { - obj = 0; - } else if (arg == long.class) { - obj = 0L; - } else if (arg == double.class) { - obj = 0.0d; - } else if (arg == float.class) { - obj = 0.0f; - } else { - obj = null; - } - } - result[i] = obj; - } - return result; - } - - /** - * Find a constructor for an inner class. - * - * @param klazz a class to find a constructor, must not be null - * @param declaringClass the declaring class for the class, must not be null - * @return found constructor to be used to make an instance - */ - private static Constructor findConstructorForInnerClass(final Class klazz, final Class declaringClass) { - final Constructor[] constructors = klazz.getDeclaredConstructors(); - if (constructors.length == 1) { - return constructors[0]; - } - for (final Constructor c : constructors) { - final Class[] params = c.getParameterTypes(); - if (params.length == 1 && params[0] == declaringClass) { - return c; - } - } - return constructors[0]; - } - - /** - * Find a constructor for a static class. - * - * @param klazz a class to find a constructor, must not be null - * @return found constructor to be used to make an instance - */ - private static Constructor findConstructorForStaticClass(final Class klazz) { - final Constructor[] constructors = klazz.getDeclaredConstructors(); - if (constructors.length == 1) { - return constructors[0]; - } - for (final Constructor c : constructors) { - final Class[] params = c.getParameterTypes(); - if (params.length == 0) { - return c; - } - } - return constructors[0]; - } - - @Override - public T makeClassInstance(final Class klazz) throws InstantiationException { - try { - if (isInnerClass(klazz) || klazz.isLocalClass()) { - final Class declaringClass = klazz.getEnclosingClass(); - final Constructor constructor = findConstructorForInnerClass(klazz, declaringClass); - constructor.setAccessible(true); - return klazz.cast(constructor.newInstance(makeStubForConstructor(constructor.getParameterTypes()))); - } else { - final Constructor constructor = findConstructorForStaticClass(klazz); - constructor.setAccessible(true); - return klazz.cast(constructor.newInstance(makeStubForConstructor(constructor.getParameterTypes()))); - } - } catch (SecurityException ex) { - throw new InstantiationException("Can't get access to the default constructor for class '" + klazz.getName() + "\' [" + ex + ']'); - } catch (IllegalArgumentException ex) { - throw new InstantiationException("Can't make class '" + klazz.getName() + "\' [" + ex + ']'); - } catch (InvocationTargetException ex) { - throw new InstantiationException("Can't make class '" + klazz.getName() + "\' [" + ex + ']'); - } catch (IllegalAccessException ex) { - throw new InstantiationException("Can't make instance of class '" + klazz.getName() + "' for access exception [" + ex + ']'); - } - } - -} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPUnsafeInstantiator.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPUnsafeInstantiator.java deleted file mode 100644 index 0350a721..00000000 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPUnsafeInstantiator.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.mapper.instantiators; - -import com.igormaznitsa.jbbp.utils.JBBPUtils; -import com.igormaznitsa.jbbp.utils.ReflectUtils; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * The Class instantiate a class through sun.misc.unsafe without any call of - * class constructors. To be more safe during porting to another platforms, all - * work with sun,misc,unsafe organized through reflection to not have static - * links the the class. - * - * @since 1.0 - */ -@SuppressWarnings("LiteralClassName") -public final class JBBPUnsafeInstantiator implements JBBPClassInstantiator { - - /** - * The sun,misc.Unsafe object. - */ - private static final Object SUN_MISC_UNSAFE; - /** - * The sun,misc.Unsafe.allocateInstance method. - */ - private static final Method ALLOCATE_INSTANCE_METHOD; - - static { - try { - final Class unsafeClass = Class.forName("sun.misc.Unsafe"); - final Field singletoneInstanceField = ReflectUtils.makeAccessible(unsafeClass.getDeclaredField("theUnsafe")); - SUN_MISC_UNSAFE = singletoneInstanceField.get(null); - ALLOCATE_INSTANCE_METHOD = ReflectUtils.makeAccessible(unsafeClass.getMethod("allocateInstance", Class.class)); - } catch (ClassNotFoundException e) { - throw new Error("Can't find 'sun.misc.Unsafe' class", e); - } catch (IllegalAccessException e) { - throw new Error("Can't get sun.misc.Unsafe for illegal access", e); - } catch (IllegalArgumentException e) { - throw new Error("Can't get sun.misc.Unsafe for wrong argument", e); - } catch (NoSuchFieldException e) { - throw new Error("Can't get sun.misc.Unsafe because it doesn't exist", e); - } catch (SecurityException e) { - throw new Error("Can't get sun.misc.Unsafe for security exception", e); - } catch (NoSuchMethodException e) { - throw new Error("Can't get the 'allocateInstance' method in sun.misc.Unsafe", e); - } - } - - @Override - public T makeClassInstance(final Class klazz) throws InstantiationException { - JBBPUtils.assertNotNull(klazz, "Class must not be null"); - try { - return klazz.cast(ALLOCATE_INSTANCE_METHOD.invoke(SUN_MISC_UNSAFE, klazz)); - } catch (InvocationTargetException ex) { - final Throwable cause = ex.getTargetException(); - if (cause instanceof InstantiationException) { - throw (InstantiationException) cause; - } else { - throw new InstantiationException("Can't instantiate class for exception [" + ex + ']'); - } - } catch (IllegalAccessException ex) { - throw new InstantiationException("Can't instantiate class for exception [" + ex + ']'); - } catch (IllegalArgumentException ex) { - throw new InstantiationException("Can't instantiate class for exception [" + ex + ']'); - } - } - -} 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 96a5c887..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; @@ -74,7 +75,7 @@ public JBBPBitNumber getBitWidth() { @Override public double getAsDouble() { - return (double) (this.value & 0xFF); + return this.value & 0xFF; } @Override diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldByte.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldByte.java index 37297ad2..e91d7f83 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldByte.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldByte.java @@ -54,12 +54,12 @@ public static long reverseBits(final byte value) { @Override public double getAsDouble() { - return (double) this.value; + return this.value; } @Override public float getAsFloat() { - return (float) this.value; + return this.value; } @Override diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldFloat.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldFloat.java index fb256a23..03ab67b5 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldFloat.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldFloat.java @@ -49,7 +49,7 @@ public float getAsFloat() { @Override public double getAsDouble() { - return (double) this.value; + return this.value; } @Override diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldInt.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldInt.java index a35e94bd..c410de18 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldInt.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldInt.java @@ -54,7 +54,7 @@ public static long reverseBits(final int value) { final int b2 = JBBPUtils.reverseBitsInByte((byte) (value >> 16)) & 0xFF; final int b3 = JBBPUtils.reverseBitsInByte((byte) (value >> 24)) & 0xFF; - return (long) ((b0 << 24) | (b1 << 16) | (b2 << 8) | b3); + return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; } @Override @@ -64,7 +64,7 @@ public int getAsInt() { @Override public double getAsDouble() { - return (double) this.value; + return this.value; } @Override 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/JBBPFieldShort.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldShort.java index 91958300..14269588 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldShort.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/model/JBBPFieldShort.java @@ -52,17 +52,17 @@ public static long reverseBits(final short value) { final int b0 = JBBPUtils.reverseBitsInByte((byte) value) & 0xFF; final int b1 = JBBPUtils.reverseBitsInByte((byte) (value >> 8)) & 0xFF; - return (long) ((short) (b0 << 8) | (short) b1); + return (short) (b0 << 8) | (short) b1; } @Override public double getAsDouble() { - return (double) this.value; + return this.value; } @Override public float getAsFloat() { - return (float) this.value; + return this.value; } @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 fields) { - this(name, fields.toArray(new JBBPAbstractField[fields.size()])); + this(name, fields.toArray(ARRAY_FIELD_EMPTY)); } /** @@ -73,7 +76,8 @@ public JBBPAbstractField[] getArray() { @Override public JBBPAbstractField findFieldForPath(final String fieldPath) { - final String[] parsedName = JBBPUtils.splitString(JBBPUtils.normalizeFieldNameOrPath(fieldPath), '.'); + final String[] parsedName = + JBBPUtils.splitString(JBBPUtils.normalizeFieldNameOrPath(fieldPath), '.'); JBBPAbstractField found = this; final int firstIndex; @@ -81,7 +85,6 @@ public JBBPAbstractField findFieldForPath(final String fieldPath) { firstIndex = 0; } else if (parsedName[0].equals(this.getNameInfo().getFieldName())) { firstIndex = 1; - found = this; } else { firstIndex = 0; found = null; @@ -91,7 +94,9 @@ public JBBPAbstractField findFieldForPath(final String fieldPath) { if (found instanceof JBBPFieldStruct) { found = ((JBBPFieldStruct) found).findFieldForName(parsedName[i]); } else { - throw new JBBPFinderException("Detected a field instead of a structure as one of nodes in the path '" + fieldPath + '\'', fieldPath, null); + throw new JBBPFinderException( + "Detected a field instead of a structure as one of nodes in the path '" + fieldPath + + '\'', fieldPath, null); } } @@ -128,7 +133,8 @@ public 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; } @@ -161,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; @@ -206,8 +213,8 @@ public boolean pathExists(final String fieldPath) { } @Override - @SuppressWarnings("unchecked") - 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; @@ -219,179 +226,240 @@ public T findFieldForPathAndType(final String fiel } /** - * Map the structure fields to a class fields. + * Find a structure by its path and map the structure fields to a class + * fields. * - * @param a class type - * @param mappingClass a mapping class to be mapped by the structure fields, - * must not be null and must have the default constructor + * @param a class type + * @param path the path to the structure to be mapped, must not be null + * @param instance object instance to be filled by values, must not be null + * @param instantiators array of functions which can instantiate object of required class, must not be null * @return a mapped instance of the class, must not be null + * @since 2.0.0 */ - public T mapTo(final Class mappingClass) { - return mapTo(mappingClass, null); + @SafeVarargs + public final T mapTo(final String path, final T instance, + final Function, Object>... instantiators) { + return JBBPMapper.map(this, path, instance, instantiators); } /** - * Map the structure fields to a class fields. + * Find a structure by its path and map the structure fields to a class + * fields. * - * @param a class type - * @param mappingClass a mapping class to be mapped by the structure fields, - * must not be null and must have the default constructor - * @param flags special flags to tune mapping + * @param a class type + * @param path the path to the structure to be mapped, must not be null + * @param instance object instance to be filled by values, must not be null + * @param flags special flags to tune mapping process + * @param instantiators array of functions which can instantiate object of required class, must not be null * @return a mapped instance of the class, must not be null + * @see JBBPMapper#FLAG_IGNORE_MISSING_VALUES + * @since 2.0.0 */ - public T mapTo(final Class mappingClass, final int flags) { - return mapTo(mappingClass, null, flags); + @SafeVarargs + 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); } /** - * Map the structure fields to a class fields. + * Find a structure by its path and map the structure fields to a class + * fields. * * @param a class type - * @param mappingClass a mapping class to be mapped by the structure fields, - * must not be null and must have the default constructor - * @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 path the path to the structure to be mapped, must not be null + * @param instance object instance to be filled by values, 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 instantiators array of functions which can instantiate object of required class, must not be null * @return a mapped instance of the class, must not be null + * @since 2.0.0 */ - public T mapTo(final Class mappingClass, final JBBPMapperCustomFieldProcessor customFieldProcessor) { - return JBBPMapper.map(this, mappingClass, customFieldProcessor); + @SafeVarargs + 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); } /** - * Map the structure fields to a class fields. + * Find a structure by its path and map the structure fields to a class + * fields. * * @param a class type - * @param mappingClass a mapping class to be mapped by the structure fields, - * must not be null and must have the default constructor - * @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 path the path to the structure to be mapped, must not be null + * @param instance object instance to be filled by values, 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 instantiators array of functions which can instantiate object of required class, must not be null * @return a mapped instance of the class, must not be null + * @see JBBPMapper#FLAG_IGNORE_MISSING_VALUES + * @since 2.0.0 */ - public T mapTo(final Class mappingClass, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags) { - return JBBPMapper.map(this, mappingClass, customFieldProcessor, flags); + @SafeVarargs + 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); } /** - * Find a structure by its path and map the structure fields to a class - * fields. + * Map the structure fields to object fields. * - * @param a class type - * @param path the path to the structure to be mapped, must not be null - * @param mappingClass a mapping class to be mapped by the structure fields, - * must not be null and must have the default constructor - * @return a mapped instance of the class, must not be null + * @param expected result type + * @param objectToMap an object to map fields of the structure, must not 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 */ - public T mapTo(final String path, final Class mappingClass) { - return JBBPMapper.map(this, path, mappingClass); + @SafeVarargs + public final T mapTo(final T objectToMap, final Function, Object>... instantiators) { + return this.mapTo(objectToMap, (JBBPMapperCustomFieldProcessor) null, instantiators); } /** - * Find a structure by its path and map the structure fields to a class - * fields. + * Map the structure fields to object fields. * - * @param a class type - * @param path the path to the structure to be mapped, must not be null - * @param mappingClass a mapping class to be mapped by the structure fields, - * must not be null and must have the default constructor - * @param flags special flags to tune mapping process - * @return a mapped instance of the class, must not be null - * @see JBBPMapper#FLAG_IGNORE_MISSING_VALUES - * @since 1.1 + * @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 */ - public T mapTo(final String path, final Class mappingClass, final int flags) { - return JBBPMapper.map(this, path, mappingClass, flags); + @SafeVarargs + public final T mapTo(final T objectToMap, final BinFieldFilter binFieldFilter, final Function, Object>... instantiators) { + return this.mapTo(objectToMap, null, binFieldFilter, instantiators); } /** - * Find a structure by its path and map the structure fields to a class - * fields. + * Map the structure fields to object fields. * - * @param a class type - * @param path the path to the structure to be mapped, must not be null - * @param mappingClass a mapping class to be mapped by the structure fields, - * must not be null and must have the default constructor - * @param customFieldProcessor a custom field processor to provide values for custom mapping fields, it can be null if there is not any custom field - * @return a mapped instance of the class, must not be null + * @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 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.0 */ - public T mapTo(final String path, final Class mappingClass, final JBBPMapperCustomFieldProcessor customFieldProcessor) { - return JBBPMapper.map(this, path, mappingClass, customFieldProcessor); + @SafeVarargs + public final T mapTo(final T instance, final int flags, + final Function, Object>... instantiators) { + return this.mapTo(instance, null, flags, instantiators); } /** - * Find a structure by its path and map the structure fields to a class - * fields. + * Map the structure fields to object fields. * - * @param a class type - * @param path the path to the structure to be mapped, must not be null - * @param mappingClass a mapping class to be mapped by the structure fields, - * must not be null and must have the default constructor - * @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 - * @return a mapped instance of the class, must not be null + * @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 1.1 + * @since 2.0.4 */ - public T mapTo(final String path, final Class mappingClass, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags) { - return JBBPMapper.map(this, path, mappingClass, customFieldProcessor, flags); + @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. * - * @param objectToMap an object to map fields of the structure, must not be - * null + * @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 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 */ - public Object mapTo(final Object objectToMap) { - return this.mapTo(objectToMap, null); + @SafeVarargs + 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 objectToMap an object to map fields of the structure, must not be - * null - * @param flags special flags to tune mapping process + * @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 - * @see JBBPMapper#FLAG_IGNORE_MISSING_VALUES - * @since 1.1 + * @since 2.0.4 */ - public Object mapTo(final Object objectToMap, final int flags) { - return this.mapTo(objectToMap, null, flags); + @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. * + * @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 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 1.1 */ - public Object mapTo(final Object objectToMap, final JBBPMapperCustomFieldProcessor customFieldProcessor) { - return JBBPMapper.map(this, objectToMap, customFieldProcessor); + @SafeVarargs + 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 1.1 + * @since 2.0.4 */ - public Object mapTo(final Object objectToMap, final JBBPMapperCustomFieldProcessor customFieldProcessor, final int flags) { - return JBBPMapper.map(this, objectToMap, customFieldProcessor, flags); + @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 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 6c8000cb..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 */ @@ -54,7 +54,7 @@ public static long reverseBits(final byte value) { @Override public double getAsDouble() { - return (double) (this.value & 0xFF); + return this.value & 0xFF; } @Override 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 d789f387..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 */ @@ -57,7 +57,7 @@ public static long reverseBits(final short value) { @Override public double getAsDouble() { - return (double) (this.value & 0xFFFF); + return this.value & 0xFFFF; } @Override 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/mapper/instantiators/JBBPClassInstantiator.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/Function.java similarity index 50% rename from jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiator.java rename to jbbp/src/main/java/com/igormaznitsa/jbbp/utils/Function.java index ab2b8217..c77ca8b1 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiator.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/Function.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Igor Maznitsa. + * Copyright 2019 Igor Maznitsa. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,21 +14,15 @@ * limitations under the License. */ -package com.igormaznitsa.jbbp.mapper.instantiators; +package com.igormaznitsa.jbbp.utils; /** - * Interface describes a memory allocator for Java classes. + * Auxiliary functional interface. Added to support Android 3. * - * @since 1.0 + * @param the type of the input to the function + * @param the type of the result of the function + * @since 2.0.0 */ -public interface JBBPClassInstantiator { - /** - * Allocate memory area for a class. - * - * @param the class type - * @param klazz the class which should be instantiated, must not be null - * @return an instance of the class - * @throws InstantiationException it will be thrown if the class can;t be instantiated - */ - T makeClassInstance(Class klazz) throws InstantiationException; +public interface Function { + 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 3f87a533..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,13 +16,15 @@ 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; @@ -42,7 +44,7 @@ public class JBBPCustomFieldTypeProcessorAggregator implements JBBPCustomFieldTy * @param processors processors which should be joined. */ public JBBPCustomFieldTypeProcessorAggregator(final JBBPCustomFieldTypeProcessor... processors) { - this.customTypeMap = new HashMap(); + this.customTypeMap = new HashMap<>(); for (final JBBPCustomFieldTypeProcessor p : processors) { for (final String s : p.getCustomFieldTypes()) { JBBPUtils.assertNotNull(s, "Type must not be null"); @@ -52,7 +54,7 @@ public JBBPCustomFieldTypeProcessorAggregator(final JBBPCustomFieldTypeProcessor this.customTypeMap.put(s, p); } } - this.types = this.customTypeMap.keySet().toArray(new String[this.customTypeMap.size()]); + this.types = this.customTypeMap.keySet().toArray(ARRAY_STRING_EMPTY); } @Override @@ -61,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 14a1917d..2d076c07 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilder.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilder.java @@ -5,7 +5,6 @@ import com.igormaznitsa.jbbp.io.JBBPByteOrder; import com.igormaznitsa.jbbp.mapper.Bin; import com.igormaznitsa.jbbp.mapper.BinType; - import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -26,7 +25,7 @@ public class JBBPDslBuilder { /** * The List contains items added into builder. */ - protected final List items = new ArrayList(); + protected final List items = new ArrayList<>(); /** * The Variable contains current byte order for all next fields. @@ -53,39 +52,11 @@ public static JBBPDslBuilder Begin() { return new JBBPDslBuilder(); } - protected void addItem(final Item item) { - if (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.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; @@ -93,13 +64,19 @@ protected static String assertTextNotNullAndTrimmedNotEmpty(final String text) { protected static String assertNameIfNotNull(final String name) { if (name != null) { + if (name.equals("_")) { + throw new IllegalArgumentException("Only underscore is not allowed as name"); + } + for (int i = 0; i < name.length(); i++) { final char c = name.charAt(i); - if (i == 0 && (Character.isDigit(c))) { + if (i == 0 && Character.isDigit(c)) { throw new IllegalArgumentException("Digit can't be first char"); } + if (!Character.isLetterOrDigit(c) && c != '_') { - throw new IllegalArgumentException("Only letters and digits allowed: " + name); + throw new IllegalArgumentException( + "Only letters, digits and underscore allowed: " + name); } } } @@ -111,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"); } @@ -146,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'); @@ -156,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. * @@ -424,6 +434,7 @@ public JBBPDslBuilder VarArray(final String sizeExpression) { /** * Create named var array with fixed size. * + * @param name name of the array, can be null for anonymous one * @param size size of the array, if negative then read till end of stream. * @return the builder instance, must not be null */ @@ -462,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); } @@ -505,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) { @@ -521,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); } @@ -534,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); @@ -710,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); @@ -726,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); @@ -1271,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. * @@ -1284,13 +1310,38 @@ public JBBPDslBuilder Double(final String name) { } /** - * Add comment. + * 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. * * @param text text of comment, can be null * @return the builder instance, must not be null */ public JBBPDslBuilder Comment(final String text) { - this.addItem(new ItemComment(text == null ? "" : text)); + this.addItem(new ItemComment(text == null ? "" : text, false)); + return this; + } + + /** + * Add comment which will be placed on new line. + * + * @param text text of comment, can be null + * @return the builder instance, must not be null + * @since 1.4.1 + */ + public JBBPDslBuilder NewLineComment(final String text) { + this.addItem(new ItemComment(text == null ? "" : text, true)); return this; } @@ -1314,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. * @@ -1325,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. * @@ -1339,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. * @@ -1351,6 +1440,7 @@ public JBBPDslBuilder String() { /** * Add named string field. * + * @param name name of field, can be null for anonymous one * @return the builder instance, must not be null */ public JBBPDslBuilder String(final String name) { @@ -1428,7 +1518,7 @@ public String End() { /** * Build a formatted script. * - * @param format if true then make some formatting of result, false if unformatted version allowed + * @param format if true then make some formatting of result, false if non-formatted version allowed * @return script in formatted form, must not be null * @throws IllegalStateException if there is an unclosed struct */ @@ -1444,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; @@ -1469,24 +1561,54 @@ 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(':' + 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) { - doTabs(format, buffer, structCounter).append("// ").append(item.name.replace("\n", " ")); + 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).isEmpty()) { + buffer.append('\n'); + } + } + doTabs(format, buffer, structCounter).append("// ").append(commentText); + } else { + final String current = buffer.toString(); + if (current.endsWith(";\n") || current.endsWith("}\n")) { + buffer.setLength(buffer.length() - 1); + } + final int lastCommentIndex = buffer.lastIndexOf("//"); + if (lastCommentIndex < 0) { + buffer.append("// "); + } else if (buffer.lastIndexOf("\n") > lastCommentIndex) { + buffer.append("// "); + } else { + buffer.append(' '); + } + buffer.append(commentText); + } } else { throw new IllegalArgumentException("Unexpected item : " + item.getClass().getName()); } } break; default: { - doTabs(format, buffer, structCounter).append(item.toString()); + doTabs(format, buffer, structCounter).append(item); } break; } @@ -1505,34 +1627,50 @@ 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 BinFieldContainer result = new BinFieldContainer(annotatedClass, defautBin, null); + final Bin defaultBin = annotatedClass.getAnnotation(Bin.class); - final Class parent = annotatedClass.getSuperclass(); + final BinFieldContainer result; + if (defaultBin != null) { + result = new BinFieldContainer(annotatedClass, defaultBin, true, null); + } else { + result = new BinFieldContainer(annotatedClass, null); + } + + final Class superClass = annotatedClass.getSuperclass(); - if (parent != null && parent != Object.class) { - final BinFieldContainer parentFields = collectAnnotatedFields(parent); + 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) { - final Bin binAnno = f.getAnnotation(Bin.class); - if (binAnno != null || defautBin != null) { - final Class type = f.getType().isArray() ? f.getType().getComponentType() : f.getType(); + if ((f.getModifiers() & + (Modifier.NATIVE | Modifier.STATIC | Modifier.FINAL | Modifier.PRIVATE | + Modifier.TRANSIENT)) == 0) { + final Bin foundFieldBin = f.getAnnotation(Bin.class); + + if (foundFieldBin != null || defaultBin != null) { + validateAnnotatedField(defaultBin, foundFieldBin, f); + + final Class type = + f.getType().isArray() ? f.getType().getComponentType() : f.getType(); if (type.isPrimitive() || type == String.class) { - final Bin foundBin = binAnno == null ? defautBin : binAnno; - result.addField(foundBin, f); + if (foundFieldBin != null) { + result.addBinField(foundFieldBin, true, f); + } else { + result.addBinField(defaultBin, false, f); + } } else { final BinFieldContainer container = collectAnnotatedFields(type); if (!container.fields.isEmpty()) { - if (binAnno != null) { - container.bin = binAnno; + if (foundFieldBin != null) { + container.bin = foundFieldBin; + container.fieldLocalAnnotation = true; } container.field = f; - result.addContaner(container); + result.addContainer(container); } } } @@ -1542,12 +1680,29 @@ protected BinFieldContainer collectAnnotatedFields(final Class annotatedClass result.sort(); if (!result.fields.isEmpty()) { - result.addContaner(BinFieldContainer.END_STRUCT); + result.addContainer(BinFieldContainer.END_STRUCT); } return result; } + private void validateAnnotatedField( + final Bin defaultBin, + final Bin fieldBin, + final Field field + ) { + //TODO + + final Bin bin = fieldBin == null ? defaultBin : fieldBin; + if ((bin.type() == BinType.UNDEFINED + && field.getType().isArray() + || bin.type().name().endsWith("_ARRAY")) + && bin.arraySizeExpr().isEmpty()) { + throw new IllegalArgumentException( + field.toString() + ": missing expression in Bin#arraySizeExpression"); + } + } + /** * Convert an annotated class into its JBBP DSL representation. * NB! the method creates structure bases on class name, so that it can't be used for auto-mapping @@ -1575,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; @@ -1583,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(); } } @@ -1608,25 +1764,25 @@ class Pair { this.Struct(collected.getName()); } - final List stack = new ArrayList(); + final List stack = new ArrayList<>(); stack.add(new Pair(collected)); 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.isArray()) { - this.StructArray(conty.getName(), conty.bin.extra()); + if (field.isArrayField()) { + 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 { @@ -1634,11 +1790,21 @@ class Pair { this.ByteOrder(pair.container.getByteOrder(field)); switch (type) { case BIT_ARRAY: { - this.BitArray(field.getName(), pair.container.getBitNumber(field), field.bin.extra()); + if (field.bin.paramExpr().isEmpty()) { + this.BitArray(field.getName(), pair.container.getBitNumber(field), + field.bin.arraySizeExpr()); + } else { + this.CustomArray("bit", field.getName(), field.bin.arraySizeExpr(), + field.bin.paramExpr()); + } } break; case BIT: { - this.Bits(field.getName(), pair.container.getBitNumber(field)); + if (field.bin.paramExpr().isEmpty()) { + this.Bits(field.getName(), pair.container.getBitNumber(field)); + } else { + this.Custom("bit", field.getName(), field.bin.paramExpr()); + } } break; case BOOL: { @@ -1646,7 +1812,7 @@ class Pair { } break; case BOOL_ARRAY: { - this.BoolArray(field.getName(), field.bin.extra()); + this.BoolArray(field.getName(), field.bin.arraySizeExpr()); } break; case BYTE: { @@ -1654,7 +1820,7 @@ class Pair { } break; case BYTE_ARRAY: { - this.ByteArray(field.getName(), field.bin.extra()); + this.ByteArray(field.getName(), field.bin.arraySizeExpr()); } break; case UBYTE: { @@ -1662,7 +1828,7 @@ class Pair { } break; case UBYTE_ARRAY: { - this.UByteArray(field.getName(), field.bin.extra()); + this.UByteArray(field.getName(), field.bin.arraySizeExpr()); } break; case SHORT: { @@ -1670,7 +1836,7 @@ class Pair { } break; case SHORT_ARRAY: { - this.ShortArray(field.getName(), field.bin.extra()); + this.ShortArray(field.getName(), field.bin.arraySizeExpr()); } break; case USHORT: { @@ -1678,7 +1844,7 @@ class Pair { } break; case USHORT_ARRAY: { - this.UShortArray(field.getName(), field.bin.extra()); + this.UShortArray(field.getName(), field.bin.arraySizeExpr()); } break; case INT: { @@ -1686,7 +1852,7 @@ class Pair { } break; case INT_ARRAY: { - this.IntArray(field.getName(), field.bin.extra()); + this.IntArray(field.getName(), field.bin.arraySizeExpr()); } break; case LONG: { @@ -1694,7 +1860,7 @@ class Pair { } break; case LONG_ARRAY: { - this.LongArray(field.getName(), field.bin.extra()); + this.LongArray(field.getName(), field.bin.arraySizeExpr()); } break; case FLOAT: { @@ -1702,7 +1868,7 @@ class Pair { } break; case FLOAT_ARRAY: { - this.FloatArray(field.getName(), field.bin.extra()); + this.FloatArray(field.getName(), field.bin.arraySizeExpr()); } break; case DOUBLE: { @@ -1710,7 +1876,7 @@ class Pair { } break; case DOUBLE_ARRAY: { - this.DoubleArray(field.getName(), field.bin.extra()); + this.DoubleArray(field.getName(), field.bin.arraySizeExpr()); } break; case STRING: { @@ -1718,13 +1884,30 @@ class Pair { } break; case STRING_ARRAY: { - this.StringArray(field.getName(), field.bin.extra()); + this.StringArray(field.getName(), field.bin.arraySizeExpr()); + } + break; + case UNDEFINED: { + 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()); + } else { + this.Custom(field.bin.customType(), field.getName(), field.bin.arraySizeExpr()); + } + } } break; - default: + default: { throw new Error("Unexpected type:" + type); + } } } + final String comment = field.getComment(); + if (!comment.isEmpty()) { + this.Comment(comment); + } } } @@ -1753,7 +1936,8 @@ protected static class Item { Item(final BinType type, final String name, final JBBPByteOrder byteOrder) { this.type = type; - this.name = name == null ? name : assertNameIfNotNull(assertTextNotNullAndTrimmedNotEmpty(name)).trim(); + this.name = name == null ? null : + assertNameIfNotNull(assertTextNotNullAndTrimmedNotEmpty(name)).trim(); this.byteOrder = byteOrder; } @@ -1808,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); } @@ -1833,17 +2017,33 @@ protected String makeExpressionForExtraField(final String expression) { } } + /** + * Internal auxiliary class to keep found annotated fields. + */ protected static class BinField implements Comparable { Bin bin; Field field; - BinField(final Bin bin, final Field field) { + boolean fieldLocalAnnotation; + + BinField(final Bin bin, final boolean fieldLocalAnnotation, final Field field) { + this.fieldLocalAnnotation = fieldLocalAnnotation; this.bin = bin; this.field = field; } - boolean isArray() { + String getComment() { + String result = ""; + if (this.fieldLocalAnnotation) { + if (this.bin != null) { + result = this.bin.comment(); + } + } + return result; + } + + boolean isArrayField() { return this.field != null && this.field.getType().isArray(); } @@ -1851,19 +2051,29 @@ BinType findType() { if (this.field == null) { return BinType.STRUCT; } - return this.bin.type() == BinType.UNDEFINED ? BinType.findCompatible(this.field.getType()) : this.bin.type(); + if (this.bin.type() == BinType.UNDEFINED) { + return this.bin.customType().isEmpty() ? BinType.findCompatible(this.field.getType()) : + this.bin.type(); + } else { + return this.bin.type(); + } } String getName() { - if (this.field == null) { - return null; - } + String result = null; - return this.bin == null ? - this.field.getName() : - this.bin.name().length() == 0 ? - this.field.getName() : - this.bin.name(); + if (this.field != null) { + if (this.fieldLocalAnnotation) { + if (this.bin != null) { + result = this.bin.name().isEmpty() ? this.field.getName() : this.bin.name(); + } else { + throw new Error("Unexpected"); + } + } else { + result = field.getName(); + } + } + return result; } @Override @@ -1876,7 +2086,9 @@ public boolean equals(final Object obj) { } if (obj instanceof BinField) { final BinField that = (BinField) obj; - return this.field.equals(that.field) && this.bin.equals(that.bin); + + return this.field.equals(that.field) + && JBBPUtils.equals(this.bin, that.bin); } return false; } @@ -1886,24 +2098,43 @@ public int hashCode() { return this.field.hashCode(); } - @SuppressWarnings("NullableProblems") + private int getOrder() { + if (this.bin != null) { + return this.bin.order(); + } + return -1; + } + @Override public int compareTo(final BinField that) { - final int thisOrder = this.bin == null ? 0 : this.bin.outOrder(); - final int thatOrder = that.bin == null ? 0 : that.bin.outOrder(); + final int thisOrder = this.getOrder(); + final int thatOrder = that.getOrder(); - return thisOrder == thatOrder ? 0 : (thisOrder < thatOrder ? -1 : 1); + if (thisOrder == thatOrder) { + return this.getName().compareTo(that.getName()); + } else { + return thisOrder < thatOrder ? -1 : 1; + } + } + + String getCustomType() { + return this.bin.customType(); } } protected static class BinFieldContainer extends BinField { - final List fields = new ArrayList(); + static final BinFieldContainer END_STRUCT = new BinFieldContainer(null, null); + final List fields = new ArrayList<>(); final Class klazz; - static BinFieldContainer END_STRUCT = new BinFieldContainer(null, null, null); + 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 Bin bin, final Field field) { - super(bin, field); + BinFieldContainer(final Class klazz, final Field field) { + super(null, false, field); this.klazz = klazz; } @@ -1911,20 +2142,24 @@ 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 addContaner(final BinFieldContainer container) { + void addContainer(final BinFieldContainer container) { this.fields.add(container); } - void addField(final Bin bin, final Field field) { - this.fields.add(new BinField(bin, field)); + void addBinField(final Bin bin, final boolean fieldLocalAnnotation, final Field field) { + this.fields.add(new BinField(bin, fieldLocalAnnotation, field)); } JBBPByteOrder getByteOrder(final BinField field) { - return field.bin.outByteOrder(); + return field.bin.byteOrder(); } String getName() { @@ -1933,13 +2168,32 @@ String getName() { } JBBPBitNumber getBitNumber(final BinField field) { - return field.bin.outBitNumber() == JBBPBitNumber.BITS_8 ? this.bin.outBitNumber() : field.bin.outBitNumber(); + final JBBPBitNumber result; + if (field.bin.bitNumber() == JBBPBitNumber.BITS_8) { + result = this.bin == null ? JBBPBitNumber.BITS_8 : this.bin.bitNumber(); + } else { + result = field.bin.bitNumber(); + } + return result; } } protected static class ItemComment extends Item { - ItemComment(final String text) { - super(BinType.UNDEFINED, text, JBBPByteOrder.BIG_ENDIAN); + private final boolean newLine; + private final String comment; + + ItemComment(final String text, final boolean newLine) { + super(BinType.UNDEFINED, "_ignored_because_comment_", JBBPByteOrder.BIG_ENDIAN); + this.comment = text; + this.newLine = newLine; + } + + String getComment() { + return this.comment == null ? "" : this.comment; + } + + boolean isNewLine() { + return this.newLine; } } @@ -1953,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/JBBPIntCounter.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPIntCounter.java index 75b9f81d..51d180b3 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPIntCounter.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPIntCounter.java @@ -132,7 +132,7 @@ public int intValue() { @Override public long longValue() { - return (long) this.counter; + return this.counter; } @Override @@ -142,7 +142,7 @@ public float floatValue() { @Override public double doubleValue() { - return (double) this.counter; + return this.counter; } } 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 ca157ed3..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,17 +47,19 @@ 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; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Field; +import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Deque; import java.util.List; -import java.util.Stack; +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 { /** @@ -130,7 +134,7 @@ public class JBBPTextWriter extends FilterWriter { /** * The List contains all registered extras. */ - private final List extras = new ArrayList(); + private final List extras = new ArrayList<>(); /** * Lazy initialized field to keep field observer for Bin marked classes. */ @@ -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); } /** @@ -325,22 +335,20 @@ public JBBPTextWriter( * Auxiliary method allows to build writer over StringWriter with system-depended next line and hex radix. * The Method allows fast instance create. * + * @return the text writer instance, must not be null * @since 1.4.0 */ 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(); } @@ -403,7 +411,7 @@ private void ensureValueMode() throws IOException { e.onBeforeFirstValue(this); } writeIndent(); - this.write(this.prefixFirtValueAtLine); + this.write(this.prefixFirstValueAtLine); } break; case MODE_COMMENTS: { @@ -413,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: @@ -424,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 */ @@ -491,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++; @@ -577,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; } @@ -663,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; } @@ -761,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; @@ -795,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; } @@ -824,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); } @@ -852,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); } @@ -884,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); } @@ -1019,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); } @@ -1037,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,12 +1117,28 @@ public JBBPTextWriter Int(final int[] values, int off, int len) throws IOExcepti } /** - * Increase indent. + * 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. + * + * @return the context */ - public JBBPTextWriter IndentInc() throws IOException { + public JBBPTextWriter IndentInc() { this.indent += this.spacesInTab; return this; } @@ -1082,9 +1161,8 @@ public JBBPTextWriter IndentInc(final int count) throws IOException { * Decrease indent. * * @return the context - * @throws IOException it will be thrown for transport error */ - public JBBPTextWriter IndentDec() throws IOException { + public JBBPTextWriter IndentDec() { if (this.indent > 0) { this.indent = Math.max(0, this.indent - this.spacesInTab); } @@ -1130,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); } @@ -1232,8 +1312,8 @@ public JBBPTextWriter Comment(final String... comment) throws IOException { } if (c.indexOf('\n') >= 0) { - final String[] splitted = c.split("\\n"); - for (final String s : splitted) { + final String[] split = c.split("\\n", -1); + for (final String s : split) { this.ensureCommentMode(); this.write(s); } @@ -1256,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; } @@ -1301,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++]); } @@ -1341,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) { @@ -1350,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()); @@ -1365,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) { @@ -1415,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) { @@ -1556,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); @@ -1680,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. * @@ -1736,33 +1833,35 @@ 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 { - private final Stack counterStack = new Stack(); + 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(); @@ -1777,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) { @@ -1823,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(); @@ -1868,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) { @@ -1880,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) { @@ -1892,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) { @@ -1904,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; @@ -1920,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) { @@ -1932,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) { @@ -1944,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) { @@ -1956,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) { @@ -1968,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) { @@ -1980,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"); @@ -2005,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 58a9c17f..58727e95 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterExtraAdapter.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterExtraAdapter.java @@ -16,9 +16,7 @@ package com.igormaznitsa.jbbp.utils; -import com.igormaznitsa.jbbp.exceptions.JBBPException; import com.igormaznitsa.jbbp.mapper.Bin; - import java.io.IOException; import java.lang.reflect.Field; @@ -43,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; } @@ -63,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; } @@ -87,19 +91,8 @@ public void onReachedMaxValueNumberForLine(final JBBPTextWriter context) throws } - /** - * Auxiliary method to extract field value. - * - * @param instance object instance, can be null - * @param field the filed which value should be extracted, must not be null - * @return the field value - */ - public Object extractFieldValue(final Object instance, final Field field) { - JBBPUtils.assertNotNull(field, "Field must not be null"); - try { - return ReflectUtils.makeAccessible(field).get(instance); - } catch (Exception ex) { - throw new JBBPException("Can't extract value from field for exception", ex); - } + @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 00821dbd..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,28 +16,45 @@ 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; import com.igormaznitsa.jbbp.model.JBBPAbstractField; - 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]; + public static final JBBPAbstractField[] ARRAY_FIELD_EMPTY = new JBBPAbstractField[0]; + + // Don't replace by StandardCharsets for Android compatibility! + @SuppressWarnings("CharsetObjectCanBeUsed") private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8"); private JBBPUtils() { @@ -72,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)); @@ -105,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}; } } @@ -155,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: { @@ -166,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; } @@ -206,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); @@ -228,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)); } @@ -300,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 @@ -308,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; } } @@ -350,7 +373,7 @@ public static String bin2str(final byte[] values, final JBBPBitOrder bitOrder, f * @return a list of JBBP fields */ public static List fieldsAsList(final JBBPAbstractField... fields) { - final List result = new ArrayList(); + final List result = new ArrayList<>(); Collections.addAll(result, fields); return result; } @@ -429,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++) { @@ -452,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; @@ -479,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) + ')'; } /** @@ -515,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 */ @@ -582,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; @@ -616,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; @@ -680,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; } @@ -779,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); @@ -808,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; @@ -856,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); @@ -882,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); @@ -940,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; } @@ -968,9 +996,290 @@ public static int makeMask(final int value) { int msk = 1; do { msk <<= 1; - } - while (msk <= value); + } while (msk <= value); return msk - 1; } + /** + * Allows to check two objects even if one of them is null + * + * @param o1 object one can be null + * @param o2 object two can be null + * @return true if objects are equal ones, false otherwise + * @since 1.4.1 + */ + public static boolean equals(final Object o1, final Object o2) { + if (o1 == o2) { + return true; + } + if (o1 == null || o2 == null) { + return false; + } + 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 7f4212de..46426e78 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JavaSrcTextBuffer.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/JavaSrcTextBuffer.java @@ -88,7 +88,7 @@ public JavaSrcTextBuffer print(final boolean value) { } /** - * Foratted print. + * Formatted print. * * @param text format string * @param args arguments for formatted string @@ -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"); + 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"); + 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"); + 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"); + 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/NullableTriple.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/NullableTriple.java new file mode 100644 index 00000000..ae693906 --- /dev/null +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/NullableTriple.java @@ -0,0 +1,34 @@ +package com.igormaznitsa.jbbp.utils; + +/** + * Auxiliary class to keep three values. Any value can be null. + * + * @param first value type + * @param second value type + * @param third value type + * @since 2.0.0 + */ +public final class NullableTriple { + private final A a; + private final B b; + private final C c; + + public NullableTriple(A a, B b, C c) { + this.a = a; + this.b = b; + this.c = c; + } + + public A getA() { + return this.a; + } + + public B getB() { + return this.b; + } + + public C getC() { + return this.c; + } + +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/ReflectApiUtil.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/ReflectApiUtil.java deleted file mode 100644 index ec0b429a..00000000 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/ReflectApiUtil.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.igormaznitsa.jbbp.utils; - -import java.lang.reflect.AccessibleObject; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; - -/** - * Auxiliary class collects methods for work with reflection. - * It is internal auxiliary class! Its method will be changed, don't use them in your developments! - * - * @since 1.4.0 - */ -public final class ReflectApiUtil { - /** - * Inside auxiliary cache of privilege processors organized as a queue. - */ - private static final Queue PROCESSORS_QUEUE = new ArrayBlockingQueue(32); - - private ReflectApiUtil() { - } - - /** - * Make accessible an accessible object (if it is not a null), AccessController.doPrivileged will be - * called. - * - * @param obj an object to make accessible, it can be null. - * @see AccessController#doPrivileged(java.security.PrivilegedAction) - */ - public static T makeAccessible(final T obj) { - if (obj != null && !obj.isAccessible()) { - PrivilegedProcessor processor = PROCESSORS_QUEUE.poll(); - if (processor == null) { - processor = new PrivilegedProcessor(); - } - processor.setAccessibleObject(obj); - AccessController.doPrivileged(processor); - if (!PROCESSORS_QUEUE.offer(processor)) { - throw new Error("Unexpected! can't queue a processor"); - } - } - return obj; - } - - /** - * Create class instance through default constructor call - * - * @param klazz class to be instantiated, must not be null - * @param type of the class - * @return instance of class, must not be null - */ - public static T newInstance(final Class klazz) { - try { - return klazz.getConstructor().newInstance(); - } catch (Exception ex) { - throw new Error(String.format("Can't create instance of %s for error %s", klazz.getCanonicalName(), ex.getMessage()), ex); - } - } - - /** - * Find class for name and make an instance through call of the default constructor. - * - * @param className the class name to be instantiated, must not be null - * @return new instance of the class, must not be null - * @throws Error if it is impossible to build instance for an exception - */ - public static Object newInstanceForClassName(final String className) { - try { - return newInstance(Class.forName(className)); - } catch (Exception ex) { - throw new Error(String.format("Can't create instance of %s for error %s", className, ex.getMessage()), ex); - } - } - - /** - * Inside auxiliary class to make makeAccessible as a privileged action. - */ - private static final class PrivilegedProcessor implements PrivilegedAction { - - private AccessibleObject theObject; - - public void setAccessibleObject(final AccessibleObject obj) { - this.theObject = obj; - } - - @Override - public AccessibleObject run() { - final AccessibleObject objectToProcess = this.theObject; - this.theObject = null; - if (objectToProcess != null) { - objectToProcess.setAccessible(true); - } - return objectToProcess; - } - } - - -} 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 9f91c6c5..c7d627af 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/ReflectUtils.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/ReflectUtils.java @@ -1,6 +1,8 @@ package com.igormaznitsa.jbbp.utils; import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Queue; @@ -16,11 +18,23 @@ public final class ReflectUtils { * Inside auxiliary queue for privileged processors to avoid mass creation of * processors. */ - private static final Queue PROCESSORS_QUEUE = new ArrayBlockingQueue(32); + private static final Queue PROCESSORS_QUEUE = new ArrayBlockingQueue<>(32); private ReflectUtils() { } + public static boolean isPotentiallyAccessibleClass(final Class klazz) { + if (klazz.isLocalClass() && !isPotentiallyAccessibleClass(klazz.getEnclosingClass())) { + return false; + } + return Modifier.isPublic(klazz.getModifiers()); + } + + public static boolean isPotentiallyAccessibleField(final Field field) { + return isPotentiallyAccessibleClass(field.getDeclaringClass()) + && Modifier.isPublic(field.getModifiers()); + } + /** * Make accessible an accessible object, AccessController.doPrivileged will be * called. @@ -31,7 +45,7 @@ private ReflectUtils() { * @see AccessController#doPrivileged(java.security.PrivilegedAction) */ public static T makeAccessible(final T obj) { - if (obj != null && !obj.isAccessible()) { + if (obj != null) { PrivilegedProcessor processor = PROCESSORS_QUEUE.poll(); if (processor == null) { processor = new PrivilegedProcessor(); @@ -51,27 +65,14 @@ public static T makeAccessible(final T obj) { * @param klazz class to be instantiated, must not be null * @param type of the class * @return instance of class, must not be null + * @throws RuntimeException if can't create instance for an error */ public static T newInstance(final Class klazz) { try { return klazz.getConstructor().newInstance(); } catch (Exception ex) { - throw new Error(String.format("Can't create instance of %s for error %s", klazz.getCanonicalName(), ex.getMessage()), ex); - } - } - - /** - * Find class for name and make an instance through call of the default constructor. - * - * @param className the class name to be instantiated, must not be null - * @return new instance of the class, must not be null - * @throws Error if it is impossible to build instance for an exception - */ - public static Object newInstanceForClassName(final String className) { - try { - return newInstance(Class.forName(className)); - } catch (Exception ex) { - throw new Error(String.format("Can't create instance of %s for error %s", className, 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/main/java/com/igormaznitsa/jbbp/utils/TargetSources.java b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/TargetSources.java index cfcb9530..cda7b084 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/TargetSources.java +++ b/jbbp/src/main/java/com/igormaznitsa/jbbp/utils/TargetSources.java @@ -24,7 +24,7 @@ */ public enum TargetSources { /** - * Java 1.6 sources. + * Generate Java sources. */ - JAVA_1_6 + JAVA } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessorTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPCustomFieldTypeProcessorTest.java index 3bad59fc..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,56 +89,74 @@ 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()); - - if (type.equals("some1")) { - assertEquals(0, extraData); - assertEquals("b", fieldName.getFieldName()); - assertFalse(readWholeStream); - assertEquals(-1, arrayLength); - return new JBBPFieldByte(fieldName, (byte) in.readByte()); - } else if (type.equals("some2")) { - assertEquals(345, extraData); - assertEquals("c", fieldName.getFieldName()); - assertFalse(readWholeStream); - assertEquals(-1, arrayLength); - return new JBBPFieldShort(fieldName, (short) in.readUnsignedShort(customFieldTypeInfo.getByteOrder())); - } else if (type.equals("some3")) { - assertEquals(0, extraData); - assertEquals("e", fieldName.getFieldName()); - assertFalse(readWholeStream); - assertEquals(5, arrayLength); - return new JBBPFieldArrayByte(fieldName, in.readByteArray(arrayLength)); - } else { - fail("Unexpected " + type); - return null; + assertEquals(type.equals("some1") ? JBBPByteOrder.LITTLE_ENDIAN : JBBPByteOrder.BIG_ENDIAN, + customFieldTypeInfo.getByteOrder()); + + switch (type) { + case "some1": + assertEquals(0, extraData); + assertEquals("b", fieldName.getFieldName()); + assertFalse(readWholeStream); + assertEquals(-1, arrayLength); + return new JBBPFieldByte(fieldName, (byte) in.readByte()); + case "some2": + assertEquals(345, extraData); + assertEquals("c", fieldName.getFieldName()); + assertFalse(readWholeStream); + assertEquals(-1, arrayLength); + return new JBBPFieldShort(fieldName, + (short) in.readUnsignedShort(customFieldTypeInfo.getByteOrder())); + case "some3": + assertEquals(0, extraData); + assertEquals("e", fieldName.getFieldName()); + assertFalse(readWholeStream); + assertEquals(5, arrayLength); + return new JBBPFieldArrayByte(fieldName, in.readByteArray(arrayLength)); + default: + fail("Unexpected " + type); + return null; } } }; - final JBBPParser parser = JBBPParser.prepare("int a; 0; final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(provider); assertEquals(0, map.size()); assertSame(provider, map.getExternalValueProvider()); @@ -60,20 +60,15 @@ public int provideArraySize(String fieldName, JBBPNamedNumericFieldMap numericFi @Test public void testGetExternalValueProvider() { - final JBBPExternalValueProvider provider = new JBBPExternalValueProvider() { - - @Override - public int provideArraySize(String fieldName, JBBPNamedNumericFieldMap numericFieldMap, JBBPCompiledBlock compiledBlock) { - return 0; - } - }; + final JBBPExternalValueProvider provider = (fieldName, numericFieldMap, compiledBlock) -> 0; final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(provider); assertSame(provider, map.getExternalValueProvider()); final JBBPNamedNumericFieldMap map2 = new JBBPNamedNumericFieldMap(null); try { - map2.getExternalFieldValue("test", JBBPCompiledBlock.prepare().setSource("").setCompiledData(new byte[] {0}).build(), null); + map2.getExternalFieldValue("test", + JBBPCompiledBlock.prepare().setSource("").setCompiledData(new byte[] {0}).build(), null); fail("Must throw JBBPEvalException"); } catch (JBBPEvalException ex) { } @@ -109,7 +104,8 @@ public void testClear() { @Test public void testFindFieldForName() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); map.putField(field); assertSame(field, map.findFieldForName("tESt")); assertNull(map.findFieldForName("test1")); @@ -124,9 +120,12 @@ public void testFindFieldForName() { @Test public void testRemove() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field1 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); - final JBBPNumericField field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 0), 123); - final JBBPNumericField field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 0), (byte) 123); + final JBBPNumericField field1 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 0), 123); + final JBBPNumericField field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 0), (byte) 123); map.putField(field1); map.putField(field2); @@ -152,9 +151,12 @@ public void testRemove() { @Test public void testFindFieldForType() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field1 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); - final JBBPNumericField field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 0), 123); - final JBBPNumericField field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 0), (byte) 123); + final JBBPNumericField field1 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 0), 123); + final JBBPNumericField field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 0), (byte) 123); map.putField(field1); map.putField(field2); @@ -180,9 +182,12 @@ public void testFindFieldForType() { @Test public void testFindLastFieldForType() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field1 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); - final JBBPNumericField field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 0), 123); - final JBBPNumericField field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 0), (byte) 123); + final JBBPNumericField field1 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 0), 123); + final JBBPNumericField field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 0), (byte) 123); map.putField(field1); map.putField(field2); @@ -201,9 +206,12 @@ public void testFindLastFieldForType() { @Test public void testFindFirstFieldForType() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field1 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); - final JBBPNumericField field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 0), 123); - final JBBPNumericField field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 0), (byte) 123); + final JBBPNumericField field1 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 0), 123); + final JBBPNumericField field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 0), (byte) 123); map.putField(field1); map.putField(field2); @@ -222,9 +230,12 @@ public void testFindFirstFieldForType() { @Test public void testFindForFieldOffset() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field1 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 1), 123); - final JBBPNumericField field2 = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 2222), 123); - final JBBPNumericField field3 = new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 3000), (byte) 123); + final JBBPNumericField field1 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 1), 123); + final JBBPNumericField field2 = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test2", "test2", 2222), 123); + final JBBPNumericField field3 = + new JBBPFieldByte(new JBBPNamedFieldInfo("test.test3", "test3", 3000), (byte) 123); map.putField(field1); map.putField(field2); @@ -239,7 +250,8 @@ public void testFindForFieldOffset() { @Test public void testFindFieldForPath() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); map.putField(field); assertSame(field, map.findFieldForPath("test.test")); assertNull(map.findFieldForPath("test.test1")); @@ -255,7 +267,8 @@ public void testFindFieldForPath() { @Test public void testFindFieldForPathAndType() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); map.putField(field); assertSame(field, map.findFieldForPathAndType("TesT.tESt", JBBPFieldInt.class)); assertNull(map.findFieldForPathAndType("test.test", JBBPFieldByte.class)); @@ -277,7 +290,8 @@ public void testFindFieldForPathAndType() { @Test public void testFindFieldForNameAndType() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); map.putField(field); assertSame(field, map.findFieldForNameAndType("tESt", JBBPFieldInt.class)); assertNull(map.findFieldForNameAndType("test", JBBPFieldByte.class)); @@ -299,7 +313,8 @@ public void testFindFieldForNameAndType() { @Test public void testPathExists() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); map.putField(field); assertTrue(map.pathExists("tESt.teSt")); assertFalse(map.pathExists("test.test1")); @@ -316,7 +331,8 @@ public void testPathExists() { @Test public void testNameExists() { final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(); - final JBBPNumericField field = new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); + final JBBPNumericField field = + new JBBPFieldInt(new JBBPNamedFieldInfo("test.test", "test", 0), 123); map.putField(field); assertTrue(map.nameExists("tESt")); assertFalse(map.nameExists("test1")); diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserExpressionArraySizeControllerTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserExpressionArraySizeControllerTest.java new file mode 100644 index 00000000..cabd3405 --- /dev/null +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserExpressionArraySizeControllerTest.java @@ -0,0 +1,65 @@ +package com.igormaznitsa.jbbp; + +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 com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; +import java.io.ByteArrayInputStream; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; + +class JBBPParserExpressionArraySizeControllerTest { + + @Test + public void testGetterAndSetter() { + final JBBPParserExpressionArraySizeController controller = + (parser, expressionEvaluator, fieldInfo, calculatedArraySize) -> 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 b882a63e..7871c567 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserTest.java @@ -16,11 +16,25 @@ 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.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.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; @@ -34,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; @@ -46,18 +61,15 @@ 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; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.IOException; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPParserTest { @@ -83,12 +95,8 @@ public void testErrorDuringReadingOfNonNamedField() throws Exception { @Test public void testFieldNameCaseInsensetive_ExceptionForDuplicationOfFieldNames() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("bool Field1; byte field1;"); - } - }); + assertThrows(JBBPCompilationException.class, + () -> JBBPParser.prepare("bool Field1; byte field1;")); } @Test @@ -104,12 +112,7 @@ public void testFieldNameCaseInsensetive() throws Exception { @Test public void testParse_Bool_ErrorForEOF() throws Exception { final JBBPParser parser = JBBPParser.prepare("bool;"); - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> parser.parse(new byte[0])); } @Test @@ -142,12 +145,7 @@ public void testParse_SingleDefaultNonamedBool_LittleEndian() throws Exception { @Test public void testParse_Byte_ErrorForEOF() throws Exception { final JBBPParser parser = JBBPParser.prepare("byte;"); - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> parser.parse(new byte[0])); } @Test @@ -180,88 +178,65 @@ public void testCompile_Value() { @Test public void testCompile_Value_CompilationErrors() { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("val;"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("val:1;"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("val:(3+5);"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("val a;"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("val:3 [_];"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("val:3 [_] field;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPParser.prepare("val;")); + assertThrows(JBBPCompilationException.class, () -> JBBPParser.prepare("val:1;")); + assertThrows(JBBPCompilationException.class, () -> JBBPParser.prepare("val:(3+5);")); + assertThrows(JBBPCompilationException.class, () -> JBBPParser.prepare("val a;")); + assertThrows(JBBPCompilationException.class, () -> JBBPParser.prepare("val:3 [_];")); + assertThrows(JBBPCompilationException.class, () -> JBBPParser.prepare("val:3 [_] field;")); } @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()); } @Test public void testParse_String_ErrorForEOF() { final JBBPParser parser = JBBPParser.prepare("stringj;"); - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> parser.parse(new byte[0])); } @Test @@ -288,12 +263,7 @@ public void testParse_String_LittleEndian() throws Exception { @Test public void testParse_UByte_ErrorForEOF() throws Exception { final JBBPParser parser = JBBPParser.prepare("ubyte;"); - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> parser.parse(new byte[0])); } @Test @@ -320,12 +290,7 @@ public void testParse_SingleDefaultNonamedUByte_LittleEndian() throws Exception @Test public void testParse_Short_ErrorForEOF() throws Exception { final JBBPParser parser = JBBPParser.prepare("short;"); - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> parser.parse(new byte[0])); } @Test @@ -352,44 +317,37 @@ public void testParse_SingleDefaultNonamedShort_LittleEndian() throws Exception @Test public void testParse_UShort_ErrorForEOF() throws Exception { final JBBPParser parser = JBBPParser.prepare("ushort;"); - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> parser.parse(new byte[0])); } @Test 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(" parser.parse(new byte[0])); } @Test @@ -416,44 +374,37 @@ public void testParse_SingleDefaultNonamedInt_LittleEndian() throws Exception { @Test public void testParse_Float_ErrorForEOF() throws Exception { final JBBPParser parser = JBBPParser.prepare("floatj;"); - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> parser.parse(new byte[0])); } @Test public void testParse_SingleDefaultNonamedFloat_Default() 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_BigEndian() 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(" parser.parse(new byte[0])); } @Test @@ -480,33 +431,31 @@ public void testParse_SingleDefaultNonamedLong_LittleEndian() throws Exception { @Test public void testParse_Double_ErrorForEOF() throws Exception { final JBBPParser parser = JBBPParser.prepare("doublej;"); - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> parser.parse(new byte[0])); } @Test public void testParse_SingleDefaultNonamedDouble_Default() 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_BigEndian() 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); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - counter.incrementAndGet(); + @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; + } - return new JBBPFieldByte(fieldName, (byte) value); - } - }, 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()); @@ -552,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()); @@ -562,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()); } @@ -589,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() { + 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 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); + @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()); @@ -610,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()); } @@ -636,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; - } + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - @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(); + @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; + } - return new JBBPFieldByte(fieldName, (byte) value); - } - }, 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()); @@ -674,45 +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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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); - } + 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, + 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); }); } @@ -720,23 +717,31 @@ public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final J public void testParse_SingleNonamedVar_ErrorForArrayResult() throws Exception { final JBBPParser parser = JBBPParser.prepare("short k; var; int;"); - assertThrows(JBBPParsingException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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); - } + 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, + 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); }); } @@ -744,24 +749,32 @@ public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final J public void testParse_SingleNonamedVar_ErrorForDifferentName() throws Exception { final JBBPParser parser = JBBPParser.prepare("short k; var name; int;"); - assertThrows(JBBPParsingException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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); - } + 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, + 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); }); } @@ -771,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(); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - return new JBBPFieldArrayByte(fieldName, new byte[] {(byte) value}); - } + @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); + @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()); } @@ -808,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()); + final JBBPFieldStruct struct = + parser.parse(new byte[] {9, 8, 33, 1, 2, 3, 4}, new JBBPVarFieldProcessor() { - 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 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); + @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()); } @@ -845,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() { + 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); + @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(0x0908, numericFieldMap.findFieldForType(JBBPFieldShort.class).getAsInt()); - assertEquals("some", fieldName.getFieldName()); - assertEquals(0, extraValue); - assertTrue(arraySize < 0); - assertEquals(JBBPByteOrder.BIG_ENDIAN, byteOrder); + assertEquals("some", fieldName.getFieldName()); + assertEquals(0, extraValue); + assertTrue(arraySize < 0); + assertEquals(JBBPByteOrder.BIG_ENDIAN, byteOrder); - counter.incrementAndGet(); + counter.incrementAndGet(); - return new JBBPFieldArrayByte(fieldName, inStream.readByteArray(-1)); - } + 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); + @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()); } @@ -882,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; } @@ -902,24 +956,32 @@ public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final J public void testParse_SingleNonamedVarArray_ErrorForNullResult() throws Exception { final JBBPParser parser = JBBPParser.prepare("short k; var [k]; int;"); - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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); - } + 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, + 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); }); } @@ -927,78 +989,79 @@ public JBBPAbstractField readVarField(final JBBPBitInputStream inStream, final J public void testParse_SingleNonamedVarArray_ErrorForDifferentName() throws Exception { final JBBPParser parser = JBBPParser.prepare("short k; var [234] name; int;"); - assertThrows(JBBPParsingException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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); - } + 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, + 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); }); } @Test public void testParse_BitFields_EOF() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("bit:4;").parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> JBBPParser.prepare("bit:4;").parse(new byte[0])); } @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, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("ubyte a; ubyte b; bit:(a+b) c;").parse(new byte[] {11, 2, (byte) 0xB4}); - } - }); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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 public void testParse_BitFieldArray_EOF() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("bit:4 [1];").parse(new byte[0]); - } - }); + assertThrows(EOFException.class, () -> JBBPParser.prepare("bit:4 [1];").parse(new byte[0])); } @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()); @@ -1026,18 +1089,17 @@ public void testParse_Align_Default_EmptyStream_NoErrors() throws Exception { @Test public void testParse_Align_ErrorForEOF() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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()); @@ -1065,22 +1127,13 @@ public void testParse_Align_LongDistance() throws Exception { @Test public void testParse_Skip_Default_ErrorForEOF() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("byte; skip;").parse(new byte[] {1}); - } - }); + assertThrows(EOFException.class, () -> JBBPParser.prepare("byte; skip;").parse(new byte[] {1})); } @Test public void testParse_Skip_ErrorForEOF() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("byte; skip:34;").parse(new byte[] {1}); - } - }); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; skip:34;").parse(new byte[] {1})); } @Test @@ -1114,12 +1167,7 @@ public void testParse_Skip_LongDistance() throws Exception { @Test public void testParse_Skip_TooLongDistance() throws Exception { final JBBPParser parser = JBBPParser.prepare("byte; skip:33; short;"); - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); - } - }); + assertThrows(EOFException.class, () -> parser.parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8})); } @Test @@ -1142,61 +1190,72 @@ public void testParse_Align_Int_WithoutEffect() throws Exception { @Test public void testParse_FixedBitArray_EOFException() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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)); @@ -1210,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)); @@ -1224,12 +1285,8 @@ public void testParse_NonFixedBitArray() throws Exception { @Test public void testParse_FixedByteArray_EOFException() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("byte; byte[1];").parse(new byte[] {1}); - } - }); + assertThrows(EOFException.class, + () -> JBBPParser.prepare("byte; byte[1];").parse(new byte[] {1})); } @Test @@ -1240,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); @@ -1250,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); @@ -1260,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); @@ -1290,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})); } @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)); @@ -1326,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)); @@ -1336,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)); @@ -1366,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})); } @Test @@ -1392,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)); @@ -1402,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)); @@ -1412,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)); @@ -1442,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})); } @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)); @@ -1476,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)); @@ -1484,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)); @@ -1508,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})); } @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)); @@ -1540,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)); @@ -1548,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)); @@ -1572,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})); } @Test @@ -1596,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)); @@ -1604,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)); @@ -1612,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)); @@ -1636,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})); } @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); @@ -1668,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); @@ -1676,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); @@ -1700,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})); } @Test @@ -1724,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)); @@ -1732,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)); @@ -1740,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)); @@ -1764,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})); } @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); @@ -1796,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); @@ -1804,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})); } @Test public void testParse_NegativeArrayLength() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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()); @@ -1985,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()); @@ -2059,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()); @@ -2081,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, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(stream); - } - }); + 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, new Executable() { - @Override - public void execute() throws Throwable { - parser.parse(stream); - } - }); + assertThrows(JBBPParsingException.class, () -> parser.parse(stream)); } @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); @@ -2269,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()); @@ -2278,10 +2483,11 @@ public void testParse_NoErrorForIgnoreRemainingFieldsFlag() throws Exception { } @Test - public void testConvertToSrc_Java16_NamedPackage() throws Exception { + public void testConvertToSrc_Java_NamedPackage() { final JBBPParser parser = JBBPParser.prepare("byte a;"); - final List src = parser.convertToSrc(TargetSources.JAVA_1_6, "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")); @@ -2289,14 +2495,122 @@ public void testConvertToSrc_Java16_NamedPackage() throws Exception { } @Test - public void testConvertToSrc_Java16_DefaultPackage() throws Exception { + public void testConvertToSrc_Java_DefaultPackage() { final JBBPParser parser = JBBPParser.prepare("byte a;"); - final List src = parser.convertToSrc(TargetSources.JAVA_1_6, "SomeClass"); + final List src = parser.convertToSrc(TargetSources.JAVA, "SomeClass"); assertEquals(1, src.size()); assertEquals("byte a;", src.get(0).getMetadata().getProperty("script")); 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 8b2d047b..79ab5b6e 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/TestUtils.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/TestUtils.java @@ -16,13 +16,16 @@ package com.igormaznitsa.jbbp; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.Locale; -import java.util.zip.CRC32; - 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; + /** * Different useful auxiliary test methods */ @@ -34,27 +37,6 @@ public enum TestUtils { */ public static final float FLOAT_DELTA = Float.MIN_VALUE; - - /** - * Inject new value into final field - * - * @param klazz a class which field must be injected, must not be null - * @param instance the instance of the class, it can be null for static fields - * @param fieldName the field name, must not be null - * @param value the value to be injected - * @throws Exception it will be thrown for any error - */ - public static void injectDeclaredFinalFieldValue(final Class klazz, final Object instance, final String fieldName, final Object value) throws Exception { - final Field field = klazz.getDeclaredField(fieldName); - field.setAccessible(true); - - final Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); - - field.set(instance, value); - } - /** * Read field value, also allows to provide dot-separated chain of fields * @@ -66,7 +48,8 @@ public static void injectDeclaredFinalFieldValue(final Class klazz, final Obj * @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) { @@ -86,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) { @@ -105,21 +89,28 @@ 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); - final CRC32 crc32 = new CRC32(); + final PureJavaCrc32 crc32 = new PureJavaCrc32(); crc32.update(etalonName.charAt(0)); crc32.update(etalonName.charAt(1)); crc32.update(etalonName.charAt(2)); crc32.update(etalonName.charAt(3)); if (etalonLength != 0) { - assertEquals(etalonLength, chunkData.length, "Data array " + etalonName + " must be " + etalonLength); - crc32.update(chunkData); + assertEquals(etalonLength, chunkData.length, + "Data array " + etalonName + " must be " + etalonLength); + for (final byte b : chunkData) { + crc32.update(b & 0xFF); + } } final int crc = (int) crc32.getValue(); @@ -127,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 4f27e71e..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,42 +54,17 @@ public void testCompile_AllowedStructInsideStructWhichShouldBeReadTillEnd() thro @Test public void testCompile_ErrorSituationsReadTillEnd() { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("ubyte [_]; ubyte [_];"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("ubyte [_]; a {byte;};"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("byte;test [_] {byte;} int error;"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("ubyte [_]; byte;"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("a [_] { byte a; } b [_] { byte a;}"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("a [_] { b [_] { byte a;}}"); - } - }); + 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;}}")); } @Test @@ -91,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]); @@ -102,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]); } @@ -113,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]); @@ -143,97 +132,53 @@ public void testCompile_ErrorForUnknownType() throws Exception { @Test public void testCompile_ErrorForNamedAlignField() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("align hello;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("align hello;")); } @Test public void testCompile_ErrorForArrayAlignField() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("align [445] hello;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("align [445] hello;")); } @Test public void testCompile_ErrorForZeroAlignValue() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("align:0;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("align:0;")); } @Test public void testCompile_ErrorForNegativeAlignValue() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("align:-1;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("align:-1;")); } @Test public void testCompile_ErrorForNonNumericAlignValue() throws Exception { - assertThrows(JBBPTokenizerException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("align:hhh;"); - } - }); + assertThrows(JBBPTokenizerException.class, () -> JBBPCompiler.compile("align:hhh;")); } @Test public void testCompile_ErrorForNamedSkipField() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("skip hello;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("skip hello;")); } @Test public void testCompile_ErrorForArraySkipField() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("skip [445] hello;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("skip [445] hello;")); } @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 public void testCompile_ErrorForNegativeSkipValue() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("skip:-1;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("skip:-1;")); } @Test public void testCompile_ErrorForNonNumericSkipValue() throws Exception { - assertThrows(JBBPTokenizerException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("skip:hhh;"); - } - }); + assertThrows(JBBPTokenizerException.class, () -> JBBPCompiler.compile("skip:hhh;")); } @Test @@ -248,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;")); } @@ -284,12 +230,15 @@ public void testCompile_ErrorForNonClosedStructure() throws Exception { @Test public void testCompile_ErrorForIllegaFieldName() throws Exception { - try { - JBBPCompiler.compile(" byte int;"); - fail("Must throw Tokenizer Exception"); - } catch (JBBPTokenizerException ex) { - assertEquals(2, ex.getPosition()); - } + assertThrows(JBBPTokenizerException.class, () -> JBBPCompiler.compile(" byte _;")); + + assertThrows(JBBPTokenizerException.class, () -> JBBPCompiler.compile(" byte $a;")); + + assertThrows(JBBPTokenizerException.class, () -> JBBPCompiler.compile(" byte $$;")); + + assertThrows(JBBPTokenizerException.class, () -> JBBPCompiler.compile(" byte a.b;")); + + assertThrows(JBBPTokenizerException.class, () -> JBBPCompiler.compile(" byte 1d;")); } @Test @@ -337,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 @@ -355,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 @@ -480,7 +439,8 @@ public void testCompile_SingleNamedIntLittleEndianField() throws Exception { final JBBPCompiledBlock block = JBBPCompiler.compile(" JBBPCompiler.compile("out { int [4] len; some {byte [len] HeLLo;} }")); } @Test public void testCompile_ErrorForFieldInStructArrayAsVarLength() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("some {byte [struct.len] HeLLo;} "); - } - }); + assertThrows(JBBPCompilationException.class, + () -> JBBPCompiler.compile("some {byte [struct.len] HeLLo;} ")); } @Test @@ -617,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 @@ -630,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, @@ -647,55 +599,27 @@ public void testCompile_FixedStructArray() throws Exception { @Test public void testCompile_correctFieldName() throws Exception { JBBPCompiler.compile("int a;int _a;int a11;int a_f;int a_1;"); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("int 1a;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("int 1a;")); } @Test public void testCompile_ErrorForNonAllowedArguments() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("reset$$:1;"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("reset$$ hello;"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("reset$$ [445];"); - } - }); - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("reset$$ [445] hello;"); - } - }); + 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;")); } @Test public void testCompile_ErrorForResetWithExtraValue() throws Exception { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPCompiler.compile("reset$$:1;"); - } - }); + assertThrows(JBBPCompilationException.class, () -> JBBPCompiler.compile("reset$$:1;")); } @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/JBBPToJBBPToJava6ConverterCompilationTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJBBPToJava6ConverterCompilationTest.java deleted file mode 100644 index 3d34ccd8..00000000 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJBBPToJava6ConverterCompilationTest.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * 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.compiler.conversion; - -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.JBBPBitInputStream; -import com.igormaznitsa.jbbp.io.JBBPBitOrder; -import com.igormaznitsa.jbbp.model.JBBPAbstractField; -import com.igormaznitsa.jbbp.testaux.AbstractJBBPToJava6ConverterTest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - -import java.io.IOException; - -import static org.junit.jupiter.api.Assertions.*; - -public class JBBPToJBBPToJava6ConverterCompilationTest extends AbstractJBBPToJava6ConverterTest { - - private static String makeSources(final JBBPParser parser, final String classComment, final boolean useSetterGetter) { - return JBBPToJava6Converter.makeBuilder(parser).setMainClassPackage(PACKAGE_NAME).setMainClassName(CLASS_NAME).setHeadComment(classComment).setAddGettersSetters(useSetterGetter).build().convert(); - } - - private void assertCompilation(final String classSrc) throws Exception { - System.out.println(classSrc); - assertNotNull(saveAndCompile(new JavaClassContent(PACKAGE_NAME + '.' + CLASS_NAME, classSrc))); - } - - @Test - public 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)); - assertCompilation(makeSources(parser, "some multiline text\nto be added into header", true)); - } - - @Test - public void testForceAbstract() throws Exception { - final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertFalse(JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).setDoMainClassAbstract(false).build().convert().contains("abstract")); - assertTrue(JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).setDoMainClassAbstract(true).build().convert().contains("abstract")); - } - - @Test - public void testMapSubstructToSuperclassesInterface() throws Exception { - final JBBPParser parser = JBBPParser.prepare("a { b { c [_] { byte d;}} }"); - final String text = JBBPToJava6Converter.makeBuilder(parser) - .setMainClassName(CLASS_NAME) - .setAddGettersSetters(true) - .setMapSubClassesSuperclasses( - makeMap( - "a.b","com.igormaznitsa.Impl", - "a.b.c", "com.igormaznitsa.Impl2" - ) - ) - .build() - .convert(); - assertTrue(text.contains("public static class B extends com.igormaznitsa.Impl")); - assertTrue(text.contains("public static class C extends com.igormaznitsa.Impl2")); - assertTrue(text.contains("public B getB() { return this.b;}")); - assertTrue(text.contains("public C [] getC() { return this.c;}")); - System.out.println(text); - } - - @Test - public void testMapSubstructToInterface() throws Exception { - final JBBPParser parser = JBBPParser.prepare("a { b { c [_] { byte d;}} }"); - final String text = JBBPToJava6Converter.makeBuilder(parser) - .setMainClassName(CLASS_NAME) - .setAddGettersSetters(true) - .setMapSubClassesInterfaces( - makeMap( - "a.b","com.igormaznitsa.Impl", - "a.b.c", "com.igormaznitsa.Impl2" - ) - ) - .build() - .convert(); - assertTrue(text.contains("public static class B implements com.igormaznitsa.Impl")); - assertTrue(text.contains("public static class C implements com.igormaznitsa.Impl2")); - assertTrue(text.contains("public com.igormaznitsa.Impl getB() { return this.b;}")); - assertTrue(text.contains("public com.igormaznitsa.Impl2 [] getC() { return this.c;}")); - System.out.println(text); - } - - @Test - public void testCustomText() throws Exception { - final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertTrue(JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassCustomText("public void test(){}").build().convert().contains("public void test(){}")); - } - - @Test - public void testSuperclass() throws Exception { - final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertTrue(JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).setSuperClass("com.igormaznitsa.Super").build().convert().contains("extends com.igormaznitsa.Super ")); - } - - @Test - public void testInterfaces() throws Exception { - final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertTrue(JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassImplements("com.igormaznitsa.InterfaceA", "com.igormaznitsa.InterfaceB").build().convert().contains("implements com.igormaznitsa.InterfaceA,com.igormaznitsa.InterfaceB ")); - } - - @Test - public void testClassPackage() throws Exception { - final JBBPParser parser = JBBPParser.prepare("byte a;"); - assertFalse(JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).build().convert().contains("package ")); - assertFalse(JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassPackage("").build().convert().contains("package ")); - assertTrue(JBBPToJava6Converter.makeBuilder(parser).setMainClassName(CLASS_NAME).setMainClassPackage("hello.world").build().convert().contains("package hello.world;")); - } - - @Test - public void testGettersSetters() throws Exception { - final JBBPParser parser = JBBPParser.prepare("byte a;"); - String text = JBBPToJava6Converter.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 = JBBPToJava6Converter.makeBuilder(parser).setAddGettersSetters(true).setMainClassName(CLASS_NAME).build().convert(); - - assertFalse(text.contains("public byte a;")); - assertTrue(text.contains("protected byte a;")); - assertTrue(text.contains("public void setA(byte value) {")); - assertTrue(text.contains("public byte getA() {")); - } - - @Test - public void testZ80snap1() throws Exception { - final JBBPParser parser = JBBPParser.prepare("byte reg_a; byte reg_f; >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")); + } + + @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)); + } + + @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")); + } + + @Test + void testMakeInternalClassObjects_StaticClasses() throws Exception { + final JBBPParser parser = JBBPParser.prepare("a { b { c [_] { byte d;}} }"); + final String text = JBBPToJavaConverter + .makeBuilder(parser) + .setMainClassName(CLASS_NAME) + .setAddGettersSetters(true) + .build() + .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; }")); + } + + @Test + void testMakeInternalClassObjects_NoMakersWithoutGettersSetters() throws Exception { + final JBBPParser parser = JBBPParser.prepare("a { b { c [_] { byte d;}} }"); + final String text = JBBPToJavaConverter + .makeBuilder(parser) + .setMainClassName(CLASS_NAME) + .setAddGettersSetters(false) + .build() + .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; }")); + } + + @Test + void testMakeInternalClassObjects_NonStaticClasses() throws Exception { + final JBBPParser parser = JBBPParser.prepare("a { b { c [_] { byte d;}} }"); + final String text = JBBPToJavaConverter + .makeBuilder(parser) + .setMainClassName(CLASS_NAME) + .setAddGettersSetters(true) + .doInternalClassesNonStatic() + .build() + .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; }")); + } + + @Test + void testMapSubstructToSuperclassesInterface() throws Exception { + final JBBPParser parser = JBBPParser.prepare("a { b { c [_] { byte d;}} }"); + final String text = JBBPToJavaConverter.makeBuilder(parser) + .setMainClassName(CLASS_NAME) + .setAddGettersSetters(true) + .setMapSubClassesSuperclasses( + makeMap( + "a.b", "com.igormaznitsa.Impl", + "a.b.c", "com.igormaznitsa.Impl2" + ) + ) + .build() + .convert(); + assertTrue(text.contains("public static class B extends com.igormaznitsa.Impl")); + assertTrue(text.contains("public static class C extends com.igormaznitsa.Impl2")); + assertTrue(text.contains("public B getB() { return this.b;}")); + assertTrue(text.contains("public C [] getC() { return this.c;}")); + System.out.println(text); + } + + @Test + void testMapSubstructToInterface() throws Exception { + final JBBPParser parser = JBBPParser.prepare("a { b { c [_] { byte d;}} }"); + final String text = JBBPToJavaConverter.makeBuilder(parser) + .setMainClassName(CLASS_NAME) + .setAddGettersSetters(true) + .setMapSubClassesInterfaces( + makeMap( + "a.b", "com.igormaznitsa.Impl", + "a.b.c", "com.igormaznitsa.Impl2" + ) + ) + .build() + .convert(); + assertTrue(text.contains("public static class B implements com.igormaznitsa.Impl")); + assertTrue(text.contains("public static class C implements com.igormaznitsa.Impl2")); + assertTrue(text.contains("public com.igormaznitsa.Impl getB() { return this.b;}")); + assertTrue(text.contains("public com.igormaznitsa.Impl2 [] getC() { return this.c;}")); + System.out.println(text); + } + + @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(){}")); + } + + @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 ")); + } + + @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 ")); + } + + @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;")); + } + + @Test + void testGettersSetters() throws Exception { + final JBBPParser parser = JBBPParser.prepare("byte a;"); + 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(); + + assertFalse(text.contains("public byte a;")); + assertTrue(text.contains("protected byte a;")); + assertTrue(text.contains("public void setA(byte value) {")); + assertTrue(text.contains("public byte getA() {")); + } + + @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))); + } + + @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))); + } + + @Test + void testPngParsing() throws Exception { + final JBBPParser parser = JBBPParser.prepare( + "long header;" + + "// chunks\n" + + "chunk [_]{" + + " int length; " + + " int type; " + + " byte[length] data; " + + " int crc;" + + "}" + ); + assertCompilation(makeSources(parser, null, false, false, false)); + assertCompilation(makeSources(parser, null, true, false, false)); + } + + @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; @@ -139,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/JBBPToJava6ConverterReadWriteTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverterReadWriteTest.java similarity index 58% rename from jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJava6ConverterReadWriteTest.java rename to jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJavaConverterReadWriteTest.java index ff5bab09..37af2d47 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/compiler/conversion/JBBPToJava6ConverterReadWriteTest.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; @@ -28,62 +42,26 @@ import com.igormaznitsa.jbbp.model.JBBPAbstractField; import com.igormaznitsa.jbbp.model.JBBPFieldArrayInt; import com.igormaznitsa.jbbp.model.JBBPFieldInt; -import com.igormaznitsa.jbbp.testaux.AbstractJBBPToJava6ConverterTest; +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 org.junit.jupiter.api.function.Executable; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.InputStream; -import java.util.Collections; 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. */ -public class JBBPToJava6ConverterReadWriteTest extends AbstractJBBPToJava6ConverterTest { +public class JBBPToJavaConverterReadWriteTest extends AbstractJBBPToJavaConverterTest { private byte[] loadResource(final String name) throws Exception { - final InputStream result = this.getClass().getClassLoader().getResourceAsStream("com/igormaznitsa/jbbp/it/" + name); - try { - if (result == null) { - throw new NullPointerException("Can't find resource '" + name + '\''); - } + try (final InputStream result = requireNonNull(this.getClass().getClassLoader() + .getResourceAsStream("com/igormaznitsa/jbbp/it/" + name))) { return IOUtils.toByteArray(result); - } finally { - IOUtils.closeQuietly(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 @@ -91,6 +69,8 @@ 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;" @@ -108,13 +88,13 @@ 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 = JBBPToJava6ConverterReadWriteTest.class.getPackage().getName(); + final String thePackage = JBBPToJavaConverterReadWriteTest.class.getPackage().getName(); - final String text = JBBPToJava6Converter.makeBuilder(parser) + final String text = JBBPToJavaConverter.makeBuilder(parser) .setMainClassName(CLASS_NAME) .setMainClassPackage(thePackage) .disableGenerateFields() @@ -125,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); @@ -149,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); @@ -166,15 +154,18 @@ public void testReadWrite_ExtendsSuperClassAndUseItsFields() throws Exception { @Test public void testReaWrite_StructMappedToInterface_Array_GettersSettersOn() throws Exception { final JBBPParser parser = JBBPParser.prepare("z { x { y [_] { byte a;}}}"); - final Map interfaceMap = new HashMap(); + final Map interfaceMap = new HashMap<>(); interfaceMap.put("z.x.y", ByteTestInterface.class.getCanonicalName()); - final String text = JBBPToJava6Converter.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()); } @@ -185,15 +176,18 @@ public void testReaWrite_StructMappedToInterface_Array_GettersSettersOn() throws @Test public void testReaWrite_StructMappedToInterface_NotArray_GettersSettersOn() throws Exception { final JBBPParser parser = JBBPParser.prepare("z { x { y { byte a;}}}"); - final Map interfaceMap = new HashMap(); + final Map interfaceMap = new HashMap<>(); interfaceMap.put("z.x.y", ByteTestInterface.class.getCanonicalName()); - final String text = JBBPToJava6Converter.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)); @@ -205,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"); @@ -223,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"); @@ -242,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}; @@ -258,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()); @@ -269,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}; @@ -280,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"); @@ -288,41 +287,74 @@ 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( + 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 testReadWite_BitArrayWholeStream() throws Exception { + 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 long[] {0xFF020304L, 0x05060708L, 0x09001621L}, + getField(instance, "uintarray", long[].class)); + assertArrayEquals(etalon, callWrite(instance)); + } + + @Test + public void testReadWrite_BitArrayWholeStream() throws Exception { final Object instance = compileAndMakeInstance("bit [_] bitArray;"); assertNull(getField(instance, "bitarray", byte[].class), "by default must be null"); final byte[] etalon = new byte[1024]; - RND.nextBytes(etalon); + testRandomGen.nextBytes(etalon); callRead(instance, etalon.clone()); @@ -331,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"); @@ -339,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"); @@ -353,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"); @@ -367,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"); @@ -381,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()); @@ -399,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()); @@ -409,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 [_]{" @@ -419,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()); @@ -429,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++; } @@ -437,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())); } @Test public void testRead_ExpressionResult_OnlyField_NegativeResultAsZero() throws Exception { - final Object instance = compileAndMakeInstance("byte len; byte [len] arr;", JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO); + final Object instance = compileAndMakeInstance("byte len; byte [len] arr;", + JBBPParser.FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO); final byte[] etalon = new byte[] {(byte) 0xFE, 1, 2, 3, 4}; callRead(instance, etalon.clone()); assertEquals((byte) 0xFE, getField(instance, "len", Byte.class).byteValue()); @@ -884,20 +968,17 @@ public void testRead_ExpressionResult_OnlyField_NegativeResultAsZero() throws Ex } @Test - public void testRead_ExpressionResult_NegativeExpression_NegativeResultNotAllowed() throws Exception { + public void testRead_ExpressionResult_NegativeExpression_NegativeResultNotAllowed() + throws Exception { final Object instance = compileAndMakeInstance("byte len; byte [len-9] arr;"); final byte[] etalon = new byte[] {8, 1, 2, 3, 4}; - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - callRead(instance, etalon.clone()); - } - }); + assertThrows(IllegalArgumentException.class, () -> callRead(instance, etalon.clone())); } @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()); @@ -946,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"); @@ -959,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); @@ -988,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()); @@ -1009,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); @@ -1034,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 7f5fddb4..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,20 +16,20 @@ package com.igormaznitsa.jbbp.compiler.conversion; -import com.igormaznitsa.jbbp.JBBPParser; -import com.igormaznitsa.jbbp.testaux.AbstractJBBPToJava6ConverterTest; -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. */ -public class ParserToJBBPToJavaClassConverterJBBPFlagsTest extends AbstractJBBPToJava6ConverterTest { +public class ParserToJBBPToJavaClassConverterJBBPFlagsTest extends AbstractJBBPToJavaConverterTest { @Test public void testFlag_SkipRemainingFieldsIfEOF() throws Exception { @@ -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 bd564057..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.AbstractJBBPToJava6ConverterTest; +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 org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class RandomAutoTest extends AbstractJBBPToJava6ConverterTest { +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; } @@ -91,10 +49,54 @@ String makeRndName() { return result.toString(); } + String genRandomString(final int length) { + final StringBuilder builder = new StringBuilder(length); + for (int i = 0; i < length; i++) { + builder.append((char) (' ' + this.RND.nextInt(100))); + } + return builder.toString(); + } + + @Test + public void testCompileParseAndWriteArray() throws Exception { + int testIndex = 1; + + long generatedFields = 0L; + + for (int i = 5; i < 500; i += 3) { + Result result; + do { + result = generate(i, true); + } while (result.bitLength > 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(); - final List counterStack = new ArrayList(); + final List counterStack = new ArrayList<>(); counterStack.add(new StructLen()); int structsTotal = 0; @@ -120,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(25); + final int rndType = RND.nextInt(29); typeFlags |= (1 << rndType); switch (rndType) { case 0: { // STRUCT @@ -171,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 @@ -277,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--; @@ -300,6 +315,14 @@ Result generate(final int items, final boolean generateNames) { } } break; + case 27: { // COMMENT + builder.Comment(genRandomString(this.RND.nextInt(32))); + } + break; + case 28: { // COMMENT NEW LINE + builder.NewLineComment(genRandomString(this.RND.nextInt(32))); + } + break; } } } @@ -311,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(0x1FFFFFFL, 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(" new JBBPTokenizer("int $$;").next()); + assertThrows(JBBPTokenizerException.class, () -> new JBBPTokenizer("int $a;").next()); + assertThrows(JBBPTokenizerException.class, () -> new JBBPTokenizer("int a%d;").next()); + assertThrows(JBBPTokenizerException.class, () -> new JBBPTokenizer("int 1a;").next()); + assertThrows(JBBPTokenizerException.class, () -> new JBBPTokenizer("int _;").next()); + } + @Test public void testError_ForEmptyString() { final JBBPTokenizer parser = new JBBPTokenizer(""); @@ -48,6 +63,7 @@ public void testError_ForArrayFieldWithoutType() { fail("Must throw Tokenizer exception"); } catch (JBBPTokenizerException ex) { assertEquals(1, ex.getPosition()); + assertEquals("->[<- 123] hello;", ex.getErrorPart()); } } @@ -63,6 +79,7 @@ public void testStructureEndAndErrorForArrayFieldWithoutType() { fail("Must throw Tokenizer exception"); } catch (JBBPTokenizerException ex) { assertEquals(2, ex.getPosition()); + assertEquals("} ->[<- 123] hello;", ex.getErrorPart()); } } @@ -119,6 +136,7 @@ public void testSingleLine_ErrorForUnsupportedText() { fail("Must throw parser exception"); } catch (JBBPTokenizerException ex) { assertEquals(0, ex.getPosition()); + assertEquals("-> <- some", ex.getErrorPart()); } } @@ -213,17 +231,13 @@ 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()); } } @Test public void testErrorForIteratorRemove() { - assertThrows(UnsupportedOperationException.class, new Executable() { - @Override - public void execute() throws Throwable { - new JBBPTokenizer("int a;").remove(); - } - }); + assertThrows(UnsupportedOperationException.class, () -> new JBBPTokenizer("int a;").remove()); } @Test @@ -236,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()); } } @@ -249,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()); } } @@ -262,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()); } } @@ -275,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()); } } @@ -357,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()); } } @@ -394,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()); } } @@ -408,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()); } } @@ -425,6 +446,7 @@ public void testErrorForNonRecognizedStringInMiddleOfText() { fail("Must throw exception"); } catch (JBBPTokenizerException ex) { assertEquals(8, ex.getPosition()); + assertEquals("test ->\\u000a<- wrong", ex.getErrorPart()); } } @@ -486,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) { @@ -517,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 6df2bcd6..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,216 +31,131 @@ 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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator(" ( ( ( ( ) )) ) ", null, null); - } - }); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator(" ( ( ( ( ) )) ) ", null, null)); } @Test public void testExpression_Error_NonClosedBracket() { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator(" ", null, null); - } - }); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator(" ", null, null)); } @Test public void testExpression_Error_Empty() { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator("", null, null); - } - }); + assertThrows(JBBPCompilationException.class, () -> new JBBPExpressionEvaluator("", null, null)); } @Test public void testExpression_Error_OnlyUnaryPlus() { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator("+", null, null); - } - }); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("+", null, null)); } @Test public void testExpression_Error_OnlyUnaryMinus() { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator("-", null, null); - } - }); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("-", null, null)); } @Test public void testExpression_Error_OnlyNot() { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator("~", null, null); - } - }); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("~", null, null)); } @Test public void testExpression_Error_WrongFirstUnaryOperator() { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator("%345", null, null); - } - }); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("%345", null, null)); } @Test public void testExpression_Error_WrongUnaryOperator() { - assertThrows(JBBPCompilationException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator("*", null, null); - } - }); + assertThrows(JBBPCompilationException.class, + () -> new JBBPExpressionEvaluator("*", null, null)); } @Test public void testExpression_Error_MulWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator("123^", null, null).eval(null, 0, null, null); - } - }); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("123^", null, null).eval(null, 0, null, null)); } @Test @@ -263,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 @@ -272,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 @@ -371,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 @@ -502,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 @@ -516,12 +449,8 @@ public void testExpression_LeftShift() { @Test public void testExpression_LeftShift_ErrorWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, new Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator("1234<<", null, null).eval(null, 0, null, null); - } - }); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("1234<<", null, null).eval(null, 0, null, null)); } @Test @@ -533,12 +462,8 @@ public void testExpression_RightShift() { @Test public void testExpression_RightShift_ErrorWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, new Executable() { - @Override - public void execute() throws Throwable { - new JBBPExpressionEvaluator("1234 >>", null, null).eval(null, 0, null, null); - } - }); + assertThrows(JBBPEvalException.class, + () -> new JBBPExpressionEvaluator("1234 >>", null, null).eval(null, 0, null, null)); } @Test @@ -557,53 +482,47 @@ public void testExpression_RightSignShiftWithInversion() { @Test public void testExpression_RightSignShift_ErrorWithoutSecondArgument() { - assertThrows(JBBPEvalException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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(new JBBPExternalValueProvider() { - - @Override - public int provideArraySize(final String fieldName, final JBBPNamedNumericFieldMap numericFieldMap, final JBBPCompiledBlock 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(new JBBPExternalValueProvider() { - - @Override - public int provideArraySize(final String fieldName, final JBBPNamedNumericFieldMap numericFieldMap, final JBBPCompiledBlock 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 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()); @@ -619,29 +538,30 @@ public void testExpression_NotAfterMinus() throws Exception { @Test public void testExpression_CheckExternalFieldAndStreamOffset() throws Exception { final int value = 1234; - final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(new JBBPExternalValueProvider() { - - @Override - public int provideArraySize(final String fieldName, final JBBPNamedNumericFieldMap numericFieldMap, final JBBPCompiledBlock 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 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 64592182..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 { @@ -40,11 +41,13 @@ public void testNumericValue() { map.putField(new JBBPFieldInt(nameInfo, value)); - final List list = new ArrayList(); + final List list = new ArrayList<>(); 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,24 +56,23 @@ public void testNumericValue() { @Test public void testExternalValue() { final int value = 1234; - final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(new JBBPExternalValueProvider() { - - @Override - public int provideArraySize(final String fieldName, final JBBPNamedNumericFieldMap numericFieldMap, final JBBPCompiledBlock 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 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)); @@ -79,24 +81,23 @@ public int provideArraySize(final String fieldName, final JBBPNamedNumericFieldM @Test public void testExternalValueNamedAsFirstCharDollar() { final int value = 1234; - final JBBPNamedNumericFieldMap map = new JBBPNamedNumericFieldMap(new JBBPExternalValueProvider() { - - @Override - public int provideArraySize(final String fieldName, final JBBPNamedNumericFieldMap numericFieldMap, final JBBPCompiledBlock 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 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)); @@ -104,14 +105,17 @@ public int provideArraySize(final String fieldName, final JBBPNamedNumericFieldM @Test public void testCounterOfStreamAsParameter() throws Exception { - final List list = new ArrayList(); + 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 e8157c3b..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,28 +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 org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.IOException; import java.util.Random; - -import static org.junit.jupiter.api.Assertions.*; +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]; } @@ -49,57 +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, new Executable() { - @Override - public void execute() throws Throwable { - asInputStream().readUnsignedShort(JBBPByteOrder.BIG_ENDIAN); - } - }); + assertThrows(EOFException.class, + () -> asInputStream().readUnsignedShort(BIG_ENDIAN)); } @Test public void testReadUnsignedShort_EOFforEmpty_LittleEndian_EOFException() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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 @@ -109,117 +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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - asInputStream(0xFF, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(8, JBBPByteOrder.BIG_ENDIAN); - } - }); - assertThrows(IOException.class, new Executable() { - @Override - public void execute() throws Throwable { - asInputStream().readStringArray(8, JBBPByteOrder.BIG_ENDIAN); - } - }); - assertThrows(IOException.class, new Executable() { - @Override - public void execute() throws Throwable { - asInputStream().readStringArray(8, JBBPByteOrder.LITTLE_ENDIAN); - } - }); - assertThrows(IOException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - asInputStream(0x80, 0x00, 3, 65, 66, 67, 0, 0).readStringArray(3, JBBPByteOrder.BIG_ENDIAN); - } - }); - assertThrows(IOException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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(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 @@ -234,179 +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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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, new Executable() { - @Override - public void execute() throws Throwable { - 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()); @@ -414,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()); @@ -433,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()); @@ -451,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()); @@ -506,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()); @@ -542,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)); @@ -570,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++) { @@ -581,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)); @@ -595,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++) { @@ -606,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)); @@ -633,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()); @@ -694,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); @@ -702,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()); @@ -727,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()); @@ -744,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()); @@ -774,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); @@ -808,24 +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 { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(JBBPUtils.str2bin("00101001_11001011_10111110", JBBPBitOrder.LSB0))); - in.readBitsArray(58, JBBPBitNumber.BITS_2); - } + public void testReadArray_Bits_EOF() { + assertThrows(EOFException.class, () -> { + 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()); @@ -858,37 +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 { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); - in.readByteArray(259); - } + 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})); + 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); @@ -897,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); @@ -912,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++) { @@ -924,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); @@ -934,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); @@ -949,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++) { @@ -961,33 +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 { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - final JBBPBitInputStream in = new JBBPBitInputStream(new ByteArrayInputStream(new byte[] {1, 2, 3, 4, 5, 6, 7, 0})); - in.readShortArray(259, JBBPByteOrder.BIG_ENDIAN); - } + 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, 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); @@ -996,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]; @@ -1011,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); @@ -1033,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]; @@ -1048,56 +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 { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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); - } + 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.readUIntArray(259, BIG_ENDIAN); }); } @Test public void testReadArray_DoubleInt_EOF() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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); - } + 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, 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); @@ -1106,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]; @@ -1121,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); @@ -1143,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]; @@ -1158,55 +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, new Executable() { - @Override - public void execute() throws Throwable { - 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); - } + 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, BIG_ENDIAN); }); } @Test public void testReadArray_Double_EOF() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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); - } + 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, 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()); @@ -1214,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(); @@ -1226,12 +1658,7 @@ public void testResetCounter_ForCachedBits() throws Exception { @Test public void testReadBooleanArray_EOF() throws Exception { - assertThrows(EOFException.class, new Executable() { - @Override - public void execute() throws Throwable { - asInputStream(1, 2, 3, 4, 5, 6).readBoolArray(256); - } - }); + assertThrows(EOFException.class, () -> asInputStream(1, 2, 3, 4, 5, 6).readBoolArray(256)); } @Test @@ -1251,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()); @@ -1292,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(); @@ -1305,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 e6c75944..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,39 +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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - 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 Executable() { - @Override - public void execute() throws Throwable { - new JBBPBitOutputStream(new ByteArrayOutputStream()).writeBits(4, JBBPBitNumber.decode(9)); - } - }); + assertThrows(IllegalArgumentException.class, + () -> new JBBPBitOutputStream(new ByteArrayOutputStream()) + .writeBits(4, JBBPBitNumber.decode(9))); } @Test @@ -482,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); @@ -547,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 69e8dff0..12b2efa1 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPOutTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPOutTest.java @@ -16,23 +16,25 @@ package com.igormaznitsa.jbbp.io; +import static com.igormaznitsa.jbbp.io.JBBPOut.BeginBin; +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.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +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 org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.Arrays; - -import static com.igormaznitsa.jbbp.io.JBBPOut.BeginBin; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPOutTest { @@ -42,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) 0x41, (byte) 0x42, (byte) 0x43}, 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(); @@ -84,29 +104,29 @@ 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 public void testSkip_ErrorForNegativeValue() throws Exception { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - BeginBin().Skip(-1); - } - }); + assertThrows(IllegalArgumentException.class, () -> BeginBin().Skip(-1)); } @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 @@ -137,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, 00, 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, 03, 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 @@ -165,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 @@ -200,175 +244,244 @@ 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 public void testShort() throws Exception { - assertArrayEquals(new byte[] {0x01, 02}, BeginBin().Short(0x0102).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02}, BeginBin().Short(0x0102).End().toByteArray()); } @Test public void testShort_BigEndian() throws Exception { - assertArrayEquals(new byte[] {0x01, 02}, BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short(0x0102).End().toByteArray()); + assertArrayEquals(new byte[] {0x01, 0x02}, + BeginBin().ByteOrder(JBBPByteOrder.BIG_ENDIAN).Short(0x0102).End().toByteArray()); } @Test public void testShort_String_NPEForNullString() throws Exception { - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - BeginBin().Short((String) null).End(); - } - }); + assertThrows(NullPointerException.class, () -> BeginBin().Short((String) null).End()); } @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, 01}, 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, 02, 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, 02, 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, 02, 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, 02, 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, 02, 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 @@ -563,12 +676,8 @@ public void testExceptionForBitOrderConfilctInCaseOfUsageBitOutputStream() throw final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); final JBBPBitOutputStream bitstream = new JBBPBitOutputStream(buffer, JBBPBitOrder.LSB0); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - BeginBin(bitstream, JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.MSB0); - } - }); + assertThrows(IllegalArgumentException.class, + () -> BeginBin(bitstream, JBBPByteOrder.BIG_ENDIAN, JBBPBitOrder.MSB0)); } @Test @@ -590,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); @@ -599,21 +710,16 @@ public void testComplexWriting_1() throws Exception { @Test public void testVar_NPEForNullProcessor() throws Exception { - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - BeginBin().Var(null).End(); - } - }); + assertThrows(NullPointerException.class, () -> BeginBin().Var(null).End()); } @Test public void testVar_ProcessRest() throws Exception { class Test { - @Bin(outOrder = 1) + @Bin(order = 1) byte a; - @Bin(outOrder = 2) + @Bin(order = 2) byte b; Test(int a, int b) { @@ -624,31 +730,28 @@ class Test { final byte[] array = BeginBin(). Byte(0xCC). - Var(new JBBPOutVarProcessor() { - - @Override - public boolean processVarOut(final JBBPOut context, final JBBPBitOutputStream outStream, final Object... args) throws IOException { - assertNotNull(context); - assertNotNull(outStream); - assertEquals(0, args.length); - outStream.write(0xDD); - return true; - } + Var((context, outStream, args) -> { + assertNotNull(context); + assertNotNull(outStream); + assertEquals(0, args.length); + outStream.write(0xDD); + return true; }). Byte(0xAA). 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 public void testVar_SkipRest() throws Exception { class Test { - @Bin(outOrder = 1) + @Bin(order = 1) byte a; - @Bin(outOrder = 2) + @Bin(order = 2) byte b; Test(int a, int b) { @@ -659,16 +762,12 @@ class Test { final byte[] array = BeginBin(). Byte(0xCC). - Var(new JBBPOutVarProcessor() { - - @Override - public boolean processVarOut(final JBBPOut context, final JBBPBitOutputStream outStream, final Object... args) throws IOException { - assertNotNull(context); - assertNotNull(outStream); - assertEquals(0, args.length); - outStream.write(0xDD); - return false; - } + Var((context, outStream, args) -> { + assertNotNull(context); + assertNotNull(outStream); + assertEquals(0, args.length); + outStream.write(0xDD); + return false; }). Byte(0xAA). Align(15). @@ -699,13 +798,9 @@ public boolean processVarOut(final JBBPOut context, final JBBPBitOutputStream ou Skip(332). Bin(new Test(12, 34)). Utf8("werwerew"). - Var(new JBBPOutVarProcessor() { - - @Override - public boolean processVarOut(JBBPOut context, JBBPBitOutputStream outStream, Object... args) throws IOException { - fail("Must not be called"); - return false; - } + Var((context, outStream, args) -> { + fail("Must not be called"); + return false; }). End().toByteArray(); @@ -714,26 +809,23 @@ public boolean processVarOut(JBBPOut context, JBBPBitOutputStream outStream, Obj @Test public void testVar_VariableContent() throws Exception { - final JBBPOutVarProcessor var = new JBBPOutVarProcessor() { - @Override - public boolean processVarOut(JBBPOut context, JBBPBitOutputStream outStream, Object... args) throws IOException { - final int type = (Integer) args[0]; - switch (type) { - case 0: { - context.Int(0x01020304); - } - break; - case 1: { - context.Int(0x05060708); - } - break; - default: { - fail("Unexpected parameter [" + type + ']'); - } - break; + final JBBPOutVarProcessor var = (context, outStream, args) -> { + final int type = (Integer) args[0]; + switch (type) { + case 0: { + context.Int(0x01020304); } - return true; + break; + case 1: { + context.Int(0x05060708); + } + break; + default: { + fail("Unexpected parameter [" + type + ']'); + } + break; } + return true; }; final byte[] array = BeginBin(). @@ -748,11 +840,32 @@ public boolean processVarOut(JBBPOut context, JBBPBitOutputStream outStream, Obj public void testBin_UndefinedType_Byte() throws Exception { class Test { - @Bin(outOrder = 3) + @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, (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(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) byte b; - @Bin(outOrder = 1) + @Bin(order = 1) byte a; Test(byte a, byte b, byte c) { @@ -761,39 +874,76 @@ 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, 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 public void testBin_UndefinedType_Boolean() throws Exception { class Test { - @Bin(outOrder = 3) + @Bin(order = 3) boolean c; - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) boolean b; - @Bin(outOrder = 1) + @Bin(order = 1) boolean a; Test(boolean a, boolean b, boolean c) { @@ -802,18 +952,77 @@ 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 public void testBin_BitType_Bits() throws Exception { class Test { - @Bin(outBitNumber = JBBPBitNumber.BITS_4, outOrder = 3, type = BinType.BIT) + @Bin(bitNumber = JBBPBitNumber.BITS_4, order = 3, type = BinType.BIT) byte c; - @Bin(outBitNumber = JBBPBitNumber.BITS_4, outOrder = 2, type = BinType.BIT, bitOrder = JBBPBitOrder.MSB0) + @Bin(bitNumber = JBBPBitNumber.BITS_4, order = 2, type = BinType.BIT, bitOrder = JBBPBitOrder.MSB0) byte b; - @Bin(outBitNumber = JBBPBitNumber.BITS_4, type = BinType.BIT, outOrder = 1) + @Bin(bitNumber = JBBPBitNumber.BITS_4, type = BinType.BIT, order = 1) byte a; Test(byte a, byte b, byte c) { @@ -822,18 +1031,47 @@ 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 public void testBin_UndefinedType_Short() throws Exception { class Test { - @Bin(outOrder = 3) + @Bin(order = 3) short c; - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) short b; - @Bin(outOrder = 1) + @Bin(order = 1) short a; Test(short a, short b, short c) { @@ -843,18 +1081,20 @@ 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 public void testBin_UndefinedType_Char() throws Exception { class Test { - @Bin(outOrder = 3) + @Bin(order = 3) char c; - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) char b; - @Bin(outOrder = 1) + @Bin(order = 1) char a; Test(char a, char b, char c) { @@ -864,18 +1104,19 @@ 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 public void testBin_UndefinedType_Int() throws Exception { class Test { - @Bin(outOrder = 3) + @Bin(order = 3) int c; - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) int b; - @Bin(outOrder = 1) + @Bin(order = 1) int a; Test(int a, int b, int c) { @@ -885,18 +1126,21 @@ 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 public void testBin_UndefinedType_Float() throws Exception { class Test { - @Bin(outOrder = 3) + @Bin(order = 3) float c; - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) float b; - @Bin(outOrder = 1) + @Bin(order = 1) float a; Test(float a, float b, float c) { @@ -908,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()); } @@ -917,11 +1162,11 @@ class Test { public void testBin_UndefinedType_Long() throws Exception { class Test { - @Bin(outOrder = 3) + @Bin(order = 3) long c; - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) long b; - @Bin(outOrder = 1) + @Bin(order = 1) long a; Test(long a, long b, long c) { @@ -935,18 +1180,19 @@ 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 public void testBin_UndefinedType_Double() throws Exception { class Test { - @Bin(outOrder = 3) + @Bin(order = 3) double c; - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) double b; - @Bin(outOrder = 1) + @Bin(order = 1) double a; Test(double a, double b, double c) { @@ -958,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()); } @@ -967,9 +1215,9 @@ class Test { public void testBin_UndefinedType_Struct() throws Exception { class Inside { - @Bin(outOrder = 1) + @Bin(order = 1) byte a; - @Bin(outOrder = 2) + @Bin(order = 2) byte b; Inside(byte a, byte b) { @@ -980,11 +1228,11 @@ class Inside { class Test { - @Bin(outOrder = 2) + @Bin(order = 2) Inside c; - @Bin(outOrder = 1) + @Bin(order = 1) byte a; - @Bin(outOrder = 3) + @Bin(order = 3) byte b; Test(byte a, byte b, Inside c) { @@ -994,18 +1242,57 @@ 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 public void testBin_DefinedType_Array_Bits() throws Exception { class Test { - @Bin(outOrder = 2, outBitNumber = JBBPBitNumber.BITS_4, type = BinType.BIT_ARRAY) + @Bin(order = 2, bitNumber = JBBPBitNumber.BITS_4, type = BinType.BIT_ARRAY) byte[] array; - @Bin(outOrder = 3, outBitNumber = JBBPBitNumber.BITS_4, type = BinType.BIT_ARRAY, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 3, bitNumber = JBBPBitNumber.BITS_4, type = BinType.BIT_ARRAY, bitOrder = JBBPBitOrder.MSB0) byte[] lsbarray; - @Bin(outOrder = 1) + @Bin(order = 1) byte prefix; Test(byte prefix, byte[] array, byte[] lsbarray) { @@ -1015,16 +1302,17 @@ 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 public void testBin_UndefinedType_Array_Bytes() throws Exception { class Test { - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) byte[] lsbarray; - @Bin(outOrder = 1) + @Bin(order = 1) byte[] array; Test(byte[] array, byte[] lsbarray) { @@ -1032,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()); } @@ -1040,9 +1329,9 @@ class Test { public void testBin_UndefinedType_Array_Boolean() throws Exception { class Test { - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) boolean[] lsbarray; - @Bin(outOrder = 1) + @Bin(order = 1) boolean[] array; Test(boolean[] array, boolean[] lsbarray) { @@ -1051,16 +1340,18 @@ 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 public void testBin_UndefinedType_Array_Bytes_String() throws Exception { class Test { - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0, type = BinType.BYTE_ARRAY) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0, type = BinType.BYTE_ARRAY) String lsbarray; - @Bin(outOrder = 1, type = BinType.BYTE_ARRAY) + @Bin(order = 1, type = BinType.BYTE_ARRAY) String array; Test(String array, String lsbarray) { @@ -1076,9 +1367,9 @@ class Test { public void testBin_UndefinedType_Array_String_String() throws Exception { class Test { - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) String lsbarray; - @Bin(outOrder = 1) + @Bin(order = 1) String array; Test(String array, String lsbarray) { @@ -1095,9 +1386,9 @@ class Test { public void testBin_UndefinedType_Array_Short() throws Exception { class Test { - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) short[] lsbarray; - @Bin(outOrder = 1) + @Bin(order = 1) short[] array; Test(short[] array, short[] lsbarray) { @@ -1105,17 +1396,21 @@ 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 public void testBin_DefinedType_Array_Short_String() throws Exception { class Test { - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0, type = BinType.SHORT_ARRAY) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0, type = BinType.SHORT_ARRAY) String lsbarray; - @Bin(outOrder = 1, type = BinType.SHORT_ARRAY) + @Bin(order = 1, type = BinType.SHORT_ARRAY) String array; Test(String array, String lsbarray) { @@ -1123,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()); } @@ -1131,9 +1428,9 @@ class Test { public void testBin_UndefinedType_Array_Int() throws Exception { class Test { - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) int[] lsbarray; - @Bin(outOrder = 1) + @Bin(order = 1) int[] array; Test(int[] array, int[] lsbarray) { @@ -1141,18 +1438,21 @@ 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 public void testBin_UndefinedType_Array_Float() throws Exception { class Test { - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) float[] lsbarray; - @Bin(outOrder = 1) + @Bin(order = 1) float[] array; Test(float[] array, float[] lsbarray) { @@ -1161,20 +1461,27 @@ 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 public void testBin_UndefinedType_Array_Long() throws Exception { class Test { - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) long[] lsbarray; - @Bin(outOrder = 1) + @Bin(order = 1) long[] array; Test(long[] array, long[] lsbarray) { @@ -1183,20 +1490,22 @@ 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 public void testBin_UndefinedType_Array_Object() throws Exception { class Inner { - @Bin(outOrder = 1) + @Bin(order = 1) byte a; - @Bin(outOrder = 2) + @Bin(order = 2) byte b; Inner(byte a, byte b) { @@ -1207,9 +1516,9 @@ class Inner { class Test { - @Bin(outOrder = 2) + @Bin(order = 2) Inner[] inner; - @Bin(outOrder = 1) + @Bin(order = 1) byte prefix; Test(byte prefix, Inner[] inner) { @@ -1218,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()); } @@ -1226,9 +1537,9 @@ class Test { public void testBin_TwoFieldWithTheSameorder() throws Exception { class Test { - @Bin(outOrder = 1) + @Bin(order = 1) byte a; - @Bin(outOrder = 1) + @Bin(order = 1) byte b; Test(byte a, byte b) { @@ -1244,9 +1555,9 @@ class Test { public void testBin_CustomField_ErrorBecauseNoCustomWriter() throws Exception { class Test { - @Bin(outOrder = 1) + @Bin(order = 1) byte a; - @Bin(outOrder = 2, custom = true) + @Bin(order = 2, custom = true) byte b; Test(byte a, byte b) { @@ -1255,21 +1566,17 @@ class Test { } } - assertThrows(JBBPIllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - BeginBin().Bin(new Test((byte) 12, (byte) 24)); - } - }); + assertThrows(JBBPIllegalArgumentException.class, + () -> BeginBin().Bin(new Test((byte) 12, (byte) 24))); } @Test public void testBin_CustomField_NoError() throws Exception { class Test { - @Bin(outOrder = 1) + @Bin(order = 1) byte a; - @Bin(outOrder = 2, custom = true) + @Bin(order = 2, custom = true) byte b; Test(byte a, byte b) { @@ -1278,31 +1585,29 @@ class Test { } } - assertArrayEquals(new byte[] {1, 2, 3}, BeginBin().Bin(new Test((byte) 1, (byte) 0), new JBBPCustomFieldWriter() { - @Override - public void writeCustomField(JBBPOut context, JBBPBitOutputStream outStream, Object instanceToSave, Field instanceCustomField, Bin fieldAnnotation, Object value) throws IOException { - 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 private static class TestWithStaticField { static int some = 111; - @Bin(outOrder = 3) + @Bin(order = 3) byte c; - @Bin(outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(order = 2, bitOrder = JBBPBitOrder.MSB0) byte b; - @Bin(outOrder = 1) + @Bin(order = 1) byte a; TestWithStaticField(byte a, byte b, byte c) { @@ -1312,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 2ee5d5f9..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,46 +16,35 @@ package com.igormaznitsa.jbbp.it; -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import com.igormaznitsa.jbbp.utils.JBBPUtils; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringWriter; -import static org.junit.jupiter.api.Assertions.*; +import com.igormaznitsa.jbbp.io.JBBPBitInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import org.apache.commons.io.IOUtils; public abstract class AbstractParserIntegrationTest { - public void assertFile(final String fileName, final String text) throws Exception { - final InputStream in = this.getClass().getResourceAsStream(fileName); - assertNotNull(in, "Can't find file [" + fileName + "]"); - Reader reader = null; - String fileText; - try { - reader = new InputStreamReader(in, "UTF-8"); - final StringWriter wr = new StringWriter(); + 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; - while (true) { - final int chr = reader.read(); - if (chr < 0) { - break; - } - wr.write(chr); - } - wr.close(); - fileText = wr.toString(); - } finally { - if (reader != null) { - reader.close(); - } + try (InputStream inStream = this.getResourceAsInputStream(fileName)) { + fileText = IOUtils.toString(inStream, StandardCharsets.UTF_8); } - assertEquals(fileText, text, "File content must be equals"); + assertEquals(normalizeEol(fileText), normalizeEol(content), "File content must be equals"); } - public InputStream getResourceAsInputStream(final String resourceName) throws Exception { + public InputStream getResourceAsInputStream(final String resourceName) { final InputStream result = this.getClass().getResourceAsStream(resourceName); if (result == null) { throw new NullPointerException("Can't find resource '" + resourceName + '\''); @@ -64,12 +53,9 @@ public InputStream getResourceAsInputStream(final String resourceName) throws Ex } public void assertResource(final String resourceName, final byte[] content) throws Exception { - final InputStream in = getResourceAsInputStream(resourceName); - try { - final byte[] fileContent = new JBBPBitInputStream(in).readByteArray(-1); - assertArrayEquals(fileContent, content, "Content of '" + resourceName + "'"); - } finally { - JBBPUtils.closeQuietly(in); + 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 051d8536..e41919ef 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/BasedOnQuestionsAndCasesTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/BasedOnQuestionsAndCasesTest.java @@ -16,44 +16,118 @@ 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.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; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; import com.igormaznitsa.jbbp.model.JBBPNumericField; import com.igormaznitsa.jbbp.utils.JBBPDslBuilder; import com.igormaznitsa.jbbp.utils.JBBPTextWriter; -import org.junit.jupiter.api.Test; - +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 static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /** * Tests based on questions and cases. */ 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 *

@@ -67,20 +141,23 @@ public class BasedOnQuestionsAndCasesTest extends AbstractParserIntegrationTest @Test public void testParseDayMonthYearFromBytePairInMSB0AndPackThemBack() throws Exception { class YearMonthDay { - @Bin(type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_6, outOrder = 1, bitOrder = JBBPBitOrder.MSB0) + @Bin(type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_6, order = 1, bitOrder = JBBPBitOrder.MSB0) byte year; - @Bin(type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_4, outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_4, order = 2, bitOrder = JBBPBitOrder.MSB0) byte month; - @Bin(type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_5, outOrder = 3, bitOrder = JBBPBitOrder.MSB0) + @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(YearMonthDay.class); + 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()); } /** @@ -96,41 +173,43 @@ public void testParseTimeStampFromTETRASavedInMSB0() throws Exception { final byte[] TEST_DATA = new byte[] {0x2, 0x42, (byte) 0x81}; class TetraTimestamp { - @Bin(type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_2, outOrder = 1, bitOrder = JBBPBitOrder.MSB0) + @Bin(type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_2, order = 1, bitOrder = JBBPBitOrder.MSB0) byte timezone; - @Bin(type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_2, outOrder = 2, bitOrder = JBBPBitOrder.MSB0) + @Bin(type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_2, order = 2, bitOrder = JBBPBitOrder.MSB0) byte reserved; - @Bin(type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_4, outOrder = 3, bitOrder = JBBPBitOrder.MSB0) + @Bin(type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_4, order = 3, bitOrder = JBBPBitOrder.MSB0) byte month; - @Bin(type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_5, outOrder = 4, bitOrder = JBBPBitOrder.MSB0) + @Bin(type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_5, order = 4, bitOrder = JBBPBitOrder.MSB0) byte day; - @Bin(type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_5, outOrder = 5, bitOrder = JBBPBitOrder.MSB0) + @Bin(type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_5, order = 5, bitOrder = JBBPBitOrder.MSB0) byte hour; - @Bin(type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_6, outOrder = 6, bitOrder = JBBPBitOrder.MSB0) + @Bin(type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_6, order = 6, bitOrder = JBBPBitOrder.MSB0) byte minute; } - 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(TetraTimestamp.class); + 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;" @@ -172,13 +251,10 @@ public void testMutlithredUsageOfParser() throws Exception { + "byte [HLEN*4-20] Option;" + "byte [_] Data;"); - InputStream inStream = getResourceAsInputStream("tcppacket.bin"); byte[] testArray; - try { + try (InputStream inStream = getResourceAsInputStream("tcppacket.bin")) { testArray = new JBBPBitInputStream(inStream).readByteArray(-1); assertEquals(173, testArray.length); - } finally { - inStream.close(); } final byte[] theData = testArray; @@ -188,21 +264,22 @@ public void testMutlithredUsageOfParser() throws Exception { final int ITERATIONS = 1000; - final Runnable test = new Runnable() { - @Override - public void run() { - for (int i = 0; i < ITERATIONS; i++) { - try { - Thread.sleep(System.nanoTime() & 0xF); - 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(); - assertEquals(4, optionsip.length); - parsingCounter.incrementAndGet(); - } catch (Exception ex) { - ex.printStackTrace(); - errorCounter.incrementAndGet(); - } + final Runnable test = () -> { + for (int i = 0; i < ITERATIONS; i++) { + try { + Thread.sleep(System.nanoTime() & 0xF); + 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(); + assertEquals(4, optionsip.length); + parsingCounter.incrementAndGet(); + } catch (Exception ex) { + ex.printStackTrace(); + errorCounter.incrementAndGet(); } } }; @@ -227,23 +304,124 @@ public void run() { @Test public void testParseBitsThroughDslBasedScriptAndMapping() throws Exception { class Bits { - @Bin(name = "a", type = BinType.BIT_ARRAY, outBitNumber = JBBPBitNumber.BITS_1, extra = "_") + @Bin(name = "a", type = BinType.BIT_ARRAY, bitNumber = JBBPBitNumber.BITS_1, arraySizeExpr = "_") 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(Bits.class); + Bits parsed = parser.parse(new byte[] {73}).mapTo(new Bits()); System.out.println(JBBPTextWriter.makeStrWriter().Bin(parsed).Close().toString()); assertArrayEquals(new byte[] {1, 0, 0, 1, 0, 0, 1, 0}, parsed.bit); } + /** + * Case 03-feb-2020 + * Issue #26, Bug in parsing of stringj written in MSB0 + * + * @throws Exception for any error + */ + @Test + public void testStringMsb0() throws Exception { + 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()); + 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 @@ -254,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; } @@ -265,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; } @@ -279,25 +459,31 @@ 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); } else { if (readWholeStream) { - ArrayList laLaLaLaLong = new ArrayList(); + ArrayList laLaLaLaLong = new ArrayList<>(); try { - while (true) { + while (!Thread.currentThread().isInterrupted()) { laLaLaLaLong.add(uint32_read(in, customTypeFieldInfo.getByteOrder(), bitOrder)); } } catch (EOFException e) { } - long longs[] = convertLongs(laLaLaLaLong); + long[] longs = convertLongs(laLaLaLaLong); return new JBBPFieldArrayLong(fieldName, longs); @@ -327,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 da409c31..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,12 +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 static org.junit.jupiter.api.Assertions.*; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; public class ClassParsingTest extends AbstractParserIntegrationTest { @@ -87,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;" @@ -130,37 +134,43 @@ 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; switch (tagItem) { - case CONSTANT_Class: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte()}); + case CONSTANT_Class: + case CONSTANT_String: + case CONSTANT_MethodType: { + result = new JBBPFieldArrayByte(fieldName, + new byte[] {(byte) tagItem, (byte) inStream.readByte(), + (byte) inStream.readByte()}); } break; case CONSTANT_InterfaceMethodref: case CONSTANT_Methodref: - case CONSTANT_Fieldref: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte()}); - } - break; - case CONSTANT_String: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte()}); - } - break; + case CONSTANT_Fieldref: case CONSTANT_Float: - case CONSTANT_Integer: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte()}); + 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()}); } 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()}); - } - break; - 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(), (byte) inStream.readByte(), + (byte) inStream.readByte(), (byte) inStream.readByte(), + (byte) inStream.readByte()}); } break; case CONSTANT_Utf8: { @@ -176,16 +186,11 @@ public JBBPAbstractArrayField readVarArray(final JB result = new JBBPFieldArrayByte(fieldName, res); } break; - case CONSTANT_MethodHandle: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte(), (byte) inStream.readByte()}); - } - break; - case CONSTANT_MethodType: { - result = new JBBPFieldArrayByte(fieldName, new byte[] {(byte) tagItem, (byte) inStream.readByte(), (byte) inStream.readByte()}); - } - 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: { @@ -200,22 +205,28 @@ 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, "UTF-8"); + return new String(utf8data, 3, utf8data.length - 3, StandardCharsets.UTF_8); } private void assertAttribute(final ClassFile klass, final AttributeInfo attr) throws Exception { @@ -228,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); @@ -266,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(ClassFile.class); + 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 { @@ -278,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(ClassFile.class); - 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); @@ -287,17 +303,17 @@ public void testParseClassFile_HexEngineClass() throws Exception { } @Bin - private class ConstantPoolItem { + public static class ConstantPoolItem { byte[] cp_item; } @Bin - private class Interface { + public static class Interface { char index; } @Bin - private class FieldMethodInfo { + public static class FieldMethodInfo { char access_flags; char name_index; char descriptor_index; @@ -306,14 +322,14 @@ private class FieldMethodInfo { } @Bin - private class AttributeInfo { + public static class AttributeInfo { char name_index; int length; byte[] info; } @Bin - private 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 a5ac5b99..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) { @@ -132,8 +132,7 @@ public static JSONObject convertToJSon(final JSONObject jsn, final JBBPAbstractF @Test public void testConvertToJSON() throws Exception { - final InputStream pngStream = getResourceAsInputStream("picture.png"); - try { + try (InputStream pngStream = getResourceAsInputStream("picture.png")) { final JBBPParser pngParser = JBBPParser.prepare( "long header;" @@ -148,15 +147,13 @@ public void testConvertToJSON() throws Exception { 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:")); assertTrue(jsonText.contains("type:")); assertTrue(jsonText.contains("data:")); assertTrue(jsonText.contains("crc:")); - } finally { - pngStream.close(); } } } 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 d289a9a6..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,34 +82,44 @@ 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(" parser.parse(new byte[] {0x01, 0x02})); } @Test public void testReadThreeByteInteger_WholeArray() throws Exception { - final JBBPParser parser = JBBPParser.prepare("int24 [_] array;", 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()); + final JBBPParser parser = + JBBPParser.prepare("int24 [_] array;", 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()); } @Test public void testReadThreeByteInteger_ArrayFirstThreeElements() throws Exception { - final JBBPParser parser = JBBPParser.prepare("int24 [3] array;", new Int24CustomTypeProcessor()); - assertArrayEquals(new int[] {0x010203, 0x040506, 0x070809}, parser.parse(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}).findFieldForType(JBBPFieldArrayInt.class).getArray()); + final JBBPParser parser = + JBBPParser.prepare("int24 [3] array;", new Int24CustomTypeProcessor()); + assertArrayEquals(new int[] {0x010203, 0x040506, 0x070809}, parser + .parse(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}) + .findFieldForType(JBBPFieldArrayInt.class).getArray()); } /** @@ -116,9 +135,9 @@ public IntBuffer(final int initialCapacity) { public IntBuffer put(final int value) { if (this.freePos == this.buffer.length) { - final int[] newbuffer = new int[(this.buffer.length * 3) / 2]; - System.arraycopy(this.buffer, 0, newbuffer, 0, this.buffer.length); - this.buffer = newbuffer; + final int[] newBuffer = new int[(this.buffer.length * 3) / 2]; + System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length); + this.buffer = newBuffer; } this.buffer[this.freePos++] = value; return this; @@ -136,12 +155,15 @@ private static final class Int24CustomTypeProcessor implements JBBPCustomFieldTy private static final String[] TYPES = new String[] {"int24"}; - private static int readThreeBytesAsInt(final JBBPBitInputStream in, final JBBPByteOrder byteOrder, final JBBPBitOrder bitOrder) throws IOException { + private static int readThreeBytesAsInt(final JBBPBitInputStream in, + final JBBPByteOrder byteOrder, + final JBBPBitOrder bitOrder) throws IOException { final int b0 = in.readByte(); final int b1 = in.readByte(); final int b2 = in.readByte(); - final int value = byteOrder == JBBPByteOrder.BIG_ENDIAN ? (b0 << 16) | (b1 << 8) | b2 : (b2 << 16) | (b1 << 8) | b0; + final int value = byteOrder == JBBPByteOrder.BIG_ENDIAN ? (b0 << 16) | (b1 << 8) | b2 : + (b2 << 16) | (b1 << 8) | b0; return bitOrder == JBBPBitOrder.LSB0 ? value : ((int) JBBPFieldInt.reverseBits(value) >>> 8); } @@ -152,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 82865dc2..2ff98ba0 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/NetPacketParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/NetPacketParsingTest.java @@ -16,6 +16,12 @@ 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.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + import com.igormaznitsa.jbbp.JBBPParser; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitNumber; @@ -30,17 +36,15 @@ import com.igormaznitsa.jbbp.model.JBBPFieldUShort; import com.igormaznitsa.jbbp.utils.JBBPTextWriter; import com.igormaznitsa.jbbp.utils.JBBPUtils; -import org.junit.jupiter.api.Test; - import java.io.StringWriter; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; 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 @@ -64,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 @@ -92,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); } @@ -111,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()); @@ -151,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); @@ -183,23 +239,25 @@ public void testParsingTCPFrameInsideNetworkFrame() throws Exception { public void testParseSomePacketGettedOverTCP_ExampleFromStackOverflow() throws Exception { final class Parsed { - @Bin(outOrder = 1) + @Bin(order = 1) byte begin; - @Bin(outOrder = 2, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_4) + @Bin(order = 2, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_4) int version; - @Bin(outOrder = 3, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_4) + @Bin(order = 3, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_4) int returnType; - @Bin(outOrder = 4) + @Bin(order = 4) byte[] productCode; - @Bin(outOrder = 5, type = BinType.USHORT) + @Bin(order = 5, type = BinType.USHORT) 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(Parsed.class); + .mapTo(new Parsed()); assertEquals(0x23, parsed.begin); assertEquals(0x01, parsed.version); @@ -214,21 +272,27 @@ final class Parsed { public void testParseUDP() throws Exception { final class Parsed { - @Bin(outOrder = 1) + @Bin(order = 1) char source; - @Bin(outOrder = 2) + @Bin(order = 2) char destination; - @Bin(outOrder = 3) + @Bin(order = 3) char length; - @Bin(outOrder = 4) + @Bin(order = 4) char checksum; - @Bin(outOrder = 5) + @Bin(order = 5) 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(Parsed.class); + 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 20b54153..2a9727c7 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PNGParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/PNGParsingTest.java @@ -16,10 +16,12 @@ package com.igormaznitsa.jbbp.it; -import com.igormaznitsa.jbbp.JBBPExternalValueProvider; -import com.igormaznitsa.jbbp.JBBPNamedNumericFieldMap; +import static com.igormaznitsa.jbbp.TestUtils.assertPngChunk; +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.compiler.JBBPCompiledBlock; import com.igormaznitsa.jbbp.io.JBBPOut; import com.igormaznitsa.jbbp.mapper.Bin; import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; @@ -28,24 +30,23 @@ import com.igormaznitsa.jbbp.model.JBBPFieldLong; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; import com.igormaznitsa.jbbp.utils.JBBPUtils; -import org.junit.jupiter.api.Test; - import java.io.InputStream; -import java.util.zip.CRC32; - -import static com.igormaznitsa.jbbp.TestUtils.assertPngChunk; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; +import org.apache.commons.codec.digest.PureJavaCrc32; +import org.junit.jupiter.api.Test; 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 CRC32 crc32 = new CRC32(); + final PureJavaCrc32 crc32 = new PureJavaCrc32(); crc32.update(name.charAt(0)); crc32.update(name.charAt(1)); crc32.update(name.charAt(2)); @@ -54,11 +55,14 @@ private static void assertChunk(final String name, final int length, final JBBPF if (length != 0) { final byte[] array = chunk.findFieldForType(JBBPFieldArrayByte.class).getArray(); assertEquals(length, array.length, "Data array " + name + " must be " + length); - crc32.update(array); + for (final byte b : array) { + crc32.update(b & 0xFF); + } } 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); } @@ -91,19 +95,31 @@ class Png { long hEAder; Chunk[] chuNK; + + Chunk makeChunk() { + return new Chunk(); + } } - final Png png = pngParser.parse(pngStream).mapTo(Png.class); + final Png result = new Png(); + final Png png = pngParser.parse(pngStream).mapTo(result, aClass -> { + if (aClass == Chunk.class) { + return result.makeChunk(); + } + return null; + }); 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()); @@ -131,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()); @@ -166,23 +185,24 @@ public void testPngParsing_WithExternalValue() throws Exception { + "}" ); - final JBBPFieldStruct result = pngParser.parse(pngStream, null, new JBBPExternalValueProvider() { - - @Override - public int provideArraySize(final String fieldName, final JBBPNamedNumericFieldMap numericFieldMap, final JBBPCompiledBlock 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()); @@ -215,24 +235,34 @@ public void testPngParsingAndSynthesisThroughMapping() throws Exception { class Chunk { - @Bin(outOrder = 1) + @Bin(order = 1) int length; - @Bin(outOrder = 2) + @Bin(order = 2) int type; - @Bin(outOrder = 3) + @Bin(order = 3) byte[] data; - @Bin(outOrder = 4) + @Bin(order = 4) int crc; } class Png { - @Bin(outOrder = 1) + @Bin(order = 1) long hEAder; - @Bin(outOrder = 2) + @Bin(order = 2) Chunk[] chuNK; + + Chunk makeNewChunk() { + return new Chunk(); + } } - final Png parsedAndMapped = pngParser.parse(pngStream).mapTo(Png.class); + final Png result = new Png(); + final Png parsedAndMapped = pngParser.parse(pngStream).mapTo(result, aClass -> { + if (aClass == Chunk.class) { + return result.makeNewChunk(); + } + return null; + }); final byte[] saved = JBBPOut.BeginBin().Bin(parsedAndMapped).End().toByteArray(); assertResource("picture.png", saved); 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 2af53101..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,14 +119,10 @@ 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, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare(" 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 b3a32e37..ce3a34f2 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/it/SNAParsingTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/it/SNAParsingTest.java @@ -16,6 +16,11 @@ package com.igormaznitsa.jbbp.it; +import static com.igormaznitsa.jbbp.io.JBBPByteOrder.LITTLE_ENDIAN; +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.io.JBBPOut; import com.igormaznitsa.jbbp.mapper.Bin; @@ -24,13 +29,8 @@ import com.igormaznitsa.jbbp.utils.JBBPDslBuilder; import com.igormaznitsa.jbbp.utils.JBBPTextWriter; import com.igormaznitsa.jbbp.utils.JBBPUtils; -import org.junit.jupiter.api.Test; - import java.io.InputStream; - -import static com.igormaznitsa.jbbp.io.JBBPByteOrder.LITTLE_ENDIAN; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; /** * Test for parsing of SNA snapshots for ZX-Spectrum emulator. @@ -52,7 +52,7 @@ public void testParseAndSave() throws Exception { final SNA sna; final InputStream in = getResourceAsInputStream("zexall.sna"); try { - sna = PARSER_SNA_48.parse(in).mapTo(SNA.class); + sna = PARSER_SNA_48.parse(in).mapTo(new SNA()); } finally { JBBPUtils.closeQuietly(in); } @@ -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,46 +103,47 @@ public void testParseAndSave_ThroughDslBuilder() throws Exception { JBBPUtils.closeQuietly(in); } - final SNA mapped = parsed.findFieldForNameAndType("SNA", JBBPFieldStruct.class).mapTo(SNA.class); + final SNA mapped = + parsed.findFieldForNameAndType("SNA", JBBPFieldStruct.class).mapTo(new SNA()); assertResource("zexall.sna", JBBPOut.BeginBin().Bin(mapped).End().toByteArray()); } @Bin(comment = "Parsed SNA snapshot") private class SNA { - @Bin(type = BinType.UBYTE, outOrder = 1, comment = "Register I") + @Bin(type = BinType.UBYTE, order = 1, comment = "Register I") int regI; - @Bin(type = BinType.USHORT, outOrder = 2, name = "altHL", comment = "Register pair HL'", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 2, name = "altHL", comment = "Register pair HL'", byteOrder = LITTLE_ENDIAN) int altRegHL; - @Bin(type = BinType.USHORT, outOrder = 3, name = "altDE", comment = "Register pair DE'", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 3, name = "altDE", comment = "Register pair DE'", byteOrder = LITTLE_ENDIAN) int altRegDE; - @Bin(type = BinType.USHORT, outOrder = 4, name = "altBC", comment = "Registe pair BC'", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 4, name = "altBC", comment = "Registe pair BC'", byteOrder = LITTLE_ENDIAN) int altRegBC; - @Bin(type = BinType.USHORT, outOrder = 5, name = "altAF", comment = "Register pair AF'", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 5, name = "altAF", comment = "Register pair AF'", byteOrder = LITTLE_ENDIAN) int altRegAF; - @Bin(type = BinType.USHORT, outOrder = 6, comment = "Register pair HL", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 6, comment = "Register pair HL", byteOrder = LITTLE_ENDIAN) int regHL; - @Bin(type = BinType.USHORT, outOrder = 7, comment = "Register pair DE", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 7, comment = "Register pair DE", byteOrder = LITTLE_ENDIAN) int regDE; - @Bin(type = BinType.USHORT, outOrder = 8, comment = "Register pair BC", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 8, comment = "Register pair BC", byteOrder = LITTLE_ENDIAN) int regBC; - @Bin(type = BinType.USHORT, outOrder = 9, comment = "Register IY", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 9, comment = "Register IY", byteOrder = LITTLE_ENDIAN) int regIY; - @Bin(type = BinType.USHORT, outOrder = 10, comment = "Register IX", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 10, comment = "Register IX", byteOrder = LITTLE_ENDIAN) int regIX; - @Bin(type = BinType.UBYTE, outOrder = 11, comment = "IFF1 and IFF2 values") + @Bin(type = BinType.UBYTE, order = 11, comment = "IFF1 and IFF2 values") int iff; - @Bin(type = BinType.UBYTE, outOrder = 12, comment = "Register R") + @Bin(type = BinType.UBYTE, order = 12, comment = "Register R") int regR; - @Bin(type = BinType.USHORT, outOrder = 13, comment = "Register pair AF", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 13, comment = "Register pair AF", byteOrder = LITTLE_ENDIAN) int regAF; - @Bin(type = BinType.USHORT, outOrder = 14, comment = "Register SP", outByteOrder = LITTLE_ENDIAN) + @Bin(type = BinType.USHORT, order = 14, comment = "Register SP", byteOrder = LITTLE_ENDIAN) int regSP; - @Bin(type = BinType.UBYTE, outOrder = 15, comment = "Interruption mode (0-IM0, 1-IM1, 2-IM2") + @Bin(type = BinType.UBYTE, order = 15, comment = "Interruption mode (0-IM0, 1-IM1, 2-IM2") int im; - @Bin(type = BinType.UBYTE, outOrder = 16, comment = "Border color") + @Bin(type = BinType.UBYTE, order = 16, comment = "Border color") int borderColor; - @Bin(outOrder = 17, comment = "Dump of memory since 16384 address", extra = "49152") + @Bin(order = 17, comment = "Dump of memory since 16384 address", arraySizeExpr = "49152") byte[] ramDump; } 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 508b7863..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); + }); assertEquals(89410, TAP_FILE_PARSER.getFinalStreamByteCounter()); assertEquals(6, tap.tapblocks.length); @@ -63,13 +70,13 @@ public void testParseTap() throws Exception { switch (t.flag & 0xFF) { case 0: { // header - td = HEADER_PARSER.parse(t.data).mapTo(Header.class); + td = HEADER_PARSER.parse(t.data).mapTo(new Header()); ((Header) td).check = t.checksum; } break; case 0xFF: { // data - td = DATA_PARSER.parse(t.data).mapTo(Data.class); + td = DATA_PARSER.parse(t.data).mapTo(new Data()); } break; default: { @@ -113,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 97dced7e..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 @@ -16,11 +16,17 @@ package com.igormaznitsa.jbbp.it; +import static com.igormaznitsa.jbbp.io.JBBPByteOrder.LITTLE_ENDIAN; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +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.JBBPParser; 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.io.JBBPOutVarProcessor; @@ -30,18 +36,15 @@ import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; import com.igormaznitsa.jbbp.model.JBBPFieldBit; import com.igormaznitsa.jbbp.model.JBBPFieldStruct; +import com.igormaznitsa.jbbp.utils.Function; import com.igormaznitsa.jbbp.utils.JBBPTextWriter; import com.igormaznitsa.jbbp.utils.JBBPTextWriterExtraAdapter; import com.igormaznitsa.jbbp.utils.JBBPUtils; -import org.junit.jupiter.api.Test; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; - -import static com.igormaznitsa.jbbp.io.JBBPByteOrder.LITTLE_ENDIAN; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * Test to parse RLE encoded snapshots in well-known Z80 format (v.1) for @@ -51,26 +54,61 @@ 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(); + } + if (aClass == EmulFlags.class) { + return new EmulFlags(); + } + 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()); + 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); + assertParseAndPackBack("test2.z80", 29330); + assertParseAndPackBack("test3.z80", 5711); + 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); try { - z80sn = z80Parser.parse(resource).mapTo(Z80Snapshot.class, new DataProcessor()); + z80sn = z80Parser.parse(resource).mapTo(new Z80Snapshot(), new DataProcessor(), INSTANTIATOR); assertEquals(etalonLen, z80Parser.getFinalStreamByteCounter()); } finally { JBBPUtils.closeQuietly(resource); @@ -103,27 +141,25 @@ private Z80Snapshot assertParseAndPackBack(final String name, final long etalonL return z80sn; } - @Test - public void testParseAndWriteTestZ80WithoutCheckOfFields() throws Exception { - assertParseAndPackBack("test1.z80", 16059); - assertParseAndPackBack("test2.z80", 29330); - assertParseAndPackBack("test3.z80", 5711); - assertParseAndPackBack("test4.z80", 9946); - } - @Test 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 { - final byte[] data = (byte[]) extractFieldValue(obj, field); - return "byte array length [" + data.length + ']'; - } + 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); @@ -175,12 +211,13 @@ public void testParseAndPackThrowMapping() throws Exception { final InputStream in = getResourceAsInputStream("test.z80"); Z80Snapshot parsed; try { - parsed = z80Parser.parse(in).mapTo(Z80Snapshot.class, new DataProcessor()); + parsed = z80Parser.parse(in).mapTo(new Z80Snapshot(), new DataProcessor(), INSTANTIATOR); } finally { 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); } @@ -188,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); @@ -246,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; @@ -297,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); @@ -308,78 +352,78 @@ public void writeCustomField(final JBBPOut context, final JBBPBitOutputStream ou } } - class EmulFlags { - @Bin(outOrder = 1, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_2, outByteOrder = LITTLE_ENDIAN) + static class EmulFlags { + @Bin(order = 1, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_2, byteOrder = LITTLE_ENDIAN) byte interruptmode; - @Bin(outOrder = 2, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_1, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 2, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_1, byteOrder = LITTLE_ENDIAN) byte issue2emulation; - @Bin(outOrder = 3, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_1, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 3, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_1, byteOrder = LITTLE_ENDIAN) byte doubleintfreq; - @Bin(outOrder = 4, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_2, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 4, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_2, byteOrder = LITTLE_ENDIAN) byte videosync; - @Bin(outOrder = 5, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_2, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 5, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_2, byteOrder = LITTLE_ENDIAN) byte inputdevice; } - class Flags { - @Bin(outOrder = 1, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_1, outByteOrder = LITTLE_ENDIAN) + static class Flags { + @Bin(order = 1, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_1, byteOrder = LITTLE_ENDIAN) byte reg_r_bit7; - @Bin(outOrder = 2, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_3, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 2, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_3, byteOrder = LITTLE_ENDIAN) byte bordercolor; - @Bin(outOrder = 3, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_1, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 3, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_1, byteOrder = LITTLE_ENDIAN) byte basic_samrom; - @Bin(outOrder = 4, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_1, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 4, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_1, byteOrder = LITTLE_ENDIAN) byte compressed; - @Bin(outOrder = 5, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_2, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 5, type = BinType.BIT, bitNumber = JBBPBitNumber.BITS_2, byteOrder = LITTLE_ENDIAN) byte nomeaning; } - class Z80Snapshot { - @Bin(outOrder = 1, outByteOrder = LITTLE_ENDIAN) + static class Z80Snapshot { + @Bin(order = 1, byteOrder = LITTLE_ENDIAN) byte reg_a; - @Bin(outOrder = 2, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 2, byteOrder = LITTLE_ENDIAN) byte reg_f; - @Bin(outOrder = 3, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 3, byteOrder = LITTLE_ENDIAN) short reg_bc; - @Bin(outOrder = 4, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 4, byteOrder = LITTLE_ENDIAN) short reg_hl; - @Bin(outOrder = 5, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 5, byteOrder = LITTLE_ENDIAN) short reg_pc; - @Bin(outOrder = 6, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 6, byteOrder = LITTLE_ENDIAN) short reg_sp; - @Bin(outOrder = 7, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 7, byteOrder = LITTLE_ENDIAN) byte reg_ir; - @Bin(outOrder = 8, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 8, byteOrder = LITTLE_ENDIAN) byte reg_r; - @Bin(outOrder = 9, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 9, byteOrder = LITTLE_ENDIAN) Flags flags; - @Bin(outOrder = 10, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 10, byteOrder = LITTLE_ENDIAN) short reg_de; - @Bin(outOrder = 11, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 11, byteOrder = LITTLE_ENDIAN) short reg_bc_alt; - @Bin(outOrder = 12, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 12, byteOrder = LITTLE_ENDIAN) short reg_de_alt; - @Bin(outOrder = 13, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 13, byteOrder = LITTLE_ENDIAN) short reg_hl_alt; - @Bin(outOrder = 14, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 14, byteOrder = LITTLE_ENDIAN) byte reg_a_alt; - @Bin(outOrder = 15, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 15, byteOrder = LITTLE_ENDIAN) byte reg_f_alt; - @Bin(outOrder = 16, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 16, byteOrder = LITTLE_ENDIAN) short reg_iy; - @Bin(outOrder = 17, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 17, byteOrder = LITTLE_ENDIAN) short reg_ix; - @Bin(outOrder = 18, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 18, byteOrder = LITTLE_ENDIAN) byte iff; - @Bin(outOrder = 19, outByteOrder = LITTLE_ENDIAN) + @Bin(order = 19, byteOrder = LITTLE_ENDIAN) byte iff2; - @Bin(outOrder = 20) + @Bin(order = 20) EmulFlags emulFlags; - @Bin(outOrder = 21, custom = true) + @Bin(order = 21, custom = true) byte[] data; } 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 ce80cfee..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,25 +16,19 @@ 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 { @Test public void testNPEInFindCompatibleForNull() { - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - BinType.findCompatible(null); - } - }); + assertThrows(NullPointerException.class, () -> BinType.findCompatible(null)); } @Test diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/ClassWithPFGSG.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/ClassWithPFGSG.java new file mode 100644 index 00000000..ba5bb30f --- /dev/null +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/ClassWithPFGSG.java @@ -0,0 +1,76 @@ +package com.igormaznitsa.jbbp.mapper; + +@Bin +public class ClassWithPFGSG { + @Bin(order = 1) + private byte a; + @Bin(order = 2) + private byte b; + @Bin(order = 3) + private Internal i; + + public Internal getI() { + return this.i; + } + + public byte getA() { + return this.a; + } + + public void setA(final byte a) { + this.a = a; + } + + public byte getB() { + return this.b; + } + + public void setB(final byte b) { + this.b = b; + } + + public Internal makeI() { + this.i = new Internal(); + return this.i; + } + + @Bin + public class Internal { + @Bin(order = 1) + private byte c; + @Bin(order = 2) + private InternalInternal ii; + + public byte getC() { + return this.c; + } + + public void setC(byte c) { + this.c = c; + } + + public InternalInternal getIi() { + return this.ii; + } + + public InternalInternal makeIi() { + this.ii = new InternalInternal(); + return ii; + } + + @Bin + public class InternalInternal { + @Bin(order = 1) + private byte d; + + public byte getD() { + return this.d; + } + + public void setD(final byte d) { + this.d = d; + } + } + } + +} diff --git a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorType.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/ClassWithPrivateFieldsAndSetterGetter.java similarity index 53% rename from jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorType.java rename to jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/ClassWithPrivateFieldsAndSetterGetter.java index ae485004..49552a37 100644 --- a/jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorType.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/ClassWithPrivateFieldsAndSetterGetter.java @@ -14,24 +14,17 @@ * limitations under the License. */ -package com.igormaznitsa.jbbp.mapper.instantiators; +package com.igormaznitsa.jbbp.mapper; -/** - * Type of class instantiator to provide new class instances for mapping. - * - * @since 1.0 - */ -public enum JBBPClassInstantiatorType { - /** - * Auto recognition of the platform features and choice of appropriate one. - */ - AUTO, - /** - * A Safe version which use standard Java approach but can be non-working in some cases. - */ - SAFE, - /** - * A Version using sun.misc.Unsafe to allocate memory for objects without constructor calls. - */ - UNSAFE +class ClassWithPrivateFieldsAndSetterGetter { + @Bin + private int field; + + public int getField() { + return this.field; + } + + public void setField(int value) { + this.field = value; + } } 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 30f7d938..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,93 +16,145 @@ 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; +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.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.mapper.instantiators.JBBPClassInstantiator; -import com.igormaznitsa.jbbp.mapper.instantiators.JBBPClassInstantiatorFactory; -import com.igormaznitsa.jbbp.mapper.instantiators.JBBPClassInstantiatorType; -import com.igormaznitsa.jbbp.mapper.instantiators.JBBPSafeInstantiator; -import com.igormaznitsa.jbbp.mapper.instantiators.JBBPUnsafeInstantiator; import com.igormaznitsa.jbbp.model.JBBPFieldInt; -import com.igormaznitsa.jbbp.model.JBBPFieldStruct; -import com.igormaznitsa.jbbp.utils.JBBPSystemProperty; -import org.junit.jupiter.api.TestTemplate; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.Extension; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolutionException; -import org.junit.jupiter.api.extension.ParameterResolver; -import org.junit.jupiter.api.extension.TestTemplateInvocationContext; -import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; -import org.junit.jupiter.api.function.Executable; - import java.io.ByteArrayInputStream; -import java.lang.reflect.Field; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.Random; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPMapperTest { - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_InsideStructAndClass() throws Exception { - class Mapped { + @Test + void testMakeNewInstanceInLocalThroughDefaultConstructors() throws Exception { + 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()); + + assertNotNull(result.levelOne); + assertNotNull(result.levelOne.levelTwos); + assertEquals(3, result.levelOne.levelTwos.length); + } + + @Test + void testMakeNewInstanceInLocalNonStaticClasses() throws Exception { + class Top { @Bin - byte a; + LevelOne levelOne; + + public Object newInstance(final Class klazz) { + if (klazz == LevelOne.class) { + return new LevelOne(); + } + return null; + } + + class LevelOne { + @Bin + LevelTwo[] levelTwos; + + public Object newInstance(final Class klazz) { + if (klazz == LevelTwo.class) { + return new LevelTwo(); + } + return null; + } + + class LevelTwo { + @Bin + byte a; + } + } } - assertEquals(3, JBBPParser.prepare("byte a; some{struc {byte a;}}").parse(new byte[] {1, 3}).mapTo("some.struc", Mapped.class).a); + + 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); + assertEquals(3, result.levelOne.levelTwos.length); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_RootStructToClassWithNullCustomProcessor() throws Exception { + @Test + void testMap_InsideStructAndClass() throws Exception { class Mapped { - @Bin byte a; } - assertEquals(3, JBBPMapper.map(JBBPParser.prepare("byte a;").parse(new byte[] {3}), Mapped.class).a); + assertEquals(3, JBBPParser.prepare("byte a; some{struc {byte a;}}").parse(new byte[] {1, 3}) + .mapTo("some.struc", new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_Byte() throws Exception { + @Test + void testMap_RootStructToClassWithNullCustomProcessor() throws Exception { class Mapped { - @Bin byte a; } - assertEquals(3, JBBPParser.prepare("byte a;").parse(new byte[] {3}).mapTo(Mapped.class).a); + assertEquals(3, + JBBPMapper.map(JBBPParser.prepare("byte a;").parse(new byte[] {3}), new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_Short() throws Exception { + @Test + void testMap_Byte() throws Exception { class Mapped { + @Bin + byte a; + } + assertEquals(3, JBBPParser.prepare("byte a;").parse(new byte[] {3}).mapTo(new Mapped()).a); + } + @Test + void testMap_Short() throws Exception { + class Mapped { @Bin short a; } - assertEquals(0x0304, JBBPParser.prepare("short a;").parse(new byte[] {3, 4}).mapTo(Mapped.class).a); + assertEquals(0x0304, + JBBPParser.prepare("short a;").parse(new byte[] {3, 4}).mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_Boolean() throws Exception { + @Test + void testMap_Boolean() throws Exception { class Mapped { - @Bin boolean a; @Bin @@ -110,52 +162,67 @@ class Mapped { @Bin boolean c; } - final Mapped mapped = JBBPParser.prepare("bool a; bool b; bool c;").parse(new byte[] {23, 0, 12}).mapTo(Mapped.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_String() throws Exception { + @Test + void testMap_String() 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(Mapped.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_StringArrayToStringArray() throws Exception { + @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(Mapped.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_IgnoreStaticField() throws Exception { - final MappedWithStaticField mapped = JBBPParser.prepare("int a;").parse(new byte[] {1, 2, 3, 4}).mapTo(MappedWithStaticField.class); + @Test + void testMap_IgnoreStaticField() throws Exception { + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_Bit() throws Exception { + @Test + void testMap_Bit() throws Exception { class Mapped { - @Bin(type = BinType.BIT) byte a; @Bin(type = BinType.BIT) @@ -163,295 +230,414 @@ 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(Mapped.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_Int() throws Exception { + @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(Mapped.class).a); + assertEquals(0x01020304, + JBBPParser.prepare("int a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapIntToFloat() throws Exception { + @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 + void testMap_MapIntToFloat() throws Exception { + class Mapped { @Bin(type = BinType.INT) 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(Mapped.class).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(Mapped.class).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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapIntArrayToFloatArray() throws Exception { + @Test + void testMap_MapIntArrayToFloatArray() throws Exception { class Mapped { - @Bin(type = BinType.INT_ARRAY) float[] a; } - final byte[] max = JBBPOut.BeginBin().Float(Float.MAX_VALUE, Float.MIN_VALUE).End().toByteArray(); - final Mapped result = JBBPParser.prepare("int [_] a;").parse(max).mapTo(Mapped.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapLongArrayToDoubleArray() throws Exception { + @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 { @Bin(type = BinType.LONG_ARRAY) double[] a; } - final byte[] max = JBBPOut.BeginBin().Double(Double.MAX_VALUE, Double.MIN_VALUE).End().toByteArray(); - final Mapped result = JBBPParser.prepare("long [_] a;").parse(max).mapTo(Mapped.class); + 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); assertEquals(Double.MIN_VALUE, result.a[1], TestUtils.FLOAT_DELTA); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapFloatToFloat() throws Exception { + @Test + void testMap_MapFloatToFloat() throws Exception { class Mapped { - @Bin float a; } final byte[] max = JBBPOut.BeginBin().Float(-1.234567f).End().toByteArray(); - assertEquals(-1.234567f, JBBPParser.prepare("floatj a;").parse(max).mapTo(Mapped.class).a, TestUtils.FLOAT_DELTA); + assertEquals(-1.234567f, JBBPParser.prepare("floatj a;").parse(max).mapTo(new Mapped()).a, + TestUtils.FLOAT_DELTA); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapFloatArrayToFloatArray() throws Exception { + @Test + void testMap_MapFloatArrayToFloatArray() throws Exception { class Mapped { - @Bin float[] a; } 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(Mapped.class).a, TestUtils.FLOAT_DELTA); + assertArrayEquals(new float[] {-1.234567f, 1.234567f}, + JBBPParser.prepare("floatj [_] a;").parse(max).mapTo(new Mapped()).a, + TestUtils.FLOAT_DELTA); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapLongToDouble() throws Exception { + @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 + void testMap_MapLongToDouble() throws Exception { + class Mapped { @Bin(type = BinType.LONG) 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(Mapped.class).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(Mapped.class).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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapDoubleToDouble() throws Exception { + @Test + void testMap_MapDoubleToDouble() throws Exception { class Mapped { - @Bin double a; } final byte[] max = JBBPOut.BeginBin().Double(-1.2345678912345d).End().toByteArray(); - assertEquals(-1.2345678912345d, JBBPParser.prepare("doublej a;").parse(max).mapTo(Mapped.class).a, TestUtils.FLOAT_DELTA); + assertEquals(-1.2345678912345d, + JBBPParser.prepare("doublej a;").parse(max).mapTo(new Mapped()).a, TestUtils.FLOAT_DELTA); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapDoubleArrayToDoubleArray() throws Exception { + @Test + void testMap_MapDoubleArrayToDoubleArray() throws Exception { class Mapped { - @Bin double[] a; } 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(Mapped.class).a, TestUtils.FLOAT_DELTA); + assertArrayEquals(new double[] {-1.2345678912345d, 45.3334d}, + JBBPParser.prepare("doublej [_] a;").parse(max).mapTo(new Mapped()).a, + TestUtils.FLOAT_DELTA); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_Long() throws Exception { + @Test + void testMap_Long() throws Exception { class Mapped { - @Bin long a; } - assertEquals(0x0102030405060708L, JBBPParser.prepare("long a;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}).mapTo(Mapped.class).a); + assertEquals(0x0102030405060708L, + JBBPParser.prepare("long a;").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}) + .mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_UByte() throws Exception { + @Test + void testMap_UByte() throws Exception { class Mapped { - @Bin(type = BinType.UBYTE) int a; } - assertEquals(0xFE, JBBPParser.prepare("ubyte a;").parse(new byte[] {(byte) 0xFE}).mapTo(Mapped.class).a); + assertEquals(0xFE, + JBBPParser.prepare("ubyte a;").parse(new byte[] {(byte) 0xFE}).mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_UShort() throws Exception { + @Test + void testMap_UShort() throws Exception { class Mapped { - @Bin char a; } - assertEquals(0x0102, JBBPParser.prepare("ushort a;").parse(new byte[] {1, 2}).mapTo(Mapped.class).a); + assertEquals(0x0102, + JBBPParser.prepare("ushort a;").parse(new byte[] {1, 2}).mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_ByteArray() throws Exception { + @Test + void testMap_ByteArray() throws Exception { class Mapped { - @Bin byte[] a; } - assertArrayEquals(new byte[] {1, 2, 3, 4}, JBBPParser.prepare("byte [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(Mapped.class).a); + assertArrayEquals(new byte[] {1, 2, 3, 4}, + JBBPParser.prepare("byte [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_UByteArrayToString() throws Exception { + @Test + void testMap_UByteArrayToString() throws Exception { 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(Mapped.class).a); + assertEquals("JFIF", JBBPParser.prepare("ubyte [_] a;") + .parse(new byte[] {(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46}) + .mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_BitArrayToString() throws Exception { + @Test + void testMap_BitArrayToString() throws Exception { 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(Mapped.class).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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_BitArrayToStringWhenWholeByte() throws Exception { + @Test + void testMap_BitArrayToStringWhenWholeByte() throws Exception { 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(Mapped.class).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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_ByteArrayToString() throws Exception { + @Test + void testMap_ByteArrayToString() throws Exception { 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(Mapped.class).a); + assertEquals("JFIF", JBBPParser.prepare("byte [_] a;") + .parse(new byte[] {(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46}) + .mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_ShortArrayToString() throws Exception { + @Test + void testMap_ShortArrayToString() throws Exception { 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(Mapped.class).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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_IntArrayToString_Error() throws Exception { + @Test + void testMap_IntArrayToString_Error() throws Exception { class Mapped { - @Bin(type = BinType.INT_ARRAY) String a; } - - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("int [_] a;").parse(new byte[] {0, (byte) 0x4A, 0, (byte) 0x46, 0, (byte) 0x49, 0, (byte) 0x46}).mapTo(Mapped.class); - } - }); + 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())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_UShortArrayToString() throws Exception { + @Test + void testMap_UShortArrayToString() throws Exception { 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(Mapped.class).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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_BitArray() throws Exception { + @Test + void testMap_BitArray() throws Exception { 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(Mapped.class).a); + assertArrayEquals(new byte[] {2, 0, 3, 2}, + JBBPParser.prepare("bit:2 [_] a;").parse(new byte[] {(byte) 0xB2}).mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_ShortArray() throws Exception { + @Test + void testMap_ShortArray() throws Exception { class Mapped { - @Bin short[] a; } - assertArrayEquals(new short[] {0x0102, 0x0304}, JBBPParser.prepare("short [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(Mapped.class).a); + assertArrayEquals(new short[] {0x0102, 0x0304}, + JBBPParser.prepare("short [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_BoolArray() throws Exception { + @Test + void testMap_BoolArray() throws Exception { class Mapped { - @Bin boolean[] a; } - final Mapped mapped = JBBPParser.prepare("bool [_] a;").parse(new byte[] {1, 0, 0, 4, 8, 0}).mapTo(Mapped.class); + 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]); @@ -461,42 +647,54 @@ class Mapped { assertFalse(mapped.a[5]); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_UShortArray() throws Exception { + @Test + void testMap_UShortArray() throws Exception { class Mapped { - @Bin char[] a; } - assertArrayEquals(new char[] {0x0102, 0x0304}, JBBPParser.prepare("ushort [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(Mapped.class).a); + assertArrayEquals(new char[] {0x0102, 0x0304}, + JBBPParser.prepare("ushort [_] a;").parse(new byte[] {1, 2, 3, 4}).mapTo(new Mapped()).a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_IntArray() throws Exception { + @Test + void testMap_IntArray() throws Exception { 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(Mapped.class).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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_LongArray() throws Exception { + @Test + public void testMap_Struct() throws Exception { + class Inside { + + @Bin + int a; + } class Mapped { @Bin - long[] a; + byte b; + @Bin + Inside 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(Mapped.class).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; + }); + assertEquals(0x02030405, mapped.a.a); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_Struct() throws Exception { + @Test + public void testMap_Struct_WithFilter() throws Exception { class Inside { @Bin @@ -509,15 +707,22 @@ class Mapped { @Bin Inside a; } - final Mapped mapped = JBBPParser.prepare("byte b; a{ int a; }").parse(new byte[] {1, 2, 3, 4, 5}).mapTo(Mapped.class); - assertEquals(0x02030405, mapped.a.a); - } - - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_StructArray() throws Exception { + 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 { - @Bin int a; } @@ -528,118 +733,180 @@ 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(Mapped.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_ErrorForMappingStructureToPrimitiveField() throws Exception { + @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); + } + + @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 + void testMap_ErrorForMappingStructureToPrimitiveField() { + class Mapped { @Bin(name = "test", type = BinType.STRUCT) long a; } - - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("test { byte [_] a;}").parse(new byte[] {1, 2, 3, 4}).mapTo(Mapped.class); - } - }); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("test { byte [_] a;}").parse(new byte[] {1, 2, 3, 4}) + .mapTo(new Mapped())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_mapInsideStructureDefinedByItsPath() throws Exception { + @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 + void testMap_mapInsideStructureDefinedByItsPath() throws Exception { + 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", Mapped.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_mapInsideStructureDefinedByItsPath_ErrorForNonStructure() throws Exception { + @Test + void testMap_mapInsideStructureDefinedByItsPath_ErrorForNonStructure() throws Exception { class Mapped { - @Bin long a; } - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("byte f; test { inside {long a;} }").parse(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}).mapTo("f", Mapped.class); - } - }); - } - - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_privateFieldInPackagelevelClass() throws Exception { - final ClassWithPrivateFields fld = JBBPParser.prepare("int field;").parse(new byte[] {1, 2, 3, 4}).mapTo(ClassWithPrivateFields.class); - assertNull(AccessController.doPrivileged(new PrivilegedAction() { - - @Override - public Void run() { - try { - final Field field = fld.getClass().getDeclaredField("field"); - field.setAccessible(true); - assertEquals(0x01020304, field.getInt(fld)); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - return null; - } - })); + 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())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_customMappingFields_Class() throws Exception { + @Test + void testMap_privateFieldWithSetterInPackagelevelClass() throws Exception { + final ClassWithPrivateFieldsAndSetterGetter instance = + JBBPParser.prepare("int field;").parse(new byte[] {1, 2, 3, 4}) + .mapTo(new ClassWithPrivateFieldsAndSetterGetter()); + assertEquals(0x1020304, instance.getField()); + } + + @Test + public void testMap_classWithGettersSettersAndGenerator() throws Exception { + final ClassWithPFGSG instance = JBBPParser.prepare("byte a; byte b; i { byte c; ii { byte d;}}") + .parse(new byte[] {1, 2, 3, 4}) + .mapTo(new ClassWithPFGSG()); + + assertEquals(1, instance.getA()); + assertEquals(2, instance.getB()); + assertEquals(3, instance.getI().getC()); + assertEquals(4, instance.getI().getIi().getD()); + + assertArrayEquals(new byte[] {1, 2, 3, 4}, + JBBPOut.BeginBin().Bin(instance).End().toByteArray()); + } + + @Test + void testMap_customMappingFields_Class() throws Exception { final class Mapped { @Bin int a; - @Bin(custom = true, extra = "TEST_TEXT") + @Bin(custom = true, paramExpr = "TEST_TEXT") String b; @Bin 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(Mapped.class, new JBBPMapperCustomFieldProcessor() { - @Override - public Object prepareObjectForMapping(final JBBPFieldStruct parsedBlock, final Bin annotation, final Field field) { - if ("b".equals(field.getName()) && "TEST_TEXT".equals(annotation.extra())) { - 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); assertEquals(0x05060708, mapped.c); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_customMappingFields_ClassInstance() throws Exception { + @Test + void testMap_customMappingFields_ClassInstance() throws Exception { final class Mapped { - @Bin int a; - @Bin(custom = true, extra = "TEST_TEXT") + @Bin(custom = true, paramExpr = "TEST_TEXT") String b; @Bin int c; @@ -647,19 +914,20 @@ final class Mapped { final Mapped mapped = new Mapped(); - final Mapped result = (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(mapped, new JBBPMapperCustomFieldProcessor() { - - @Override - public Object prepareObjectForMapping(final JBBPFieldStruct parsedBlock, final Bin annotation, final Field field) { - if ("b".equals(field.getName()) && "TEST_TEXT".equals(annotation.extra())) { - 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); @@ -668,29 +936,27 @@ public Object prepareObjectForMapping(final JBBPFieldStruct parsedBlock, final B assertEquals(0x05060708, mapped.c); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_AnnotationForWholeClass() throws Exception { + @Test + void testMap_AnnotationForWholeClass() throws Exception { @Bin final class Parsed { - int a; int b; @Bin(type = BinType.BYTE_ARRAY) 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(Parsed.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_InstanceOfInnerClass() throws Exception { + @Test + void testMap_InstanceOfInnerClass() throws Exception { final class Outer { - @Bin int value; @Bin @@ -712,7 +978,8 @@ final class Inner { final Outer oldouter = new Outer(); final Outer.Inner inner = oldouter.inner; - final Outer newouter = (Outer) 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); @@ -721,11 +988,9 @@ final class Inner { assertEquals(6, inner.b); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_InstanceOfInnerClassPreparedArray() throws Exception { + @Test + void testMap_InstanceOfInnerClassPreparedArray() throws Exception { final class Outer { - @Bin int value; @Bin @@ -751,7 +1016,8 @@ final class Inner { final Outer.Inner inner0 = oldouter.inner[0]; final Outer.Inner inner1 = oldouter.inner[1]; - final Outer newouter = (Outer) 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); @@ -764,9 +1030,8 @@ final class Inner { assertEquals(8, inner[1].b); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_InstanceOfInnerClassNonPreparedArray() throws Exception { + @Test + void testMap_InstanceOfInnerClassNonPreparedArray() throws Exception { final class Outer { @Bin @@ -778,6 +1043,10 @@ public Outer() { inner = new Outer.Inner[2]; } + Inner makeInner() { + return new Inner(); + } + final class Inner { @Bin @@ -792,7 +1061,13 @@ final class Inner { assertNull(inner[0]); assertNull(inner[1]); - final Outer newouter = (Outer) 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, aClass -> { + if (aClass == Outer.Inner.class) { + return oldouter.makeInner(); + } + return null; + }); assertSame(oldouter, newouter); assertSame(inner, newouter.inner); @@ -803,9 +1078,8 @@ final class Inner { assertEquals(8, inner[1].b); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_InstanceOfInnerClassNonPreparedArray_ErrorForDifferentSize() throws Exception { + @Test + void testMap_InstanceOfInnerClassNonPreparedArray_ErrorForDifferentSize() { final class Outer { @Bin @@ -826,17 +1100,13 @@ final class Inner { } } - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapToClassHierarchyWithAnnotationInheritance() throws Exception { + @Test + void testMap_MapToClassHierarchyWithAnnotationInheritance() throws Exception { @Bin class Ancestor { @@ -848,15 +1118,16 @@ 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(Successor.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapElementsByTheirPaths() throws Exception { + @Test + void testMap_MapElementsByTheirPaths() throws Exception { class Parsed { @Bin(path = "struct.a") @@ -865,14 +1136,15 @@ 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(Parsed.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapElementsByTheirPaths_ErrorForUnknownField() throws Exception { + @Test + void testMap_MapElementsByTheirPaths_ErrorForUnknownField() { class Parsed { @Bin(path = "struct.a") @@ -881,17 +1153,14 @@ class Parsed { String str; } - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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(Parsed.class); - } - }); + 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())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapElementsByTheirPaths_ErrorForFieldIncompatibleType() throws Exception { + @Test + void testMap_MapElementsByTheirPaths_ErrorForFieldIncompatibleType() { class Parsed { @Bin(path = "struct.a") @@ -900,17 +1169,14 @@ class Parsed { String str; } - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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(Parsed.class); - } - }); + 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())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapElementsByTheirPaths_ErrorForFieldIncompatibleType_ArrayMappingField() throws Exception { + @Test + void testMap_MapElementsByTheirPaths_ErrorForFieldIncompatibleType_ArrayMappingField() { class Parsed { @Bin(path = "struct.a", type = BinType.BYTE) @@ -919,39 +1185,31 @@ class Parsed { String str; } - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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(Parsed.class); - } - }); + 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())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_MapElementsByTheirPaths_ErrorForFieldIncompatibleType_ArrayBinField() throws Exception { + @Test + void testMap_MapElementsByTheirPaths_ErrorForFieldIncompatibleType_ArrayBinField() { class Parsed { - @Bin(path = "struct.a") byte num; @Bin(path = "struct.b", type = BinType.BYTE_ARRAY) byte str; } - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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(Parsed.class); - } - }); + 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())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_IgnoreMarkedFieldByDefaultIfTransient() throws Exception { + @Test + void testMap_IgnoreMarkedFieldByDefaultIfTransient() throws Exception { @Bin class Parsed { - @Bin(path = "struct.a") byte num; @Bin(path = "struct.b", type = BinType.BYTE_ARRAY) @@ -959,33 +1217,36 @@ 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(Parsed.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_IgnoreMarkedFieldForTransient() throws Exception { + @Test + void testMap_ParsedMarkedTransientField() throws Exception { @Bin class Parsed { - @Bin(path = "struct.a") byte num; @Bin(path = "struct.b", type = BinType.BYTE_ARRAY) String str; @Bin(path = "struct.c", type = BinType.BYTE_ARRAY) - transient String ignored; + transient String trans; } - 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(Parsed.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_IgnoreNonMarkedField() throws Exception { + @Test + void testMap_IgnoreNonMarkedField() throws Exception { class Parsed { @Bin(path = "struct.a") @@ -995,14 +1256,15 @@ 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(Parsed.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_Structure_WholeStream_LocalClassesNonDefaultConstructorsAndFinalFields() throws Exception { + @Test + void testMap_Structure_IgnoringFinalFieldsInMapping() throws Exception { @Bin class Struct { @@ -1029,88 +1291,79 @@ 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(Parsed.class); - assertEquals(array.length / 2, parsed.struct.length); - - for (int i = 0; i < array.length; i += 2) { - final Struct s = parsed.struct[i / 2]; - assertEquals(array[i], s.a); - assertEquals(array[i + 1], s.b); - } + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_FieldWithDefinedBitNumberToBitField_FieldPresented() throws Exception { + @Test + void testMap_FieldWithDefinedBitNumberToBitField_FieldPresented() throws Exception { class Parsed { - - @Bin(outBitNumber = JBBPBitNumber.BITS_5) + @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(Parsed.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_FieldWithDefinedBitNumberToBitField_FieldPresentedWithDifferentBitNumber() throws Exception { + @Test + void testMap_FieldWithDefinedBitNumberToBitField_FieldPresentedWithDifferentBitNumber() + throws Exception { class Parsed { - - @Bin(outBitNumber = JBBPBitNumber.BITS_5) + @Bin(bitNumber = JBBPBitNumber.BITS_5) byte field; } - - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("int fieldint; bit:6 field;").parse(new byte[] {1, 2, 3, 4, 0x35}).mapTo(Parsed.class); - } - }); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int fieldint; bit:6 field;").parse(new byte[] {1, 2, 3, 4, 0x35}) + .mapTo(new Parsed())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_ArrayFieldWithDefinedBitNumberToArrayBitField_FieldPresented() throws Exception { + @Test + void testMap_ArrayFieldWithDefinedBitNumberToArrayBitField_FieldPresented() throws Exception { class Parsed { - - @Bin(outBitNumber = JBBPBitNumber.BITS_4) + @Bin(bitNumber = JBBPBitNumber.BITS_4) byte[] field; } - final Parsed parsed = JBBPParser.prepare("int fieldint; bit:4 [2] field;").parse(new byte[] {1, 2, 3, 4, 0x35}).mapTo(Parsed.class); + + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_ArrayFieldIgnoredBitNumberFieldForDefinedType() throws Exception { + @Test + void testMap_ArrayFieldIgnoredBitNumberFieldForDefinedType() throws Exception { class Parsed { - - @Bin(type = BinType.INT_ARRAY, outBitNumber = JBBPBitNumber.BITS_4) + @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(Parsed.class); + 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); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_ArrayFieldWithDefinedBitNumberToArrayBitField_FieldPresentedWithDifferentBitNumber() throws Exception { + @Test + void testMap_ArrayFieldWithDefinedBitNumberToArrayBitField_FieldPresentedWithDifferentBitNumber() + throws Exception { class Parsed { - @Bin(outBitNumber = JBBPBitNumber.BITS_4) + @Bin(bitNumber = JBBPBitNumber.BITS_4) byte field; } - assertThrows(JBBPMapperException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPParser.prepare("int fieldint; bit:3 [2] field;").parse(new byte[] {1, 2, 3, 4, 0x35}).mapTo(Parsed.class); - } - }); + assertThrows(JBBPMapperException.class, + () -> JBBPParser.prepare("int fieldint; bit:3 [2] field;") + .parse(new byte[] {1, 2, 3, 4, 0x35}).mapTo(new Parsed())); } - @TestTemplate - @ExtendWith(MapperTestProvider.class) - public void testMap_IgnoreNotFoundFields() throws Exception { + @Test + void testMap_IgnoreNotFoundFields() throws Exception { class Parsed { @Bin @@ -1119,62 +1372,51 @@ 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(Parsed.class, 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); } - final static class MapperTestProvider implements TestTemplateInvocationContextProvider { - - @Override - public boolean supportsTestTemplate(final ExtensionContext context) { - return true; - } + public static class StaticTop { + @Bin + public StaticLevelOne levelOne; - @Override - public Stream provideTestTemplateInvocationContexts(final ExtensionContext context) { - return Arrays.asList(makeInvocationContext(JBBPUnsafeInstantiator.class.getName()), makeInvocationContext(JBBPSafeInstantiator.class.getName())).stream(); + public Object newInstance(final Class klazz) { + if (klazz == StaticTop.StaticLevelOne.class) { + return new StaticTop.StaticLevelOne(); + } + if (klazz == StaticTop.StaticLevelOne.StaticLevelTwo.class) { + return new StaticTop.StaticLevelOne.StaticLevelTwo(); + } + return null; } - private TestTemplateInvocationContext makeInvocationContext(final String parameter) { - return new TestTemplateInvocationContext() { - @Override - public String getDisplayName(int invocationIndex) { - return parameter; - } - - @Override - public List getAdditionalExtensions() { - final List result = new ArrayList(); - result.add(makeParameterResolver(parameter)); - return result; - } + public static class StaticLevelOne { + @Bin + public StaticLevelTwo[] levelTwos; - }; + public static class StaticLevelTwo { + @Bin + byte a; + } } + } - private ParameterResolver makeParameterResolver(final String className) { - return new ParameterResolver() { - @Override - public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { - return parameterContext.getParameter() - .getType() - .equals(String.class); - } + public static class StaticTopNoInstanceMethod { + @Bin + public StaticLevelOne levelOne; - @Override - public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { - JBBPSystemProperty.PROPERTY_INSTANTIATOR_CLASS.set(className); - final JBBPClassInstantiator instance = JBBPClassInstantiatorFactory.getInstance().make(JBBPClassInstantiatorType.AUTO); - JBBPSystemProperty.PROPERTY_INSTANTIATOR_CLASS.remove(); - try { - TestUtils.injectDeclaredFinalFieldValue(JBBPMapper.class, null, "CLASS_INSTANTIATOR", instance); - } catch (Exception ex) { - throw new Error("Can't inject field value", ex); - } - return className; - } - }; + public static class StaticLevelOne { + @Bin + public StaticLevelTwo[] levelTwos; + + public static class StaticLevelTwo { + @Bin + byte a; + } } } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorFactoryTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorFactoryTest.java deleted file mode 100644 index 0b2e11ac..00000000 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorFactoryTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.mapper.instantiators; - -import com.igormaznitsa.jbbp.utils.JBBPSystemProperty; -import org.junit.jupiter.api.AfterEach; -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; - -public class JBBPClassInstantiatorFactoryTest { - - @AfterEach - public void afterTest() { - System.clearProperty(JBBPSystemProperty.PROPERTY_INSTANTIATOR_CLASS.getPropertyName()); - } - - @Test - public void testMake_Default() { - assertEquals(JBBPUnsafeInstantiator.class, JBBPClassInstantiatorFactory.getInstance().make().getClass()); - } - - @Test - public void testMake_WithArgument_NPEForNuill() { - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPClassInstantiatorFactory.getInstance().make(null); - } - }); - } - - @Test - public void testMake_WithArgument() { - assertEquals(JBBPSafeInstantiator.class, JBBPClassInstantiatorFactory.getInstance().make(JBBPClassInstantiatorType.SAFE).getClass()); - assertEquals(JBBPUnsafeInstantiator.class, JBBPClassInstantiatorFactory.getInstance().make(JBBPClassInstantiatorType.UNSAFE).getClass()); - assertEquals(JBBPUnsafeInstantiator.class, JBBPClassInstantiatorFactory.getInstance().make(JBBPClassInstantiatorType.AUTO).getClass()); - - } - - @Test - public void testMake_CustomClass() { - System.setProperty(JBBPSystemProperty.PROPERTY_INSTANTIATOR_CLASS.getPropertyName(), FakeInstantiator.class.getName()); - assertEquals(FakeInstantiator.class, JBBPClassInstantiatorFactory.getInstance().make(JBBPClassInstantiatorType.AUTO).getClass()); - } - - public static class FakeInstantiator implements JBBPClassInstantiator { - @Override - public T makeClassInstance(Class klazz) throws InstantiationException { - return null; - } - } - -} diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorTest.java deleted file mode 100644 index 2deb1dbb..00000000 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/instantiators/JBBPClassInstantiatorTest.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * 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.mapper.instantiators; - -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import java.util.Arrays; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -public class JBBPClassInstantiatorTest { - - @ParameterizedTest - @ArgumentsSource(InstantiatorProvider.class) - public void testStaticClass(final JBBPClassInstantiator instantiator) throws Exception { - assertNotNull(instantiator.makeClassInstance(Static.class)); - assertNotNull(instantiator.makeClassInstance(StaticInnerOne.class)); - assertNotNull(instantiator.makeClassInstance(PrivateStaticInnerTwo.class)); - } - - @ParameterizedTest - @ArgumentsSource(InstantiatorProvider.class) - public void testNonStaticClass(final JBBPClassInstantiator instantiator) throws Exception { - assertNotNull(instantiator.makeClassInstance(NonStatic.class)); - assertNotNull(instantiator.makeClassInstance(NonStaticInnerOne.class)); - assertNotNull(instantiator.makeClassInstance(PrivateNonStaticInnerTwo.class)); - } - - @ParameterizedTest - @ArgumentsSource(InstantiatorProvider.class) - public void testInnerClass(final JBBPClassInstantiator instantiator) throws Exception { - class InnerTwo { - - int a; - } - class InnerOne { - - InnerTwo two; - } - class Inner { - - InnerOne one; - } - - assertNotNull(instantiator.makeClassInstance(Inner.class)); - assertNotNull(instantiator.makeClassInstance(InnerOne.class)); - assertNotNull(instantiator.makeClassInstance(InnerTwo.class)); - } - - @ParameterizedTest - @ArgumentsSource(InstantiatorProvider.class) - public void testInnerClassHierarchy(final JBBPClassInstantiator instantiator) throws Exception { - class InnerOne { - - int a; - } - class InnerTwo extends InnerOne { - - int b; - } - class InnerThree extends InnerTwo { - - int c; - } - - assertNotNull(instantiator.makeClassInstance(InnerOne.class)); - assertNotNull(instantiator.makeClassInstance(InnerTwo.class)); - assertNotNull(instantiator.makeClassInstance(InnerThree.class)); - } - - @ParameterizedTest - @ArgumentsSource(InstantiatorProvider.class) - public void testCreateLocalClass_OnlyNonDefaultConstructor(final JBBPClassInstantiator instantiator) throws Exception { - class NoDefaultConstructor { - - int i; - - NoDefaultConstructor(byte a, short m, char b, boolean c, int d, long e, float f, double g, String h, byte[] array) { - i = d; - } - } - - assertNotNull(instantiator.makeClassInstance(NoDefaultConstructor.class)); - } - - @ParameterizedTest - @ArgumentsSource(InstantiatorProvider.class) - public void testCreateLocalClass_TwoCounsturctorsPlusDefaultConstructor(final JBBPClassInstantiator instantiator) throws Exception { - class WithDefaultConstructor { - - int i; - - WithDefaultConstructor(byte a, short m, char b, boolean c, int d, long e, float f, double g, String h, byte[] array) { - i = d; - } - - WithDefaultConstructor(int d) { - i = d; - } - - WithDefaultConstructor() { - i = 0; - } - } - - assertNotNull(instantiator.makeClassInstance(WithDefaultConstructor.class)); - } - - @ParameterizedTest - @ArgumentsSource(InstantiatorProvider.class) - public void testCreateLocalClass_TwoCounsturctors(final JBBPClassInstantiator instantiator) throws Exception { - class NoDefaultConstructor { - - int i; - - NoDefaultConstructor(byte a, short m, char b, boolean c, int d, long e, float f, double g, String h, byte[] array) { - i = d; - } - - NoDefaultConstructor(int d) { - i = d; - } - } - - assertNotNull(instantiator.makeClassInstance(NoDefaultConstructor.class)); - } - - @ParameterizedTest - @ArgumentsSource(InstantiatorProvider.class) - public void testCreateStaticClass_TwoConstructorsPlusDefaultConstructor(final JBBPClassInstantiator instantiator) throws Exception { - assertNotNull(instantiator.makeClassInstance(StaticTwoConstructorsPlusDefaultConstructor.class)); - } - - @ParameterizedTest - @ArgumentsSource(InstantiatorProvider.class) - public void testCreateStaticClass_TwoConstructors(final JBBPClassInstantiator instantiator) throws Exception { - assertNotNull(instantiator.makeClassInstance(StaticTwoConstructors.class)); - } - - final static class InstantiatorProvider implements ArgumentsProvider { - - @Override - public Stream provideArguments(ExtensionContext ec) throws Exception { - return Arrays.asList( - new Arguments() { - @Override - public Object[] get() { - return new Object[] {new JBBPUnsafeInstantiator()}; - } - }, - new Arguments() { - @Override - public Object[] get() { - return new Object[] {new JBBPSafeInstantiator()}; - } - }).stream(); - } - - } - - static class StaticInnerOne { - - PrivateStaticInnerTwo two; - } - - private static class PrivateStaticInnerTwo { - - int hello; - } - - public static class Static { - - StaticInnerOne inner; - } - - private static final class StaticTwoConstructorsPlusDefaultConstructor { - - int i; - - private StaticTwoConstructorsPlusDefaultConstructor(byte a, short m, char b, boolean c, int d, long e, float f, double g, String h, byte[] array) { - i = d; - } - - private StaticTwoConstructorsPlusDefaultConstructor(int d) { - i = d; - } - - private StaticTwoConstructorsPlusDefaultConstructor() { - i = 0; - } - } - - private static final class StaticTwoConstructors { - - int i; - - private StaticTwoConstructors(byte a, short m, char b, boolean c, int d, long e, float f, double g, String h, byte[] array) { - i = d; - } - - private StaticTwoConstructors(int d) { - i = d; - } - } - - class NonStaticInnerOne { - - PrivateStaticInnerTwo two; - } - - private class PrivateNonStaticInnerTwo { - - int hello; - } - - public class NonStatic { - - StaticInnerOne inner; - } -} 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 1df5434a..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,27 +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 Executable() { - @Override - public void execute() throws Throwable { - 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 @@ -107,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 c97a49f5..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,28 +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 Executable() { - @Override - public void execute() throws Throwable { - 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()); @@ -47,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 ea88972d..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,15 +1,18 @@ package com.igormaznitsa.jbbp.model; +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; -import static org.junit.jupiter.api.Assertions.*; - 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()); @@ -29,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 fdbffea9..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(ClassTestMapToClass.class); + 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/AbstractJBBPToJava6ConverterTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJavaConverterTest.java similarity index 65% rename from jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJava6ConverterTest.java rename to jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJavaConverterTest.java index ccfd0853..47ca4b78 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJava6ConverterTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/testaux/AbstractJBBPToJavaConverterTest.java @@ -18,22 +18,12 @@ import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor; import com.igormaznitsa.jbbp.JBBPParser; -import com.igormaznitsa.jbbp.compiler.conversion.JBBPToJava6Converter; +import com.igormaznitsa.jbbp.compiler.conversion.JBBPToJavaConverter; import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.io.JBBPBitOrder; import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; import com.igormaznitsa.jbbp.utils.ReflectUtils; import com.igormaznitsa.jbbp.utils.TargetSources; -import org.apache.commons.io.FileUtils; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -import javax.tools.Diagnostic; -import javax.tools.DiagnosticCollector; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -41,6 +31,7 @@ import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -50,14 +41,24 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; -public abstract class AbstractJBBPToJava6ConverterTest { +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 RND = new Random(123456); - + 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) { - final Map result = new HashMap(); + 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 = JBBPToJava6Converter.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_1_6, 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[klazzes.size()])); - 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(); + 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()) { @@ -179,25 +183,48 @@ 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); - - if (!compiler.getTask(null, fileManager, null, null, null, compilationUnits).call()) { + final DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + final StandardJavaFileManager fileManager = + compiler.getStandardFileManager(diagnostics, null, null); + final Iterable compilationUnits = + fileManager.getJavaFileObjectsFromFiles(classFiles); + + 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) { System.err.println("File '" + f.getName() + '\''); System.err.println("-------------------------------------------"); - System.err.println(FileUtils.readFileToString(f)); + System.err.println(FileUtils.readFileToString(f, StandardCharsets.UTF_8)); } 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 { @@ -208,7 +235,7 @@ protected static class TemporaryFolder { public TemporaryFolder() { final String localTmpFolderPath = System.getProperty("jbbp.target.folder", null); if (localTmpFolderPath == null) { - throw new Error("Temp folder is not defined among system prperties"); + throw new Error("Temp folder is not defined among system properties"); } final File localTmpFolderAsFile = new File(localTmpFolderPath); @@ -234,7 +261,8 @@ public File newFolder() { result.deleteOnExit(); return result; } catch (IOException ex) { - throw new Error("Can't make new subfolder 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 fadc9123..4a047238 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/DynamicIntBuffer.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/DynamicIntBuffer.java @@ -16,14 +16,13 @@ package com.igormaznitsa.jbbp.utils; -import com.igormaznitsa.jbbp.compiler.conversion.JBBPToJava6ConverterReadWriteTest; - +import com.igormaznitsa.jbbp.compiler.conversion.JBBPToJavaConverterReadWriteTest; import java.util.Arrays; /** * Buffer to accumulate integer values. NB! It is being used in tests. * - * @see JBBPToJava6ConverterReadWriteTest + * @see JBBPToJavaConverterReadWriteTest */ public class DynamicIntBuffer { protected static final int INITIAL_CAPACITY_INCREASE = 128; 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 9d99e2f1..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,69 +16,86 @@ 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 { @Test public void testConstructor_ErrorForDuplicatedType() throws Exception { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - final JBBPCustomFieldTypeProcessor proc1 = new JBBPCustomFieldTypeProcessor() { - - @Override - public String[] getCustomFieldTypes() { - return new String[] {"type1", "type2", "type3"}; - } - - @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. - } - - @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. - } - }; - - final JBBPCustomFieldTypeProcessor proc2 = new JBBPCustomFieldTypeProcessor() { - - @Override - public String[] getCustomFieldTypes() { - return new String[] {"type5", "type6", "type3"}; - } - - @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. - } - - @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. - } - }; - - new JBBPCustomFieldTypeProcessorAggregator(proc1, proc2); - } + assertThrows(IllegalArgumentException.class, () -> { + final JBBPCustomFieldTypeProcessor proc1 = new JBBPCustomFieldTypeProcessor() { + + @Override + public String[] getCustomFieldTypes() { + return new String[] {"type1", "type2", "type3"}; + } + + @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. + } + + @Override + 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 JBBPCustomFieldTypeProcessor proc2 = new JBBPCustomFieldTypeProcessor() { + + @Override + public String[] getCustomFieldTypes() { + return new String[] {"type5", "type6", "type3"}; + } + + @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. + } + + @Override + 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. + } + }; + + new JBBPCustomFieldTypeProcessorAggregator(proc1, proc2); }); } @@ -92,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. } }; @@ -110,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")); @@ -134,8 +170,8 @@ public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder @Test public void testAllowedAndRead() throws Exception { - final List allowed = new ArrayList(); - final List read = new ArrayList(); + final List allowed = new ArrayList<>(); + final List read = new ArrayList<>(); final JBBPCustomFieldTypeProcessor proc1 = new JBBPCustomFieldTypeProcessor() { @@ -145,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()); } @@ -165,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 3a5223af..fd2c4199 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilderTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPDslBuilderTest.java @@ -1,14 +1,22 @@ package com.igormaznitsa.jbbp.utils; +import static com.igormaznitsa.jbbp.utils.JBBPDslBuilder.Begin; +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.assertThrows; +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.io.JBBPBitNumber; import com.igormaznitsa.jbbp.io.JBBPByteOrder; import com.igormaznitsa.jbbp.mapper.Bin; import com.igormaznitsa.jbbp.mapper.BinType; +import com.igormaznitsa.jbbp.model.JBBPFieldArrayBit; +import com.igormaznitsa.jbbp.model.JBBPFieldStruct; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - -import static com.igormaznitsa.jbbp.utils.JBBPDslBuilder.Begin; -import static org.junit.jupiter.api.Assertions.*; class JBBPDslBuilderTest { @@ -31,97 +39,52 @@ public void testAllowedVarName() { @Test public void testWrongName() { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Int("").End(); - } - }); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Int(" ").End(); - } - }); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Int("3a").End(); - } - }); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Int("ab\n").End(); - } - }); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Int("a$\n").End(); - } - }); + assertThrows(IllegalArgumentException.class, () -> Begin().Int("").End()); + assertThrows(IllegalArgumentException.class, () -> Begin().Int(" ").End()); + assertThrows(IllegalArgumentException.class, () -> Begin().Int("3a").End()); + assertThrows(IllegalArgumentException.class, () -> Begin().Int("ab\n").End()); + assertThrows(IllegalArgumentException.class, () -> Begin().Int("a$\n").End()); } @Test public void testCheckForDuplicatedNameInSameStructure() { final JBBPDslBuilder builder = JBBPDslBuilder.Begin().Int("test"); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - builder.Bool("test"); - } - }); + assertThrows(IllegalArgumentException.class, () -> builder.Bool("test")); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - builder.Bool("Test"); - } - }); + assertThrows(IllegalArgumentException.class, () -> builder.Bool("Test")); final JBBPDslBuilder builder1 = JBBPDslBuilder.Begin().Int("test").Struct().CloseStruct(); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - builder1.Bool("test"); - } - }); + assertThrows(IllegalArgumentException.class, () -> builder1.Bool("test")); final JBBPDslBuilder builder2 = JBBPDslBuilder.Begin().Int("test"); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - builder2.Struct("test"); - } - }); + assertThrows(IllegalArgumentException.class, () -> builder2.Struct("test")); - final JBBPDslBuilder builder3 = JBBPDslBuilder.Begin().Struct("test").Int("a").CloseStruct().Bool("b"); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - builder3.Struct("test"); - } - }); + final JBBPDslBuilder builder3 = + JBBPDslBuilder.Begin().Struct("test").Int("a").CloseStruct().Bool("b"); + assertThrows(IllegalArgumentException.class, () -> builder3.Struct("test")); } @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 @@ -140,6 +103,19 @@ public void testType_Var() { assertEquals("var:(a+b) huzzaa;", Begin().Var("huzzaa", "a+b").End()); } + @Test + 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()); + } + @Test public void testType_VarArray() { assertEquals("var[1234];", Begin().VarArray(1234).End()); @@ -157,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 @@ -242,12 +219,7 @@ public void testType_Skip() { assertEquals("skip:3;", Begin().Skip(3).End()); assertEquals("skip:(a+b);", Begin().Skip("a+b").End()); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Skip(-3); - } - }); + assertThrows(IllegalArgumentException.class, () -> Begin().Skip(-3)); } @Test @@ -257,30 +229,10 @@ public void testResetCounter() { @Test public void testVal() { - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Val(null, "a+b").End(); - } - }); - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Val("hello", null).End(); - } - }); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Val("", "a+b").End(); - } - }); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Val("hello", "").End(); - } - }); + assertThrows(NullPointerException.class, () -> Begin().Val(null, "a+b").End()); + assertThrows(NullPointerException.class, () -> Begin().Val("hello", null).End()); + assertThrows(IllegalArgumentException.class, () -> Begin().Val("", "a+b").End()); + assertThrows(IllegalArgumentException.class, () -> Begin().Val("hello", "").End()); assertEquals("val:(a+b) hello;", Begin().Val("hello", "a+b").End()); } @@ -290,12 +242,7 @@ public void testType_Align() { assertEquals("align:3;", Begin().Align(3).End()); assertEquals("align:(a+b);", Begin().Align("a+b").End()); - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().Align(-3); - } - }); + assertThrows(IllegalArgumentException.class, () -> Begin().Align(-3)); } @Test @@ -399,12 +346,7 @@ public void testStruct_CloseStruct_All() { "\t}\n" + "}\n", Begin().Struct().Struct().Struct().CloseStruct(true).End(true)); - assertThrows(IllegalStateException.class, new Executable() { - @Override - public void execute() throws Throwable { - Begin().CloseStruct(true); - } - }); + assertThrows(IllegalStateException.class, () -> Begin().CloseStruct(true)); } @Test @@ -435,20 +377,17 @@ 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, new Executable() { - @Override - public void execute() throws Throwable { - Begin().CloseStruct(); - } - }); + assertThrows(IllegalStateException.class, () -> Begin().CloseStruct()); } @Test @@ -474,95 +413,181 @@ class Test { @Test public void testAnotatedClass_AnnottatedButWithoutType() { class Test { - @Bin(outOrder = 1) + @Bin(order = 1) int a; - @Bin(outOrder = 3) + @Bin(order = 3) int c; - @Bin(outOrder = 2, outByteOrder = JBBPByteOrder.LITTLE_ENDIAN) + @Bin(order = 2, byteOrder = JBBPByteOrder.LITTLE_ENDIAN) int b; + @Bin(order = 4, arraySizeExpr = "a+b") + Internal[] d; class Internal { - @Bin(outOrder = 1) + @Bin(order = 1) short a; - @Bin(outOrder = 2, extra = "8") + @Bin(order = 2, arraySizeExpr = "8") short[] b; } + } - @Bin(outOrder = 4, extra = "a+b") - Internal[] d; + assertEquals("Test{int a; { + JBBPSystemProperty.PROPERTY_INSTANTIATOR_CLASS.remove(); + System.setProperty(JBBPSystemProperty.PROPERTY_INSTANTIATOR_CLASS.getPropertyName(), "abcd"); + JBBPSystemProperty.PROPERTY_INSTANTIATOR_CLASS.getAsInteger(12345); }); } diff --git a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterTest.java b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterTest.java index ad2ceee7..8f4b2b8e 100644 --- a/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterTest.java +++ b/jbbp/src/test/java/com/igormaznitsa/jbbp/utils/JBBPTextWriterTest.java @@ -16,15 +16,20 @@ package com.igormaznitsa.jbbp.utils; +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.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.JBBPParser; import com.igormaznitsa.jbbp.io.JBBPByteOrder; import com.igormaznitsa.jbbp.it.AbstractParserIntegrationTest; import com.igormaznitsa.jbbp.mapper.Bin; import com.igormaznitsa.jbbp.mapper.BinType; import com.igormaznitsa.jbbp.utils.JBBPTextWriter.Extra; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; @@ -32,19 +37,20 @@ import java.lang.reflect.Field; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JBBPTextWriterTest extends AbstractParserIntegrationTest { private static JBBPTextWriter makeWriter() { - return new JBBPTextWriter(new StringWriter(), JBBPByteOrder.BIG_ENDIAN, "\n", 16, "0x", ".", ";", "~", ","); + return new JBBPTextWriter(new StringWriter(), JBBPByteOrder.BIG_ENDIAN, "\n", 16, "0x", ".", + ";", "~", ","); } @Test public void testMakeStrWriter() throws Exception { - final String generated = JBBPTextWriter.makeStrWriter().Int(12).Byte(34).BR().Comment("Huzzaaa").Close().toString(); - assertEquals(String.format(".0x0000000C,0x22%n;Huzzaaa"),generated); + final String generated = + JBBPTextWriter.makeStrWriter().Int(12).Byte(34).BR().Comment("Huzzaaa").Close().toString(); + assertEquals(String.format(".0x0000000C,0x22%n;Huzzaaa"), generated); } @Test @@ -82,47 +88,57 @@ public void testMultilineCommentHelloWorld() throws Exception { @Test public void testMultilineCommentAfterValue() throws Exception { - assertEquals(".0x12345678;Hello\n ;World", makeWriter().Int(0x12345678).Comment("Hello\nWorld").Close().toString()); + assertEquals(".0x12345678;Hello\n ;World", + makeWriter().Int(0x12345678).Comment("Hello\nWorld").Close().toString()); } @Test public void testCommentAndValue() throws Exception { - assertEquals(";Hello World\n.0x01,0x00000001,0x0000000000000001", makeWriter().Comment("Hello World").Byte(1).Int(1).Long(1).Close().toString()); + assertEquals(";Hello World\n.0x01,0x00000001,0x0000000000000001", + makeWriter().Comment("Hello World").Byte(1).Int(1).Long(1).Close().toString()); } @Test public void testComment_DisableEnable() throws Exception { - assertEquals(";Hrum\n.0x01,0x00000001,0x0000000000000001", makeWriter().DisableComments().Comment("Hello World").EnableComments().Comment("Hrum").Byte(1).Int(1).Long(1).Close().toString()); + assertEquals(";Hrum\n.0x01,0x00000001,0x0000000000000001", + makeWriter().DisableComments().Comment("Hello World").EnableComments().Comment("Hrum") + .Byte(1).Int(1).Long(1).Close().toString()); } @Test public void testDouble_Max_radix10() throws Exception { - assertEquals(".1.7976931348623157E308", makeWriter().SetValuePrefix("").Radix(10).Double(Double.MAX_VALUE).Close().toString()); + assertEquals(".1.7976931348623157E308", + makeWriter().SetValuePrefix("").Radix(10).Double(Double.MAX_VALUE).Close().toString()); } @Test public void testDouble_Max_radix16() throws Exception { - assertEquals(".1.FFFFFFFFFFFFFP1023", makeWriter().SetValuePrefix("").Radix(16).Double(Double.MAX_VALUE).Close().toString()); + assertEquals(".1.FFFFFFFFFFFFFP1023", + makeWriter().SetValuePrefix("").Radix(16).Double(Double.MAX_VALUE).Close().toString()); } @Test public void testFloat_Max_radix10() throws Exception { - assertEquals(".3.4028234663852886E38", makeWriter().SetValuePrefix("").Radix(10).Float(Float.MAX_VALUE).Close().toString()); + assertEquals(".3.4028234663852886E38", + makeWriter().SetValuePrefix("").Radix(10).Float(Float.MAX_VALUE).Close().toString()); } @Test public void testFloat_Min_radix10() throws Exception { - assertEquals(".-1.401298464324817E-45", makeWriter().SetValuePrefix("").Radix(10).Float(-Float.MIN_VALUE).Close().toString()); + assertEquals(".-1.401298464324817E-45", + makeWriter().SetValuePrefix("").Radix(10).Float(-Float.MIN_VALUE).Close().toString()); } @Test public void testFloat_Max_radix16() throws Exception { - assertEquals(".1.FFFFFEP127", makeWriter().SetValuePrefix("").Radix(16).Float(Float.MAX_VALUE).Close().toString()); + assertEquals(".1.FFFFFEP127", + makeWriter().SetValuePrefix("").Radix(16).Float(Float.MAX_VALUE).Close().toString()); } @Test public void testFloat_Min_radix16() throws Exception { - assertEquals(".-1.0P-149", makeWriter().SetValuePrefix("").Radix(16).Float(-Float.MIN_VALUE).Close().toString()); + assertEquals(".-1.0P-149", + makeWriter().SetValuePrefix("").Radix(16).Float(-Float.MIN_VALUE).Close().toString()); } @Test @@ -152,27 +168,17 @@ public void testValueAndMultilineComment() throws Exception { System.out.println(text); - assertFile("testwriter.txt", text); + assertFileContent("testwriter.txt", text); } @Test public void testExtras_ErrorForNull() throws Exception { - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - makeWriter().AddExtras((Extra[]) null); - } - }); + assertThrows(NullPointerException.class, () -> makeWriter().AddExtras((Extra[]) null)); } @Test public void testExtras_ErrorForEmptyExtras() throws Exception { - assertThrows(IllegalStateException.class, new Executable() { - @Override - public void execute() throws Throwable { - makeWriter().Obj(0, new Object()); - } - }); + assertThrows(IllegalStateException.class, () -> makeWriter().Obj(0, new Object())); } @Test @@ -180,7 +186,8 @@ public void testExtras_NotPrintedForNull() 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 { return null; } }).Obj(1, new Object()); @@ -221,7 +228,8 @@ public void testExtras_PrintInfoAboutComplexObjectIntoWriter() throws Exception final JBBPTextWriter writer = makeWriter(); writer.SetMaxValuesPerLine(16).AddExtras(new JBBPTextWriterExtraAdapter() { @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 { context .BR() .Comment("Complex object") @@ -242,7 +250,7 @@ public String doConvertObjToStr(final JBBPTextWriter context, final int id, fina final String text = writer.Byte(0xFF).Obj(111, "Hello").Int(0xCAFEBABE).Close().toString(); System.out.println(text); - assertFile("testwriter3.txt", text); + assertFileContent("testwriter3.txt", text); } @Test @@ -253,39 +261,45 @@ public void testStringNumerationWithExtras() throws Exception { final AtomicInteger bytePrintCounter = new AtomicInteger(0); final AtomicInteger closeCounter = new AtomicInteger(0); - writer.SetMaxValuesPerLine(32).SetCommentPrefix(" // ").AddExtras(new JBBPTextWriterExtraAdapter() { - @Override - public void onClose(final JBBPTextWriter context) throws IOException { - context.Comment("The Last Line"); - closeCounter.incrementAndGet(); - } - - @Override - public void onNewLine(final JBBPTextWriter context, final int lineNumber) throws IOException { - newLineCounter.incrementAndGet(); - } - - @Override - public void onBeforeFirstValue(final JBBPTextWriter context) throws IOException { - context.write(JBBPUtils.ensureMinTextLength(Integer.toString(context.getLine()), 8, '0', 0) + ' '); - } - - @Override - public String doConvertByteToStr(final JBBPTextWriter context, final int value) throws IOException { - bytePrintCounter.incrementAndGet(); - return null; - } - - @Override - public void onReachedMaxValueNumberForLine(final JBBPTextWriter context) throws IOException { - context.Comment("End of line"); - } - }); + writer.SetMaxValuesPerLine(32).SetCommentPrefix(" // ") + .AddExtras(new JBBPTextWriterExtraAdapter() { + @Override + public void onClose(final JBBPTextWriter context) throws IOException { + context.Comment("The Last Line"); + closeCounter.incrementAndGet(); + } + + @Override + public void onNewLine(final JBBPTextWriter context, final int lineNumber) + throws IOException { + newLineCounter.incrementAndGet(); + } + + @Override + public void onBeforeFirstValue(final JBBPTextWriter context) throws IOException { + context.write( + JBBPUtils.ensureMinTextLength(Integer.toString(context.getLine()), 8, '0', 0) + + ' '); + } + + @Override + public String doConvertByteToStr(final JBBPTextWriter context, final int value) + throws IOException { + bytePrintCounter.incrementAndGet(); + return null; + } + + @Override + public void onReachedMaxValueNumberForLine(final JBBPTextWriter context) + throws IOException { + context.Comment("End of line"); + } + }); for (int i = 0; i < 130; i++) { writer.Byte(i); } - assertFile("testwriter2.txt", writer.Close().toString()); + assertFileContent("testwriter2.txt", writer.Close().toString()); assertEquals(4, newLineCounter.get()); assertEquals(130, bytePrintCounter.get()); assertEquals(1, closeCounter.get()); @@ -303,12 +317,7 @@ public void testByteOrder() throws Exception { @Test public void testObj_NoExtras() throws Exception { - assertThrows(IllegalStateException.class, new Executable() { - @Override - public void execute() throws Throwable { - makeWriter().Obj(123, "Str1", "Str2", "Str3"); - } - }); + assertThrows(IllegalStateException.class, () -> makeWriter().Obj(123, "Str1", "Str2", "Str3")); } @Test @@ -327,7 +336,8 @@ public void testObj_PrintIntervalFromArray() throws Exception { 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(1234, id); assertNotNull(obj); assertSame(writer, context); @@ -335,7 +345,9 @@ public String doConvertObjToStr(JBBPTextWriter context, int id, Object obj) thro } }); - assertEquals(".0xHello,0xWorld,0xHurraaa", writer.Obj(1234, new Object[] {1, 2, "Hello", "World", "Hurraaa", 3}, 2, 3).Close().toString()); + assertEquals(".0xHello,0xWorld,0xHurraaa", + writer.Obj(1234, new Object[] {1, 2, "Hello", "World", "Hurraaa", 3}, 2, 3).Close() + .toString()); } @Test @@ -345,7 +357,8 @@ public void testObj_ExtrasReturnValue() throws Exception { writer.SetValuePrefix("").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 { return obj.toString(); } @@ -437,6 +450,14 @@ public void testInt_OneValue() throws Exception { assertEquals(".0x12345678,0xFFFFFFFF", writer.Close().toString()); } + @Test + public void testUInt_OneValue() throws Exception { + final JBBPTextWriter writer = makeWriter(); + writer.UInt(0x12345678); + writer.UInt(-1); + assertEquals(".0x12345678,0xFFFFFFFF", writer.Close().toString()); + } + @Test public void testInt_Array() throws Exception { final JBBPTextWriter writer = makeWriter(); @@ -444,6 +465,13 @@ public void testInt_Array() throws Exception { assertEquals(".0x12345678,0xFFFFFFFF", writer.Close().toString()); } + @Test + public void testUInt_Array() throws Exception { + final JBBPTextWriter writer = makeWriter(); + writer.UInt(new int[] {0x12345678, -1}); + assertEquals(".0x12345678,0xFFFFFFFF", writer.Close().toString()); + } + @Test public void testInt_Array_InversedByteOrder() throws Exception { final JBBPTextWriter writer = makeWriter(); @@ -451,6 +479,13 @@ public void testInt_Array_InversedByteOrder() throws Exception { assertEquals(".0x78563412,0xFFFFFFFF", writer.Close().toString()); } + @Test + public void testUInt_Array_InversedByteOrder() throws Exception { + final JBBPTextWriter writer = makeWriter(); + writer.ByteOrder(JBBPByteOrder.LITTLE_ENDIAN).UInt(new int[] {0x12345678, -1}); + assertEquals(".0x78563412,0xFFFFFFFF", writer.Close().toString()); + } + @Test public void testInt_PartOfArray() throws Exception { final JBBPTextWriter writer = makeWriter(); @@ -458,6 +493,13 @@ public void testInt_PartOfArray() throws Exception { assertEquals(".0x12345678,0xFFFFFFFF", writer.Close().toString()); } + @Test + public void testUInt_PartOfArray() throws Exception { + final JBBPTextWriter writer = makeWriter(); + writer.UInt(new int[] {0, 0x12345678, -1, 0}, 1, 2); + assertEquals(".0x12345678,0xFFFFFFFF", writer.Close().toString()); + } + @Test public void testLong_OneValue() throws Exception { final JBBPTextWriter writer = makeWriter(); @@ -489,22 +531,12 @@ public void testLong_PartOfArray() throws Exception { @Test public void testRadix_ErrorForLessThan2() { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - makeWriter().Radix(1); - } - }); + assertThrows(IllegalArgumentException.class, () -> makeWriter().Radix(1)); } @Test public void testRadix_ErrorForGreaterThan36() { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - makeWriter().Radix(37); - } - }); + assertThrows(IllegalArgumentException.class, () -> makeWriter().Radix(37)); } @Test @@ -515,12 +547,15 @@ public void testRadix() throws Exception { writer.Radix(12); assertEquals(12, writer.getRadix()); writer.SetValuePrefix("").Radix(16).Int(0x12345).Radix(2).Int(0x12345).Radix(10).Int(0x12345); - assertEquals(".00012345,00000000000000010010001101000101,0000074565", writer.Close().toString()); + assertEquals(".00012345,00000000000000010010001101000101,0000074565", + writer.Close().toString()); } @Test public void testGetLineSeparator() throws Exception { - assertEquals("hello", new JBBPTextWriter(makeWriter(), JBBPByteOrder.BIG_ENDIAN, "hello", 11, "", "", "", "", "").getLineSeparator()); + assertEquals("hello", + new JBBPTextWriter(makeWriter(), JBBPByteOrder.BIG_ENDIAN, "hello", 11, "", "", "", "", "") + .getLineSeparator()); } @Test @@ -554,17 +589,13 @@ public String doConvertByteToStr(JBBPTextWriter context, int value) throws IOExc @Test public void testStr_ErrorForNull() throws Exception { - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - makeWriter().Str((String[]) null); - } - }); + assertThrows(NullPointerException.class, () -> makeWriter().Str((String[]) null)); } @Test public void testStr() throws Exception { - assertEquals(".0x01,Hello,World,,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 @@ -640,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 @@ -652,22 +684,12 @@ public void testSetTabSpaces() throws Exception { @Test public void testSetTabSpaces_ErrorForNegative() throws Exception { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - makeWriter().SetTabSpaces(-1); - } - }); + assertThrows(IllegalArgumentException.class, () -> makeWriter().SetTabSpaces(-1)); } @Test public void testSetTabSpaces_ErrorForZero() throws Exception { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - makeWriter().SetTabSpaces(0); - } - }); + assertThrows(IllegalArgumentException.class, () -> makeWriter().SetTabSpaces(0)); } @Test @@ -675,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; } @@ -712,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 @@ -722,19 +747,19 @@ public void testBin_EasyCase() throws Exception { @Bin(name = "some class") class SomeClass { - @Bin(outOrder = 1) + @Bin(order = 1) byte a; - @Bin(outOrder = 2, comment = "Short field") + @Bin(order = 2, comment = "Short field") short b; - @Bin(outOrder = 3) + @Bin(order = 3) int c; - @Bin(outOrder = 4, comment = "Long field") + @Bin(order = 4, comment = "Long field") long d; - @Bin(outOrder = 5, comment = "some array") + @Bin(order = 5, comment = "some array") byte[] arr = new byte[128]; - @Bin(outOrder = 6, comment = "some string") + @Bin(order = 6, comment = "some string") String str = "Hello String"; - @Bin(outOrder = 7, comment = "some string array") + @Bin(order = 7, comment = "some string array") String[] strs = new String[] {"Hello", null, "World"}; } @@ -749,7 +774,7 @@ class SomeClass { final String text = writer.SetCommentPrefix("; ").Bin(cl).Close().toString(); System.out.println(text); - assertFile("testwriterbin1.txt", text); + assertFileContent("testwriterbin1.txt", text); } @Test @@ -772,31 +797,36 @@ public void testBin_ParsedPng() throws Exception { class Chunk { - @Bin(outOrder = 1) + @Bin(order = 1) int Length; - @Bin(outOrder = 2) + @Bin(order = 2) int Type; - @Bin(outOrder = 3) + @Bin(order = 3) byte[] Data; - @Bin(outOrder = 4) + @Bin(order = 4) int CRC; } class Png { - @Bin(outOrder = 1) + @Bin(order = 1) long Header; - @Bin(outOrder = 2) + @Bin(order = 2) Chunk[] Chunks; } - final Png png = pngParser.parse(pngStream).mapTo(Png.class); + final Png png = pngParser.parse(pngStream).mapTo(new Png(), aClass -> { + if (aClass == Chunk.class) { + return new Chunk(); + } + return null; + }); final String text = writer.SetMaxValuesPerLine(16).Bin(png).Close().toString(); System.out.println(text); - assertFile("testwriterbin2.txt", text); + assertFileContent("testwriterbin2.txt", text); } finally { JBBPUtils.closeQuietly(pngStream); } @@ -807,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 { @@ -824,12 +855,12 @@ class Klazz { final byte[] data = new byte[4 + 8 + 4 * 2 + 8 * 2]; new Random(111222).nextBytes(data); - final Klazz parsed = parser.parse(data).mapTo(Klazz.class); + final Klazz parsed = parser.parse(data).mapTo(new Klazz()); final String text = writer.SetMaxValuesPerLine(16).Bin(parsed).Close().toString(); System.out.println(text); - assertFile("testwriterbinfloatdouble.txt", text); + assertFileContent("testwriterbinfloatdouble.txt", text); } @Test @@ -848,9 +879,10 @@ 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); - assertFile("testwriterbin2b.txt", text); + assertFileContent("testwriterbin2b.txt", text); } finally { JBBPUtils.closeQuietly(pngStream); } @@ -858,30 +890,40 @@ 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); - assertFile("txtwrtrjbbpobj1.txt", text); + assertFileContent("txtwrtrjbbpobj1.txt", text); } @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, @@ -890,9 +932,10 @@ 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); - assertFile("txtwrtrjbbpobj2.txt", text); + assertFileContent("txtwrtrjbbpobj2.txt", text); } @Test @@ -904,19 +947,25 @@ 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); - assertFile("txtwrtrjbbpobj3.txt", text); + assertFileContent("txtwrtrjbbpobj3.txt", text); } @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); - assertFile("boolarrayraw.txt", text); + assertFileContent("boolarrayraw.txt", text); } @Test @@ -928,21 +977,22 @@ 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(Parsed.class); + 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); - assertFile("testwriterbin5.txt", text); + assertFileContent("testwriterbin5.txt", text); } @Test public void testCustomFieldInMappedClass() throws Exception { class TestClass { - @Bin(outOrder = 1) + @Bin(order = 1) int a; - @Bin(outOrder = 2, custom = true) + @Bin(order = 2, custom = true) int b; } @@ -951,30 +1001,34 @@ 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); - assertFile("testwriterbin3.txt", text); + assertFileContent("testwriterbin3.txt", text); } @Test public void testCustomArrayFieldInMappedClass() throws Exception { class TestClass { - @Bin(outOrder = 1) + @Bin(order = 1) int a; - @Bin(outOrder = 2, custom = true) + @Bin(order = 2, custom = true) int[] b = new int[3]; } @@ -983,21 +1037,25 @@ 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); - assertFile("testwriterbin4.txt", 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 d95e501e..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 @@ -145,22 +256,13 @@ public void testIsNumber() { @Test public void testUnpackInt_NPEForArrayIsNull() { - assertThrows(NullPointerException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPUtils.unpackInt(null, new JBBPIntCounter()); - } - }); + assertThrows(NullPointerException.class, () -> JBBPUtils.unpackInt(null, new JBBPIntCounter())); } @Test public void testUnpackInt_IAEForWrongPrefix() { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - 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 @@ -173,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); @@ -205,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 @@ -250,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})); } @@ -261,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"); @@ -279,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); @@ -293,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); } @@ -307,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); @@ -357,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 @@ -373,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)); @@ -385,64 +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() { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPUtils.reverseByteOrder(1234, 0); - } - }); + public void testReverseByteOrder_ErrorForZeroByteNumber() { + assertThrows(IllegalArgumentException.class, () -> JBBPUtils.reverseByteOrder(1234, 0)); } @Test - public void testReverdeByteOrder_ErrorForTooBigByteNumber() { - assertThrows(IllegalArgumentException.class, new Executable() { - @Override - public void execute() throws Throwable { - JBBPUtils.reverseByteOrder(1234, 9); - } - }); + 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)); @@ -564,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 dcbfa0ec..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 @@ -20,7 +20,6 @@ import com.igormaznitsa.jbbp.io.JBBPBitInputStream; import com.igormaznitsa.jbbp.mapper.Bin; import com.igormaznitsa.jbbp.mapper.BinType; -import com.igormaznitsa.jbbp.utils.TargetSources; import org.openjdk.jmh.annotations.Benchmark; import java.io.ByteArrayInputStream; @@ -33,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); @@ -48,7 +48,7 @@ public class JBBP_Benchmark { @Benchmark public void measureParse_DynamicAndMapping() throws IOException { - parser.parse(DATA).mapTo(Data.class); + parser.parse(DATA).mapTo(new Data()); } @Benchmark @@ -76,5 +76,9 @@ public static class Data { @Bin(name = "data") public InData[] data; + + public Object newInstance(Class klazz) { + return klazz == InData.class ? new InData() : null; + } } } 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.png b/logo.png index e4e8c964..05bb8e01 100644 Binary files a/logo.png and b/logo.png differ diff --git a/logo.svg b/logo.svg index 8256dcda..6ed51689 100644 --- a/logo.svg +++ b/logo.svg @@ -2,13247 +2,13267 @@ image/svg+xml + + + + + + + + + + + + + - + + + + + + + + 0 -1 - + + + + + + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 985aa56f..456878cf 100644 --- a/pom.xml +++ b/pom.xml @@ -4,27 +4,31 @@ com.igormaznitsa jbbp-main-pom - 1.4.1-SNAPSHOT + 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 - ${project.version} - 1.6 - 1.6 - 5.2.0 + 1.2.1 + 11 + 11 + 11 + 5.13.3 + 4.13.2 + 2.17.0 + 1.36 @@ -42,7 +46,6 @@ http://www.igormaznitsa.com +3 - architect developer @@ -71,38 +74,88 @@ + + + + org.apache.maven.shared + maven-verifier + 2.0.0-M1 + + + org.junit.jupiter + junit-jupiter-engine + ${junit5.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit5.version} + + + org.junit.jupiter + junit-jupiter-params + ${junit5.version} + + + org.junit.platform + junit-platform-launcher + 1.13.4 + + + commons-io + commons-io + ${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 + + + + org.junit.jupiter junit-jupiter-api - ${junit5.version} test org.junit.jupiter junit-jupiter-engine - ${junit5.version} test org.junit.jupiter junit-jupiter-params - ${junit5.version} test - org.apache.maven.surefire - surefire-logger-api - 2.21.0 - + org.junit.platform + junit-platform-launcher test - true - assemble + plugins + + jbbp-plugins + + + + bundle ${basedir}/src/assemble @@ -113,7 +166,6 @@ org.apache.maven.plugins maven-assembly-plugin - 3.1.0 make-bundle @@ -132,62 +184,151 @@ - - localrepo - - - local-oss-git-repo - file:///home/igorm/Projects_PET/iam-oss-mvn-snapshots - - - - - coverage - - - - org.jacoco - jacoco-maven-plugin - 0.7.9 - - - - prepare-agent - - - - report - prepare-package - - report - - - - - - - + + + + org.codehaus.mojo + properties-maven-plugin + 1.2.1 + + + org.apache.maven + maven-clean-plugin + 3.1.0 + + + org.codehaus.mojo + animal-sniffer-maven-plugin + 1.24 + + + org.apache.maven.plugins + maven-assembly-plugin + 3.7.1 + + + org.apache.maven.plugins + maven-gpg-plugin + 3.2.7 + + + net.nicoulaj.maven.plugins + checksum-maven-plugin + 1.11 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.10.1 + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.5.0 + + + org.apache.maven.plugins + maven-source-plugin + 3.3.1 + + + com.igormaznitsa + uber-pom + 1.0.3 + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.2 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.3 + + + + org.apache.maven.plugins maven-compiler-plugin - 3.7.0 -Xlint:all false - 1.6 - 1.6 true 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 - 2.21.0 1 false @@ -204,11 +345,6 @@ junit-jupiter-engine ${junit5.version} - - org.junit.platform - junit-platform-surefire-provider - 1.2.0 -