1 package be
.nikiroo
.utils
;
3 import java
.io
.ByteArrayInputStream
;
4 import java
.io
.ByteArrayOutputStream
;
5 import java
.io
.IOException
;
6 import java
.io
.InputStream
;
7 import java
.io
.OutputStream
;
8 import java
.io
.UnsupportedEncodingException
;
9 import java
.security
.MessageDigest
;
10 import java
.security
.NoSuchAlgorithmException
;
11 import java
.text
.Normalizer
;
12 import java
.text
.Normalizer
.Form
;
13 import java
.text
.ParseException
;
14 import java
.text
.SimpleDateFormat
;
15 import java
.util
.AbstractMap
;
16 import java
.util
.ArrayList
;
17 import java
.util
.Arrays
;
18 import java
.util
.Date
;
19 import java
.util
.List
;
20 import java
.util
.Map
.Entry
;
21 import java
.util
.regex
.Pattern
;
22 import java
.util
.zip
.GZIPInputStream
;
23 import java
.util
.zip
.GZIPOutputStream
;
25 import org
.unbescape
.html
.HtmlEscape
;
26 import org
.unbescape
.html
.HtmlEscapeLevel
;
27 import org
.unbescape
.html
.HtmlEscapeType
;
29 import be
.nikiroo
.utils
.streams
.Base64InputStream
;
30 import be
.nikiroo
.utils
.streams
.Base64OutputStream
;
33 * This class offer some utilities based around {@link String}s.
37 public class StringUtils
{
39 * This enum type will decide the alignment of a {@link String} when padding
40 * or justification is applied (if there is enough horizontal space for it
43 public enum Alignment
{
44 /** Aligned at left. */
48 /** Aligned at right. */
50 /** Full justified (to both left and right). */
53 // Old Deprecated values:
55 /** DEPRECATED: please use LEFT. */
58 /** DEPRECATED: please use CENTER. */
61 /** DEPRECATED: please use RIGHT. */
66 * Return the non-deprecated version of this enum if needed (or return
69 * @return the non-deprecated value
71 Alignment
undeprecate() {
72 if (this == Beginning
)
82 static private Pattern marks
= getMarks();
85 * Fix the size of the given {@link String} either with space-padding or by
89 * the {@link String} to fix
91 * the size of the resulting {@link String} or -1 for a noop
93 * @return the resulting {@link String} of size <i>size</i>
95 static public String
padString(String text
, int width
) {
96 return padString(text
, width
, true, null);
100 * Fix the size of the given {@link String} either with space-padding or by
101 * optionally shortening it.
104 * the {@link String} to fix
106 * the size of the resulting {@link String} if the text fits or
107 * if cut is TRUE or -1 for a noop
109 * cut the {@link String} shorter if needed
111 * align the {@link String} in this position if we have enough
112 * space (default is Alignment.Beginning)
114 * @return the resulting {@link String} of size <i>size</i> minimum
116 static public String
padString(String text
, int width
, boolean cut
,
120 align
= Alignment
.LEFT
;
123 align
= align
.undeprecate();
129 int diff
= width
- text
.length();
133 text
= text
.substring(0, width
);
134 } else if (diff
> 0) {
135 if (diff
< 2 && align
!= Alignment
.RIGHT
)
136 align
= Alignment
.LEFT
;
140 text
= new String(new char[diff
]).replace('\0', ' ') + text
;
143 int pad1
= (diff
) / 2;
144 int pad2
= (diff
+ 1) / 2;
145 text
= new String(new char[pad1
]).replace('\0', ' ') + text
146 + new String(new char[pad2
]).replace('\0', ' ');
150 text
= text
+ new String(new char[diff
]).replace('\0', ' ');
160 * Justify a text into width-sized (at the maximum) lines and return all the
161 * lines concatenated into a single '\\n'-separated line of text.
164 * the {@link String} to justify
166 * the maximum size of the resulting lines
168 * @return a list of justified text lines concatenated into a single
169 * '\\n'-separated line of text
171 static public String
justifyTexts(String text
, int width
) {
172 StringBuilder builder
= new StringBuilder();
173 for (String line
: justifyText(text
, width
, null)) {
174 if (builder
.length() > 0) {
175 builder
.append('\n');
177 builder
.append(line
);
180 return builder
.toString();
184 * Justify a text into width-sized (at the maximum) lines.
187 * the {@link String} to justify
189 * the maximum size of the resulting lines
191 * @return a list of justified text lines
193 static public List
<String
> justifyText(String text
, int width
) {
194 return justifyText(text
, width
, null);
198 * Justify a text into width-sized (at the maximum) lines.
201 * the {@link String} to justify
203 * the maximum size of the resulting lines
205 * align the lines in this position (default is
206 * Alignment.Beginning)
208 * @return a list of justified text lines
210 static public List
<String
> justifyText(String text
, int width
,
213 align
= Alignment
.LEFT
;
216 align
= align
.undeprecate();
220 return StringJustifier
.center(text
, width
);
222 return StringJustifier
.right(text
, width
);
224 return StringJustifier
.full(text
, width
);
227 return StringJustifier
.left(text
, width
);
232 * Justify a text into width-sized (at the maximum) lines.
235 * the {@link String} to justify
237 * the maximum size of the resulting lines
239 * @return a list of justified text lines
241 static public List
<String
> justifyText(List
<String
> text
, int width
) {
242 return justifyText(text
, width
, null);
246 * Justify a text into width-sized (at the maximum) lines.
249 * the {@link String} to justify
251 * the maximum size of the resulting lines
253 * align the lines in this position (default is
254 * Alignment.Beginning)
256 * @return a list of justified text lines
258 static public List
<String
> justifyText(List
<String
> text
, int width
,
260 List
<String
> result
= new ArrayList
<String
>();
262 // Content <-> Bullet spacing (null = no spacing)
263 List
<Entry
<String
, String
>> lines
= new ArrayList
<Entry
<String
, String
>>();
264 StringBuilder previous
= null;
265 StringBuilder tmp
= new StringBuilder();
266 String previousItemBulletSpacing
= null;
267 String itemBulletSpacing
= null;
268 for (String inputLine
: text
) {
269 boolean previousLineComplete
= true;
271 String current
= inputLine
.replace("\t", " ");
272 itemBulletSpacing
= getItemSpacing(current
);
273 boolean bullet
= isItemLine(current
);
274 if ((previousItemBulletSpacing
== null || itemBulletSpacing
275 .length() <= previousItemBulletSpacing
.length()) && !bullet
) {
276 itemBulletSpacing
= null;
279 if (itemBulletSpacing
!= null) {
280 current
= current
.trim();
281 if (!current
.isEmpty() && bullet
) {
282 current
= current
.substring(1);
284 current
= current
.trim();
285 previousLineComplete
= bullet
;
288 for (String word
: current
.split(" ")) {
289 if (word
.isEmpty()) {
293 if (tmp
.length() > 0) {
296 tmp
.append(word
.trim());
298 current
= tmp
.toString();
300 previousLineComplete
= current
.isEmpty()
301 || previousItemBulletSpacing
!= null
302 || (previous
!= null && isFullLine(previous
))
303 || isHrLine(current
) || isHrLine(previous
);
306 if (previous
== null) {
307 previous
= new StringBuilder();
309 if (previousLineComplete
) {
310 lines
.add(new AbstractMap
.SimpleEntry
<String
, String
>(
311 previous
.toString(), previousItemBulletSpacing
));
312 previous
.setLength(0);
313 previousItemBulletSpacing
= itemBulletSpacing
;
315 previous
.append(' ');
319 previous
.append(current
);
323 if (previous
!= null) {
324 lines
.add(new AbstractMap
.SimpleEntry
<String
, String
>(previous
325 .toString(), previousItemBulletSpacing
));
328 for (Entry
<String
, String
> line
: lines
) {
329 String content
= line
.getKey();
330 String spacing
= line
.getValue();
332 String bullet
= "- ";
333 if (spacing
== null) {
338 if (spacing
.length() > width
+ 3) {
342 for (String subline
: StringUtils
.justifyText(content
, width
343 - (spacing
.length() + bullet
.length()), align
)) {
344 result
.add(spacing
+ bullet
+ subline
);
345 if (!bullet
.isEmpty()) {
355 * Sanitise the given input to make it more Terminal-friendly by removing
356 * combining characters.
359 * the input to sanitise
360 * @param allowUnicode
361 * allow Unicode or only allow ASCII Latin characters
363 * @return the sanitised {@link String}
365 static public String
sanitize(String input
, boolean allowUnicode
) {
366 return sanitize(input
, allowUnicode
, !allowUnicode
);
370 * Sanitise the given input to make it more Terminal-friendly by removing
371 * combining characters.
374 * the input to sanitise
375 * @param allowUnicode
376 * allow Unicode or only allow ASCII Latin characters
377 * @param removeAllAccents
378 * TRUE to replace all accentuated characters by their non
379 * accentuated counter-parts
381 * @return the sanitised {@link String}
383 static public String
sanitize(String input
, boolean allowUnicode
,
384 boolean removeAllAccents
) {
386 if (removeAllAccents
) {
387 input
= Normalizer
.normalize(input
, Form
.NFKD
);
389 input
= marks
.matcher(input
).replaceAll("");
393 input
= Normalizer
.normalize(input
, Form
.NFKC
);
396 StringBuilder builder
= new StringBuilder();
397 for (int index
= 0; index
< input
.length(); index
++) {
398 char car
= input
.charAt(index
);
399 // displayable chars in ASCII are in the range 32<->255,
401 if (car
>= 32 && car
<= 255 && car
!= 127) {
405 input
= builder
.toString();
412 * Convert between the time in milliseconds to a {@link String} in a "fixed"
413 * way (to exchange data over the wire, for instance).
415 * Precise to the second.
418 * the specified number of milliseconds since the standard base
419 * time known as "the epoch", namely January 1, 1970, 00:00:00
422 * @return the time as a {@link String}
424 static public String
fromTime(long time
) {
425 SimpleDateFormat sdf
= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
426 return sdf
.format(new Date(time
));
430 * Convert between the time as a {@link String} to milliseconds in a "fixed"
431 * way (to exchange data over the wire, for instance).
433 * Precise to the second.
436 * the time as a {@link String}
438 * @return the number of milliseconds since the standard base time known as
439 * "the epoch", namely January 1, 1970, 00:00:00 GMT, or -1 in case
442 * @throws ParseException
443 * in case of parse error
445 static public long toTime(String displayTime
) throws ParseException
{
446 SimpleDateFormat sdf
= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
447 return sdf
.parse(displayTime
).getTime();
451 * Return a hash of the given {@link String}.
458 static public String
getMd5Hash(String input
) {
460 MessageDigest md
= MessageDigest
.getInstance("MD5");
461 md
.update(getBytes(input
));
462 byte byteData
[] = md
.digest();
464 StringBuffer hexString
= new StringBuffer();
465 for (int i
= 0; i
< byteData
.length
; i
++) {
466 String hex
= Integer
.toHexString(0xff & byteData
[i
]);
467 if (hex
.length() == 1)
468 hexString
.append('0');
469 hexString
.append(hex
);
472 return hexString
.toString();
473 } catch (NoSuchAlgorithmException e
) {
479 * Remove the HTML content from the given input, and un-html-ize the rest.
482 * the HTML-encoded content
484 * @return the HTML-free equivalent content
486 public static String
unhtml(String html
) {
487 StringBuilder builder
= new StringBuilder();
490 for (char car
: html
.toCharArray()) {
493 } else if (car
== '>') {
495 } else if (inTag
<= 0) {
500 char nbsp
= ' '; // non-breakable space (a special char)
502 return HtmlEscape
.unescapeHtml(builder
.toString()).replace(nbsp
, space
);
506 * Escape the given {@link String} so it can be used in XML, as content.
509 * the input {@link String}
511 * @return the escaped {@link String}
513 public static String
xmlEscape(String input
) {
518 return HtmlEscape
.escapeHtml(input
,
519 HtmlEscapeType
.HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA
,
520 HtmlEscapeLevel
.LEVEL_1_ONLY_MARKUP_SIGNIFICANT
);
524 * Escape the given {@link String} so it can be used in XML, as text content
525 * inside double-quotes.
528 * the input {@link String}
530 * @return the escaped {@link String}
532 public static String
xmlEscapeQuote(String input
) {
537 return HtmlEscape
.escapeHtml(input
,
538 HtmlEscapeType
.HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA
,
539 HtmlEscapeLevel
.LEVEL_1_ONLY_MARKUP_SIGNIFICANT
);
543 * Zip the data and then encode it into Base64.
548 * @return the Base64 zipped version
550 * @throws IOException
551 * in case of I/O error
553 public static String
zip64(String data
) throws IOException
{
555 return zip64(getBytes(data
));
556 } catch (UnsupportedEncodingException e
) {
557 // All conforming JVM are required to support UTF-8
564 * Zip the data and then encode it into Base64.
569 * @return the Base64 zipped version
571 * @throws IOException
572 * in case of I/O error
574 public static String
zip64(byte[] data
) throws IOException
{
576 ByteArrayOutputStream bout
= new ByteArrayOutputStream();
578 OutputStream out
= new GZIPOutputStream(bout
);
585 data
= bout
.toByteArray();
590 InputStream in
= new ByteArrayInputStream(data
);
592 in
= new Base64InputStream(in
, true);
593 return new String(IOUtils
.toByteArray(in
), "UTF-8");
600 * Unconvert from Base64 then unzip the content, which is assumed to be a
604 * the data in Base64 format
606 * @return the raw data
608 * @throws IOException
609 * in case of I/O error
611 public static String
unzip64s(String data
) throws IOException
{
612 return new String(unzip64(data
), "UTF-8");
616 * Unconvert from Base64 then unzip the content.
619 * the data in Base64 format
621 * @return the raw data
623 * @throws IOException
624 * in case of I/O error
626 public static byte[] unzip64(String data
) throws IOException
{
627 InputStream in
= new Base64InputStream(new ByteArrayInputStream(
628 getBytes(data
)), false);
630 in
= new GZIPInputStream(in
);
631 return IOUtils
.toByteArray(in
);
638 * Convert the given data to Base64 format.
641 * the data to convert
643 * @return the Base64 {@link String} representation of the data
645 * @throws IOException
646 * in case of I/O errors
648 public static String
base64(String data
) throws IOException
{
649 return base64(getBytes(data
));
653 * Convert the given data to Base64 format.
656 * the data to convert
658 * @return the Base64 {@link String} representation of the data
660 * @throws IOException
661 * in case of I/O errors
663 public static String
base64(byte[] data
) throws IOException
{
664 Base64InputStream in
= new Base64InputStream(new ByteArrayInputStream(
667 return new String(IOUtils
.toByteArray(in
), "UTF-8");
674 * Unconvert the given data from Base64 format back to a raw array of bytes.
677 * the data to unconvert
679 * @return the raw data represented by the given Base64 {@link String},
681 * @throws IOException
682 * in case of I/O errors
684 public static byte[] unbase64(String data
) throws IOException
{
685 Base64InputStream in
= new Base64InputStream(new ByteArrayInputStream(
686 getBytes(data
)), false);
688 return IOUtils
.toByteArray(in
);
695 * Unonvert the given data from Base64 format back to a {@link String}.
698 * the data to unconvert
700 * @return the {@link String} represented by the given Base64 {@link String}
702 * @throws IOException
703 * in case of I/O errors
705 public static String
unbase64s(String data
) throws IOException
{
706 return new String(unbase64(data
), "UTF-8");
710 * Return a display {@link String} for the given value, which can be
711 * suffixed with "k" or "M" depending upon the number, if it is big enough.
716 * <li><tt>8 765</tt> becomes "8 k"</li>
717 * <li><tt>998 765</tt> becomes "998 k"</li>
718 * <li><tt>12 987 364</tt> becomes "12 M"</li>
719 * <li><tt>5 534 333 221</tt> becomes "5 G"</li>
723 * the value to convert
725 * @return the display value
727 public static String
formatNumber(long value
) {
728 return formatNumber(value
, 0);
732 * Return a display {@link String} for the given value, which can be
733 * suffixed with "k" or "M" depending upon the number, if it is big enough.
735 * Examples (assuming decimalPositions = 1):
737 * <li><tt>8 765</tt> becomes "8.7 k"</li>
738 * <li><tt>998 765</tt> becomes "998.7 k"</li>
739 * <li><tt>12 987 364</tt> becomes "12.9 M"</li>
740 * <li><tt>5 534 333 221</tt> becomes "5.5 G"</li>
744 * the value to convert
745 * @param decimalPositions
746 * the number of decimal positions to keep
748 * @return the display value
750 public static String
formatNumber(long value
, int decimalPositions
) {
751 long userValue
= value
;
755 if (value
>= 1000000000l) {
757 userValue
= value
/ 1000000000l;
759 } else if (value
>= 1000000l) {
761 userValue
= value
/ 1000000l;
763 } else if (value
>= 1000l) {
765 userValue
= value
/ 1000l;
770 if (decimalPositions
> 0) {
771 deci
= Long
.toString(value
% mult
);
772 int size
= Long
.toString(mult
).length() - 1;
773 while (deci
.length() < size
) {
777 deci
= deci
.substring(0, Math
.min(decimalPositions
, deci
.length()));
778 while (deci
.length() < decimalPositions
) {
785 return Long
.toString(userValue
) + deci
+ suffix
;
789 * The reverse operation to {@link StringUtils#formatNumber(long)}: it will
790 * read a "display" number that can contain a "M" or "k" suffix and return
793 * Of course, the conversion to and from display form is lossy (example:
794 * <tt>6870</tt> to "6.5k" to <tt>6500</tt>).
797 * the value in display form with possible "M" and "k" suffixes,
800 * @return the value as a number, or 0 if not possible to convert
802 public static long toNumber(String value
) {
803 return toNumber(value
, 0l);
807 * The reverse operation to {@link StringUtils#formatNumber(long)}: it will
808 * read a "display" number that can contain a "M" or "k" suffix and return
811 * Of course, the conversion to and from display form is lossy (example:
812 * <tt>6870</tt> to "6.5k" to <tt>6500</tt>).
815 * the value in display form with possible "M" and "k" suffixes,
818 * the default value if it is not possible to convert the given
821 * @return the value as a number, or 0 if not possible to convert
823 public static long toNumber(String value
, long def
) {
826 value
= value
.trim().toLowerCase();
829 if (value
.endsWith("g")) {
830 value
= value
.substring(0, value
.length() - 1).trim();
832 } else if (value
.endsWith("m")) {
833 value
= value
.substring(0, value
.length() - 1).trim();
835 } else if (value
.endsWith("k")) {
836 value
= value
.substring(0, value
.length() - 1).trim();
841 if (value
.contains(".")) {
842 String
[] tab
= value
.split("\\.");
843 if (tab
.length
!= 2) {
844 throw new NumberFormatException(value
);
846 double decimal
= Double
.parseDouble("0."
847 + tab
[tab
.length
- 1]);
848 deci
= ((long) (mult
* decimal
));
851 count
= mult
* Long
.parseLong(value
) + deci
;
852 } catch (Exception e
) {
860 * Return the bytes array representation of the given {@link String} in
864 * the {@link String} to transform into bytes
865 * @return the content in bytes
867 static public byte[] getBytes(String str
) {
869 return str
.getBytes("UTF-8");
870 } catch (UnsupportedEncodingException e
) {
871 // All conforming JVM must support UTF-8
878 * The "remove accents" pattern.
880 * @return the pattern, or NULL if a problem happens
882 private static Pattern
getMarks() {
885 .compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");
886 } catch (Exception e
) {
887 // Can fail on Android...
893 // justify List<String> related:
897 * Check if this line ends as a complete line (ends with a "." or similar).
899 * Note that we consider an empty line as full, and a line ending with
900 * spaces as not complete.
905 * @return TRUE if it does
907 static private boolean isFullLine(StringBuilder line
) {
908 if (line
.length() == 0) {
912 char lastCar
= line
.charAt(line
.length() - 1);
922 case '"': // double quotes
934 * Check if this line represent an item in a list or description (i.e.,
935 * check that the first non-space char is "-").
940 * @return TRUE if it is
942 static private boolean isItemLine(String line
) {
943 String spacing
= getItemSpacing(line
);
944 return spacing
!= null && !spacing
.isEmpty()
945 && line
.charAt(spacing
.length()) == '-';
949 * Return all the spaces that start this line (or Empty if none).
952 * the line to get the starting spaces from
954 * @return the left spacing
956 static private String
getItemSpacing(String line
) {
958 for (i
= 0; i
< line
.length(); i
++) {
959 if (line
.charAt(i
) != ' ') {
960 return line
.substring(0, i
);
968 * This line is an horizontal spacer line.
973 * @return TRUE if it is
975 static private boolean isHrLine(CharSequence line
) {
978 for (int i
= 0; i
< line
.length(); i
++) {
979 char car
= line
.charAt(i
);
980 if (car
== ' ' || car
== '\t' || car
== '*' || car
== '-'
981 || car
== '_' || car
== '~' || car
== '=' || car
== '/'
993 // Deprecated functions, please do not use //
996 * @deprecated please use {@link StringUtils#zip64(byte[])} or
997 * {@link StringUtils#base64(byte[])} instead.
1000 * the data to encode
1002 * TRUE to zip it before Base64 encoding it, FALSE for Base64
1005 * @return the encoded data
1007 * @throws IOException
1008 * in case of I/O error
1011 public static String
base64(String data
, boolean zip
) throws IOException
{
1012 return base64(getBytes(data
), zip
);
1016 * @deprecated please use {@link StringUtils#zip64(String)} or
1017 * {@link StringUtils#base64(String)} instead.
1020 * the data to encode
1022 * TRUE to zip it before Base64 encoding it, FALSE for Base64
1025 * @return the encoded data
1027 * @throws IOException
1028 * in case of I/O error
1031 public static String
base64(byte[] data
, boolean zip
) throws IOException
{
1036 Base64InputStream b64
= new Base64InputStream(new ByteArrayInputStream(
1039 return IOUtils
.readSmallStream(b64
);
1046 * @deprecated please use {@link Base64OutputStream} and
1047 * {@link GZIPOutputStream} instead.
1050 * NOT USED ANYMORE, it is always considered FALSE now
1053 public static OutputStream
base64(OutputStream data
, boolean zip
,
1054 boolean breakLines
) throws IOException
{
1055 OutputStream out
= new Base64OutputStream(data
);
1057 out
= new java
.util
.zip
.GZIPOutputStream(out
);
1064 * Unconvert the given data from Base64 format back to a raw array of bytes.
1066 * Will automatically detect zipped data and also uncompress it before
1067 * returning, unless ZIP is false.
1069 * @deprecated DO NOT USE ANYMORE (bad perf, will be dropped)
1072 * the data to unconvert
1074 * TRUE to also uncompress the data from a GZIP format
1075 * automatically; if set to FALSE, zipped data can be returned
1077 * @return the raw data represented by the given Base64 {@link String},
1078 * optionally compressed with GZIP
1080 * @throws IOException
1081 * in case of I/O errors
1084 public static byte[] unbase64(String data
, boolean zip
) throws IOException
{
1085 byte[] buffer
= unbase64(data
);
1091 GZIPInputStream zipped
= new GZIPInputStream(
1092 new ByteArrayInputStream(buffer
));
1094 ByteArrayOutputStream out
= new ByteArrayOutputStream();
1096 IOUtils
.write(zipped
, out
);
1097 return out
.toByteArray();
1104 } catch (Exception e
) {
1110 * Unconvert the given data from Base64 format back to a raw array of bytes.
1112 * Will automatically detect zipped data and also uncompress it before
1113 * returning, unless ZIP is false.
1115 * @deprecated DO NOT USE ANYMORE (bad perf, will be dropped)
1118 * the data to unconvert
1120 * TRUE to also uncompress the data from a GZIP format
1121 * automatically; if set to FALSE, zipped data can be returned
1123 * @return the raw data represented by the given Base64 {@link String},
1124 * optionally compressed with GZIP
1126 * @throws IOException
1127 * in case of I/O errors
1130 public static InputStream
unbase64(InputStream data
, boolean zip
)
1131 throws IOException
{
1132 return new ByteArrayInputStream(unbase64(IOUtils
.readSmallStream(data
),
1137 * @deprecated DO NOT USE ANYMORE (bad perf, will be dropped)
1140 public static byte[] unbase64(byte[] data
, int offset
, int count
,
1141 boolean zip
) throws IOException
{
1142 byte[] dataPart
= Arrays
.copyOfRange(data
, offset
, offset
+ count
);
1143 return unbase64(new String(dataPart
, "UTF-8"), zip
);
1147 * @deprecated DO NOT USE ANYMORE (bad perf, will be dropped)
1150 public static String
unbase64s(String data
, boolean zip
) throws IOException
{
1151 return new String(unbase64(data
, zip
), "UTF-8");
1155 * @deprecated DO NOT USE ANYMORE (bad perf, will be dropped)
1158 public static String
unbase64s(byte[] data
, int offset
, int count
,
1159 boolean zip
) throws IOException
{
1160 return new String(unbase64(data
, offset
, count
, zip
), "UTF-8");