├── .github └── workflows │ └── maven.yml ├── .gitignore ├── README.md ├── licence.txt ├── pom.xml └── src ├── main └── java │ └── fr │ └── devnied │ └── bitlib │ ├── BitUtils.java │ └── BytesUtils.java └── test ├── java └── fr │ └── devnied │ └── bitlib │ ├── BitUtilsTest.java │ └── BytesUtilsTest.java └── resources └── log4j.properties /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Bit-lib4j CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | java: [ 7, 8, 9, 10, 11] 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up JDK ${{ matrix.java }} 19 | uses: actions/setup-java@v2 20 | with: 21 | distribution: 'zulu' 22 | java-version: ${{ matrix.java }} 23 | - name: Build with Maven 24 | run: mvn -B clean package 25 | 26 | finish: 27 | needs: build 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v2 31 | - name: Set up JDK 1.8 32 | uses: actions/setup-java@v2 33 | with: 34 | distribution: 'zulu' 35 | java-version: 8 36 | - name: Build with Maven 37 | run: mvn -B clean cobertura:cobertura coveralls:report -DrepoToken=${{ secrets.COVERALLS_TOKEN }} 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Directories # 2 | /build/ 3 | /bin/ 4 | target/ 5 | .idea 6 | *.iml 7 | 8 | # OS Files # 9 | .DS_Store 10 | 11 | *.class 12 | 13 | # Package Files # 14 | *.war 15 | *.ear 16 | *.db 17 | 18 | ###################### 19 | # Windows 20 | ###################### 21 | 22 | # Windows image file caches 23 | Thumbs.db 24 | 25 | # Folder config file 26 | Desktop.ini 27 | 28 | ###################### 29 | # OSX 30 | ###################### 31 | 32 | .svn 33 | 34 | # Thumbnails 35 | ._* 36 | 37 | # Files that might appear on external disk 38 | .Spotlight-V100 39 | .Trashes 40 | 41 | 42 | ###################### 43 | # Eclipse 44 | ###################### 45 | 46 | *.pydevproject 47 | .project 48 | .metadata 49 | bin/** 50 | tmp/** 51 | tmp/**/* 52 | *.tmp 53 | *.bak 54 | *.swp 55 | *~.nib 56 | local.properties 57 | .classpath 58 | .settings/ 59 | .loadpath 60 | /src/main/resources/rebel.xml 61 | # External tool builders 62 | .externalToolBuilders/ 63 | 64 | # Locally stored "Eclipse launch configurations" 65 | *.launch 66 | 67 | # CDT-specific 68 | .cproject 69 | 70 | # PDT-specific 71 | .buildpath 72 | pom.xml.releaseBackup 73 | 74 | release.properties 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Bit-lib4j ![Bit-lib4j CI](https://github.com/devnied/Bit-lib4j/workflows/Bit-lib4j%20CI/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/devnied/Bit-lib4j/badge.svg?branch=master)](https://coveralls.io/github/devnied/Bit-lib4j?branch=master) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.devnied/bit-lib4j/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/com.github.devnied/bit-lib4j) 2 | ======== 3 | 4 | Bit-Lib4j is an useful library to handle bytes or bits in Java.
5 | With this library you can read/write data in a byte array with a custom size for Java primitive types. 6 | 7 | ## Simple API 8 | 9 | It is very easy to get started with bit-lib4j: 10 | 11 | * Read data from byte array 12 | 13 | ```java 14 | byte[] array = new byte[]{0x12,0x25} 15 | BitUtils bit = new BitUtils(array); 16 | int res = bit.getNextInteger(4); // read the first 4 bits to an integer 17 | ``` 18 | 19 | * Create byte array with bit 20 | 21 | ```java 22 | BitUtils bit = new BitUtils(8); 23 | bit.setNextInteger(3,3); // set an integer on 3 bits 24 | bit.setNextInteger(1,5); // set one value on 5 bits 25 | 26 | // Result 27 | bit.getData(); // return Ox61 (0110 0001b) 28 | ``` 29 | 30 | * Read/write signed values 31 | 32 | ```java 33 | BitUtils bit = new BitUtils(4); 34 | bit.setNextInteger(-2 , 4); // set an integer (-2) on 4 bits 35 | 36 | // Result 37 | bit.getNextIntegerSigned(4); // return -2 38 | ``` 39 | You can also use ```getNextSignedLong()``` to handle long signed values. 40 | 41 | 42 | ## Handle bytes more easily 43 | 44 | The class ByteUtils provided static methods to convert byte array to String, String to byte array, int to byte array, byte array to binary representation. 45 | 46 | 47 | More documentation into the [wiki](https://github.com/devnied/Bit-lib4j/wiki) 48 | 49 | ## Download 50 | 51 | ### Maven 52 | 53 | ```xml 54 | 55 | com.github.devnied 56 | bit-lib4j 57 | 1.5.2 58 | 59 | ``` 60 | 61 | ### JAR 62 | 63 | You can download this library on [Maven central](http://search.maven.org/#search%7Cga%7C1%7Cbit-lib4j) or in Github [release tab](https://github.com/devnied/Bit-lib4j/releases) 64 | 65 | ## Dependencies 66 | 67 | If you are not using Maven or some other dependency management tool that can understand Maven repositories, the list below is what you need to run bit-lib4j. 68 | 69 | **Runtime Dependencies** 70 | * slf4j-api 1.7.30 71 | 72 | ## Bugs 73 | 74 | Please report bugs and feature requests to the GitHub issue tracker.
75 | Forks and Pull Requests are also welcome. 76 | 77 | ## Author 78 | 79 | **Millau Julien** 80 | 81 | + [http://twitter.com/devnied](http://twitter.com/devnied) 82 | + [http://github.com/devnied](http://github.com/devnied) 83 | 84 | 85 | ## Copyright and license 86 | 87 | Copyright 2020 Millau Julien. 88 | 89 | Licensed under the Apache License, Version 2.0 (the "License"); 90 | you may not use this work except in compliance with the License. 91 | You may obtain a copy of the License in the LICENSE file, or at: 92 | 93 | [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) 94 | 95 | Unless required by applicable law or agreed to in writing, software 96 | distributed under the License is distributed on an "AS IS" BASIS, 97 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 98 | See the License for the specific language governing permissions and 99 | limitations under the License. 100 | 101 | [![Analytics](https://ga-beacon.appspot.com/UA-19411627-5/Bit-lib4j/index)](https://github.com/igrigorik/ga-beacon) 102 | -------------------------------------------------------------------------------- /licence.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2013 Millau Julien 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.github.devnied 4 | bit-lib4j 5 | jar 6 | 1.5.3-SNAPSHOT 7 | bit-lib4j 8 | 9 | 10 | org.sonatype.oss 11 | oss-parent 12 | 7 13 | 14 | 15 | 2013 16 | 17 | Useful library to manipulate bits in Java. 18 | Read and write data in a byte array with a custom size for Java types 19 | 20 | 21 | https://github.com/devnied/Bit-lib4j/ 22 | 23 | 24 | MILLAU Julien 25 | devnied 26 | mxjulien@gmail.com 27 | 28 | Java Developer 29 | 30 | 31 | 32 | 33 | 34 | The Apache Software License, Version 2.0 35 | http://www.apache.org/licenses/LICENSE-2.0.txt 36 | repo 37 | 38 | 39 | 40 | 41 | scm:git:git@github.com:devnied/Bit-lib4j.git 42 | scm:git:git@github.com:devnied/Bit-lib4j.git 43 | scm:git:git@github.com:devnied/Bit-lib4j.git 44 | HEAD 45 | 46 | 47 | 48 | 49 | 50 | 1.7.32 51 | 52 | 53 | 54 | 55 | 56 | org.slf4j 57 | slf4j-api 58 | ${slf4j.version} 59 | 60 | 61 | org.slf4j 62 | slf4j-log4j12 63 | ${slf4j.version} 64 | test 65 | 66 | 67 | 68 | org.apache.logging.log4j 69 | log4j-core 70 | 2.17.0 71 | test 72 | 73 | 74 | 75 | 76 | junit 77 | junit 78 | 4.13.2 79 | test 80 | 81 | 82 | org.easytesting 83 | fest-assert 84 | 1.4 85 | test 86 | 87 | 88 | 89 | 90 | 91 | sonatype-nexus-snapshots 92 | Sonatype Nexus Snapshots 93 | https://oss.sonatype.org/content/repositories/snapshots 94 | 95 | 96 | sonatype-nexus-staging 97 | Nexus Release Repository 98 | https://oss.sonatype.org/service/local/staging/deploy/maven2 99 | 100 | 101 | 102 | 103 | install 104 | 105 | 106 | maven-compiler-plugin 107 | 3.8.1 108 | 109 | 1.6 110 | 1.6 111 | UTF-8 112 | 113 | 114 | 115 | org.apache.maven.plugins 116 | maven-resources-plugin 117 | 3.1.0 118 | 119 | UTF-8 120 | 121 | 122 | 123 | org.apache.maven.plugins 124 | maven-release-plugin 125 | 2.5.3 126 | 127 | forked-path 128 | true 129 | 130 | 131 | 132 | maven-source-plugin 133 | 3.2.1 134 | 135 | 136 | attach-sources 137 | 138 | jar 139 | 140 | 141 | 142 | 143 | 144 | org.eluder.coveralls 145 | coveralls-maven-plugin 146 | 4.3.0 147 | 148 | 149 | org.codehaus.mojo 150 | cobertura-maven-plugin 151 | 2.7 152 | 153 | xml 154 | 256m 155 | 156 | true 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | release-sign-artifacts 166 | 167 | 168 | performRelease 169 | true 170 | 171 | 172 | 173 | 174 | 175 | org.apache.maven.plugins 176 | maven-gpg-plugin 177 | 178 | 179 | sign-artifacts 180 | verify 181 | 182 | sign 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /src/main/java/fr/devnied/bitlib/BitUtils.java: -------------------------------------------------------------------------------- 1 | package fr.devnied.bitlib; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.nio.Buffer; 7 | import java.nio.ByteBuffer; 8 | import java.nio.charset.Charset; 9 | import java.text.ParseException; 10 | import java.text.SimpleDateFormat; 11 | import java.util.Arrays; 12 | import java.util.Date; 13 | 14 | /** 15 | * Class to manage bit with java 16 | * 17 | * @author Millau Julien 18 | * 19 | */ 20 | public final class BitUtils { 21 | /*** 22 | * Bit utils class logger 23 | */ 24 | private static final Logger LOGGER = LoggerFactory.getLogger(BitUtils.class.getName()); 25 | /** 26 | * Constant for byte size 27 | */ 28 | public static final int BYTE_SIZE = Byte.SIZE; 29 | /** 30 | * Constant for byte size (float) 31 | */ 32 | public static final float BYTE_SIZE_F = Byte.SIZE; 33 | /** 34 | * 255 init value 35 | */ 36 | private static final int DEFAULT_VALUE = 0xFF; 37 | /** 38 | * Constant for the default charset 39 | */ 40 | private static final Charset DEFAULT_CHARSET = Charset.forName("ASCII"); 41 | 42 | /** 43 | * Simple date format (yyyMMdd) 44 | */ 45 | public static final String DATE_FORMAT = "yyyyMMdd"; 46 | 47 | /** 48 | * Table of read byte 49 | */ 50 | private final byte[] byteTab; 51 | 52 | /** 53 | * Current index 54 | */ 55 | private int currentBitIndex; 56 | 57 | /** 58 | * Size in bit of the byte tab 59 | */ 60 | private final int size; 61 | 62 | /** 63 | * Constructor of the class 64 | * 65 | * @param pByte 66 | * byte read 67 | */ 68 | public BitUtils(final byte[] pByte) { 69 | byteTab = new byte[pByte.length]; 70 | System.arraycopy(pByte, 0, byteTab, 0, pByte.length); 71 | size = pByte.length * BYTE_SIZE; 72 | } 73 | 74 | /** 75 | * Constructor for empty byte tab 76 | * 77 | * @param pSize 78 | * the size of the tab in bit 79 | */ 80 | public BitUtils(final int pSize) { 81 | byteTab = new byte[(int) Math.ceil(pSize / BYTE_SIZE_F)]; 82 | size = pSize; 83 | } 84 | 85 | /** 86 | * Add pIndex to the current value of bitIndex 87 | * 88 | * @param pIndex 89 | * the value to add to bitIndex 90 | */ 91 | public void addCurrentBitIndex(final int pIndex) { 92 | currentBitIndex += pIndex; 93 | if (currentBitIndex < 0) { 94 | currentBitIndex = 0; 95 | } 96 | } 97 | 98 | /** 99 | * Getter for the currentBitIndex 100 | * 101 | * @return the currentBitIndex 102 | */ 103 | public int getCurrentBitIndex() { 104 | return currentBitIndex; 105 | } 106 | 107 | /** 108 | * Method to get all data 109 | * 110 | * @return a byte tab which contain all data 111 | */ 112 | public byte[] getData() { 113 | byte[] ret = new byte[byteTab.length]; 114 | System.arraycopy(byteTab, 0, ret, 0, byteTab.length); 115 | return ret; 116 | } 117 | 118 | /** 119 | * This method is used to get a mask dynamically 120 | * 121 | * @param pIndex 122 | * start index of the mask 123 | * @param pLength 124 | * size of mask 125 | * @return the mask in byte 126 | */ 127 | public byte getMask(final int pIndex, final int pLength) { 128 | byte ret = (byte) DEFAULT_VALUE; 129 | // Add X 0 to the left 130 | ret = (byte) (ret << pIndex); 131 | ret = (byte) ((ret & DEFAULT_VALUE) >> pIndex); 132 | // Add X 0 to the right 133 | int dec = BYTE_SIZE - (pLength + pIndex); 134 | if (dec > 0) { 135 | ret = (byte) (ret >> dec); 136 | ret = (byte) (ret << dec); 137 | } 138 | return ret; 139 | } 140 | 141 | /** 142 | * Get the Next boolean (read 1 bit) 143 | * 144 | * @return true or false 145 | */ 146 | public boolean getNextBoolean() { 147 | return getNextInteger(1) == 1; 148 | } 149 | 150 | /** 151 | * Method used to get the next byte and shift read data to the beginning of 152 | * the array.
153 | * (Ex 00110000b if we start read 2 bit at index 2 the data returned will be 154 | * 11000000b) 155 | * 156 | * @param pSize 157 | * the size in bit to read 158 | * @return the byte array read 159 | */ 160 | public byte[] getNextByte(final int pSize) { 161 | return getNextByte(pSize, true); 162 | } 163 | 164 | /** 165 | * Method to get The next bytes with the specified size 166 | * 167 | * @param pSize 168 | * the size in bit to read 169 | * @param pShift 170 | * boolean to indicate if the data read will be shift to the 171 | * left.
172 | * 178 | * @return a byte array 179 | */ 180 | public byte[] getNextByte(final int pSize, final boolean pShift) { 181 | byte[] tab = new byte[(int) Math.ceil(pSize / BYTE_SIZE_F)]; 182 | 183 | if (currentBitIndex % BYTE_SIZE != 0) { 184 | int index = 0; 185 | int max = currentBitIndex + pSize; 186 | while (currentBitIndex < max) { 187 | int mod = currentBitIndex % BYTE_SIZE; 188 | int modTab = index % BYTE_SIZE; 189 | int length = Math.min(max - currentBitIndex, Math.min(BYTE_SIZE - mod, BYTE_SIZE - modTab)); 190 | byte val = (byte) (byteTab[currentBitIndex / BYTE_SIZE] & getMask(mod, length)); 191 | if (pShift || pSize % BYTE_SIZE == 0) { 192 | if (mod != 0) { 193 | val = (byte) (val << Math.min(mod, BYTE_SIZE - length)); 194 | } else { 195 | val = (byte) ((val & DEFAULT_VALUE) >> modTab); 196 | } 197 | } 198 | tab[index / BYTE_SIZE] |= val; 199 | currentBitIndex += length; 200 | index += length; 201 | } 202 | if (!pShift && pSize % BYTE_SIZE != 0) { 203 | tab[tab.length - 1] = (byte) (tab[tab.length - 1] & getMask((max - pSize - 1) % BYTE_SIZE, BYTE_SIZE)); 204 | } 205 | } else { 206 | System.arraycopy(byteTab, currentBitIndex / BYTE_SIZE, tab, 0, tab.length); 207 | int val = pSize % BYTE_SIZE; 208 | if (val == 0) { 209 | val = BYTE_SIZE; 210 | } 211 | tab[tab.length - 1] = (byte) (tab[tab.length - 1] & getMask(currentBitIndex % BYTE_SIZE, val)); 212 | currentBitIndex += pSize; 213 | } 214 | 215 | return tab; 216 | } 217 | 218 | /** 219 | * Method to get the next date 220 | * 221 | * @param pSize 222 | * the size of the string date in bit 223 | * @param pPattern 224 | * the Date pattern 225 | * @return a date object or null 226 | */ 227 | public Date getNextDate(final int pSize, final String pPattern) { 228 | return getNextDate(pSize, pPattern, false); 229 | } 230 | 231 | /** 232 | * Method to get the next date 233 | * 234 | * @param pSize 235 | * the size of the string date in bit 236 | * @param pPattern 237 | * the Date pattern 238 | * @param pUseBcd 239 | * get the Date with BCD format (Binary coded decimal) 240 | * @return a date object or null 241 | */ 242 | public Date getNextDate(final int pSize, final String pPattern, final boolean pUseBcd) { 243 | Date date = null; 244 | // create date formatter 245 | SimpleDateFormat sdf = new SimpleDateFormat(pPattern); 246 | // get String 247 | String dateTxt = null; 248 | if (pUseBcd) { 249 | dateTxt = getNextHexaString(pSize); 250 | } else { 251 | dateTxt = getNextString(pSize); 252 | } 253 | 254 | try { 255 | date = sdf.parse(dateTxt); 256 | } catch (ParseException e) { 257 | LOGGER.error("Parsing date error. date:" + dateTxt + " pattern:" + pPattern, e); 258 | } 259 | return date; 260 | } 261 | 262 | /** 263 | * This method is used to get the next String in Hexa 264 | * 265 | * @param pSize 266 | * the length of the string in bit 267 | * @return the string 268 | */ 269 | public String getNextHexaString(final int pSize) { 270 | return BytesUtils.bytesToStringNoSpace(getNextByte(pSize, true)); 271 | } 272 | 273 | /** 274 | * Method used to get get a signed long with the specified size 275 | * @param pLength length of long to get (must be lower than 64) 276 | * @return the long value 277 | */ 278 | public long getNextLongSigned(final int pLength) { 279 | if (pLength > Long.SIZE) { 280 | throw new IllegalArgumentException("Long overflow with length > 64"); 281 | } 282 | long decimal = getNextLong(pLength); 283 | long signMask = 1L << pLength - 1; 284 | 285 | if ( (decimal & signMask) != 0) { 286 | return - (signMask - (signMask ^ decimal)); 287 | } 288 | return decimal; 289 | } 290 | 291 | /** 292 | * Method used to get get a signed integer with the specified size 293 | * @param pLength the length of the integer (must be lower than 32) 294 | * @return the integer value 295 | */ 296 | public int getNextIntegerSigned(final int pLength) { 297 | if (pLength > Integer.SIZE) { 298 | throw new IllegalArgumentException("Integer overflow with length > 32"); 299 | } 300 | return (int) getNextLongSigned(pLength); 301 | } 302 | 303 | /** 304 | * This method is used to get a long with the specified size 305 | * 306 | * Be careful with java long bit sign. This method doesn't handle signed values.
307 | * For that, @see BitUtils.getNextLongSigned() 308 | * 309 | * @param pLength 310 | * the length of the data to read in bit 311 | * @return an long 312 | */ 313 | public long getNextLong(final int pLength) { 314 | // allocate Size of Integer 315 | ByteBuffer buffer = ByteBuffer.allocate(BYTE_SIZE * 2); 316 | // final value 317 | long finalValue = 0; 318 | // Incremental value 319 | long currentValue = 0; 320 | // Size to read 321 | int readSize = pLength; 322 | // length max of the index 323 | int max = currentBitIndex + pLength; 324 | while (currentBitIndex < max) { 325 | int mod = currentBitIndex % BYTE_SIZE; 326 | // apply the mask to the selected byte 327 | currentValue = byteTab[currentBitIndex / BYTE_SIZE] & getMask(mod, readSize) & DEFAULT_VALUE; 328 | // Shift right the read value 329 | int dec = Math.max(BYTE_SIZE - (mod + readSize), 0); 330 | currentValue = (currentValue & DEFAULT_VALUE) >>> dec & DEFAULT_VALUE; 331 | // Shift left the previously read value and add the current value 332 | finalValue = finalValue << Math.min(readSize, BYTE_SIZE) | currentValue; 333 | // calculate read value size 334 | int val = BYTE_SIZE - mod; 335 | // Decrease the size left 336 | readSize = readSize - val; 337 | currentBitIndex = Math.min(currentBitIndex + val, max); 338 | } 339 | buffer.putLong(finalValue); 340 | // reset the current bytebuffer index to 0 341 | ((Buffer)buffer).rewind(); 342 | // return integer 343 | return buffer.getLong(); 344 | } 345 | 346 | /** 347 | * This method is used to get an integer with the specified size 348 | * 349 | * Be careful with java integer bit sign. This method doesn't handle signed values.
350 | * For that, @see BitUtils.getNextIntegerSigned() 351 | * 352 | * @param pLength 353 | * the length of the data to read in bit 354 | * @return an integer 355 | */ 356 | public int getNextInteger(final int pLength) { 357 | return (int) (getNextLong(pLength)); 358 | } 359 | 360 | /** 361 | * This method is used to get the next String with the specified size with 362 | * the charset ASCII 363 | * 364 | * @param pSize 365 | * the length of the string in bit 366 | * @return the string 367 | */ 368 | public String getNextString(final int pSize) { 369 | return getNextString(pSize, DEFAULT_CHARSET); 370 | } 371 | 372 | /** 373 | * This method is used to get the next String with the specified size 374 | * 375 | * @param pSize 376 | * the length of the string int bit 377 | * @param pCharset 378 | * the charset 379 | * @return the string 380 | */ 381 | public String getNextString(final int pSize, final Charset pCharset) { 382 | return new String(getNextByte(pSize, true), pCharset); 383 | } 384 | 385 | /** 386 | * Method used to get the size of the bit array 387 | * 388 | * @return the size in bits of the current bit array 389 | */ 390 | public int getSize() { 391 | return size; 392 | } 393 | 394 | /** 395 | * Reset the current bit index to the initial position 396 | */ 397 | public void reset() { 398 | setCurrentBitIndex(0); 399 | } 400 | 401 | /** 402 | * Method used to clear data and reset current bit index 403 | */ 404 | public void clear() { 405 | Arrays.fill(byteTab, (byte) 0); 406 | reset(); 407 | } 408 | 409 | /** 410 | * Set to 0 the next N bits 411 | * 412 | * @param pLength 413 | * the number of bit to set at 0 414 | */ 415 | public void resetNextBits(final int pLength) { 416 | int max = currentBitIndex + pLength; 417 | while (currentBitIndex < max) { 418 | int mod = currentBitIndex % BYTE_SIZE; 419 | int length = Math.min(max - currentBitIndex, BYTE_SIZE - mod); 420 | byteTab[currentBitIndex / BYTE_SIZE] &= ~getMask(mod, length); 421 | currentBitIndex += length; 422 | } 423 | } 424 | 425 | /** 426 | * Setter currentBitIndex 427 | * 428 | * @param pCurrentBitIndex 429 | * the currentBitIndex to set 430 | */ 431 | public void setCurrentBitIndex(final int pCurrentBitIndex) { 432 | currentBitIndex = pCurrentBitIndex; 433 | } 434 | 435 | /** 436 | * Method to set a boolean 437 | * 438 | * @param pBoolean 439 | * the boolean to set 440 | */ 441 | public void setNextBoolean(final boolean pBoolean) { 442 | if (pBoolean) { 443 | setNextInteger(1, 1); 444 | } else { 445 | setNextInteger(0, 1); 446 | } 447 | } 448 | 449 | /** 450 | * Method to write bytes with the max length 451 | * 452 | * @param pValue 453 | * the value to write 454 | * @param pLength 455 | * the length of the data in bits 456 | */ 457 | public void setNextByte(final byte[] pValue, final int pLength) { 458 | setNextByte(pValue, pLength, true); 459 | } 460 | 461 | /** 462 | * Method to write bytes with the max length 463 | * 464 | * @param pValue 465 | * the value to write 466 | * @param pLength 467 | * the length of the data in bits 468 | * @param pPadBefore 469 | * if true pad with 0 470 | */ 471 | public void setNextByte(final byte[] pValue, final int pLength, final boolean pPadBefore) { 472 | int totalSize = (int) Math.ceil(pLength / BYTE_SIZE_F); 473 | ByteBuffer buffer = ByteBuffer.allocate(totalSize); 474 | int size = Math.max(totalSize - pValue.length, 0); 475 | if (pPadBefore) { 476 | for (int i = 0; i < size; i++) { 477 | buffer.put((byte) 0); 478 | } 479 | } 480 | buffer.put(pValue, 0, Math.min(totalSize, pValue.length)); 481 | if (!pPadBefore) { 482 | for (int i = 0; i < size; i++) { 483 | buffer.put((byte) 0); 484 | } 485 | } 486 | byte[] tab = buffer.array(); 487 | if (currentBitIndex % BYTE_SIZE != 0) { 488 | int index = 0; 489 | int max = currentBitIndex + pLength; 490 | while (currentBitIndex < max) { 491 | int mod = currentBitIndex % BYTE_SIZE; 492 | int modTab = index % BYTE_SIZE; 493 | int length = Math.min(max - currentBitIndex, Math.min(BYTE_SIZE - mod, BYTE_SIZE - modTab)); 494 | byte val = (byte) (tab[index / BYTE_SIZE] & getMask(modTab, length)); 495 | if (mod == 0) { 496 | val = (byte) (val << Math.min(modTab, BYTE_SIZE - length)); 497 | } else { 498 | val = (byte) ((val & DEFAULT_VALUE) >> mod); 499 | } 500 | byteTab[currentBitIndex / BYTE_SIZE] |= val; 501 | currentBitIndex += length; 502 | index += length; 503 | } 504 | 505 | } else { 506 | System.arraycopy(tab, 0, byteTab, currentBitIndex / BYTE_SIZE, tab.length); 507 | currentBitIndex += pLength; 508 | } 509 | } 510 | 511 | /** 512 | * Method to write a date 513 | * 514 | * @param pValue 515 | * the value to write 516 | * @param pPattern 517 | * the Date pattern 518 | */ 519 | public void setNextDate(final Date pValue, final String pPattern) { 520 | setNextDate(pValue, pPattern, false); 521 | } 522 | 523 | /** 524 | * Method to write a date 525 | * 526 | * @param pValue 527 | * the value to write 528 | * @param pPattern 529 | * the Date pattern 530 | * @param pUseBcd 531 | * write date as BCD (binary coded decimal) 532 | */ 533 | public void setNextDate(final Date pValue, final String pPattern, final boolean pUseBcd) { 534 | // create date formatter 535 | SimpleDateFormat sdf = new SimpleDateFormat(pPattern); 536 | String value = sdf.format(pValue); 537 | 538 | if (pUseBcd) { 539 | setNextHexaString(value, value.length() * 4); 540 | } else { 541 | setNextString(value, value.length() * 8); 542 | } 543 | } 544 | 545 | /** 546 | * Method to write Hexa String with the max length 547 | * 548 | * @param pValue 549 | * the value to write 550 | * @param pLength 551 | * the length of the data in bits 552 | */ 553 | public void setNextHexaString(final String pValue, final int pLength) { 554 | setNextByte(BytesUtils.fromString(pValue), pLength); 555 | } 556 | 557 | /** 558 | * Add Long to the current position with the specified size 559 | * 560 | * Be careful with java long bit sign 561 | * 562 | * @param pValue 563 | * the value to set 564 | * 565 | * @param pLength 566 | * the length of the long 567 | */ 568 | public void setNextLong(final long pValue, final int pLength) { 569 | 570 | if (pLength > Long.SIZE) { 571 | throw new IllegalArgumentException("Long overflow with length > 64"); 572 | } 573 | 574 | setNextValue(pValue, pLength, Long.SIZE - 1); 575 | } 576 | 577 | /** 578 | * Add Value to the current position with the specified size 579 | * 580 | * @param pValue 581 | * value to add 582 | * @param pLength 583 | * length of the value 584 | * @param pMaxSize 585 | * max size in bits 586 | */ 587 | private void setNextValue(final long pValue, final int pLength, final int pMaxSize) { 588 | long value = pValue; 589 | // Set to max value if pValue cannot be stored on pLength bits. 590 | long bitMax = (long) Math.pow(2, Math.min(pLength, pMaxSize)); 591 | if (pValue > bitMax) { 592 | value = bitMax - 1; 593 | } 594 | // size to wrote 595 | int writeSize = pLength; 596 | while (writeSize > 0) { 597 | // modulo 598 | int mod = currentBitIndex % BYTE_SIZE; 599 | byte ret = 0; 600 | if (mod == 0 && writeSize <= BYTE_SIZE || pLength < BYTE_SIZE - mod) { 601 | // shift left value 602 | ret = (byte) (value << BYTE_SIZE - (writeSize + mod)); 603 | } else { 604 | // shift right 605 | long length = Long.toBinaryString(value).length(); 606 | ret = (byte) (value >> writeSize - length - (BYTE_SIZE - length - mod)); 607 | } 608 | byteTab[currentBitIndex / BYTE_SIZE] |= ret; 609 | long val = Math.min(writeSize, BYTE_SIZE - mod); 610 | writeSize -= val; 611 | currentBitIndex += val; 612 | } 613 | } 614 | 615 | /** 616 | * Add Integer to the current position with the specified size 617 | * 618 | * Be careful with java integer bit sign 619 | * 620 | * @param pValue 621 | * the value to set 622 | * 623 | * @param pLength 624 | * the length of the integer 625 | */ 626 | public void setNextInteger(final int pValue, final int pLength) { 627 | 628 | if (pLength > Integer.SIZE) { 629 | throw new IllegalArgumentException("Integer overflow with length > 32"); 630 | } 631 | 632 | setNextValue(pValue, pLength, Integer.SIZE - 1); 633 | } 634 | 635 | /** 636 | * Method to write String 637 | * 638 | * @param pValue 639 | * the string to write 640 | * 641 | * @param pLength 642 | * the length of the integer 643 | */ 644 | public void setNextString(final String pValue, final int pLength) { 645 | setNextString(pValue, pLength, true); 646 | } 647 | 648 | /** 649 | * Method to write a String 650 | * 651 | * @param pValue 652 | * the string to write 653 | * @param pLength 654 | * the string length 655 | * @param pPaddedBefore 656 | * indicate if the string is padded before or after 657 | */ 658 | public void setNextString(final String pValue, final int pLength, final boolean pPaddedBefore) { 659 | setNextByte(pValue.getBytes(Charset.defaultCharset()), pLength, pPaddedBefore); 660 | } 661 | } 662 | -------------------------------------------------------------------------------- /src/main/java/fr/devnied/bitlib/BytesUtils.java: -------------------------------------------------------------------------------- 1 | package fr.devnied.bitlib; 2 | 3 | import java.math.BigInteger; 4 | 5 | /** 6 | * Class used to manage String/byte/int converter 7 | * 8 | * @author Millau Julien 9 | * 10 | */ 11 | public final class BytesUtils { 12 | 13 | /** 14 | * Integer bit size 15 | */ 16 | private static final int MAX_BIT_INTEGER = 31; 17 | 18 | /** 19 | * Constant for Hexa 20 | */ 21 | private static final int HEXA = 16; 22 | 23 | /** 24 | * Byte left mask 25 | */ 26 | private static final int LEFT_MASK = 0xF0; 27 | 28 | /** 29 | * Byte right mask 30 | */ 31 | private static final int RIGHT_MASK = 0xF; 32 | 33 | /** 34 | * Char digit 0 (0x30) :
35 | * 41 | */ 42 | private static final int CHAR_DIGIT_ZERO = 0x30; 43 | 44 | /** 45 | * Char digit 7 (0x37) :
46 | * 52 | */ 53 | private static final int CHAR_DIGIT_SEVEN = 0x37; 54 | 55 | /** 56 | * Char space 57 | */ 58 | private static final char CHAR_SPACE = (char) 0x20; 59 | 60 | /** 61 | * Method used to convert byte array to int 62 | * 63 | * @param byteArray 64 | * byte array to convert 65 | * @return int value 66 | */ 67 | public static int byteArrayToInt(final byte[] byteArray) { 68 | if (byteArray == null) { 69 | throw new IllegalArgumentException("Parameter 'byteArray' cannot be null"); 70 | } 71 | return byteArrayToInt(byteArray, 0, byteArray.length); 72 | } 73 | 74 | /** 75 | * Method used to convert byte array to int 76 | * 77 | * @param byteArray 78 | * byte array to convert 79 | * @param startPos 80 | * start position in array in the 81 | * @param length 82 | * length of data 83 | * @return int value of byte array 84 | */ 85 | public static int byteArrayToInt(final byte[] byteArray, final int startPos, final int length) { 86 | if (byteArray == null) { 87 | throw new IllegalArgumentException("Parameter 'byteArray' cannot be null"); 88 | } 89 | if (length <= 0 || length > 4) { 90 | throw new IllegalArgumentException("Length must be between 1 and 4. Length = " + length); 91 | } 92 | if (startPos < 0 || byteArray.length < startPos + length) { 93 | throw new IllegalArgumentException("Length or startPos not valid"); 94 | } 95 | int value = 0; 96 | for (int i = 0; i < length; i++) { 97 | value += (byteArray[startPos + i] & 0xFF) << 8 * (length - i - 1); 98 | } 99 | return value; 100 | } 101 | 102 | /** 103 | * Method to convert bytes to string with space between bytes 104 | * 105 | * @param pBytes 106 | * Bytes to convert 107 | * 108 | * @return a string 109 | */ 110 | public static String bytesToString(final byte[] pBytes) { 111 | return formatByte(pBytes, true, false); 112 | } 113 | 114 | /** 115 | * Method to convert bytes to string with space between bytes 116 | * 117 | * bytes to convert 118 | * 119 | * @param pBytes 120 | * Bytes to convert 121 | * @param pTruncate 122 | * true to remove 0 left byte value 123 | * @return a string 124 | */ 125 | public static String bytesToString(final byte[] pBytes, final boolean pTruncate) { 126 | return formatByte(pBytes, true, pTruncate); 127 | } 128 | 129 | /** 130 | * Method to convert byte to string without space between byte 131 | * 132 | * @param pByte 133 | * byte to convert 134 | * @return a string 135 | */ 136 | public static String bytesToStringNoSpace(final byte pByte) { 137 | return formatByte(new byte[] { pByte }, false, false); 138 | } 139 | 140 | /** 141 | * Method to convert bytes to string without space between bytes 142 | * 143 | * @param pBytes 144 | * bytes to convert 145 | * @return a string 146 | */ 147 | public static String bytesToStringNoSpace(final byte[] pBytes) { 148 | return formatByte(pBytes, false, false); 149 | } 150 | 151 | /** 152 | * Method to convert bytes to string without space between bytes 153 | * 154 | * @param pBytes 155 | * bytes to convert 156 | * @param pTruncate 157 | * true to remove 0 left byte value 158 | * @return a string 159 | */ 160 | public static String bytesToStringNoSpace(final byte[] pBytes, final boolean pTruncate) { 161 | return formatByte(pBytes, false, pTruncate); 162 | } 163 | 164 | /** 165 | * Private method to format bytes to hexa string 166 | * 167 | * @param pByte 168 | * the bytes to format 169 | * @param pSpace 170 | * true if add spaces between bytes 171 | * @param pTruncate 172 | * true to remove 0 left bytes value 173 | * @return a string containing the requested string 174 | */ 175 | private static String formatByte(final byte[] pByte, final boolean pSpace, final boolean pTruncate) { 176 | String result; 177 | if (pByte == null) { 178 | result = ""; 179 | } else { 180 | int i = 0; 181 | if (pTruncate) { 182 | while (i < pByte.length && pByte[i] == 0) { 183 | i++; 184 | } 185 | } 186 | if (i < pByte.length) { 187 | int sizeMultiplier = pSpace ? 3 : 2; 188 | char[] c = new char[(pByte.length - i) * sizeMultiplier]; 189 | byte b; 190 | for (int j = 0; i < pByte.length; i++, j++) { 191 | b = (byte) ((pByte[i] & LEFT_MASK) >> 4); 192 | c[j] = (char) (b > 9 ? b + CHAR_DIGIT_SEVEN : b + CHAR_DIGIT_ZERO); 193 | b = (byte) (pByte[i] & RIGHT_MASK); 194 | c[++j] = (char) (b > 9 ? b + CHAR_DIGIT_SEVEN : b + CHAR_DIGIT_ZERO); 195 | if (pSpace) { 196 | c[++j] = CHAR_SPACE; 197 | } 198 | } 199 | result = pSpace ? new String(c, 0, c.length - 1) : new String(c); 200 | } else { 201 | result = ""; 202 | } 203 | } 204 | return result; 205 | } 206 | 207 | /** 208 | * Method to get bytes form string 209 | * 210 | * @param pData 211 | * String to parse 212 | * @return a table of string 213 | */ 214 | public static byte[] fromString(final String pData) { 215 | if (pData == null) { 216 | throw new IllegalArgumentException("Argument can't be null"); 217 | } 218 | StringBuilder sb = new StringBuilder(pData); 219 | int j = 0; 220 | for (int i = 0; i < sb.length(); i++) { 221 | if (!Character.isWhitespace(sb.charAt(i))) { 222 | sb.setCharAt(j++, sb.charAt(i)); 223 | } 224 | } 225 | sb.delete(j, sb.length()); 226 | if (sb.length() % 2 != 0) { 227 | throw new IllegalArgumentException("Hex binary needs to be even-length :" + pData); 228 | } 229 | byte[] result = new byte[sb.length() / 2]; 230 | j = 0; 231 | for (int i = 0; i < sb.length(); i += 2) { 232 | result[j++] = (byte) ((Character.digit(sb.charAt(i), 16) << 4) + Character.digit(sb.charAt(i + 1), 16)); 233 | } 234 | return result; 235 | } 236 | 237 | /** 238 | * Test if bit at given index of given value is = 1. 239 | * 240 | * @param pVal 241 | * value to test 242 | * @param pBitIndex 243 | * bit index between 0 and 31 244 | * @return true bit at given index of give value is = 1 245 | */ 246 | public static boolean matchBitByBitIndex(final int pVal, final int pBitIndex) { 247 | if (pBitIndex < 0 || pBitIndex > MAX_BIT_INTEGER) { 248 | throw new IllegalArgumentException( 249 | "parameter 'pBitIndex' must be between 0 and 31. pBitIndex=" + pBitIndex); 250 | } 251 | return (pVal & 1 << pBitIndex) != 0; 252 | } 253 | 254 | /** 255 | * Method used to set a bit index to 1 or 0. 256 | * 257 | * @param pData 258 | * data to modify 259 | * @param pBitIndex 260 | * index to set 261 | * @param pOn 262 | * set bit at specified index to 1 or 0 263 | * @return the modified byte 264 | */ 265 | public static byte setBit(final byte pData, final int pBitIndex, final boolean pOn) { 266 | if (pBitIndex < 0 || pBitIndex > 7) { 267 | throw new IllegalArgumentException("parameter 'pBitIndex' must be between 0 and 7. pBitIndex=" + pBitIndex); 268 | } 269 | byte ret = pData; 270 | if (pOn) { // Set bit 271 | ret |= 1 << pBitIndex; 272 | } else { // Unset bit 273 | ret &= ~(1 << pBitIndex); 274 | } 275 | return ret; 276 | } 277 | 278 | /** 279 | * Convert byte array to binary String 280 | * 281 | * @param pBytes 282 | * byte array to convert 283 | * @return a binary representation of the byte array 284 | */ 285 | public static String toBinary(final byte[] pBytes) { 286 | String ret = null; 287 | if (pBytes != null && pBytes.length > 0) { 288 | BigInteger val = new BigInteger(bytesToStringNoSpace(pBytes), HEXA); 289 | StringBuilder build = new StringBuilder(val.toString(2)); 290 | // left pad with 0 to fit byte size 291 | for (int i = build.length(); i < pBytes.length * BitUtils.BYTE_SIZE; i++) { 292 | build.insert(0, 0); 293 | } 294 | ret = build.toString(); 295 | } 296 | return ret; 297 | } 298 | 299 | /** 300 | * Method used to convert integer to byet array 301 | * 302 | * @param value 303 | * the value to convert 304 | * @return a byte array 305 | */ 306 | public static byte[] toByteArray(final int value) { 307 | return new byte[] { // 308 | (byte) (value >> 24), // 309 | (byte) (value >> 16), // 310 | (byte) (value >> 8), // 311 | (byte) value // 312 | }; 313 | } 314 | 315 | /** 316 | * private constructor 317 | */ 318 | private BytesUtils() { 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /src/test/java/fr/devnied/bitlib/BitUtilsTest.java: -------------------------------------------------------------------------------- 1 | package fr.devnied.bitlib; 2 | 3 | import org.fest.assertions.Assertions; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | import java.text.ParseException; 8 | import java.text.SimpleDateFormat; 9 | import java.util.Date; 10 | 11 | /** 12 | * Class to test the bitutils class 13 | * 14 | * @author Millau Julien 15 | * 16 | */ 17 | public final class BitUtilsTest { 18 | 19 | /** 20 | * Test byte value 21 | */ 22 | private final byte[] test = new byte[] { (byte) 0x11, (byte) 0x00, (byte) 0x00, (byte) 0x67, (byte) 0xEF }; 23 | 24 | /** 25 | * @throws ParseException 26 | */ 27 | @Test 28 | public void testBitIndex() throws ParseException { 29 | 30 | BitUtils bit = new BitUtils(test); 31 | 32 | Assertions.assertThat(bit.getCurrentBitIndex()).isEqualTo(0); 33 | Assertions.assertThat(bit.getNextInteger(4)).isEqualTo(1); 34 | Assertions.assertThat(bit.getCurrentBitIndex()).isEqualTo(4); 35 | bit.setCurrentBitIndex(5); 36 | bit.addCurrentBitIndex(-1); 37 | bit.addCurrentBitIndex(1); 38 | Assertions.assertThat(bit.getCurrentBitIndex()).isEqualTo(5); 39 | Assertions.assertThat(bit.getNextInteger(3)).isEqualTo(1); 40 | bit.addCurrentBitIndex(-1000); 41 | Assertions.assertThat(bit.getCurrentBitIndex()).isEqualTo(0); 42 | 43 | BitUtils bit2 = new BitUtils(new byte[] { (byte) 0xFE }); 44 | bit2.addCurrentBitIndex(7); 45 | Assertions.assertThat(bit2.getNextBoolean()).isEqualTo(false); 46 | 47 | } 48 | 49 | /** 50 | * Test the method getData 51 | */ 52 | @Test 53 | public void testGetData() { 54 | 55 | BitUtils bit = new BitUtils(test); 56 | Assertions.assertThat(bit.getData()).isEqualTo(test); 57 | } 58 | 59 | /** 60 | * Test the method get Hexa String 61 | */ 62 | @Test 63 | public void testGetHexaString() { 64 | 65 | BitUtils bit = new BitUtils(test); 66 | 67 | Assertions.assertThat(bit.getNextHexaString(8)).isEqualTo("11"); 68 | Assertions.assertThat(bit.getNextHexaString(16)).isEqualTo("0000"); 69 | Assertions.assertThat(bit.getNextHexaString(8)).isEqualTo("67"); 70 | Assertions.assertThat(bit.getNextHexaString(8)).isEqualTo("EF"); 71 | } 72 | 73 | @Test 74 | public void testGetNextByte() { 75 | BitUtils bit = new BitUtils(test); 76 | Assertions.assertThat(bit.getNextByte(4, false)).isEqualTo(new byte[] { 0x10 }); 77 | Assertions.assertThat(bit.getNextByte(4, false)).isEqualTo(new byte[] { 0x01 }); 78 | Assertions.assertThat(bit.getNextByte(16, false)).isEqualTo(new byte[] { 0x00, 0x00 }); 79 | Assertions.assertThat(bit.getNextByte(2, false)).isEqualTo(new byte[] { 0x40 }); 80 | Assertions.assertThat(bit.getNextByte(2, false)).isEqualTo(new byte[] { 0x20 }); 81 | bit.reset(); 82 | Assertions.assertThat(bit.getNextByte(2, false)).isEqualTo(new byte[] { 0x00 }); 83 | Assertions.assertThat(bit.getNextByte(8, false)).isEqualTo(new byte[] { 0x44 }); 84 | bit.reset(); 85 | Assertions.assertThat(bit.getNextByte(4)).isEqualTo(new byte[] { 0x10 }); 86 | Assertions.assertThat(bit.getNextByte(4)).isEqualTo(new byte[] { 0x10 }); 87 | 88 | bit = new BitUtils(new byte[] { 0x44, (byte) 0xFE }); 89 | Assertions.assertThat(bit.getNextByte(4, false)).isEqualTo(new byte[] { 0x40 }); 90 | Assertions.assertThat(bit.getNextByte(8, false)).isEqualTo(new byte[] { (byte) 0x4F }); 91 | Assertions.assertThat(bit.getNextByte(4, false)).isEqualTo(new byte[] { (byte) 0x0E }); 92 | bit.reset(); 93 | Assertions.assertThat(bit.getNextByte(4, true)).isEqualTo(new byte[] { 0x40 }); 94 | Assertions.assertThat(bit.getNextByte(8, true)).isEqualTo(new byte[] { (byte) 0x4F }); 95 | Assertions.assertThat(bit.getNextByte(4, true)).isEqualTo(new byte[] { (byte) 0xE0 }); 96 | } 97 | 98 | /** 99 | * @throws ParseException 100 | */ 101 | @Test 102 | public void testGetNextDate() throws ParseException { 103 | 104 | String val = "20130108"; 105 | BitUtils bit = new BitUtils(val.getBytes()); 106 | SimpleDateFormat sdf = new SimpleDateFormat(BitUtils.DATE_FORMAT); 107 | Date d = sdf.parse(val); 108 | 109 | Assertions.assertThat(bit.getNextDate(8 * 8, BitUtils.DATE_FORMAT)).isEqualTo(d); 110 | bit.reset(); 111 | 112 | String valYear = "2013"; 113 | SimpleDateFormat sdfyear = new SimpleDateFormat("yyyy"); 114 | Date year = sdfyear.parse(valYear); 115 | 116 | Assertions.assertThat(bit.getNextDate(4 * 8, "yyyy")).isEqualTo(year); 117 | bit.reset(); 118 | 119 | Assertions.assertThat(bit.getNextDate(4 * 8, BitUtils.DATE_FORMAT)).isEqualTo(null); 120 | 121 | bit = new BitUtils(BytesUtils.fromString(val)); 122 | Assertions.assertThat(bit.getNextDate(8 * 4, BitUtils.DATE_FORMAT, true)).isEqualTo(d); 123 | 124 | } 125 | 126 | /** 127 | * Method to test the GetNextint method 128 | */ 129 | @Test 130 | public void testGetNextInt() { 131 | 132 | BitUtils bit = new BitUtils(test); 133 | 134 | Assertions.assertThat(bit.getNextInteger(4)).isEqualTo(1); 135 | Assertions.assertThat(bit.getNextInteger(20)).isEqualTo(65536); 136 | Assertions.assertThat(bit.getNextInteger(1)).isEqualTo(0); 137 | Assertions.assertThat(bit.getNextInteger(4)).isEqualTo(12); 138 | Assertions.assertThat(bit.getNextInteger(1)).isEqualTo(1); 139 | Assertions.assertThat(bit.getNextInteger(4)).isEqualTo(15); 140 | Assertions.assertThat(bit.getNextInteger(1)).isEqualTo(1); 141 | Assertions.assertThat(bit.getNextInteger(5)).isEqualTo(15); 142 | 143 | BitUtils bit2 = new BitUtils(new byte[] { (byte) 0x04, (byte) 0x21, 0x60 }); 144 | Assertions.assertThat(bit2.getNextInteger(2)).isEqualTo(0); 145 | Assertions.assertThat(bit2.getNextInteger(14)).isEqualTo(1057); 146 | Assertions.assertThat(bit2.getNextInteger(1)).isEqualTo(0); 147 | Assertions.assertThat(bit2.getNextInteger(1)).isEqualTo(1); 148 | Assertions.assertThat(bit2.getNextInteger(1)).isEqualTo(1); 149 | Assertions.assertThat(bit2.getNextInteger(1)).isEqualTo(0); 150 | } 151 | 152 | /** 153 | * Test the 154 | */ 155 | @Test 156 | public void testGetNextString() { 157 | 158 | String val = "TEST VaLeUr e'*/"; 159 | BitUtils bit = new BitUtils(val.getBytes()); 160 | Assertions.assertThat(bit.getNextString(val.length() * 8)).isEqualTo(val); 161 | 162 | BitUtils bit2 = new BitUtils(val.getBytes()); 163 | Assertions.assertThat(bit2.getNextString(2 * 8)).isEqualTo("TE"); 164 | Assertions.assertThat(bit2.getNextString(2 * 8)).isEqualTo("ST"); 165 | Assertions.assertThat(bit2.getNextString(4 * 8)).isEqualTo(" VaL"); 166 | Assertions.assertThat(bit2.getNextString(8 * 8)).isEqualTo("eUr e'*/"); 167 | } 168 | 169 | /** 170 | * Test the method get/set boolean 171 | */ 172 | @Test 173 | public void testGetSetBoolean() { 174 | 175 | BitUtils bit = new BitUtils(8); 176 | bit.setNextBoolean(false); 177 | bit.setNextBoolean(true); 178 | bit.setNextBoolean(false); 179 | bit.setNextBoolean(false); 180 | bit.reset(); 181 | 182 | Assertions.assertThat(bit.getData()).isEqualTo(new byte[] { (byte) 0x40 }); 183 | Assertions.assertThat(bit.getNextBoolean()).isEqualTo(false); 184 | Assertions.assertThat(bit.getNextBoolean()).isEqualTo(true); 185 | Assertions.assertThat(bit.getNextBoolean()).isEqualTo(false); 186 | Assertions.assertThat(bit.getNextBoolean()).isEqualTo(false); 187 | } 188 | 189 | /** 190 | * Test the mask function 191 | */ 192 | @Test 193 | public void testMask() { 194 | 195 | BitUtils bit = new BitUtils(test); 196 | 197 | Assertions.assertThat(bit.getMask(0, 1)).isEqualTo((byte) 0x80); 198 | Assertions.assertThat(bit.getMask(2, 2)).isEqualTo((byte) 0x30); 199 | Assertions.assertThat(bit.getMask(0, 2)).isEqualTo((byte) 0xC0); 200 | Assertions.assertThat(bit.getMask(3, 4)).isEqualTo((byte) 0x1E); 201 | Assertions.assertThat(bit.getMask(7, 1)).isEqualTo((byte) 0x01); 202 | Assertions.assertThat(bit.getMask(0, 8)).isEqualTo((byte) 0xFF); 203 | Assertions.assertThat(bit.getMask(2, 2)).isEqualTo((byte) 0x30); 204 | Assertions.assertThat(bit.getMask(1, 6)).isEqualTo((byte) 0x7E); 205 | } 206 | 207 | /** 208 | * Unit test for resetNextBits 209 | */ 210 | @Test 211 | public void testResetNextBits() { 212 | BitUtils bit = new BitUtils(10); 213 | bit.setNextInteger(1000, 8); 214 | bit.reset(); 215 | Assertions.assertThat(bit.getNextHexaString(8)).isEqualTo("FF"); 216 | bit.reset(); 217 | bit.resetNextBits(4); 218 | bit.reset(); 219 | Assertions.assertThat(bit.getNextHexaString(8)).isEqualTo("0F"); 220 | bit = new BitUtils(new byte[] { (byte) 0xFF, (byte) 0xFF }); 221 | bit.resetNextBits(12); 222 | bit.reset(); 223 | Assertions.assertThat(bit.getNextHexaString(16)).isEqualTo("000F"); 224 | bit = new BitUtils(new byte[] { (byte) 0xFF, (byte) 0xFF }); 225 | bit.addCurrentBitIndex(2); 226 | bit.resetNextBits(11); 227 | bit.reset(); 228 | Assertions.assertThat(bit.getNextHexaString(16)).isEqualTo("C007"); 229 | } 230 | 231 | /** 232 | * Test the method to set an integer 233 | */ 234 | @Test 235 | public void testSetInteger() { 236 | 237 | BitUtils bit3 = new BitUtils(128); 238 | bit3.setNextInteger(10, 6); 239 | bit3.setNextInteger(23, 12); 240 | bit3.setNextInteger(5, 8); 241 | bit3.setNextInteger(930, 16); 242 | bit3.setNextInteger(5, 3); 243 | bit3.setNextInteger(159, 8); 244 | bit3.setNextInteger(7, 3); 245 | bit3.reset(); 246 | 247 | Assertions.assertThat(bit3.getNextInteger(6)).isEqualTo(10); 248 | Assertions.assertThat(bit3.getNextInteger(12)).isEqualTo(23); 249 | Assertions.assertThat(bit3.getNextInteger(8)).isEqualTo(5); 250 | Assertions.assertThat(bit3.getNextInteger(16)).isEqualTo(930); 251 | Assertions.assertThat(bit3.getNextInteger(3)).isEqualTo(5); 252 | Assertions.assertThat(bit3.getNextInteger(8)).isEqualTo(159); 253 | Assertions.assertThat(bit3.getNextInteger(3)).isEqualTo(7); 254 | 255 | BitUtils bit2 = new BitUtils(128); 256 | bit2.setNextInteger(3, 2); 257 | bit2.setNextInteger(1057, 14); 258 | bit2.setNextInteger(1, 1); 259 | bit2.setNextInteger(1532, 15); 260 | bit2.setNextInteger(8, 8); 261 | bit2.setNextInteger(1532, 15); 262 | 263 | bit2.reset(); 264 | 265 | Assertions.assertThat(bit2.getNextInteger(2)).isEqualTo(3); 266 | Assertions.assertThat(bit2.getNextInteger(14)).isEqualTo(1057); 267 | Assertions.assertThat(bit2.getNextInteger(1)).isEqualTo(1); 268 | Assertions.assertThat(bit2.getNextInteger(15)).isEqualTo(1532); 269 | Assertions.assertThat(bit2.getNextInteger(8)).isEqualTo(8); 270 | Assertions.assertThat(bit2.getNextInteger(15)).isEqualTo(1532); 271 | 272 | BitUtils bit = new BitUtils(64); 273 | bit.setNextInteger(3, 2); 274 | bit.setNextInteger(255, 8); 275 | bit.setNextInteger(0, 2); 276 | bit.setNextInteger(15, 4); 277 | bit.setNextInteger(2, 2); 278 | bit.setNextInteger(3, 3); 279 | bit.setNextInteger(1, 1); 280 | bit.setNextInteger(0, 1); 281 | bit.setNextInteger(1, 1); 282 | bit.reset(); 283 | 284 | Assertions.assertThat(bit.getNextInteger(2)).isEqualTo(3); 285 | Assertions.assertThat(bit.getNextInteger(8)).isEqualTo(255); 286 | Assertions.assertThat(bit.getNextInteger(2)).isEqualTo(0); 287 | Assertions.assertThat(bit.getNextInteger(4)).isEqualTo(15); 288 | Assertions.assertThat(bit.getNextInteger(2)).isEqualTo(2); 289 | Assertions.assertThat(bit.getNextInteger(3)).isEqualTo(3); 290 | Assertions.assertThat(bit.getNextInteger(1)).isEqualTo(1); 291 | Assertions.assertThat(bit.getNextInteger(1)).isEqualTo(0); 292 | Assertions.assertThat(bit.getNextInteger(1)).isEqualTo(1); 293 | 294 | bit.clear(); 295 | try { 296 | bit.setNextInteger(500, 33); 297 | Assert.fail(); 298 | } catch (IllegalArgumentException iae) { 299 | } 300 | bit.clear(); 301 | bit.setNextInteger(127, 5); 302 | bit.reset(); 303 | Assertions.assertThat(bit.getNextInteger(5)).isEqualTo(31); 304 | } 305 | 306 | @Test 307 | public void testOverflowValueInSize() { 308 | BitUtils bit = new BitUtils(64); 309 | bit.setNextInteger(Integer.MAX_VALUE, 3); 310 | bit.reset(); 311 | Assertions.assertThat(bit.getNextInteger(3)).isEqualTo(7); 312 | 313 | bit.clear(); 314 | bit.setNextLong(Long.MAX_VALUE, 40); 315 | bit.reset(); 316 | Assertions.assertThat(bit.getNextLong(40)).isEqualTo(1099511627775L); 317 | } 318 | 319 | @Test 320 | public void testMaxMinValueInteger() { 321 | BitUtils bit = new BitUtils(64); 322 | bit.setNextInteger(Integer.MIN_VALUE, 32); 323 | bit.reset(); 324 | Assertions.assertThat(bit.getNextHexaString(32)).isEqualTo("80000000"); 325 | bit.reset(); 326 | Assertions.assertThat(bit.getNextInteger(32)).isEqualTo(Integer.MIN_VALUE); 327 | 328 | bit.clear(); 329 | bit.setNextInteger(Integer.MAX_VALUE, 32); 330 | bit.reset(); 331 | Assertions.assertThat(bit.getNextHexaString(32)).isEqualTo("7FFFFFFF"); 332 | bit.reset(); 333 | Assertions.assertThat(bit.getNextInteger(32)).isEqualTo(Integer.MAX_VALUE); 334 | } 335 | 336 | /** 337 | * Test the method to set an long 338 | */ 339 | @Test 340 | public void testSetLong() { 341 | 342 | BitUtils bit3 = new BitUtils(128); 343 | bit3.setNextLong(10, 6); 344 | bit3.setNextLong(23, 12); 345 | bit3.setNextLong(5, 8); 346 | bit3.setNextLong(930, 16); 347 | bit3.setNextLong(5, 3); 348 | bit3.setNextLong(159, 8); 349 | bit3.setNextLong(7, 3); 350 | bit3.reset(); 351 | 352 | Assertions.assertThat(bit3.getNextLong(6)).isEqualTo(10); 353 | Assertions.assertThat(bit3.getNextLong(12)).isEqualTo(23); 354 | Assertions.assertThat(bit3.getNextLong(8)).isEqualTo(5); 355 | Assertions.assertThat(bit3.getNextLong(16)).isEqualTo(930); 356 | Assertions.assertThat(bit3.getNextLong(3)).isEqualTo(5); 357 | Assertions.assertThat(bit3.getNextLong(8)).isEqualTo(159); 358 | Assertions.assertThat(bit3.getNextLong(3)).isEqualTo(7); 359 | 360 | BitUtils bit2 = new BitUtils(128); 361 | bit2.setNextLong(3, 2); 362 | bit2.setNextLong(1057, 14); 363 | bit2.setNextLong(1, 1); 364 | bit2.setNextLong(1532, 15); 365 | bit2.setNextLong(8, 8); 366 | bit2.setNextLong(1532, 15); 367 | 368 | bit2.reset(); 369 | 370 | Assertions.assertThat(bit2.getNextLong(2)).isEqualTo(3); 371 | Assertions.assertThat(bit2.getNextLong(14)).isEqualTo(1057); 372 | Assertions.assertThat(bit2.getNextLong(1)).isEqualTo(1); 373 | Assertions.assertThat(bit2.getNextLong(15)).isEqualTo(1532); 374 | Assertions.assertThat(bit2.getNextLong(8)).isEqualTo(8); 375 | Assertions.assertThat(bit2.getNextLong(15)).isEqualTo(1532); 376 | 377 | BitUtils bit = new BitUtils(64); 378 | bit.setNextLong(3, 2); 379 | bit.setNextLong(255, 8); 380 | bit.setNextLong(0, 2); 381 | bit.setNextLong(15, 4); 382 | bit.setNextLong(2, 2); 383 | bit.setNextLong(3, 3); 384 | bit.setNextLong(1, 1); 385 | bit.setNextLong(0, 1); 386 | bit.setNextLong(1, 1); 387 | bit.reset(); 388 | 389 | Assertions.assertThat(bit.getNextLong(2)).isEqualTo(3); 390 | Assertions.assertThat(bit.getNextLong(8)).isEqualTo(255); 391 | Assertions.assertThat(bit.getNextLong(2)).isEqualTo(0); 392 | Assertions.assertThat(bit.getNextLong(4)).isEqualTo(15); 393 | Assertions.assertThat(bit.getNextLong(2)).isEqualTo(2); 394 | Assertions.assertThat(bit.getNextLong(3)).isEqualTo(3); 395 | Assertions.assertThat(bit.getNextLong(1)).isEqualTo(1); 396 | Assertions.assertThat(bit.getNextLong(1)).isEqualTo(0); 397 | Assertions.assertThat(bit.getNextLong(1)).isEqualTo(1); 398 | 399 | bit.reset(); 400 | try { 401 | bit.setNextLong(500, 65); 402 | Assert.fail(); 403 | } catch (IllegalArgumentException iae) { 404 | } 405 | } 406 | 407 | @Test 408 | public void testMaxMinValueLong() { 409 | BitUtils bit = new BitUtils(64); 410 | bit.setNextLong(Long.MIN_VALUE, 64); 411 | bit.reset(); 412 | Assertions.assertThat(bit.getNextHexaString(64)).isEqualTo("8000000000000000"); 413 | bit.reset(); 414 | Assertions.assertThat(bit.getNextLong(64)).isEqualTo(Long.MIN_VALUE); 415 | 416 | bit.clear(); 417 | bit.setNextLong(Long.MAX_VALUE, 64); 418 | bit.reset(); 419 | Assertions.assertThat(bit.getNextHexaString(64)).isEqualTo("7FFFFFFFFFFFFFFF"); 420 | bit.reset(); 421 | Assertions.assertThat(bit.getNextLong(64)).isEqualTo(Long.MAX_VALUE); 422 | } 423 | 424 | @Test 425 | public void testLongMaxMinValue(){ 426 | BitUtils bit = new BitUtils(64); 427 | bit.setNextHexaString("FFFFFFFFFFFFFFFF", 64); 428 | bit.reset(); 429 | Assertions.assertThat(bit.getNextInteger(64)).isEqualTo(-1); 430 | } 431 | 432 | /** 433 | * Test the method to set an integer 434 | */ 435 | @Test 436 | public void testSetIntegerOverflow() { 437 | 438 | BitUtils bit = new BitUtils(128); 439 | bit.setNextInteger(10, 2); 440 | bit.setNextInteger(256, 1); 441 | bit.reset(); 442 | Assertions.assertThat(bit.getNextInteger(2)).isEqualTo(3); 443 | Assertions.assertThat(bit.getNextInteger(1)).isEqualTo(1); 444 | } 445 | 446 | /** 447 | * Test the method to set bytes 448 | */ 449 | @Test 450 | public void testSetNextByte() { 451 | 452 | byte[] tab = new byte[] { (byte) 0x12, (byte) 0x20 }; 453 | BitUtils bit = new BitUtils(tab.length * 8 * 2); 454 | bit.setNextByte(tab, tab.length * 8); 455 | bit.setNextByte(tab, tab.length * 8); 456 | bit.reset(); 457 | 458 | Assertions.assertThat(bit.getNextHexaString(tab.length * 8)).isEqualTo("1220"); 459 | Assertions.assertThat(bit.getNextHexaString(tab.length * 8)).isEqualTo("1220"); 460 | 461 | byte[] tab2 = new byte[] { (byte) 0x22, (byte) 0x50 }; 462 | BitUtils bit2 = new BitUtils(16); 463 | bit2.setNextInteger(3, 3); 464 | bit2.setNextByte(tab2, 13); 465 | bit2.reset(); 466 | 467 | Assertions.assertThat(bit2.getNextHexaString(16)).isEqualTo("644A"); 468 | } 469 | 470 | /** 471 | * Test the method to set bytes 472 | */ 473 | @Test 474 | public void testSetNextByte2() { 475 | 476 | byte[] tab = new byte[] { (byte) 0x12 }; 477 | BitUtils bit = new BitUtils(9); 478 | bit.setNextInteger(1, 1); 479 | bit.setNextByte(tab, 8); 480 | bit.reset(); 481 | 482 | Assertions.assertThat(bit.getNextHexaString(9)).isEqualTo("8900"); 483 | bit.reset(); 484 | Assertions.assertThat(bit.getNextHexaString(8)).isEqualTo("89"); 485 | } 486 | 487 | @Test 488 | public void testSetNextDate() throws ParseException { 489 | 490 | String val = "20130108"; 491 | BitUtils bit = new BitUtils(100); 492 | SimpleDateFormat sdf = new SimpleDateFormat(BitUtils.DATE_FORMAT); 493 | Date d = sdf.parse(val); 494 | bit.setNextDate(d, BitUtils.DATE_FORMAT); 495 | bit.reset(); 496 | Assertions.assertThat(sdf.format(bit.getNextDate(8 * 8, BitUtils.DATE_FORMAT))).isEqualTo(val); 497 | bit.reset(); 498 | bit.setNextDate(d, BitUtils.DATE_FORMAT, true); 499 | bit.reset(); 500 | Assertions.assertThat(bit.getNextHexaString(8 * 4)).isEqualTo(val); 501 | } 502 | 503 | /** 504 | * Test the method to set an hexa string 505 | */ 506 | @Test 507 | public void testSetNextHexaString() { 508 | 509 | String text1 = "1122334455"; 510 | BitUtils bit = new BitUtils(text1.length() * 4 + 1); 511 | bit.setNextBoolean(true); 512 | bit.setNextHexaString(text1, text1.length() * 4); 513 | bit.reset(); 514 | Assertions.assertThat(bit.getNextBoolean()).isEqualTo(true); 515 | Assertions.assertThat(bit.getNextHexaString(text1.length() * 4)).isEqualTo(text1); 516 | bit.reset(); 517 | Assertions.assertThat(bit.getNextBoolean()).isEqualTo(true); 518 | Assertions.assertThat(bit.getNextHexaString(text1.length() / 2 * 4)).isEqualTo("112230"); 519 | 520 | bit = new BitUtils(20); 521 | try { 522 | bit.setNextHexaString("AAB", 20); 523 | org.junit.Assert.fail(); 524 | } catch (IllegalArgumentException iae) { 525 | org.junit.Assert.assertTrue(true); 526 | } 527 | 528 | } 529 | 530 | /** 531 | * Test the method to set an integer 532 | */ 533 | @Test 534 | public void testSetPaddedString() { 535 | 536 | String text = "123456789"; 537 | BitUtils bit = new BitUtils(160); 538 | bit.setNextString(text, 10 * 8, true); 539 | bit.setNextString(text, 10 * 8, false); 540 | bit.reset(); 541 | Assertions.assertThat(bit.getNextString(10 * 8)).isEqualTo('\0' + text); 542 | Assertions.assertThat(bit.getNextString(10 * 8)).isEqualTo(text + '\0'); 543 | } 544 | 545 | /** 546 | * Test the method to set an integer 547 | */ 548 | @Test 549 | public void testSetString() { 550 | 551 | String text1 = "test"; 552 | String text2 = " OK"; 553 | BitUtils bit = new BitUtils((text1.length() + text2.length()) * 8 + 5); 554 | bit.setNextInteger(3, 5); 555 | bit.setNextString(text1, text1.length() * 8); 556 | bit.setNextString(text2, 2 * 8); 557 | bit.reset(); 558 | 559 | Assertions.assertThat(bit.getNextInteger(5)).isEqualTo(3); 560 | Assertions.assertThat(bit.getNextString(text1.length() * 8)).isEqualTo(text1); 561 | Assertions.assertThat(bit.getNextString(2 * 8)).isEqualTo(" O"); 562 | bit.reset(); 563 | Assertions.assertThat(bit.getNextInteger(5)).isEqualTo(3); 564 | Assertions.assertThat(bit.getNextString((text1.length() + 2) * 8)).isEqualTo(text1 + " O"); 565 | } 566 | 567 | /** 568 | * Unit test for size 569 | */ 570 | @Test 571 | public void testSize() { 572 | BitUtils bit = new BitUtils(289); 573 | Assertions.assertThat(bit.getSize()).isEqualTo(289); 574 | 575 | bit = new BitUtils(new byte[] { 0x33, 0x12 }); 576 | Assertions.assertThat(bit.getSize()).isEqualTo(2 * 8); 577 | } 578 | 579 | /** 580 | * Unit test for signed value 581 | */ 582 | @Test 583 | public void testSign() { 584 | BitUtils bit = new BitUtils(Long.SIZE); 585 | bit.setNextInteger(-2, 4); 586 | bit.reset(); 587 | Assertions.assertThat(bit.getNextIntegerSigned(4)).isEqualTo(-2); 588 | bit.clear(); 589 | bit.setNextInteger(0, 8); 590 | bit.reset(); 591 | Assertions.assertThat(bit.getNextIntegerSigned(8)).isEqualTo(0); 592 | bit.clear(); 593 | bit.setNextInteger(127, 8); 594 | bit.reset(); 595 | Assertions.assertThat(bit.getNextIntegerSigned(8)).isEqualTo(127); 596 | bit.clear(); 597 | bit.setNextInteger(-128, 8); 598 | bit.reset(); 599 | Assertions.assertThat(bit.getNextIntegerSigned(8)).isEqualTo(-128); 600 | bit.clear(); 601 | bit.setNextInteger(-256, 16); 602 | bit.reset(); 603 | Assertions.assertThat(bit.getNextIntegerSigned(16)).isEqualTo(-256); 604 | bit.clear(); 605 | bit.setNextInteger(Integer.MIN_VALUE, Integer.SIZE); 606 | bit.reset(); 607 | Assertions.assertThat(bit.getNextIntegerSigned(Integer.SIZE)).isEqualTo(Integer.MIN_VALUE); 608 | bit.clear(); 609 | bit.setNextLong(Long.MIN_VALUE, Long.SIZE); 610 | bit.reset(); 611 | Assertions.assertThat(bit.getNextLongSigned(Long.SIZE)).isEqualTo(Long.MIN_VALUE); 612 | } 613 | 614 | /** 615 | * Unit test for signed value 616 | */ 617 | @Test(expected = IllegalArgumentException.class) 618 | public void testOverflowIntegerSign() { 619 | BitUtils bit = new BitUtils(Integer.SIZE); 620 | bit.setNextInteger(-2, 4); 621 | bit.reset(); 622 | Assertions.assertThat(bit.getNextIntegerSigned(33)).isEqualTo(-2); 623 | } 624 | 625 | /** 626 | * Unit test for signed value 627 | */ 628 | @Test(expected = IllegalArgumentException.class) 629 | public void testOverflowLongSign() { 630 | BitUtils bit = new BitUtils(Long.SIZE); 631 | bit.setNextInteger(-2, 4); 632 | bit.reset(); 633 | Assertions.assertThat(bit.getNextLongSigned(65)).isEqualTo(-2); 634 | } 635 | 636 | } 637 | -------------------------------------------------------------------------------- /src/test/java/fr/devnied/bitlib/BytesUtilsTest.java: -------------------------------------------------------------------------------- 1 | package fr.devnied.bitlib; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.lang.reflect.InvocationTargetException; 5 | 6 | import org.fest.assertions.Assertions; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | /** 11 | * Class to test the Utils class bytesUtils 12 | * 13 | * @author Millau Julien 14 | * 15 | */ 16 | public final class BytesUtilsTest { 17 | 18 | /** 19 | * First test byte tab 20 | */ 21 | private final byte[] tab = new byte[] { 0x12, (byte) 0x92, (byte) 0xAB, 0x3A }; 22 | /** 23 | * Second test byte tab 24 | */ 25 | private final byte[] tab2 = new byte[] { 0x00, (byte) 0x01, (byte) 0x02, 0x45 }; 26 | 27 | /** 28 | * 29 | */ 30 | @Test 31 | public void testByteArrayToInt() { 32 | Assertions.assertThat(BytesUtils.byteArrayToInt(BytesUtils.fromString("00000000"))).isEqualTo(0); 33 | Assertions.assertThat(BytesUtils.byteArrayToInt(BytesUtils.fromString("00000001"))).isEqualTo(1); 34 | Assertions.assertThat(BytesUtils.byteArrayToInt(BytesUtils.fromString("7FFFFFFF"))) 35 | .isEqualTo(Integer.MAX_VALUE); 36 | Assertions.assertThat(BytesUtils.byteArrayToInt(BytesUtils.fromString("80000000"))) 37 | .isEqualTo(Integer.MIN_VALUE); 38 | Assertions.assertThat(BytesUtils.byteArrayToInt(BytesUtils.fromString("00000100"))).isEqualTo(256); 39 | // partial int 40 | Assertions.assertThat(BytesUtils.byteArrayToInt(BytesUtils.fromString("0100"))).isEqualTo(256); 41 | Assertions.assertThat(BytesUtils.byteArrayToInt(BytesUtils.fromString("FF"))).isEqualTo(255); 42 | Assertions.assertThat(BytesUtils.byteArrayToInt(BytesUtils.fromString("FFFF"))).isEqualTo(65535); 43 | 44 | Assertions.assertThat(BytesUtils.byteArrayToInt(BytesUtils.fromString("00000100"), 2, 1)).isEqualTo(1); 45 | 46 | try { 47 | BytesUtils.byteArrayToInt(null); 48 | Assert.fail(); 49 | } catch (Exception e) { 50 | Assert.assertTrue(true); 51 | } 52 | 53 | try { 54 | BytesUtils.byteArrayToInt(null, 2, 2); 55 | Assert.fail(); 56 | } catch (Exception e) { 57 | Assert.assertTrue(true); 58 | } 59 | 60 | try { 61 | BytesUtils.byteArrayToInt(tab, 0, 10); 62 | Assert.fail(); 63 | } catch (Exception e) { 64 | Assert.assertTrue(true); 65 | } 66 | 67 | try { 68 | BytesUtils.byteArrayToInt(tab, 2, 3); 69 | Assert.fail(); 70 | } catch (Exception e) { 71 | Assert.assertTrue(true); 72 | } 73 | 74 | } 75 | 76 | /** 77 | * 78 | */ 79 | @Test 80 | public void testBytesFromString() { 81 | try { 82 | BytesUtils.fromString(" 00 5"); 83 | Assert.fail(); 84 | } catch (Exception e) { 85 | } 86 | 87 | try { 88 | BytesUtils.fromString(null); 89 | Assert.fail(); 90 | } catch (Exception e) { 91 | } 92 | 93 | Assertions.assertThat(BytesUtils.fromString(" 00 54 ")).isEqualTo(new byte[] { 0x00, 0x54 }); 94 | 95 | Assertions.assertThat(BytesUtils.fromString("00 54 0A9B")) 96 | .isEqualTo(new byte[] { 0x00, 0x54, 0x0A, (byte) 0x9B }); 97 | Assertions.assertThat(BytesUtils.fromString("000ABC")).isEqualTo(new byte[] { 0x00, 0x0A, (byte) 0xBC }); 98 | } 99 | 100 | /** 101 | * 102 | */ 103 | @Test 104 | public void testBytesToString() { 105 | Assertions.assertThat(BytesUtils.bytesToString(tab)).isEqualTo("12 92 AB 3A"); 106 | Assertions.assertThat(BytesUtils.bytesToString(null)).isEqualTo(""); 107 | Assertions.assertThat(BytesUtils.bytesToString(tab2)).isEqualTo("00 01 02 45"); 108 | } 109 | 110 | /** 111 | * 112 | */ 113 | @Test 114 | public void testBytesToStringNoSpace() { 115 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(tab)).isEqualTo("1292AB3A"); 116 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(null)).isEqualTo(""); 117 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(tab2)).isEqualTo("00010245"); 118 | } 119 | 120 | /** 121 | * 122 | */ 123 | @Test 124 | public void testBytesToStringNoSpacebyte() { 125 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace((byte) 0)).isEqualTo("00"); 126 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace((byte) 255)).isEqualTo("FF"); 127 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(null)).isEqualTo(""); 128 | } 129 | 130 | /** 131 | * 132 | */ 133 | @Test 134 | public void testBytesToStringNoSpaceTruncate() { 135 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(4608), true)).isEqualTo("1200"); 136 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(206), true)).isEqualTo("CE"); 137 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(266), true)).isEqualTo("010A"); 138 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(0), true)).isEqualTo(""); 139 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(Integer.MAX_VALUE), true)) 140 | .isEqualTo("7FFFFFFF"); 141 | 142 | Assertions.assertThat(BytesUtils.bytesToString(BytesUtils.toByteArray(4608), true)).isEqualTo("12 00"); 143 | Assertions.assertThat(BytesUtils.bytesToString(BytesUtils.toByteArray(206), true)).isEqualTo("CE"); 144 | Assertions.assertThat(BytesUtils.bytesToString(BytesUtils.toByteArray(266), true)).isEqualTo("01 0A"); 145 | Assertions.assertThat(BytesUtils.bytesToString(BytesUtils.toByteArray(0), true)).isEqualTo(""); 146 | Assertions.assertThat(BytesUtils.bytesToString(BytesUtils.toByteArray(Integer.MAX_VALUE), true)) 147 | .isEqualTo("7F FF FF FF"); 148 | } 149 | 150 | @Test(expected = IllegalAccessException.class) 151 | public void testConstructorPrivate() throws Exception { 152 | BytesUtils.class.newInstance(); 153 | Assert.fail("Utility class constructor should be private"); 154 | } 155 | 156 | /** 157 | * 158 | */ 159 | @Test 160 | public void testMatchBitByBitIndex() { 161 | Assertions.assertThat(BytesUtils.matchBitByBitIndex(1, 0)).isEqualTo(true); 162 | Assertions.assertThat(BytesUtils.matchBitByBitIndex(128, 7)).isEqualTo(true); 163 | Assertions.assertThat(BytesUtils.matchBitByBitIndex(127, 7)).isEqualTo(false); 164 | Assertions.assertThat(BytesUtils.matchBitByBitIndex(255, 7)).isEqualTo(true); 165 | Assertions.assertThat(BytesUtils.matchBitByBitIndex(0, 0)).isEqualTo(false); 166 | Assertions.assertThat(BytesUtils.matchBitByBitIndex(256, 8)).isEqualTo(true); 167 | Assertions.assertThat(BytesUtils.matchBitByBitIndex(Integer.MIN_VALUE, 31)).isEqualTo(true); 168 | Assertions.assertThat(BytesUtils.matchBitByBitIndex(Integer.MAX_VALUE, 31)).isEqualTo(false); 169 | 170 | try { 171 | BytesUtils.matchBitByBitIndex(0, -1); 172 | Assert.fail(); 173 | } catch (Exception e) { 174 | } 175 | try { 176 | BytesUtils.matchBitByBitIndex(0, 32); 177 | Assert.fail(); 178 | } catch (Exception e) { 179 | } 180 | } 181 | 182 | /** 183 | * 184 | */ 185 | @Test 186 | public void testSetBytes() { 187 | byte max = (byte) 0xFF; 188 | byte min = 0; 189 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.setBit(min, 7, true))).isEqualTo("80"); 190 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.setBit(min, 0, true))).isEqualTo("01"); 191 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.setBit(max, 4, false))).isEqualTo("EF"); 192 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.setBit(max, 0, false))).isEqualTo("FE"); 193 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.setBit(min, 0, false))).isEqualTo("00"); 194 | try { 195 | BytesUtils.setBit(max, -1, false); 196 | Assert.fail(); 197 | } catch (Exception e) { 198 | } 199 | try { 200 | BytesUtils.setBit(max, 8, false); 201 | Assert.fail(); 202 | } catch (Exception e) { 203 | } 204 | } 205 | 206 | /** 207 | * 208 | */ 209 | @Test 210 | public void testToBinary() { 211 | Assertions.assertThat(BytesUtils.toBinary(null)).isEqualTo(null); 212 | Assertions.assertThat(BytesUtils.toBinary(new byte[] { 0x44, 0x01 })).isEqualTo("0100010000000001"); 213 | Assertions.assertThat(BytesUtils.toBinary(new byte[] { 0x00, 0x00, 0x00 })) 214 | .isEqualTo("000000000000000000000000"); 215 | Assertions.assertThat(BytesUtils.toBinary(new byte[] { (byte) 0xF0, 0x00, 0x00 })) 216 | .isEqualTo("111100000000000000000000"); 217 | Assertions.assertThat(BytesUtils.toBinary(new byte[] { (byte) 0xFF })).isEqualTo("11111111"); 218 | } 219 | 220 | /** 221 | * 222 | */ 223 | @Test 224 | public void testToByteArray() { 225 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(0))).isEqualTo("00000000"); 226 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(1))).isEqualTo("00000001"); 227 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(Integer.MAX_VALUE))) 228 | .isEqualTo("7FFFFFFF"); 229 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(Integer.MIN_VALUE))) 230 | .isEqualTo("80000000"); 231 | Assertions.assertThat(BytesUtils.bytesToStringNoSpace(BytesUtils.toByteArray(256))).isEqualTo("00000100"); 232 | } 233 | 234 | @Test 235 | public final void privateConstructor() throws NoSuchMethodException, SecurityException, InstantiationException, 236 | IllegalAccessException, IllegalArgumentException, InvocationTargetException { 237 | final Constructor constructor = BytesUtils.class.getDeclaredConstructor(); 238 | constructor.setAccessible(true); 239 | Assertions.assertThat(constructor.newInstance()).isNotNull(); 240 | } 241 | 242 | } 243 | -------------------------------------------------------------------------------- /src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # A default log4j configuration for log4j users. 2 | 3 | # Configure the console as our appender 4 | log4j.rootLogger=INFO, STDOUT 5 | log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender 6 | log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout 7 | log4j.appender.STDOUT.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n 8 | 9 | # Print only messages of level INFO 10 | log4j.logger.fr.devnied.bitlib = INFO --------------------------------------------------------------------------------