X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2FStringUtils.java;h=1ee9ac4b569001fda8036815fe8a43277e8e18ef;hb=79961c53a472a86ee151a35149c27cc1617eb779;hp=79bccec76f26ba9148c3b7658e219e863ec7ac65;hpb=bb60bd13efae59e804e5d7a5a7590a020835966f;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/StringUtils.java b/src/be/nikiroo/utils/StringUtils.java index 79bccec..1ee9ac4 100644 --- a/src/be/nikiroo/utils/StringUtils.java +++ b/src/be/nikiroo/utils/StringUtils.java @@ -1,7 +1,8 @@ package be.nikiroo.utils; -import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -14,7 +15,6 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map.Entry; -import java.util.Scanner; import java.util.regex.Pattern; import org.unbescape.html.HtmlEscape; @@ -523,7 +523,7 @@ public class StringUtils { @Deprecated public static String zip64(String data) { try { - return Base64.encodeBytes(data.getBytes(), Base64.GZIP); + return Base64.encodeBytes(data.getBytes("UTF-8"), Base64.GZIP); } catch (IOException e) { e.printStackTrace(); return null; @@ -546,16 +546,26 @@ public class StringUtils { */ @Deprecated public static String unzip64(String data) throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream(Base64.decode(data, - Base64.GZIP)); + return new String(Base64.decode(data, Base64.GZIP), "UTF-8"); + } - Scanner scan = new Scanner(in); - scan.useDelimiter("\\A"); - try { - return scan.next(); - } finally { - scan.close(); - } + /** + * Convert the given data to Base64 format. + * + * @param data + * the data to convert + * @param zip + * TRUE to also compress the data in GZIP format; remember that + * compressed and not-compressed content are different; you need + * to know which is which when decoding + * + * @return the Base64 {@link String} representation of the data + * + * @throws IOException + * in case of I/O errors + */ + public static String base64(String data, boolean zip) throws IOException { + return base64(data.getBytes("UTF-8"), zip); } /** @@ -578,14 +588,73 @@ public class StringUtils { } /** - * Unonvert the given data from Base64 format back to a raw array of bytes. + * Convert the given data to Base64 format. * * @param data - * the data to unconvert + * the data to convert * @param zip * TRUE to also uncompress the data from a GZIP format; take care * about this flag, as it could easily cause errors in the * returned content or an {@link IOException} + * @param breakLines + * TRUE to break lines on every 76th character + * + * @return the Base64 {@link String} representation of the data + * + * @throws IOException + * in case of I/O errors + */ + public static OutputStream base64(OutputStream data, boolean zip, + boolean breakLines) throws IOException { + OutputStream out = new Base64.OutputStream(data, + breakLines ? Base64.DO_BREAK_LINES & Base64.ENCODE + : Base64.ENCODE); + + if (zip) { + out = new java.util.zip.GZIPOutputStream(out); + } + + return out; + } + + /** + * Convert the given data to Base64 format. + * + * @param data + * the data to convert + * @param zip + * TRUE to also uncompress the data from a GZIP format; take care + * about this flag, as it could easily cause errors in the + * returned content or an {@link IOException} + * @param breakLines + * TRUE to break lines on every 76th character + * + * @return the Base64 {@link String} representation of the data + * + * @throws IOException + * in case of I/O errors + */ + public static InputStream base64(InputStream data, boolean zip, + boolean breakLines) throws IOException { + if (zip) { + data = new java.util.zip.GZIPInputStream(data); + } + + return new Base64.InputStream(data, breakLines ? Base64.DO_BREAK_LINES + & Base64.ENCODE : Base64.ENCODE); + } + + /** + * Unconvert the given data from Base64 format back to a raw array of bytes. + *

+ * Will automatically detect zipped data and also uncompress it before + * returning, unless ZIP is false. + * + * @param data + * the data to unconvert + * @param zip + * TRUE to also uncompress the data from a GZIP format + * automatically; if set to FALSE, zipped data can be returned * * @return the raw data represented by the given Base64 {@link String}, * optionally compressed with GZIP @@ -594,11 +663,12 @@ public class StringUtils { * in case of I/O errors */ public static byte[] unbase64(String data, boolean zip) throws IOException { - return Base64.decode(data, zip ? Base64.GZIP : Base64.NO_OPTIONS); + return Base64 + .decode(data, zip ? Base64.NO_OPTIONS : Base64.DONT_GUNZIP); } /** - * Unonvert the given data from Base64 format back to a {@link String}. + * Unconvert the given data from Base64 format back to a raw array of bytes. * * @param data * the data to unconvert @@ -607,6 +677,87 @@ public class StringUtils { * about this flag, as it could easily cause errors in the * returned content or an {@link IOException} * + * @return the raw data represented by the given Base64 {@link String} + * + * @throws IOException + * in case of I/O errors + */ + public static OutputStream unbase64(OutputStream data, boolean zip) + throws IOException { + OutputStream out = new Base64.OutputStream(data, Base64.DECODE); + + if (zip) { + out = new java.util.zip.GZIPOutputStream(out); + } + + return out; + } + + /** + * Unconvert the given data from Base64 format back to a raw array of bytes. + * + * @param data + * the data to unconvert + * @param zip + * TRUE to also uncompress the data from a GZIP format; take care + * about this flag, as it could easily cause errors in the + * returned content or an {@link IOException} + * + * @return the raw data represented by the given Base64 {@link String} + * + * @throws IOException + * in case of I/O errors + */ + public static InputStream unbase64(InputStream data, boolean zip) + throws IOException { + if (zip) { + data = new java.util.zip.GZIPInputStream(data); + } + + return new Base64.InputStream(data, Base64.DECODE); + } + + /** + * Unconvert the given data from Base64 format back to a raw array of bytes. + *

+ * Will automatically detect zipped data and also uncompress it before + * returning, unless ZIP is false. + * + * @param data + * the data to unconvert + * @param offset + * the offset at which to start taking the data (do not take the + * data before it into account) + * @param count + * the number of bytes to take into account (do not process after + * this number of bytes has been processed) + * @param zip + * TRUE to also uncompress the data from a GZIP format + * automatically; if set to FALSE, zipped data can be returned + * + * @return the raw data represented by the given Base64 {@link String} + * + * @throws IOException + * in case of I/O errors + */ + public static byte[] unbase64(byte[] data, int offset, int count, + boolean zip) throws IOException { + return Base64.niki_decode(data, offset, count, zip ? Base64.NO_OPTIONS + : Base64.DONT_GUNZIP); + } + + /** + * Unonvert the given data from Base64 format back to a {@link String}. + *

+ * Will automatically detect zipped data and also uncompress it before + * returning, unless ZIP is false. + * + * @param data + * the data to unconvert + * @param zip + * TRUE to also uncompress the data from a GZIP format + * automatically; if set to FALSE, zipped data can be returned + * * @return the {@link String} represented by the given Base64 {@link String} * , optionally compressed with GZIP * @@ -614,15 +765,184 @@ public class StringUtils { * in case of I/O errors */ public static String unbase64s(String data, boolean zip) throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream(unbase64(data, zip)); + return new String(unbase64(data, zip), "UTF-8"); + } - Scanner scan = new Scanner(in); - scan.useDelimiter("\\A"); - try { - return scan.next(); - } finally { - scan.close(); + /** + * Unconvert the given data from Base64 format back into a {@link String}. + * + * @param data + * the data to unconvert + * @param offset + * the offset at which to start taking the data (do not take the + * data before it into account) + * @param count + * the number of bytes to take into account (do not process after + * this number of bytes has been processed) + * @param zip + * TRUE to also uncompress the data from a GZIP format; take care + * about this flag, as it could easily cause errors in the + * returned content or an {@link IOException} + * + * @return the {@link String} represented by the given Base64 {@link String} + * , optionally compressed with GZIP + * + * @throws IOException + * in case of I/O errors + */ + public static String unbase64s(byte[] data, int offset, int count, + boolean zip) throws IOException { + return new String(unbase64(data, offset, count, zip), "UTF-8"); + } + + /** + * Return a display {@link String} for the given value, which can be + * suffixed with "k" or "M" depending upon the number, if it is big enough. + *

+ *

+ * Examples: + *

+ * + * @param value + * the value to convert + * + * @return the display value + */ + public static String formatNumber(long value) { + return formatNumber(value, 0); + } + + /** + * Return a display {@link String} for the given value, which can be + * suffixed with "k" or "M" depending upon the number, if it is big enough. + *

+ * Examples (assuming decimalPositions = 1): + *

+ * + * @param value + * the value to convert + * @param decimalPositions + * the number of decimal positions to keep + * + * @return the display value + */ + public static String formatNumber(long value, int decimalPositions) { + long userValue = value; + String suffix = ""; + long mult = 1; + + if (value >= 1000000000l) { + mult = 1000000000l; + userValue = value / 1000000000l; + suffix = "G"; + } else if (value >= 1000000l) { + mult = 1000000l; + userValue = value / 1000000l; + suffix = "M"; + } else if (value >= 1000l) { + mult = 1000l; + userValue = value / 1000l; + suffix = "k"; + } + + String deci = ""; + if (decimalPositions > 0) { + deci = Long.toString(value % mult); + int size = Long.toString(mult).length() - 1; + while (deci.length() < size) { + deci = "0" + deci; + } + + deci = deci.substring(0, Math.min(decimalPositions, deci.length())); + while (deci.length() < decimalPositions) { + deci += "0"; + } + + deci = "." + deci; } + + return Long.toString(userValue) + deci + suffix; + } + + /** + * The reverse operation to {@link StringUtils#formatNumber(long)}: it will + * read a "display" number that can contain a "M" or "k" suffix and return + * the full value. + *

+ * Of course, the conversion to and from display form is lossy (example: + * 6870 to "6.5k" to 6500). + * + * @param value + * the value in display form with possible "M" and "k" suffixes, + * can be NULL + * + * @return the value as a number, or 0 if not possible to convert + */ + public static long toNumber(String value) { + return toNumber(value, 0l); + } + + /** + * The reverse operation to {@link StringUtils#formatNumber(long)}: it will + * read a "display" number that can contain a "M" or "k" suffix and return + * the full value. + *

+ * Of course, the conversion to and from display form is lossy (example: + * 6870 to "6.5k" to 6500). + * + * @param value + * the value in display form with possible "M" and "k" suffixes, + * can be NULL + * @param def + * the default value if it is not possible to convert the given + * value to a number + * + * @return the value as a number, or 0 if not possible to convert + */ + public static long toNumber(String value, long def) { + long count = def; + if (value != null) { + value = value.trim().toLowerCase(); + try { + long mult = 1; + if (value.endsWith("g")) { + value = value.substring(0, value.length() - 1).trim(); + mult = 1000000000; + } else if (value.endsWith("m")) { + value = value.substring(0, value.length() - 1).trim(); + mult = 1000000; + } else if (value.endsWith("k")) { + value = value.substring(0, value.length() - 1).trim(); + mult = 1000; + } + + long deci = 0; + if (value.contains(".")) { + String[] tab = value.split("\\."); + if (tab.length != 2) { + throw new NumberFormatException(value); + } + double decimal = Double.parseDouble("0." + + tab[tab.length - 1]); + deci = ((long) (mult * decimal)); + value = tab[0]; + } + count = mult * Long.parseLong(value) + deci; + } catch (Exception e) { + } + } + + return count; } /**