StringUtil.java
/*******************************************************************************
* Copyhacked (H) 2012-2025.
* This program and the accompanying materials
* are made available under no term at all, use it like
* you want, but share and discuss it
* every time possible with every body.
*
* Contributors:
* ron190 at ymail dot com - initial implementation
******************************************************************************/
package com.jsql.util;
import com.jsql.util.bruter.Base16;
import com.jsql.util.bruter.Base58;
import org.apache.commons.codec.binary.Base32;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mozilla.universalchardet.UniversalDetector;
import java.awt.*;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterOutputStream;
/**
* Utility class adding String operations like join() which are not
* part of standard JVM.
*/
public final class StringUtil {
/**
* Log4j logger sent to view.
*/
private static final Logger LOGGER = LogManager.getRootLogger();
// Define the schema of conversion to html entities
private static final CharEncoder DECIMAL_HTML_ENCODER = new CharEncoder("&#", ";", 10);
public static final String GET = "GET";
public static final String POST = "POST";
public static final String INFORMATION_SCHEMA = "information_schema";
public static final String APP_NAME = "jSQL Injection";
/**
* This utility class defines a schema used to encode a text into a specialized
* representation
*/
private static class CharEncoder {
private final String prefix;
private final String suffix;
private final int radix;
public CharEncoder(String prefix, String suffix, int radix) {
this.prefix = prefix;
this.suffix = suffix;
this.radix = radix;
}
protected void encode(char c, StringBuilder buff) {
buff
.append(this.prefix)
.append(Integer.toString(c, this.radix))
.append(this.suffix);
}
}
private StringUtil() {
// Utility class
}
/**
* Convert special characters like Chinese and Arabic letters to the corresponding html entities.
* @param text string to encode
* @return string encoded in html entities
*/
public static String toHtmlDecimal(String text) {
return StringUtil.encode(text);
}
/**
* Non-trivial methods to convert unicode characters to html entities.
* @param text string to encode
* @return string representation using the encoder schema
*/
private static String encode(String text) {
var buff = new StringBuilder();
for (var i = 0 ; i < text.length() ; i++) {
if (text.charAt(i) > 128) {
StringUtil.DECIMAL_HTML_ENCODER.encode(text.charAt(i), buff);
} else {
buff.append(text.charAt(i));
}
}
return buff.toString();
}
/**
* Convert a hexadecimal String to String.
* @param hex Hexadecimal String to convert
* @return The string converted from hex
*/
public static String hexstr(String hex) {
var bytes = new byte[hex.length() / 2];
for (var i = 0 ; i < bytes.length ; i++) {
bytes[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
}
return new String(bytes, StandardCharsets.UTF_8);
}
public static boolean isUtf8(String text) {
if (text == null) {
return false;
}
var detector = new UniversalDetector(null);
detector.handleData(text.getBytes(StandardCharsets.UTF_8), 0, text.length() - 1);
detector.dataEnd();
String encoding = detector.getDetectedCharset();
return encoding != null;
}
public static String detectUtf8(String text) {
if (text == null) {
return StringUtils.EMPTY;
}
String encoding = null;
// ArrayIndexOutOfBoundsException on handleData()
try {
var detector = new UniversalDetector(null);
detector.handleData(text.getBytes(StandardCharsets.UTF_8), 0, text.length() - 1);
detector.dataEnd();
encoding = detector.getDetectedCharset();
} catch (ArrayIndexOutOfBoundsException e) {
LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
}
String result = text;
if (encoding != null) {
result = new String(text.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
}
return result;
}
public static String base32Encode(String s) {
var base32 = new Base32();
return base32.encodeToString(StringUtil.getBytesUtf8(s));
}
public static String base32Decode(String s) {
var base32 = new Base32();
return StringUtil.newStringUtf8(base32.decode(s));
}
public static String base58Encode(String s) {
return Base58.encode(StringUtil.getBytesUtf8(s));
}
public static String base58Decode(String s) {
return StringUtil.newStringUtf8(Base58.decode(s));
}
public static String base16Encode(String s) {
var base16 = new Base16();
return base16.encodeToString(StringUtil.getBytesUtf8(s));
}
public static String base16Decode(String s) {
var base16 = new Base16();
return StringUtil.newStringUtf8(base16.decode(s));
}
public static String base64Decode(String s) {
return StringUtil.newStringUtf8(Base64.getDecoder().decode(s));
}
public static String base64Encode(String s) {
return Base64.getEncoder().encodeToString(StringUtil.getBytesUtf8(s));
}
public static String toHex(String text) {
return StringUtil.encodeHexString(text.getBytes(StandardCharsets.UTF_8));
}
public static String fromHex(String text) {
byte[] hex = StringUtil.decodeHexString(text);
return new String(hex, StandardCharsets.UTF_8);
}
public static String toHexZip(String text) throws IOException {
byte[] zip = StringUtil.compress(text);
return StringUtil.encodeHexString(zip);
}
public static String fromHexZip(String text) throws IOException {
return new String(StringUtil.decompress(StringUtil.decodeHexString(text)), StandardCharsets.UTF_8);
}
public static String toBase64Zip(String text) throws IOException {
return new String(Base64.getEncoder().encode(StringUtil.compress(text)));
}
public static String fromBase64Zip(String text) throws IOException {
byte[] decompressedBArray = StringUtil.decompress(Base64.getDecoder().decode(text));
return new String(decompressedBArray, StandardCharsets.UTF_8);
}
public static String toHtml(String text) {
return StringEscapeUtils.escapeHtml4(text);
}
public static String fromHtml(String text) {
return StringEscapeUtils.unescapeHtml4(text);
}
public static String toUrl(String text) {
return URLEncoder.encode(text, StandardCharsets.UTF_8);
}
public static String fromUrl(String text) {
return URLDecoder.decode(text, StandardCharsets.UTF_8);
}
public static String cleanSql(String query) {
return StringUtil.removeSqlComment(query)
.replaceAll("(?s)([^\\s\\w])(\\s+)", "$1") // Remove spaces after a word
.replaceAll("(?s)(\\s+)([^\\s\\w])", "$2") // Remove spaces before a word
.replaceAll("(?s)\\s+", " ") // Replace spaces
.trim();
}
/**
* Remove SQL comments except tamper /**\/ /*!...*\/
* Negative lookahead: don't match tamper empty comment /**\/ or version comment /*!...*\/
* JavaScript: (?!\/\*!.*\*\/|\/\*\*\/)\/\*.*\*\/
*/
public static String removeSqlComment(String query) {
return query.replaceAll(
"(?s)(?!/\\*\\*/|/\\*!.*\\*/)/\\*.*?\\*/",
StringUtils.EMPTY
);
}
public static String formatReport(Color color, String text) {
return String.format(
"<span style=color:rgb(%s,%s,%s)>%s</span>",
color.getRed(),
color.getGreen(),
color.getBlue(),
text
);
}
// Utils
private static byte[] compress(String text) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try (DeflaterOutputStream dos = new DeflaterOutputStream(os)) {
dos.write(text.getBytes());
}
return os.toByteArray();
}
private static byte[] decompress(byte[] compressedTxt) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try (OutputStream ios = new InflaterOutputStream(os)) {
ios.write(compressedTxt);
}
return os.toByteArray();
}
private static byte hexToByte(String hexString) {
int firstDigit = StringUtil.toDigit(hexString.charAt(0));
int secondDigit = StringUtil.toDigit(hexString.charAt(1));
return (byte) ((firstDigit << 4) + secondDigit);
}
private static int toDigit(char hexChar) {
int digit = Character.digit(hexChar, 16);
if (digit == -1) {
throw new IllegalArgumentException("Invalid Hexadecimal Character: "+ hexChar);
}
return digit;
}
private static String byteToHex(byte num) {
char[] hexDigits = new char[2];
hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
hexDigits[1] = Character.forDigit(num & 0xF, 16);
return new String(hexDigits);
}
private static String encodeHexString(byte[] byteArray) {
StringBuilder hexStringBuffer = new StringBuilder();
for (byte b : byteArray) {
hexStringBuffer.append(StringUtil.byteToHex(b));
}
return hexStringBuffer.toString();
}
private static byte[] decodeHexString(String hexString) {
if (hexString.length() % 2 == 1) {
throw new IllegalArgumentException("Invalid hexadecimal String supplied.");
}
byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0 ; i < hexString.length() ; i += 2) {
bytes[i / 2] = StringUtil.hexToByte(hexString.substring(i, i + 2));
}
return bytes;
}
private static byte[] getBytesUtf8(String string) {
return string == null ? null : string.getBytes(StandardCharsets.UTF_8);
}
private static String newStringUtf8(byte[] bytes) {
return bytes == null ? null : new String(bytes, StandardCharsets.UTF_8);
}
public static byte[] xor(byte[] plaintext, int key) {
var ciphertext = new byte[plaintext.length];
for (var i = 0 ; i < plaintext.length ; i++) {
ciphertext[i] = (byte) (plaintext[i] ^ (key >>> (8 * (i % 4))));
}
return ciphertext;
}
public static List<String> toHexChunks(byte[] fileData) {
StringBuilder hexString = new StringBuilder();
for (byte b : fileData) {
hexString.append(String.format("%02X", b));
}
int chunkSize = 900; // 450 bytes = 900 hex characters
List<String> chunks = new ArrayList<>();
for (int i = 0 ; i < hexString.length() ; i += chunkSize) {
int endIndex = Math.min(i + chunkSize, hexString.length());
chunks.add(hexString.substring(i, endIndex));
}
return chunks;
}
public static String getFile(String path) {
var content = new StringBuilder();
try (
var inputStream = PreferencesUtil.class.getClassLoader().getResourceAsStream(path);
var inputStreamReader = new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8);
var reader = new BufferedReader(inputStreamReader)
) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n"); // required to prevent \n<text>\r on edit
}
} catch (IOException e) {
LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
}
return content.toString();
}
public static byte[] uncloak(byte[] fileData) {
fileData = StringUtil.xor(fileData, 353837730);
ArrayUtils.reverse(fileData);
return fileData;
}
}