├── .gitignore ├── .github ├── CODEOWNERS ├── RELEASE_TEMPLATE.md ├── dependabot.yml └── workflows │ └── java.yml ├── CHANGELOG.md ├── src ├── main │ └── java │ │ └── com │ │ └── paritytrading │ │ └── foundation │ │ ├── package-info.java │ │ ├── Longs.java │ │ ├── ByteArrays.java │ │ ├── ByteBuffers.java │ │ └── ASCII.java └── test │ └── java │ └── com │ └── paritytrading │ └── foundation │ ├── ByteArraysTest.java │ ├── ByteBuffersTest.java │ └── ASCIITest.java ├── README.md ├── checkstyle.xml ├── pom.xml └── LICENSE.txt /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jvirtanen 2 | -------------------------------------------------------------------------------- /.github/RELEASE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Release Notes 2 | 3 | - ... 4 | 5 | ## Maven 6 | 7 | The following artifacts are available in the Central Repository: 8 | 9 | Group ID | Artifact ID | Version 10 | -------------------------------|--------------|-------- 11 | `com.paritytrading.foundation` | `foundation` | `...` 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Release Notes 2 | 3 | ## 1.0.0 (2022-02-28) 4 | 5 | - No changes 6 | 7 | ## 0.3.0 (2021-03-20) 8 | 9 | - Fix `ByteArrays#pack` (Jussi Virtanen) 10 | 11 | Treat each byte as unsigned when packing a byte array into an integer. 12 | 13 | - Remove redundant casts (Jonathan Heusser) 14 | 15 | ## 0.2.1 (2017-02-18) 16 | 17 | - Fix JUnit dependency scope 18 | 19 | ## 0.2.0 (2016-07-04) 20 | 21 | - Make powers of ten public 22 | 23 | ## 0.1.0 (2016-04-20) 24 | 25 | - Initial release 26 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'maven' 4 | directory: '/' 5 | schedule: 6 | interval: 'daily' 7 | ignore: 8 | - dependency-name: 'com.puppycrawl.tools:checkstyle' 9 | update-types: ['version-update:semver-major'] 10 | - dependency-name: 'org.junit.jupiter:junit-jupiter' 11 | update-types: ['version-update:semver-major'] 12 | - package-ecosystem: 'github-actions' 13 | directory: '/' 14 | schedule: 15 | interval: 'weekly' 16 | -------------------------------------------------------------------------------- /src/main/java/com/paritytrading/foundation/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Foundation authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Foundation contains building blocks for implementing network protocols. 19 | */ 20 | package com.paritytrading.foundation; 21 | -------------------------------------------------------------------------------- /.github/workflows/java.yml: -------------------------------------------------------------------------------- 1 | name: Java 2 | 3 | on: 4 | - push 5 | - pull_request 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | java: 11 | name: ${{ matrix.java-version }} 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | java-version: 16 | - 11 17 | - 17 18 | - 21 19 | - 25 20 | steps: 21 | - name: Check out GitHub repository 22 | uses: actions/checkout@v6 23 | - name: Set up Java 24 | uses: actions/setup-java@v5 25 | with: 26 | distribution: 'temurin' 27 | java-version: ${{ matrix.java-version }} 28 | cache: 'maven' 29 | - name: Run tests 30 | run: mvn test 31 | - name: Run Checkstyle 32 | run: mvn checkstyle:check 33 | - name: Generate Javadoc 34 | run: mvn javadoc:javadoc 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Foundation 2 | 3 | Foundation is a utility library for network protocols on the JVM. 4 | 5 | Foundation requires Java Runtime Environment (JRE) 11 or newer. 6 | 7 | ## Download 8 | 9 | Add a Maven dependency to Foundation: 10 | 11 | ```xml 12 | 13 | com.paritytrading.foundation 14 | foundation 15 | 16 | 17 | ``` 18 | 19 | See the [latest release][] on GitHub. 20 | 21 | [latest release]: https://github.com/paritytrading/foundation/releases/latest 22 | 23 | ## Links 24 | 25 | For more information on Foundation: 26 | 27 | - Follow [paritytrading@fosstodon.org](https://fosstodon.org/@paritytrading) 28 | on Mastodon for news and announcements 29 | 30 | ## License 31 | 32 | Copyright 2016 Foundation authors. 33 | 34 | Released under the Apache License, Version 2.0. See `LICENSE.txt` for details. 35 | -------------------------------------------------------------------------------- /src/main/java/com/paritytrading/foundation/Longs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Foundation authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.paritytrading.foundation; 17 | 18 | /** 19 | * This class contains methods for working with the primitive type 20 | * {@code long}. 21 | */ 22 | public class Longs { 23 | 24 | /** 25 | * The powers of ten. 26 | */ 27 | public static final long[] POWERS_OF_TEN = new long[] { 28 | 1L, 29 | 10L, 30 | 100L, 31 | 1000L, 32 | 10000L, 33 | 100000L, 34 | 1000000L, 35 | 10000000L, 36 | 100000000L, 37 | 1000000000L, 38 | 10000000000L, 39 | 100000000000L, 40 | 1000000000000L, 41 | 10000000000000L, 42 | 100000000000000L, 43 | 1000000000000000L, 44 | 10000000000000000L, 45 | 100000000000000000L, 46 | 1000000000000000000L, 47 | }; 48 | 49 | private Longs() { 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /checkstyle.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/test/java/com/paritytrading/foundation/ByteArraysTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Foundation authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.paritytrading.foundation; 17 | 18 | import static org.junit.jupiter.api.Assertions.*; 19 | 20 | import org.junit.jupiter.api.Test; 21 | 22 | class ByteArraysTest { 23 | 24 | @Test 25 | void reverseEvenLength() { 26 | byte[] a = new byte[] { 1, 2, 3, 4 }; 27 | 28 | ByteArrays.reverse(a); 29 | 30 | assertArrayEquals(new byte[] { 4, 3, 2, 1 }, a); 31 | } 32 | 33 | @Test 34 | void reverseOddLength() { 35 | byte[] a = new byte[] { 1, 2, 3, 4, 5 }; 36 | 37 | ByteArrays.reverse(a); 38 | 39 | assertArrayEquals(new byte[] { 5, 4, 3, 2, 1 }, a); 40 | } 41 | 42 | @Test 43 | void reverseEvenLengthRange() { 44 | byte[] a = new byte[] { 1, 2, 3, 4 }; 45 | 46 | ByteArrays.reverse(a, 1, 3); 47 | 48 | assertArrayEquals(new byte[] { 1, 3, 2, 4 }, a); 49 | } 50 | 51 | @Test 52 | void reverseOddLengthRange() { 53 | byte[] a = new byte[] { 1, 2, 3, 4, 5 }; 54 | 55 | ByteArrays.reverse(a, 1, 4); 56 | 57 | assertArrayEquals(new byte[] { 1, 4, 3, 2, 5 }, a); 58 | } 59 | 60 | @Test 61 | void packShort() { 62 | short s = ByteArrays.packShort(new byte[] { 0x01, 0x02, 0x03 }, (byte)0x00); 63 | 64 | assertEquals(0x0102, s); 65 | } 66 | 67 | @Test 68 | void packInt() { 69 | int i = ByteArrays.packInt(new byte[] { 0x01, 0x02, 0x03 }, (byte)0x00); 70 | 71 | assertEquals(0x01020300, i); 72 | } 73 | 74 | @Test 75 | void packLong() { 76 | long l = ByteArrays.packLong(new byte[] { 0x01, 0x02, 0x03, }, (byte)0x00); 77 | 78 | assertEquals(0x0102030000000000L, l); 79 | } 80 | 81 | @Test 82 | void unpackShort() { 83 | byte[] a = new byte[2]; 84 | 85 | ByteArrays.unpackShort(a, (short)0x0102); 86 | 87 | assertArrayEquals(new byte[] { 0x01, 0x02 }, a); 88 | } 89 | 90 | @Test 91 | void unpackShortWithAllocation() { 92 | byte[] a = ByteArrays.unpackShort((short)0x0102); 93 | 94 | assertArrayEquals(new byte[] { 0x01, 0x02 }, a); 95 | } 96 | 97 | @Test 98 | void unpackInt() { 99 | byte[] a = new byte[4]; 100 | 101 | ByteArrays.unpackInt(a, 0x01020300); 102 | 103 | assertArrayEquals(new byte[] { 0x01, 0x02, 0x03, 0x00 }, a); 104 | } 105 | 106 | @Test 107 | void unpackIntWithAllocation() { 108 | byte[] a = ByteArrays.unpackInt(0x01020300); 109 | 110 | assertArrayEquals(new byte[] { 0x01, 0x02, 0x03, 0x00 }, a); 111 | } 112 | 113 | @Test 114 | void unpackLong() { 115 | byte[] a = new byte[8]; 116 | 117 | ByteArrays.unpackLong(a, 0x0102030000000000L); 118 | 119 | assertArrayEquals(new byte[] { 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, a); 120 | } 121 | 122 | @Test 123 | void unpackLongWithAllocation() { 124 | byte[] a = ByteArrays.unpackLong(0x0102030000000000L); 125 | 126 | assertArrayEquals(new byte[] { 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, a); 127 | } 128 | 129 | @Test 130 | void shortRoundtrip() { 131 | short s = 0x01FF; 132 | 133 | assertEquals(s, ByteArrays.packShort(ByteArrays.unpackShort(s), (byte)0x00)); 134 | } 135 | 136 | @Test 137 | void intRoundtrip() { 138 | int i = 0x017F81FF; 139 | 140 | assertEquals(i, ByteArrays.packInt(ByteArrays.unpackInt(i), (byte)0x00)); 141 | } 142 | 143 | @Test 144 | void longRoundtrip() { 145 | long l = 0x01407F81C0FFL; 146 | 147 | assertEquals(l, ByteArrays.packLong(ByteArrays.unpackLong(l), (byte)0x00)); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 4.0.0 19 | 20 | 21 | org.sonatype.oss 22 | oss-parent 23 | 7 24 | 25 | 26 | com.paritytrading.foundation 27 | foundation 28 | 1.0.1-SNAPSHOT 29 | 30 | Foundation 31 | A utility library for network protocols. 32 | https://github.com/paritytrading/foundation 33 | 34 | 35 | 36 | Apache License, Version 2.0 37 | http://www.apache.org/licenses/LICENSE-2.0.txt 38 | 39 | 40 | 41 | 42 | 43 | Jussi Virtanen 44 | jussi.virtanen@paritytrading.com 45 | 46 | 47 | 48 | 49 | scm:git:git@github.com:paritytrading/foundation.git 50 | scm:git:git@github.com:paritytrading/foundation.git 51 | https://github.com/paritytrading/foundation 52 | HEAD 53 | 54 | 55 | 56 | 11 57 | UTF-8 58 | 59 | 60 | 61 | 62 | org.junit.jupiter 63 | junit-jupiter 64 | 5.14.1 65 | test 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-checkstyle-plugin 74 | 3.6.0 75 | 76 | checkstyle.xml 77 | true 78 | 79 | 80 | 81 | com.puppycrawl.tools 82 | checkstyle 83 | 10.26.1 84 | 85 | 86 | 87 | 88 | org.apache.maven.plugins 89 | maven-compiler-plugin 90 | 3.14.1 91 | 92 | ${java.version} 93 | 94 | 95 | 96 | org.apache.maven.plugins 97 | maven-dependency-plugin 98 | 3.9.0 99 | 100 | 101 | org.apache.maven.plugins 102 | maven-javadoc-plugin 103 | 3.12.0 104 | 105 | true 106 | ${java.version} 107 | 108 | 109 | 110 | org.apache.maven.plugins 111 | maven-release-plugin 112 | 3.2.0 113 | 114 | false 115 | @{project.version} 116 | 117 | 118 | 119 | org.apache.maven.plugins 120 | maven-surefire-plugin 121 | 3.5.4 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /src/test/java/com/paritytrading/foundation/ByteBuffersTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Foundation authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.paritytrading.foundation; 17 | 18 | import static org.junit.jupiter.api.Assertions.*; 19 | 20 | import java.nio.ByteBuffer; 21 | import org.junit.jupiter.api.Test; 22 | 23 | class ByteBuffersTest { 24 | 25 | @Test 26 | void gettingAbsoluteBulk() { 27 | ByteBuffer src = ByteBuffer.wrap(new byte[] { 0x01, 0x02, 0x03, 0x04 }); 28 | byte[] dst = new byte[2]; 29 | 30 | ByteBuffers.get(src, dst, 1); 31 | 32 | assertArrayEquals(new byte[] { 0x02, 0x03 }, dst); 33 | } 34 | 35 | @Test 36 | void gettingAbsoluteBulkWithOffsetAndLength() { 37 | ByteBuffer src = ByteBuffer.wrap(new byte[] { 0x01, 0x02, 0x03, 0x04 }); 38 | byte[] dst = new byte[4]; 39 | 40 | ByteBuffers.get(src, dst, 1, 2, 2); 41 | 42 | assertArrayEquals(new byte[] { 0x00, 0x00, 0x02, 0x03 }, dst); 43 | } 44 | 45 | @Test 46 | void puttingAbsoluteBulk() { 47 | byte[] src = new byte[] { 0x01, 0x02 }; 48 | ByteBuffer dst = ByteBuffer.wrap(new byte[4]); 49 | 50 | ByteBuffers.put(dst, src, 1); 51 | 52 | assertArrayEquals(new byte[] { 0x00, 0x01, 0x02, 0x00 }, dst.array()); 53 | } 54 | 55 | @Test 56 | void puttingAbsoluteBulkWithOffsetAndLength() { 57 | byte[] src = new byte[] { 0x01, 0x02, 0x03, 0x04 }; 58 | ByteBuffer dst = ByteBuffer.wrap(new byte[4]); 59 | 60 | ByteBuffers.put(dst, src, 1, 2, 2); 61 | 62 | assertArrayEquals(new byte[] { 0x00, 0x03, 0x04, 0x00 }, dst.array()); 63 | } 64 | 65 | @Test 66 | void gettingRelativeUnsignedByte() { 67 | ByteBuffer buffer = ByteBuffer.allocate(1); 68 | 69 | buffer.put((byte)0xff); 70 | buffer.flip(); 71 | 72 | assertEquals(255, ByteBuffers.getUnsigned(buffer)); 73 | } 74 | 75 | @Test 76 | void gettingAbsoluteUnsignedByte() { 77 | ByteBuffer buffer = ByteBuffer.allocate(1); 78 | 79 | buffer.put((byte)0xff); 80 | buffer.flip(); 81 | 82 | assertEquals(255, ByteBuffers.getUnsigned(buffer, 0)); 83 | } 84 | 85 | @Test 86 | void puttingRelativeUnsignedByte() { 87 | ByteBuffer buffer = ByteBuffer.allocate(1); 88 | 89 | ByteBuffers.putUnsigned(buffer, (short)255); 90 | buffer.flip(); 91 | 92 | assertEquals((byte)0xff, buffer.get()); 93 | } 94 | 95 | @Test 96 | void puttingAbsoluteUnsignedByte() { 97 | ByteBuffer buffer = ByteBuffer.allocate(1); 98 | 99 | ByteBuffers.putUnsigned(buffer, 0, (short)255); 100 | 101 | assertEquals((byte)0xff, buffer.get()); 102 | } 103 | 104 | @Test 105 | void gettingRelativeUnsignedShort() { 106 | ByteBuffer buffer = ByteBuffer.allocate(2); 107 | 108 | buffer.putShort((short)0xffff); 109 | buffer.flip(); 110 | 111 | assertEquals(65535, ByteBuffers.getUnsignedShort(buffer)); 112 | } 113 | 114 | @Test 115 | void gettingAbsoluteUnsignedShort() { 116 | ByteBuffer buffer = ByteBuffer.allocate(2); 117 | 118 | buffer.putShort((short)0xffff); 119 | buffer.flip(); 120 | 121 | assertEquals(65535, ByteBuffers.getUnsignedShort(buffer, 0)); 122 | } 123 | 124 | @Test 125 | void puttingRelativeUnsignedShort() { 126 | ByteBuffer buffer = ByteBuffer.allocate(2); 127 | 128 | ByteBuffers.putUnsignedShort(buffer, 65535); 129 | buffer.flip(); 130 | 131 | assertEquals((short)0xffff, buffer.getShort()); 132 | } 133 | 134 | @Test 135 | void puttingAbsoluteUnsignedShort() { 136 | ByteBuffer buffer = ByteBuffer.allocate(2); 137 | 138 | ByteBuffers.putUnsignedShort(buffer, 0, 65535); 139 | 140 | assertEquals((short)0xffff, buffer.getShort()); 141 | } 142 | 143 | @Test 144 | void gettingRelativeUnsignedInteger() { 145 | ByteBuffer buffer = ByteBuffer.allocate(4); 146 | 147 | buffer.putInt(0xffffffff); 148 | buffer.flip(); 149 | 150 | assertEquals(4294967295L, ByteBuffers.getUnsignedInt(buffer)); 151 | } 152 | 153 | @Test 154 | void gettingAbsoluteUnsignedInteger() { 155 | ByteBuffer buffer = ByteBuffer.allocate(4); 156 | 157 | buffer.putInt(0xffffffff); 158 | buffer.flip(); 159 | 160 | assertEquals(4294967295L, ByteBuffers.getUnsignedInt(buffer, 0)); 161 | } 162 | 163 | @Test 164 | void puttingRelativeUnsignedInteger() { 165 | ByteBuffer buffer = ByteBuffer.allocate(4); 166 | 167 | ByteBuffers.putUnsignedInt(buffer, 4294967295L); 168 | buffer.flip(); 169 | 170 | assertEquals(0xffffffff, buffer.getInt()); 171 | } 172 | 173 | @Test 174 | void puttingAbsoluteUnsignedInteger() { 175 | ByteBuffer buffer = ByteBuffer.allocate(4); 176 | 177 | ByteBuffers.putUnsignedInt(buffer, 0, 4294967295L); 178 | 179 | assertEquals(0xffffffff, buffer.getInt()); 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /src/main/java/com/paritytrading/foundation/ByteArrays.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Foundation authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.paritytrading.foundation; 17 | 18 | /** 19 | * This class contains methods for manipulating byte arrays. 20 | */ 21 | public class ByteArrays { 22 | 23 | private ByteArrays() { 24 | } 25 | 26 | /** 27 | * Reverse a byte array. 28 | * 29 | * @param a a byte array 30 | */ 31 | public static void reverse(byte[] a) { 32 | reverse(a, 0, a.length); 33 | } 34 | 35 | /** 36 | * Reverse the specified range in a byte array. 37 | * 38 | * @param a a byte array 39 | * @param from the index of the first element (inclusive) 40 | * @param to the index of the last element (exclusive) 41 | */ 42 | public static void reverse(byte[] a, int from, int to) { 43 | byte tmp; 44 | 45 | for (int i = 0; i < (to - from) / 2; i++) { 46 | tmp = a[from + i ]; 47 | a[from + i] = a[to - i - 1]; 48 | a[to - i - 1] = tmp; 49 | } 50 | } 51 | 52 | /** 53 | * Pack a byte array into a short. 54 | * 55 | *

If the length of the byte array is less than two bytes, the pad byte 56 | * is used to fill the less significant bits.

57 | * 58 | *

If the length of the byte array is more than two bytes, only the 59 | * first two bytes are packed.

60 | * 61 | * @param a a byte array 62 | * @param pad the pad byte 63 | * @return a short 64 | */ 65 | public static short packShort(byte[] a, byte pad) { 66 | return (short)pack(a, pad, 2); 67 | } 68 | 69 | /** 70 | * Pack a byte array into an integer. 71 | * 72 | *

If the length of the byte array is less than four bytes, the 73 | * pad byte is used to fill the less significant bits.

74 | * 75 | *

If the length of the byte array is more than four bytes, only 76 | * the first four bytes are packed.

77 | * 78 | * @param a a byte array 79 | * @param pad the pad byte 80 | * @return an integer 81 | */ 82 | public static int packInt(byte[] a, byte pad) { 83 | return (int)pack(a, pad, 4); 84 | } 85 | 86 | /** 87 | * Pack a byte array into a long. 88 | * 89 | *

If the length of the byte array is less than eight bytes, the pad 90 | * byte is used to fill the less significant bits.

91 | * 92 | *

If the length of the byte array is more than eight bytes, only the 93 | * first eight bytes are packed.

94 | * 95 | * @param a a byte array 96 | * @param pad the bad byte 97 | * @return a long 98 | */ 99 | public static long packLong(byte[] a, byte pad) { 100 | return pack(a, pad, 8); 101 | } 102 | 103 | private static long pack(byte[] a, byte pad, int size) { 104 | long l = 0; 105 | int i = 0; 106 | 107 | for (; i < Math.min(a.length, size); i++) 108 | l = (l << 8) | a[i] & 0xFF; 109 | 110 | for (; i < size; i++) 111 | l = (l << 8) | pad; 112 | 113 | return l; 114 | } 115 | 116 | /** 117 | * Unpack a short into a byte array. 118 | * 119 | *

If the length of the array is less than two bytes, only the first 120 | * bytes that fit into the array are unpacked.

121 | * 122 | * @param a a byte array 123 | * @param s a short 124 | */ 125 | public static void unpackShort(byte[] a, short s) { 126 | unpack(a, s, 2); 127 | } 128 | 129 | /** 130 | * Unpack a short into a byte array. 131 | * 132 | * @param s a short 133 | * @return an array of two bytes 134 | */ 135 | public static byte[] unpackShort(short s) { 136 | return unpack(s, 2); 137 | } 138 | 139 | /** 140 | * Unpack an integer into a byte array. 141 | * 142 | *

If the length of the array is less than four bytes, only the first 143 | * bytes that fit into the array are unpacked.

144 | * 145 | * @param a a byte array 146 | * @param i an integer 147 | */ 148 | public static void unpackInt(byte[] a, int i) { 149 | unpack(a, i, 4); 150 | } 151 | 152 | /** 153 | * Unpack an integer into a byte array. 154 | * 155 | * @param i an integer 156 | * @return an array of four bytes 157 | */ 158 | public static byte[] unpackInt(int i) { 159 | return unpack(i, 4); 160 | } 161 | 162 | /** 163 | * Unpack a long into a byte array. 164 | * 165 | *

If the length of the array is less than eight bytes, only the first 166 | * bytes that fit into the array are unpacked.

167 | * 168 | * @param a a byte array 169 | * @param l a long 170 | */ 171 | public static void unpackLong(byte[] a, long l) { 172 | unpack(a, l, 8); 173 | } 174 | 175 | /** 176 | * Unpack a long into a byte array. 177 | * 178 | * @param l a long 179 | * @return an array of eight bytes 180 | */ 181 | public static byte[] unpackLong(long l) { 182 | return unpack(l, 8); 183 | } 184 | 185 | private static void unpack(byte[] a, long l, int size) { 186 | for (int i = 0; i < Math.min(a.length, size); i++) 187 | a[i] = (byte)((l >> (8 * (size - 1 - i))) & 0xFF); 188 | } 189 | 190 | private static byte[] unpack(long l, int size) { 191 | byte[] a = new byte[size]; 192 | 193 | unpack(a, l, size); 194 | 195 | return a; 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /src/main/java/com/paritytrading/foundation/ByteBuffers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Foundation authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.paritytrading.foundation; 17 | 18 | import java.nio.BufferOverflowException; 19 | import java.nio.BufferUnderflowException; 20 | import java.nio.ByteBuffer; 21 | import java.nio.ReadOnlyBufferException; 22 | 23 | /** 24 | * This class contains methods for manipulating byte buffers. 25 | */ 26 | public class ByteBuffers { 27 | 28 | private ByteBuffers() { 29 | } 30 | 31 | /** 32 | * Absolute bulk get method. 33 | * 34 | *

This method transfers bytes from the source buffer into the given 35 | * destination array.

36 | * 37 | * @param src the source buffer 38 | * @param dst the destination array 39 | * @param index the index from which the bytes will be read 40 | * @throws BufferUnderflowException if there are fewer bytes than the 41 | * length of the array between the index and the limit 42 | */ 43 | public static void get(ByteBuffer src, byte[] dst, int index) { 44 | get(src, dst, index, 0, dst.length); 45 | } 46 | 47 | /** 48 | * Absolute bulk get method. 49 | * 50 | *

This method transfers bytes from the source buffer into the given 51 | * destination array.

52 | * 53 | * @param src the source buffer 54 | * @param dst the destination array 55 | * @param index the index from which the bytes will be read 56 | * @param offset the offset within the array of the first byte to be 57 | * written 58 | * @param length the number of bytes to be written to the array 59 | * @throws BufferUnderflowException if there are fewer bytes than the 60 | * length between the index and the limit 61 | * @throws IndexOutOfBoundsException if the preconditions on the offset 62 | * and length do not hold 63 | */ 64 | public static void get(ByteBuffer src, byte[] dst, int index, int offset, int length) { 65 | if (src.limit() - index < length) 66 | throw new BufferUnderflowException(); 67 | 68 | for (int i = 0; i < length; i++) 69 | dst[offset + i] = src.get(index + i); 70 | } 71 | 72 | /** 73 | * Absolute bulk put method. 74 | * 75 | *

This method transfers bytes from the source array to the destination 76 | * buffer.

77 | * 78 | * @param dst the destination buffer 79 | * @param src the source array 80 | * @param index the index at which the bytes will be written 81 | * @throws BufferOverflowException if there are fewer bytes than the 82 | * length of the array between the index and the limit 83 | */ 84 | public static void put(ByteBuffer dst, byte[] src, int index) { 85 | put(dst, src, index, 0, src.length); 86 | } 87 | 88 | /** 89 | * Absolute bulk put method. 90 | * 91 | *

This method transfers bytes from the source array to the destination 92 | * buffer.

93 | * 94 | * 95 | * @param dst the destination buffer 96 | * @param src the source array 97 | * @param index the index at which the bytes will be written 98 | * @param offset the offset within the array of the first byte to be 99 | * written 100 | * @param length the number of bytes to be written to the buffer 101 | * @throws BufferOverflowException if there are fewer bytes than the 102 | * length between the index and the limit 103 | * @throws IndexOutOfBoundsException if the preconditions on the offset 104 | * and length do not hold 105 | */ 106 | public static void put(ByteBuffer dst, byte[] src, int index, int offset, int length) { 107 | if (dst.limit() - index < length) 108 | throw new BufferOverflowException(); 109 | 110 | for (int i = 0; i < length; i++) 111 | dst.put(index + i, src[offset + i]); 112 | } 113 | 114 | /** 115 | * Relative get method for reading an unsigned byte. 116 | * 117 | * @param buffer a buffer 118 | * @return the unsigned byte 119 | * @throws BufferUnderflowException if there are no bytes remaining in 120 | * the buffer 121 | */ 122 | public static short getUnsigned(ByteBuffer buffer) { 123 | return (short)(buffer.get() & 0xff); 124 | } 125 | 126 | /** 127 | * Absolute get method for reading an unsigned byte. 128 | * 129 | * @param buffer a buffer 130 | * @param index the index from which the unsigned byte will be read 131 | * @return the unsigned byte at the given index 132 | * @throws IndexOutOfBoundsException if the index is negative or not 133 | * smaller than the buffer's limit 134 | */ 135 | public static short getUnsigned(ByteBuffer buffer, int index) { 136 | return (short)(buffer.get(index) & 0xff); 137 | } 138 | 139 | /** 140 | * Relative put method for writing an unsigned byte. 141 | * 142 | * @param buffer a buffer 143 | * @param b the unsigned byte 144 | * @throws BufferOverflowException if there are no bytes remaining in the 145 | * buffer 146 | * @throws ReadOnlyBufferException if the buffer is read-only 147 | */ 148 | public static void putUnsigned(ByteBuffer buffer, short b) { 149 | buffer.put((byte)b); 150 | } 151 | 152 | /** 153 | * Absolute put method for writing an unsigned byte. 154 | * 155 | * @param buffer a buffer 156 | * @param index the index at which the unsigned byte will be written 157 | * @param b the unsigned byte 158 | * @throws IndexOutOfBoundsException if the index is negative or not 159 | * smaller than the buffer's limit 160 | * @throws ReadOnlyBufferException if the buffer is read-only 161 | */ 162 | public static void putUnsigned(ByteBuffer buffer, int index, short b) { 163 | buffer.put(index, (byte)b); 164 | } 165 | 166 | /** 167 | * Relative get method for reading an unsigned short value. 168 | * 169 | * @param buffer a buffer 170 | * @return the unsigned short value 171 | * @throws BufferUnderflowException if there are fewer than two bytes 172 | * remaining in the buffer 173 | */ 174 | public static int getUnsignedShort(ByteBuffer buffer) { 175 | return buffer.getShort() & 0xffff; 176 | } 177 | 178 | /** 179 | * Absolute get method for reading an unsigned short value. 180 | * 181 | * @param buffer a buffer 182 | * @param index the index from which the unsigned short value will be 183 | * read 184 | * @return the unsigned short value at the given index 185 | * @throws IndexOutOfBoundsException if the index is negative or not 186 | * smaller than the buffer's limit, minus one 187 | */ 188 | public static int getUnsignedShort(ByteBuffer buffer, int index) { 189 | return buffer.getShort(index) & 0xffff; 190 | } 191 | 192 | /** 193 | * Relative put method for writing an unsigned short value. 194 | * 195 | * @param buffer a buffer 196 | * @param value the unsigned short value 197 | * @throws BufferOverflowException if there are fewer than two bytes 198 | * remaining in the buffer 199 | * @throws ReadOnlyBufferException if the buffer is read-only 200 | */ 201 | public static void putUnsignedShort(ByteBuffer buffer, int value) { 202 | buffer.putShort((short)value); 203 | } 204 | 205 | /** 206 | * Absolute put method for writing an unsigned short value. 207 | * 208 | * @param buffer a buffer 209 | * @param index the index at which the unsigned short value will be 210 | * written 211 | * @param value the unsigned short value 212 | * @throws IndexOutOfBoundsException if the index is negative or not 213 | * smaller than the buffer's limit, minus one 214 | * @throws ReadOnlyBufferException if the buffer is read-only 215 | */ 216 | public static void putUnsignedShort(ByteBuffer buffer, int index, int value) { 217 | buffer.putShort(index, (short)value); 218 | } 219 | 220 | /** 221 | * Relative get method for reading an unsigned integer value. 222 | * 223 | * @param buffer a buffer 224 | * @return the unsigned integer value 225 | * @throws BufferUnderflowException if there are fewer than four bytes 226 | * remaining in the buffer 227 | */ 228 | public static long getUnsignedInt(ByteBuffer buffer) { 229 | return buffer.getInt() & 0xffffffffL; 230 | } 231 | 232 | /** 233 | * Absolute get method for reading an unsigned integer value. 234 | * 235 | * @param buffer a buffer 236 | * @param index the index from which the unsigned integer value will be 237 | * read 238 | * @return the unsigned integer value at the given index 239 | * @throws IndexOutOfBoundsException if the index is negative or not 240 | * smaller than the buffer's limit, minus three 241 | */ 242 | public static long getUnsignedInt(ByteBuffer buffer, int index) { 243 | return buffer.getInt(index) & 0xffffffffL; 244 | } 245 | 246 | /** 247 | * Relative put method for writing an unsigned integer value. 248 | * 249 | * @param buffer a buffer 250 | * @param value the unsigned integer value 251 | * @throws BufferOverflowException if the are fewer than four bytes 252 | * remaining in the buffer 253 | * @throws ReadOnlyBufferException if the buffer is read-only 254 | */ 255 | public static void putUnsignedInt(ByteBuffer buffer, long value) { 256 | buffer.putInt((int)value); 257 | } 258 | 259 | /** 260 | * Absolute put method for writing an unsigned integer value. 261 | * 262 | * @param buffer a buffer 263 | * @param index the index at which the unsigned integer value will be 264 | * written 265 | * @param value the unsigned integer value 266 | * @throws IndexOutOfBoundsException if the index is negative or not 267 | * smaller than the buffer's limit, minus three 268 | * @throws ReadOnlyBufferException if the buffer is read-only 269 | */ 270 | public static void putUnsignedInt(ByteBuffer buffer, int index, long value) { 271 | buffer.putInt(index, (int)value); 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /src/test/java/com/paritytrading/foundation/ASCIITest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Foundation authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.paritytrading.foundation; 17 | 18 | import static org.junit.jupiter.api.Assertions.*; 19 | 20 | import org.junit.jupiter.api.Test; 21 | 22 | class ASCIITest { 23 | 24 | @Test 25 | void get() { 26 | byte[] bytes = new byte[] { 'f', 'o', 'o', ' ', ' ' }; 27 | 28 | assertEquals("foo ", ASCII.get(bytes)); 29 | } 30 | 31 | @Test 32 | void getWithStringBuilder() { 33 | byte[] bytes = new byte[] { 'f', 'o', 'o', ' ', ' ' }; 34 | 35 | StringBuilder b = new StringBuilder(); 36 | 37 | ASCII.get(bytes, b); 38 | 39 | assertEquals("foo ", b.toString()); 40 | } 41 | 42 | @Test 43 | void put() { 44 | assertArrayEquals(new byte[] { 'f', 'o', 'o' }, ASCII.put("foo")); 45 | } 46 | 47 | @Test 48 | void putLeft() { 49 | byte[] bytes = new byte[5]; 50 | 51 | ASCII.putLeft(bytes, "foo"); 52 | 53 | assertArrayEquals(new byte[] { 'f', 'o', 'o', ' ', ' ' }, bytes); 54 | } 55 | 56 | @Test 57 | void putTooLongLeft() { 58 | byte[] bytes = new byte[2]; 59 | 60 | assertThrows(IndexOutOfBoundsException.class, () -> ASCII.putLeft(bytes, "foo")); 61 | } 62 | 63 | @Test 64 | void putRight() { 65 | byte[] bytes = new byte[5]; 66 | 67 | ASCII.putRight(bytes, "foo"); 68 | 69 | assertArrayEquals(new byte[] { ' ', ' ', 'f', 'o', 'o' }, bytes); 70 | } 71 | 72 | @Test 73 | void putTooLongRight() { 74 | byte[] bytes = new byte[2]; 75 | 76 | assertThrows(IndexOutOfBoundsException.class, () -> ASCII.putRight(bytes, "foo")); 77 | } 78 | 79 | @Test 80 | void getLongRight() { 81 | byte[] bytes = new byte[] { ' ', ' ', '1', '2', '3' }; 82 | 83 | assertEquals(123, ASCII.getLong(bytes)); 84 | } 85 | 86 | @Test 87 | void getNegativeLongRight() { 88 | byte[] bytes = new byte[] { ' ', '-', '1', '2', '3' }; 89 | 90 | assertEquals(-123, ASCII.getLong(bytes)); 91 | } 92 | 93 | @Test 94 | void getLongLeft() { 95 | byte[] bytes = new byte[] { '1', '2', '3', ' ', ' ' }; 96 | 97 | assertEquals(123, ASCII.getLong(bytes)); 98 | } 99 | 100 | @Test 101 | void getNegativeLongLeft() { 102 | byte[] bytes = new byte[] { '-', '1', '2', '3', ' ' }; 103 | 104 | assertEquals(-123, ASCII.getLong(bytes)); 105 | } 106 | 107 | @Test 108 | void putLongLeft() { 109 | byte[] bytes = new byte[5]; 110 | 111 | ASCII.putLongLeft(bytes, 123); 112 | 113 | assertArrayEquals(new byte[] { '1', '2', '3', ' ', ' ' }, bytes); 114 | } 115 | 116 | @Test 117 | void putNegativeLongLeft() { 118 | byte[] bytes = new byte[5]; 119 | 120 | ASCII.putLongLeft(bytes, -123); 121 | 122 | assertArrayEquals(new byte[] { '-', '1', '2', '3', ' ' }, bytes); 123 | } 124 | 125 | @Test 126 | void putTooLongLongLeft() { 127 | byte[] bytes = new byte[5]; 128 | 129 | assertThrows(IndexOutOfBoundsException.class, () -> ASCII.putLongLeft(bytes, 123456)); 130 | } 131 | 132 | @Test 133 | void putLongRight() { 134 | byte[] bytes = new byte[5]; 135 | 136 | ASCII.putLongRight(bytes, 123); 137 | 138 | assertArrayEquals(new byte[] { ' ', ' ', '1', '2', '3' }, bytes); 139 | } 140 | 141 | @Test 142 | void putNegativeLongRight() { 143 | byte[] bytes = new byte[5]; 144 | 145 | ASCII.putLongRight(bytes, -123); 146 | 147 | assertArrayEquals(new byte[] { ' ', '-', '1', '2', '3' }, bytes); 148 | } 149 | 150 | @Test 151 | void putTooLongLongRight() { 152 | byte[] bytes = new byte[5]; 153 | 154 | assertThrows(IndexOutOfBoundsException.class, () -> ASCII.putLongRight(bytes, 123456)); 155 | } 156 | 157 | @Test 158 | void getFixedLeft() { 159 | byte[] bytes = new byte[] { '1', '.', '2', '3', ' ' }; 160 | 161 | assertEquals(123, ASCII.getFixed(bytes, 2)); 162 | } 163 | 164 | @Test 165 | void getFixedLeftWithoutDecimalDigits() { 166 | byte[] bytes = new byte[] { '1', '2', '3', ' ', ' ' }; 167 | 168 | assertEquals(12300, ASCII.getFixed(bytes, 2)); 169 | } 170 | 171 | @Test 172 | void getFixedLeftWithFewerDecimalDigits() { 173 | byte[] bytes = new byte[] { '1', '2', '.', '3', ' ' }; 174 | 175 | assertEquals(1230, ASCII.getFixed(bytes, 2)); 176 | } 177 | 178 | @Test 179 | void getFixedLeftWithMoreDecimalDigits() { 180 | byte[] bytes = new byte[] { '1', '.', '2', '3', ' ' }; 181 | 182 | assertEquals(12, ASCII.getFixed(bytes, 1)); 183 | } 184 | 185 | @Test 186 | void getFixedRight() { 187 | byte[] bytes = new byte[] { ' ', '1', '.', '2', '3' }; 188 | 189 | assertEquals(123, ASCII.getFixed(bytes, 2)); 190 | } 191 | 192 | @Test 193 | void getFixedRightWithoutDecimalDigits() { 194 | byte[] bytes = new byte[] { ' ', ' ', '1', '2', '3' }; 195 | 196 | assertEquals(12300, ASCII.getFixed(bytes, 2)); 197 | } 198 | 199 | @Test 200 | void getFixedRightWithFewerDecimalDigits() { 201 | byte[] bytes = new byte[] { ' ', '1', '2', '.', '3' }; 202 | 203 | assertEquals(1230, ASCII.getFixed(bytes, 2)); 204 | } 205 | 206 | @Test 207 | void getFixedRightWithMoreDecimalDigits() { 208 | byte[] bytes = new byte[] { ' ', '1', '.', '2', '3' }; 209 | 210 | assertEquals(12, ASCII.getFixed(bytes, 1)); 211 | } 212 | 213 | @Test 214 | void getNegativeFixed() { 215 | byte[] bytes = new byte[] { '-', '1', '.', '2', '3' }; 216 | 217 | assertEquals(-123, ASCII.getFixed(bytes, 2)); 218 | } 219 | 220 | @Test 221 | void getNegativeFixedWithoutDecimalDigits() { 222 | byte[] bytes = new byte[] { ' ', '-', '1', '2', '3' }; 223 | 224 | assertEquals(-12300, ASCII.getFixed(bytes, 2)); 225 | } 226 | 227 | @Test 228 | void getNegativeFixedWithFewerDecimalDigits() { 229 | byte[] bytes = new byte[] { '-', '1', '2', '.', '3' }; 230 | 231 | assertEquals(-1230, ASCII.getFixed(bytes, 2)); 232 | } 233 | 234 | @Test 235 | void getNegativeFixedWithMoreDecimalDigits() { 236 | byte[] bytes = new byte[] { '-', '1', '.', '2', '3' }; 237 | 238 | assertEquals(-12, ASCII.getFixed(bytes, 1)); 239 | } 240 | 241 | @Test 242 | void putFixedLeft() { 243 | byte[] bytes = new byte[5]; 244 | 245 | ASCII.putFixedLeft(bytes, 123, 2); 246 | 247 | assertArrayEquals(new byte[] { '1', '.', '2', '3', ' ' }, bytes); 248 | } 249 | 250 | @Test 251 | void putSmallFixedLeft() { 252 | byte[] bytes = new byte[5]; 253 | 254 | ASCII.putFixedLeft(bytes, 1, 2); 255 | 256 | assertArrayEquals(new byte[] { '0', '.', '0', '1', ' ' }, bytes); 257 | } 258 | 259 | @Test 260 | void putNegativeFixedLeft() { 261 | byte[] bytes = new byte[5]; 262 | 263 | ASCII.putFixedLeft(bytes, -123, 2); 264 | 265 | assertArrayEquals(new byte[] { '-', '1', '.', '2', '3' }, bytes); 266 | } 267 | 268 | @Test 269 | void putSmallNegativeFixedLeft() { 270 | byte[] bytes = new byte[5]; 271 | 272 | ASCII.putFixedLeft(bytes, -1, 2); 273 | 274 | assertArrayEquals(new byte[] { '-', '0', '.', '0', '1' }, bytes); 275 | } 276 | 277 | @Test 278 | void putTooLongFixedLeft() { 279 | byte[] bytes = new byte[5]; 280 | 281 | assertThrows(IndexOutOfBoundsException.class, () -> ASCII.putFixedLeft(bytes, 123456, 2)); 282 | } 283 | 284 | @Test 285 | void putFixedRight() { 286 | byte[] bytes = new byte[5]; 287 | 288 | ASCII.putFixedRight(bytes, 123, 2); 289 | 290 | assertArrayEquals(new byte[] { ' ', '1', '.', '2', '3' }, bytes); 291 | } 292 | 293 | @Test 294 | void putSmallFixedRight() { 295 | byte[] bytes = new byte[5]; 296 | 297 | ASCII.putFixedRight(bytes, 1, 2); 298 | 299 | assertArrayEquals(new byte[] { ' ', '0', '.', '0', '1' }, bytes); 300 | } 301 | 302 | @Test 303 | void putNegativeFixedRight() { 304 | byte[] bytes = new byte[5]; 305 | 306 | ASCII.putFixedRight(bytes, -123, 2); 307 | 308 | assertArrayEquals(new byte[] { '-', '1', '.', '2', '3' }, bytes); 309 | } 310 | 311 | @Test 312 | void putSmallNegativeFixedRight() { 313 | byte[] bytes = new byte[5]; 314 | 315 | ASCII.putFixedRight(bytes, -1, 2); 316 | 317 | assertArrayEquals(new byte[] { '-', '0', '.', '0', '1' }, bytes); 318 | } 319 | 320 | @Test 321 | void putTooLongFixedRight() { 322 | byte[] bytes = new byte[5]; 323 | 324 | assertThrows(IndexOutOfBoundsException.class, () -> ASCII.putFixedRight(bytes, 123456, 2)); 325 | } 326 | 327 | @Test 328 | void packShort() { 329 | assertEquals(0x666f, ASCII.packShort("foo")); 330 | } 331 | 332 | @Test 333 | void packInt() { 334 | assertEquals(0x666f6f20, ASCII.packInt("foo")); 335 | } 336 | 337 | @Test 338 | void packLong() { 339 | assertEquals(0x666f6f2020202020L, ASCII.packLong("foo")); 340 | } 341 | 342 | @Test 343 | void unpackShort() { 344 | assertEquals("fo", ASCII.unpackShort((short)0x666f)); 345 | } 346 | 347 | @Test 348 | void unpackShortWithStringBuilder() { 349 | StringBuilder b = new StringBuilder(); 350 | 351 | ASCII.unpackShort((short)0x666f, b); 352 | 353 | assertEquals("fo", b.toString()); 354 | } 355 | 356 | @Test 357 | void unpackInt() { 358 | assertEquals("foo ", ASCII.unpackInt(0x666f6f20)); 359 | } 360 | 361 | @Test 362 | void unpackIntWithStringBuilder() { 363 | StringBuilder b = new StringBuilder(); 364 | 365 | ASCII.unpackInt(0x666f6f20, b); 366 | 367 | assertEquals("foo ", b.toString()); 368 | } 369 | 370 | @Test 371 | void unpackLong() { 372 | assertEquals("foo ", ASCII.unpackLong(0x666f6f2020202020L)); 373 | } 374 | 375 | @Test 376 | void unpackLongWithStringBuilder() { 377 | StringBuilder b = new StringBuilder(); 378 | 379 | ASCII.unpackLong(0x666f6f2020202020L, b); 380 | 381 | assertEquals("foo ", b.toString()); 382 | } 383 | 384 | } 385 | -------------------------------------------------------------------------------- /LICENSE.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 {yyyy} {name of copyright owner} 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. 202 | -------------------------------------------------------------------------------- /src/main/java/com/paritytrading/foundation/ASCII.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Foundation authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.paritytrading.foundation; 17 | 18 | import static com.paritytrading.foundation.Longs.POWERS_OF_TEN; 19 | import static java.nio.charset.StandardCharsets.US_ASCII; 20 | 21 | /** 22 | * This class contains methods for manipulating ASCII strings. 23 | */ 24 | public class ASCII { 25 | 26 | private ASCII() { 27 | } 28 | 29 | /** 30 | * Get an ASCII string from a byte array. 31 | * 32 | * @param bytes a byte array 33 | * @return a string 34 | */ 35 | public static String get(byte[] bytes) { 36 | return new String(bytes, US_ASCII); 37 | } 38 | 39 | /** 40 | * Get an ASCII string from a byte array. 41 | * 42 | * @param bytes a byte array 43 | * @param b a string builder 44 | */ 45 | public static void get(byte[] bytes, StringBuilder b) { 46 | for (int i = 0; i < bytes.length; i++) 47 | b.append((char)bytes[i]); 48 | } 49 | 50 | /** 51 | * Put an ASCII string into a byte array. 52 | * 53 | * @param s a string 54 | * @return a byte array 55 | */ 56 | public static byte[] put(String s) { 57 | return s.getBytes(US_ASCII); 58 | } 59 | 60 | /** 61 | * Put an ASCII string into a byte array. 62 | * 63 | *

If the length of the string is smaller than the length of the array, 64 | * the space character is used to fill the trailing bytes.

65 | * 66 | * @param bytes a byte array 67 | * @param s a string 68 | * @throws IndexOutOfBoundsException if the length of the string is larger 69 | * than the length of the array 70 | */ 71 | public static void putLeft(byte[] bytes, CharSequence s) { 72 | int i = 0; 73 | 74 | for (; i < s.length(); i++) 75 | bytes[i] = (byte)s.charAt(i); 76 | 77 | for (; i < bytes.length; i++) 78 | bytes[i] = (byte)' '; 79 | } 80 | 81 | /** 82 | * Put an ASCII string into a byte array. 83 | * 84 | *

If the length of the string is smaller than the length of the array, 85 | * the space character is used to fill the leading bytes.

86 | * 87 | * @param bytes a byte array 88 | * @param s a string 89 | * @throws IndexOutOfBoundsException if the length of the string is larger 90 | * than the length of the array 91 | */ 92 | public static void putRight(byte[] bytes, CharSequence s) { 93 | int i = 0; 94 | 95 | for (; i < bytes.length - s.length(); i++) 96 | bytes[i] = (byte)' '; 97 | 98 | for (int j = 0; j < s.length(); i++, j++) 99 | bytes[i] = (byte)s.charAt(j); 100 | } 101 | 102 | /** 103 | * Get an integer formatted as an ASCII string from a byte array. 104 | * 105 | * @param bytes a byte array 106 | * @return an integer 107 | */ 108 | public static long getLong(byte[] bytes) { 109 | long sign = +1; 110 | 111 | int i = 0; 112 | 113 | while (bytes[i] == ' ') 114 | i++; 115 | 116 | if (bytes[i] == '-') { 117 | sign = -1; 118 | 119 | i++; 120 | } 121 | 122 | long l = 0; 123 | 124 | while (i < bytes.length && bytes[i] != ' ') 125 | l = 10 * l + bytes[i++] - '0'; 126 | 127 | return sign * l; 128 | } 129 | 130 | /** 131 | * Put an integer formatted as an ASCII string into a byte array. 132 | * 133 | *

If the length of the string is smaller than the length of the array, 134 | * the space character is used to fill the trailing bytes.

135 | * 136 | * @param bytes a byte array 137 | * @param l an integer 138 | * @throws IndexOutOfBoundsException if the length of the string is larger 139 | * than the length of the array 140 | */ 141 | public static void putLongLeft(byte[] bytes, long l) { 142 | long sign = l; 143 | 144 | if (sign < 0) 145 | l = -l; 146 | 147 | int i = 0; 148 | 149 | do { 150 | bytes[i++] = (byte)('0' + l % 10); 151 | 152 | l /= 10; 153 | } while (l > 0); 154 | 155 | if (sign < 0) 156 | bytes[i++] = '-'; 157 | 158 | ByteArrays.reverse(bytes, 0, i); 159 | 160 | for (; i < bytes.length; i++) 161 | bytes[i] = ' '; 162 | } 163 | 164 | /** 165 | * Put an integer formatted as an ASCII string into a byte array. 166 | * 167 | *

If the length of the string is smaller than the length of the array, 168 | * the space character is used to fill the leading bytes.

169 | * 170 | * @param bytes a byte array 171 | * @param l an integer 172 | * @throws IndexOutOfBoundsException if the length of the string is larger 173 | * than the length of the array 174 | */ 175 | public static void putLongRight(byte[] bytes, long l) { 176 | long sign = l; 177 | 178 | if (sign < 0) 179 | l = -l; 180 | 181 | int i = bytes.length - 1; 182 | 183 | do { 184 | bytes[i--] = (byte)('0' + l % 10); 185 | 186 | l /= 10; 187 | } while (l > 0); 188 | 189 | if (sign < 0) 190 | bytes[i--] = '-'; 191 | 192 | for (; i >= 0; i--) 193 | bytes[i] = ' '; 194 | } 195 | 196 | /** 197 | * Get a decimal number formatted as an ASCII string from a byte array in 198 | * a fixed-point representation. 199 | * 200 | * @param bytes a byte array 201 | * @param decimals the number of decimal digits in the fixed-point 202 | * representation 203 | * @return a decimal number 204 | */ 205 | public static long getFixed(byte[] bytes, int decimals) { 206 | long sign = +1; 207 | 208 | int i = 0; 209 | 210 | while (bytes[i] == ' ') 211 | i++; 212 | 213 | if (bytes[i] == '-') { 214 | sign = -1; 215 | 216 | i++; 217 | } 218 | 219 | long f = 0; 220 | 221 | while (i < bytes.length && bytes[i] != '.' && bytes[i] != ' ') 222 | f = 10 * f + bytes[i++] - '0'; 223 | 224 | if (i == bytes.length || bytes[i] != '.') 225 | return sign * f * POWERS_OF_TEN[decimals]; 226 | 227 | int point = i++; 228 | 229 | while (i < bytes.length && bytes[i] != ' ') 230 | f = 10 * f + bytes[i++] - '0'; 231 | 232 | int count = i - point - 1; 233 | 234 | if (count > decimals) 235 | return sign * f / POWERS_OF_TEN[count - decimals]; 236 | else 237 | return sign * f * POWERS_OF_TEN[decimals - count]; 238 | } 239 | 240 | /** 241 | * Put a decimal number formatted as an ASCII string into a byte array 242 | * from a fixed-point representation. 243 | * 244 | *

If the length of the string is smaller than the length of the byte 245 | * array, the space character is used to fill the trailing bytes.

246 | * 247 | * @param bytes a byte array 248 | * @param f a decimal number 249 | * @param decimals the number of decimal digits in the fixed-point 250 | * representation 251 | * @throws IndexOutOfBoundsException if the length of the string is larger 252 | * than the length of the array 253 | */ 254 | public static void putFixedLeft(byte[] bytes, long f, int decimals) { 255 | long sign = f; 256 | 257 | if (sign < 0) 258 | f = -f; 259 | 260 | int i = 0; 261 | 262 | do { 263 | bytes[i++] = (byte)('0' + f % 10); 264 | 265 | f /= 10; 266 | } while (i < decimals); 267 | 268 | bytes[i++] = '.'; 269 | 270 | do { 271 | bytes[i++] = (byte)('0' + f % 10); 272 | 273 | f /= 10; 274 | } while (f > 0); 275 | 276 | if (sign < 0) 277 | bytes[i++] = '-'; 278 | 279 | ByteArrays.reverse(bytes, 0, i); 280 | 281 | for (; i < bytes.length; i++) 282 | bytes[i] = ' '; 283 | } 284 | 285 | /** 286 | * Put a decimal number formatted as an ASCII string into a byte array 287 | * from a fixed-point representation. 288 | * 289 | *

If the length of the string is smaller than the length of the byte 290 | * array, the space character is used to fill the leading bytes.

291 | * 292 | * @param bytes a byte array 293 | * @param f a decimal number 294 | * @param decimals the number of decimal digits in the fixed-point 295 | * representation 296 | * @throws IndexOutOfBoundsException if the length of the string is larger 297 | * than the length of the array 298 | */ 299 | public static void putFixedRight(byte[] bytes, long f, int decimals) { 300 | long sign = f; 301 | 302 | if (sign < 0) 303 | f = -f; 304 | 305 | int i = bytes.length - 1; 306 | 307 | do { 308 | bytes[i--] = (byte)('0' + f % 10); 309 | 310 | f /= 10; 311 | } while (bytes.length - 1 - i < decimals); 312 | 313 | bytes[i--] = '.'; 314 | 315 | do { 316 | bytes[i--] = (byte)('0' + f % 10); 317 | 318 | f /= 10; 319 | } while (f > 0); 320 | 321 | if (sign < 0) 322 | bytes[i--] = '-'; 323 | 324 | for (; i >= 0; i--) 325 | bytes[i] = ' '; 326 | } 327 | 328 | /** 329 | * Pack an ASCII string into a short. 330 | * 331 | *

If the length of the string is less than two characters, the space 332 | * character is used to fill the least significant bits.

333 | * 334 | *

If the length of the string is more than two characters, only the 335 | * first two characters are packed.

336 | * 337 | * @param s a string 338 | * @return a short 339 | */ 340 | public static short packShort(CharSequence s) { 341 | return (short)pack(s, 2); 342 | } 343 | 344 | /** 345 | * Pack an ASCII string into an integer. 346 | * 347 | *

If the length of the string is less than four characters, the space 348 | * character is used to fill the least significant bits.

349 | * 350 | *

If the length of the string is more than four characters, only the 351 | * first four characters are packed.

352 | * 353 | * @param s a string 354 | * @return an integer 355 | */ 356 | public static int packInt(CharSequence s) { 357 | return (int)pack(s, 4); 358 | } 359 | 360 | /** 361 | * Pack an ASCII string into a long. 362 | * 363 | *

If the length of the string is less than eight characters, the space 364 | * character is used to fill the least significant bits.

365 | * 366 | *

If the length of the string is more than eight characters, only the 367 | * first eight characters are packed.

368 | * 369 | * @param s a string 370 | * @return a long 371 | */ 372 | public static long packLong(CharSequence s) { 373 | return pack(s, 8); 374 | } 375 | 376 | private static long pack(CharSequence s, int size) { 377 | long l = 0; 378 | int i = 0; 379 | 380 | for (; i < Math.min(s.length(), size); i++) 381 | l = (l << 8) | (byte)s.charAt(i); 382 | 383 | for (; i < size; i++) 384 | l = (l << 8) | (byte)' '; 385 | 386 | return l; 387 | } 388 | 389 | /** 390 | * Unpack a short into an ASCII string. 391 | * 392 | * @param s a short 393 | * @param b a string builder 394 | */ 395 | public static void unpackShort(short s, StringBuilder b) { 396 | unpack(s, 2, b); 397 | } 398 | 399 | /** 400 | * Unpack a short into an ASCII string. 401 | * 402 | * @param s a short 403 | * @return a string 404 | */ 405 | public static String unpackShort(short s) { 406 | return unpack(s, 2); 407 | } 408 | 409 | /** 410 | * Unpack an integer into an ASCII string. 411 | * 412 | * @param i an integer 413 | * @param b a string builder 414 | */ 415 | public static void unpackInt(int i, StringBuilder b) { 416 | unpack(i, 4, b); 417 | } 418 | 419 | /** 420 | * Unpack an integer into an ASCII string. 421 | * 422 | * @param i an integer 423 | * @return a string 424 | */ 425 | public static String unpackInt(int i) { 426 | return unpack(i, 4); 427 | } 428 | 429 | /** 430 | * Unpack a long into an ASCII string. 431 | * 432 | * @param l a long 433 | * @param b a string builder 434 | */ 435 | public static void unpackLong(long l, StringBuilder b) { 436 | unpack(l, 8, b); 437 | } 438 | 439 | /** 440 | * Unpack a long into an ASCII string. 441 | * 442 | * @param l a long 443 | * @return a string 444 | */ 445 | public static String unpackLong(long l) { 446 | return unpack(l, 8); 447 | } 448 | 449 | private static void unpack(long l, int size, StringBuilder b) { 450 | for (int i = 0; i < size; i++) 451 | b.append((char)((l >> (8 * (size - 1 - i))) & 0xFF)); 452 | } 453 | 454 | private static String unpack(long l, int size) { 455 | StringBuilder b = new StringBuilder(size); 456 | 457 | unpack(l, size, b); 458 | 459 | return b.toString(); 460 | } 461 | 462 | } 463 | --------------------------------------------------------------------------------