Compare commits
4 Commits
ed5d2d2f74
...
3bf845f355
Author | SHA1 | Date |
---|---|---|
Robinson | 3bf845f355 | |
Robinson | 0ff5f377d1 | |
Robinson | 5fa2e2aff6 | |
Robinson | db0be638b4 |
7
LICENSE
7
LICENSE
|
@ -21,13 +21,6 @@
|
|||
Lightweight Java Game Library Project
|
||||
Riven
|
||||
|
||||
- Modified hex conversion utility methods -
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/Utilities
|
||||
https://netty.io
|
||||
Copyright 2014
|
||||
The Netty Project
|
||||
|
||||
- Retrofit - A type-safe HTTP client for Android and Java
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://github.com/square/retrofit
|
||||
|
|
|
@ -17,7 +17,7 @@ Maven Info
|
|||
<dependency>
|
||||
<groupId>com.dorkbox</groupId>
|
||||
<artifactId>Utilities</artifactId>
|
||||
<version>1.45</version>
|
||||
<version>1.46</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
@ -27,7 +27,7 @@ Gradle Info
|
|||
```
|
||||
dependencies {
|
||||
...
|
||||
compile "com.dorkbox:Utilities:1.45"
|
||||
compile "com.dorkbox:Utilities:1.46"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS // always show th
|
|||
|
||||
plugins {
|
||||
id("com.dorkbox.GradleUtils") version "3.17"
|
||||
id("com.dorkbox.Licensing") version "2.24"
|
||||
id("com.dorkbox.Licensing") version "2.26"
|
||||
id("com.dorkbox.VersionUpdate") version "2.8"
|
||||
id("com.dorkbox.GradlePublish") version "1.18"
|
||||
|
||||
|
@ -35,7 +35,7 @@ object Extras {
|
|||
// set for the project
|
||||
const val description = "Utilities for use within Java projects"
|
||||
const val group = "com.dorkbox"
|
||||
const val version = "1.45"
|
||||
const val version = "1.46"
|
||||
|
||||
// set as project.ext
|
||||
const val name = "Utilities"
|
||||
|
@ -75,12 +75,6 @@ licensing {
|
|||
author("Riven")
|
||||
}
|
||||
|
||||
extra("Modified hex conversion utility methods", License.APACHE_2) {
|
||||
url(Extras.url)
|
||||
url("https://netty.io")
|
||||
copyright(2014)
|
||||
author("The Netty Project")
|
||||
}
|
||||
extra("Retrofit", License.APACHE_2) {
|
||||
copyright(2020)
|
||||
description("A type-safe HTTP client for Android and Java")
|
||||
|
@ -142,8 +136,6 @@ dependencies {
|
|||
// api("org.slf4j:slf4j-api:2.0.7")
|
||||
|
||||
|
||||
compileOnly("com.fasterxml.uuid:java-uuid-generator:4.1.0")
|
||||
|
||||
// api "com.koloboke:koloboke-api-jdk8:1.0.0"
|
||||
// runtime "com.koloboke:koloboke-impl-jdk8:1.0.0"
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
@ -80,10 +80,10 @@ do
|
|||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
@ -143,12 +143,16 @@ fi
|
|||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
|
|
|
@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal
|
|||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package dorkbox.util
|
||||
|
||||
import dorkbox.os.OS.LINE_SEPARATOR
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
@ -27,7 +26,7 @@ object Sys {
|
|||
/**
|
||||
* Gets the version number.
|
||||
*/
|
||||
val version = "1.45"
|
||||
val version = "1.46"
|
||||
|
||||
init {
|
||||
// Add this project to the updates system, which verifies this class + UUID + version information
|
||||
|
@ -39,52 +38,7 @@ object Sys {
|
|||
const val MEGABYTE = 1024 * KILOBYTE
|
||||
const val GIGABYTE = 1024 * MEGABYTE
|
||||
const val TERABYTE = 1024L * GIGABYTE
|
||||
val HEX_CHARS = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
|
||||
|
||||
fun convertStringToChars(string: String): CharArray {
|
||||
val charArray = string.toCharArray()
|
||||
eraseString(string)
|
||||
return charArray
|
||||
}
|
||||
|
||||
fun eraseString(string: String?) {
|
||||
// You can change the value of the inner char[] using reflection.
|
||||
//
|
||||
// You must be careful to either change it with an array of the same length,
|
||||
// or to also update the count field.
|
||||
//
|
||||
// If you want to be able to use it as an entry in a set or as a value in map,
|
||||
// you will need to recalculate the hash code and set the value of the hashCode field.
|
||||
try {
|
||||
val valueField = String::class.java.getDeclaredField("value")
|
||||
valueField.isAccessible = true
|
||||
val chars = valueField[string] as CharArray
|
||||
Arrays.fill(chars, '*') // asterisk it out in case of GC not picking up the old char array.
|
||||
valueField[string] = CharArray(0) // replace it.
|
||||
|
||||
// set count to 0
|
||||
try {
|
||||
// newer versions of java don't have this field
|
||||
val countField = String::class.java.getDeclaredField("count")
|
||||
countField.isAccessible = true
|
||||
countField[string] = 0
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
// set hash to 0
|
||||
val hashField = String::class.java.getDeclaredField("hash")
|
||||
hashField.isAccessible = true
|
||||
hashField[string] = 0
|
||||
} catch (e: SecurityException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM: https://www.cqse.eu/en/blog/string-replace-performance/
|
||||
|
@ -245,6 +199,7 @@ object Sys {
|
|||
*
|
||||
* @return "" if there is no extension
|
||||
*/
|
||||
@Deprecated("Use kotlin")
|
||||
fun getExtension(fileName: String): String {
|
||||
val dot = fileName.lastIndexOf('.')
|
||||
return if (dot > -1) {
|
||||
|
@ -254,10 +209,10 @@ object Sys {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the contents of the input stream to a byte array.
|
||||
*/
|
||||
@Deprecated("Use kotlin")
|
||||
@Throws(IOException::class)
|
||||
fun getBytesFromStream(inputStream: InputStream): ByteArray {
|
||||
val baos = ByteArrayOutputStream(8192)
|
||||
|
@ -271,6 +226,7 @@ object Sys {
|
|||
return baos.toByteArray()
|
||||
}
|
||||
|
||||
@Deprecated("Use kotlin")
|
||||
@JvmOverloads
|
||||
fun copyBytes(src: ByteArray, position: Int = 0): ByteArray {
|
||||
val length = src.size - position
|
||||
|
@ -279,6 +235,7 @@ object Sys {
|
|||
return b
|
||||
}
|
||||
|
||||
@Deprecated("Use kotlin")
|
||||
fun concatBytes(vararg arrayBytes: ByteArray): ByteArray {
|
||||
var length = 0
|
||||
for (bytes in arrayBytes) {
|
||||
|
@ -292,272 +249,46 @@ object Sys {
|
|||
}
|
||||
return concatBytes
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun bytesToHex(bytes: ByteArray, startPosition: Int = 0, length: Int = bytes.size, padding: Boolean = false): String {
|
||||
val endPosition = startPosition + length
|
||||
return if (padding) {
|
||||
val hexString = CharArray(3 * length)
|
||||
var j = 0
|
||||
for (i in startPosition until endPosition) {
|
||||
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0xF0 shr 4]
|
||||
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0x0F]
|
||||
hexString[j++] = ' '
|
||||
}
|
||||
String(hexString)
|
||||
} else {
|
||||
val hexString = CharArray(2 * length)
|
||||
var j = 0
|
||||
for (i in startPosition until endPosition) {
|
||||
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0xF0 shr 4]
|
||||
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0x0F]
|
||||
}
|
||||
String(hexString)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an ASCII character representing a hexadecimal
|
||||
* value into its integer equivalent.
|
||||
*/
|
||||
fun hexByteToInt(b: Byte): Int {
|
||||
return when (b.toInt()) {
|
||||
'0'.code -> 0
|
||||
'1'.code -> 1
|
||||
'2'.code -> 2
|
||||
'3'.code -> 3
|
||||
'4'.code -> 4
|
||||
'5'.code -> 5
|
||||
'6'.code -> 6
|
||||
'7'.code -> 7
|
||||
'8'.code -> 8
|
||||
'9'.code -> 9
|
||||
'A'.code, 'a'.code -> 10
|
||||
'B'.code, 'b'.code -> 11
|
||||
'C'.code, 'c'.code -> 12
|
||||
'D'.code, 'd'.code -> 13
|
||||
'E'.code, 'e'.code -> 14
|
||||
'F'.code, 'f'.code -> 15
|
||||
else -> throw IllegalArgumentException("Error decoding byte")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an ASCII character representing a hexadecimal
|
||||
* value into its integer equivalent.
|
||||
*/
|
||||
fun hexCharToInt(b: Char): Int {
|
||||
return when (b) {
|
||||
'0' -> 0
|
||||
'1' -> 1
|
||||
'2' -> 2
|
||||
'3' -> 3
|
||||
'4' -> 4
|
||||
'5' -> 5
|
||||
'6' -> 6
|
||||
'7' -> 7
|
||||
'8' -> 8
|
||||
'9' -> 9
|
||||
'A', 'a' -> 10
|
||||
'B', 'b' -> 11
|
||||
'C', 'c' -> 12
|
||||
'D', 'd' -> 13
|
||||
'E', 'e' -> 14
|
||||
'F', 'f' -> 15
|
||||
else -> throw IllegalArgumentException("Error decoding byte")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A 4-digit hex result.
|
||||
*/
|
||||
fun hex4(c: Char, sb: StringBuilder) {
|
||||
sb.append(HEX_CHARS[c.code and 0xF000 shr 12])
|
||||
sb.append(HEX_CHARS[c.code and 0x0F00 shr 8])
|
||||
sb.append(HEX_CHARS[c.code and 0x00F0 shr 4])
|
||||
sb.append(HEX_CHARS[c.code and 0x000F])
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the byte array as a series of
|
||||
* hexadecimal characters.
|
||||
*
|
||||
* @param bytes byte array to convert
|
||||
* @return a string representation of the byte array as a series of
|
||||
* hexadecimal characters
|
||||
*/
|
||||
fun toHexString(bytes: ByteArray): String {
|
||||
val hexString = CharArray(2 * bytes.size)
|
||||
var j = 0
|
||||
for (i in bytes.indices) {
|
||||
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0xF0 shr 4]
|
||||
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0x0F]
|
||||
}
|
||||
return String(hexString)
|
||||
}
|
||||
|
||||
/**
|
||||
* from netty 4.1, apache 2.0, https://netty.io
|
||||
*/
|
||||
fun hexToByte(s: CharSequence, pos: Int): Byte {
|
||||
val hi = hexCharToInt(s[pos])
|
||||
val lo = hexCharToInt(s[pos + 1])
|
||||
require(!(hi == -1 || lo == -1)) {
|
||||
String.format(
|
||||
"invalid hex byte '%s' at index %d of '%s'", s.subSequence(pos, pos + 2), pos, s
|
||||
)
|
||||
}
|
||||
return ((hi shl 4) + lo).toByte()
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a string with [hex dump](http://en.wikipedia.org/wiki/Hex_dump)
|
||||
*
|
||||
* @param hex a [CharSequence] which contains the hex dump
|
||||
*/
|
||||
fun hexToBytes(hex: CharSequence): ByteArray {
|
||||
return hexToBytes(hex, 0, hex.length)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes part of a string with [hex dump](http://en.wikipedia.org/wiki/Hex_dump)
|
||||
*
|
||||
* from netty 4.1, apache 2.0, https://netty.io
|
||||
*
|
||||
* @param hexDump a [CharSequence] which contains the hex dump
|
||||
* @param fromIndex start of hex dump in `hexDump`
|
||||
* @param length hex string length
|
||||
*/
|
||||
fun hexToBytes(hexDump: CharSequence, fromIndex: Int, length: Int): ByteArray {
|
||||
require(!(length < 0 || length and 1 != 0)) { "length: $length" }
|
||||
if (length == 0) {
|
||||
return ByteArray(0)
|
||||
}
|
||||
val bytes = ByteArray(length ushr 1)
|
||||
var i = 0
|
||||
while (i < length) {
|
||||
bytes[i ushr 1] = hexToByte(hexDump, fromIndex + i)
|
||||
i += 2
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun encodeStringArray(array: List<String>): ByteArray {
|
||||
var length = 0
|
||||
for (s in array) {
|
||||
val bytes = s.toByteArray()
|
||||
length += bytes.size
|
||||
}
|
||||
if (length == 0) {
|
||||
return ByteArray(0)
|
||||
}
|
||||
val bytes = ByteArray(length + array.size)
|
||||
length = 0
|
||||
for (s in array) {
|
||||
val sBytes = s.toByteArray()
|
||||
System.arraycopy(sBytes, 0, bytes, length, sBytes.size)
|
||||
length += sBytes.size
|
||||
bytes[length++] = 0x01.toByte()
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
fun decodeStringArray(bytes: ByteArray): ArrayList<String> {
|
||||
val length = bytes.size
|
||||
var position = 0
|
||||
val token = 0x01.toByte()
|
||||
val list = ArrayList<String>(0)
|
||||
var last = 0
|
||||
while (last + position < length) {
|
||||
val b = bytes[last + position++]
|
||||
if (b == token) {
|
||||
val xx = ByteArray(position - 1)
|
||||
System.arraycopy(bytes, last, xx, 0, position - 1)
|
||||
list.add(String(xx))
|
||||
last += position
|
||||
position = 0
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun printArrayRaw(bytes: ByteArray, lineLength: Int = 0): String {
|
||||
return if (lineLength > 0) {
|
||||
val length = bytes.size
|
||||
val comma = length - 1
|
||||
val builder = StringBuilder(length + length / lineLength)
|
||||
for (i in 0 until length) {
|
||||
builder.append(bytes[i].toInt())
|
||||
if (i < comma) {
|
||||
builder.append(",")
|
||||
}
|
||||
if (i > 0 && i % lineLength == 0) {
|
||||
builder.append(LINE_SEPARATOR)
|
||||
}
|
||||
}
|
||||
builder.toString()
|
||||
} else {
|
||||
val length = bytes.size
|
||||
val comma = length - 1
|
||||
val builder = StringBuilder(length + length)
|
||||
for (i in 0 until length) {
|
||||
builder.append(bytes[i].toInt())
|
||||
if (i < comma) {
|
||||
builder.append(",")
|
||||
}
|
||||
}
|
||||
builder.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun printArray(bytes: ByteArray, length: Int = bytes.size, includeByteCount: Boolean = true) {
|
||||
printArray(bytes, 0, length, includeByteCount, 40, null)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun printArray(
|
||||
bytes: ByteArray,
|
||||
inputOffset: Int,
|
||||
length: Int,
|
||||
includeByteCount: Boolean,
|
||||
lineLength: Int = 40,
|
||||
header: String? = null
|
||||
) {
|
||||
val comma = length - 1
|
||||
var builderLength = length + comma + 2
|
||||
if (includeByteCount) {
|
||||
builderLength += 7 + Integer.toString(length).length
|
||||
}
|
||||
if (lineLength > 0) {
|
||||
builderLength += length / lineLength
|
||||
}
|
||||
if (header != null) {
|
||||
builderLength += header.length + 2
|
||||
}
|
||||
val builder = StringBuilder(builderLength)
|
||||
if (header != null) {
|
||||
builder.append(header).append(LINE_SEPARATOR)
|
||||
}
|
||||
if (includeByteCount) {
|
||||
builder.append("Bytes: ").append(length).append(LINE_SEPARATOR)
|
||||
}
|
||||
builder.append("{")
|
||||
for (i in inputOffset until length) {
|
||||
builder.append(bytes[i].toInt())
|
||||
if (i < comma) {
|
||||
builder.append(",")
|
||||
}
|
||||
if (i > inputOffset && lineLength > 0 && i % lineLength == 0) {
|
||||
builder.append(LINE_SEPARATOR)
|
||||
}
|
||||
}
|
||||
builder.append("}")
|
||||
System.err.println(builder.toString())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase the contents of a string, in-memory. This has no effect if the string has been interned.
|
||||
*/
|
||||
fun String.eraseString() {
|
||||
// You can change the value of the inner char[] using reflection.
|
||||
//
|
||||
// You must be careful to either change it with an array of the same length,
|
||||
// or to also update the count field.
|
||||
//
|
||||
// If you want to be able to use it as an entry in a set or as a value in map,
|
||||
// you will need to recalculate the hash code and set the value of the hashCode field.
|
||||
try {
|
||||
val valueField = String::class.java.getDeclaredField("value")
|
||||
valueField.isAccessible = true
|
||||
val chars = valueField[this] as CharArray
|
||||
Arrays.fill(chars, '*') // asterisk it out in case of GC not picking up the old char array.
|
||||
valueField[this] = CharArray(0) // replace it.
|
||||
|
||||
// set count to 0
|
||||
try {
|
||||
// newer versions of java don't have this field
|
||||
val countField = String::class.java.getDeclaredField("count")
|
||||
countField.isAccessible = true
|
||||
countField[this] = 0
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
// set hash to 0
|
||||
val hashField = String::class.java.getDeclaredField("hash")
|
||||
hashField.isAccessible = true
|
||||
hashField[this] = 0
|
||||
} catch (e: SecurityException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue