1
2
3
4
5 package oshi.util;
6
7 import java.math.BigInteger;
8 import java.net.InetAddress;
9 import java.net.UnknownHostException;
10 import java.nio.ByteBuffer;
11 import java.nio.ByteOrder;
12 import java.nio.charset.StandardCharsets;
13 import java.time.LocalTime;
14 import java.time.OffsetDateTime;
15 import java.time.format.DateTimeFormatter;
16 import java.time.format.DateTimeParseException;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.EnumMap;
20 import java.util.EnumSet;
21 import java.util.HashMap;
22 import java.util.LinkedHashMap;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.TimeZone;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
29
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import oshi.annotation.SuppressForbidden;
34 import oshi.annotation.concurrent.ThreadSafe;
35 import oshi.util.tuples.Pair;
36 import oshi.util.tuples.Triplet;
37
38
39
40
41 @ThreadSafe
42 @SuppressForbidden(reason = "Require parse methods to parse in utility class")
43 public final class ParseUtil {
44
45 private static final Logger LOG = LoggerFactory.getLogger(ParseUtil.class);
46
47 private static final String DEFAULT_LOG_MSG = "{} didn't parse. Returning default. {}";
48
49
50
51
52 private static final Pattern HERTZ_PATTERN = Pattern.compile("(\\d+(.\\d+)?) ?([kKMGT]?Hz).*");
53 private static final Pattern BYTES_PATTERN = Pattern.compile("(\\d+) ?([kKMGT]?B?).*");
54 private static final Pattern UNITS_PATTERN = Pattern.compile("(\\d+(.\\d+)?)[\\s]?([kKMGT])?");
55
56
57
58
59 private static final Pattern VALID_HEX = Pattern.compile("[0-9a-fA-F]+");
60
61
62
63
64 private static final Pattern DHMS = Pattern.compile("(?:(\\d+)-)?(?:(\\d+):)??(?:(\\d+):)?(\\d+)(?:\\.(\\d+))?");
65
66
67
68
69 private static final Pattern UUID_PATTERN = Pattern
70 .compile(".*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}).*");
71
72
73
74
75 private static final Pattern VENDOR_PRODUCT_ID_SERIAL = Pattern
76 .compile(".*(?:VID|VEN)_(\\p{XDigit}{4})&(?:PID|DEV)_(\\p{XDigit}{4})(.*)\\\\(.*)");
77
78
79
80
81 private static final Pattern LSPCI_MACHINE_READABLE = Pattern.compile("(.+)\\s\\[(.*?)\\]");
82
83
84
85
86 private static final Pattern LSPCI_MEMORY_SIZE = Pattern.compile(".+\\s\\[size=(\\d+)([kKMGT])\\]");
87
88
89
90
91 private static final String HZ = "Hz";
92 private static final String KHZ = "kHz";
93 private static final String MHZ = "MHz";
94 private static final String GHZ = "GHz";
95 private static final String THZ = "THz";
96 private static final String PHZ = "PHz";
97
98 private static final Map<String, Long> multipliers;
99
100
101
102 private static final long EPOCH_DIFF = 11_644_473_600_000L;
103 private static final int TZ_OFFSET = TimeZone.getDefault().getOffset(System.currentTimeMillis());
104
105
106 public static final Pattern whitespacesColonWhitespace = Pattern.compile("\\s+:\\s");
107
108
109 public static final Pattern whitespaces = Pattern.compile("\\s+");
110
111
112 public static final Pattern notDigits = Pattern.compile("[^0-9]+");
113
114
115 public static final Pattern startWithNotDigits = Pattern.compile("^[^0-9]*");
116
117
118 public static final Pattern slash = Pattern.compile("\\/");
119
120 static {
121 multipliers = new HashMap<>();
122 multipliers.put(HZ, 1L);
123 multipliers.put(KHZ, 1_000L);
124 multipliers.put(MHZ, 1_000_000L);
125 multipliers.put(GHZ, 1_000_000_000L);
126 multipliers.put(THZ, 1_000_000_000_000L);
127 multipliers.put(PHZ, 1_000_000_000_000_000L);
128 }
129
130
131 private static final long[] POWERS_OF_TEN = { 1L, 10L, 100L, 1_000L, 10_000L, 100_000L, 1_000_000L, 10_000_000L,
132 100_000_000L, 1_000_000_000L, 10_000_000_000L, 100_000_000_000L, 1_000_000_000_000L, 10_000_000_000_000L,
133 100_000_000_000_000L, 1_000_000_000_000_000L, 10_000_000_000_000_000L, 100_000_000_000_000_000L,
134 1_000_000_000_000_000_000L };
135
136
137 private static final DateTimeFormatter CIM_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss.SSSSSSZZZZZ",
138 Locale.US);
139
140 private ParseUtil() {
141 }
142
143
144
145
146
147
148
149 public static long parseHertz(String hertz) {
150 Matcher matcher = HERTZ_PATTERN.matcher(hertz.trim());
151 if (matcher.find() && matcher.groupCount() == 3) {
152
153 double value = Double.valueOf(matcher.group(1)) * multipliers.getOrDefault(matcher.group(3), -1L);
154 if (value >= 0d) {
155 return (long) value;
156 }
157 }
158 return -1L;
159 }
160
161
162
163
164
165
166
167
168 public static int parseLastInt(String s, int i) {
169 try {
170 String ls = parseLastString(s);
171 if (ls.toLowerCase(Locale.ROOT).startsWith("0x")) {
172 return Integer.decode(ls);
173 } else {
174 return Integer.parseInt(ls);
175 }
176 } catch (NumberFormatException e) {
177 LOG.trace(DEFAULT_LOG_MSG, s, e);
178 return i;
179 }
180 }
181
182
183
184
185
186
187
188
189 public static long parseLastLong(String s, long li) {
190 try {
191 String ls = parseLastString(s);
192 if (ls.toLowerCase(Locale.ROOT).startsWith("0x")) {
193 return Long.decode(ls);
194 } else {
195 return Long.parseLong(ls);
196 }
197 } catch (NumberFormatException e) {
198 LOG.trace(DEFAULT_LOG_MSG, s, e);
199 return li;
200 }
201 }
202
203
204
205
206
207
208
209
210 public static double parseLastDouble(String s, double d) {
211 try {
212 return Double.parseDouble(parseLastString(s));
213 } catch (NumberFormatException e) {
214 LOG.trace(DEFAULT_LOG_MSG, s, e);
215 return d;
216 }
217 }
218
219
220
221
222
223
224
225 public static String parseLastString(String s) {
226 String[] ss = whitespaces.split(s);
227
228 return ss[ss.length - 1];
229 }
230
231
232
233
234
235
236
237 public static String byteArrayToHexString(byte[] bytes) {
238 StringBuilder sb = new StringBuilder(bytes.length * 2);
239 for (byte b : bytes) {
240 sb.append(Character.forDigit((b & 0xf0) >>> 4, 16));
241 sb.append(Character.forDigit(b & 0x0f, 16));
242 }
243 return sb.toString().toUpperCase(Locale.ROOT);
244 }
245
246
247
248
249
250
251
252
253 public static byte[] hexStringToByteArray(String digits) {
254 int len = digits.length();
255
256 if (!VALID_HEX.matcher(digits).matches() || (len & 0x1) != 0) {
257 LOG.warn("Invalid hexadecimal string: {}", digits);
258 return new byte[0];
259 }
260 byte[] data = new byte[len / 2];
261 for (int i = 0; i < len; i += 2) {
262 data[i / 2] = (byte) (Character.digit(digits.charAt(i), 16) << 4
263 | Character.digit(digits.charAt(i + 1), 16));
264 }
265 return data;
266 }
267
268
269
270
271
272
273
274
275
276
277 public static byte[] asciiStringToByteArray(String text, int length) {
278 return Arrays.copyOf(text.getBytes(StandardCharsets.US_ASCII), length);
279 }
280
281
282
283
284
285
286
287
288
289
290 public static byte[] longToByteArray(long value, int valueSize, int length) {
291 long val = value;
292
293 byte[] b = new byte[8];
294 for (int i = 7; i >= 0 && val != 0L; i--) {
295 b[i] = (byte) val;
296 val >>>= 8;
297 }
298
299
300 return Arrays.copyOfRange(b, 8 - valueSize, 8 + length - valueSize);
301 }
302
303
304
305
306
307
308
309
310 public static long strToLong(String str, int size) {
311 return byteArrayToLong(str.getBytes(StandardCharsets.US_ASCII), size);
312 }
313
314
315
316
317
318
319
320
321 public static long byteArrayToLong(byte[] bytes, int size) {
322 return byteArrayToLong(bytes, size, true);
323 }
324
325
326
327
328
329
330
331
332
333 public static long byteArrayToLong(byte[] bytes, int size, boolean bigEndian) {
334 if (size > 8) {
335 throw new IllegalArgumentException("Can't convert more than 8 bytes.");
336 }
337 if (size > bytes.length) {
338 throw new IllegalArgumentException("Size can't be larger than array length.");
339 }
340 long total = 0L;
341 for (int i = 0; i < size; i++) {
342 if (bigEndian) {
343 total = total << 8 | bytes[i] & 0xff;
344 } else {
345 total = total << 8 | bytes[size - i - 1] & 0xff;
346 }
347 }
348 return total;
349 }
350
351
352
353
354
355
356
357
358
359
360 public static float byteArrayToFloat(byte[] bytes, int size, int fpBits) {
361 return byteArrayToLong(bytes, size) / (float) (1 << fpBits);
362 }
363
364
365
366
367
368
369
370
371
372
373 public static long unsignedIntToLong(int unsignedValue) {
374
375
376
377
378 long longValue = unsignedValue;
379 return longValue & 0xffff_ffffL;
380 }
381
382
383
384
385
386
387
388
389 public static long unsignedLongToSignedLong(long unsignedValue) {
390 return unsignedValue & 0x7fff_ffff_ffff_ffffL;
391 }
392
393
394
395
396
397
398
399 public static String hexStringToString(String hexString) {
400
401 if (hexString.length() % 2 > 0) {
402 return hexString;
403 }
404 int charAsInt;
405 StringBuilder sb = new StringBuilder();
406 try {
407 for (int pos = 0; pos < hexString.length(); pos += 2) {
408 charAsInt = Integer.parseInt(hexString.substring(pos, pos + 2), 16);
409 if (charAsInt < 32 || charAsInt > 127) {
410 return hexString;
411 }
412 sb.append((char) charAsInt);
413 }
414 } catch (NumberFormatException e) {
415 LOG.trace(DEFAULT_LOG_MSG, hexString, e);
416
417 return hexString;
418 }
419 return sb.toString();
420 }
421
422
423
424
425
426
427
428
429 public static int parseIntOrDefault(String s, int defaultInt) {
430 try {
431 return Integer.parseInt(s);
432 } catch (NumberFormatException e) {
433 LOG.trace(DEFAULT_LOG_MSG, s, e);
434 return defaultInt;
435 }
436 }
437
438
439
440
441
442
443
444
445 public static long parseLongOrDefault(String s, long defaultLong) {
446 try {
447 return Long.parseLong(s);
448 } catch (NumberFormatException e) {
449 LOG.trace(DEFAULT_LOG_MSG, s, e);
450 return defaultLong;
451 }
452 }
453
454
455
456
457
458
459
460
461
462 public static long parseUnsignedLongOrDefault(String s, long defaultLong) {
463 try {
464 return new BigInteger(s).longValue();
465 } catch (NumberFormatException e) {
466 LOG.trace(DEFAULT_LOG_MSG, s, e);
467 return defaultLong;
468 }
469 }
470
471
472
473
474
475
476
477
478 public static double parseDoubleOrDefault(String s, double defaultDouble) {
479 try {
480 return Double.parseDouble(s);
481 } catch (NumberFormatException e) {
482 LOG.trace(DEFAULT_LOG_MSG, s, e);
483 return defaultDouble;
484 }
485 }
486
487
488
489
490
491
492
493
494
495 public static long parseDHMSOrDefault(String s, long defaultLong) {
496 Matcher m = DHMS.matcher(s);
497 if (m.matches()) {
498 long milliseconds = 0L;
499 if (m.group(1) != null) {
500 milliseconds += parseLongOrDefault(m.group(1), 0L) * 86_400_000L;
501 }
502 if (m.group(2) != null) {
503 milliseconds += parseLongOrDefault(m.group(2), 0L) * 3_600_000L;
504 }
505 if (m.group(3) != null) {
506 milliseconds += parseLongOrDefault(m.group(3), 0L) * 60_000L;
507 }
508 milliseconds += parseLongOrDefault(m.group(4), 0L) * 1000L;
509 if (m.group(5) != null) {
510 milliseconds += (long) (1000 * parseDoubleOrDefault("0." + m.group(5), 0d));
511 }
512 return milliseconds;
513 }
514 return defaultLong;
515 }
516
517
518
519
520
521
522
523
524 public static String parseUuidOrDefault(String s, String defaultStr) {
525 Matcher m = UUID_PATTERN.matcher(s.toLowerCase(Locale.ROOT));
526 if (m.matches()) {
527 return m.group(1);
528 }
529 return defaultStr;
530 }
531
532
533
534
535
536
537
538 public static String getSingleQuoteStringValue(String line) {
539 return getStringBetween(line, '\'');
540 }
541
542
543
544
545
546
547
548 public static String getDoubleQuoteStringValue(String line) {
549 return getStringBetween(line, '"');
550 }
551
552
553
554
555
556
557
558
559
560
561
562
563 public static String getStringBetween(String line, char c) {
564 int firstOcc = line.indexOf(c);
565 if (firstOcc < 0) {
566 return "";
567 }
568 return line.substring(firstOcc + 1, line.lastIndexOf(c)).trim();
569 }
570
571
572
573
574
575
576
577
578 public static int getFirstIntValue(String line) {
579 return getNthIntValue(line, 1);
580 }
581
582
583
584
585
586
587
588
589
590 public static int getNthIntValue(String line, int n) {
591
592 String[] split = notDigits.split(startWithNotDigits.matcher(line).replaceFirst(""));
593 if (split.length >= n) {
594 return parseIntOrDefault(split[n - 1], 0);
595 }
596 return 0;
597 }
598
599
600
601
602
603
604
605
606 public static String removeMatchingString(final String original, final String toRemove) {
607 if (original == null || original.isEmpty() || toRemove == null || toRemove.isEmpty()) {
608 return original;
609 }
610
611 int matchIndex = original.indexOf(toRemove, 0);
612 if (matchIndex == -1) {
613 return original;
614 }
615
616 StringBuilder buffer = new StringBuilder(original.length() - toRemove.length());
617 int currIndex = 0;
618 do {
619 buffer.append(original.substring(currIndex, matchIndex));
620 currIndex = matchIndex + toRemove.length();
621 matchIndex = original.indexOf(toRemove, currIndex);
622 } while (matchIndex != -1);
623
624 buffer.append(original.substring(currIndex));
625 return buffer.toString();
626 }
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649 public static long[] parseStringToLongArray(String s, int[] indices, int length, char delimiter) {
650
651 s = s.trim();
652
653 long[] parsed = new long[indices.length];
654
655
656 int charIndex = s.length();
657 int parsedIndex = indices.length - 1;
658 int stringIndex = length - 1;
659
660 int power = 0;
661 int c;
662 boolean delimCurrent = false;
663 boolean numeric = true;
664 boolean numberFound = false;
665 boolean dashSeen = false;
666 while (--charIndex >= 0 && parsedIndex >= 0) {
667 c = s.charAt(charIndex);
668 if (c == delimiter) {
669
670 if (!numberFound && numeric) {
671 numberFound = true;
672 }
673 if (!delimCurrent) {
674 if (numberFound && indices[parsedIndex] == stringIndex--) {
675 parsedIndex--;
676 }
677 delimCurrent = true;
678 power = 0;
679 dashSeen = false;
680 numeric = true;
681 }
682 } else if (indices[parsedIndex] != stringIndex || c == '+' || !numeric) {
683
684 delimCurrent = false;
685 } else if (c >= '0' && c <= '9' && !dashSeen) {
686 if (power > 18 || power == 17 && c == '9' && parsed[parsedIndex] > 223_372_036_854_775_807L) {
687 parsed[parsedIndex] = Long.MAX_VALUE;
688 } else {
689 parsed[parsedIndex] += (c - '0') * ParseUtil.POWERS_OF_TEN[power++];
690 }
691 delimCurrent = false;
692 } else if (c == '-') {
693 parsed[parsedIndex] *= -1L;
694 delimCurrent = false;
695 dashSeen = true;
696 } else {
697
698
699 if (numberFound) {
700 if (!noLog(s)) {
701 LOG.error("Illegal character parsing string '{}' to long array: {}", s, s.charAt(charIndex));
702 }
703 return new long[indices.length];
704 }
705 parsed[parsedIndex] = 0;
706 numeric = false;
707 }
708 }
709 if (parsedIndex > 0) {
710 if (!noLog(s)) {
711 LOG.error("Not enough fields in string '{}' parsing to long array: {}", s,
712 indices.length - parsedIndex);
713 }
714 return new long[indices.length];
715 }
716 return parsed;
717 }
718
719
720
721
722
723
724
725 private static boolean noLog(String s) {
726 return s.startsWith("NOLOG: ");
727 }
728
729
730
731
732
733
734
735
736
737
738
739 public static int countStringToLongArray(String s, char delimiter) {
740
741 s = s.trim();
742
743
744
745 int charIndex = s.length();
746 int numbers = 0;
747
748 int c;
749 boolean delimCurrent = false;
750 boolean numeric = true;
751 boolean dashSeen = false;
752 while (--charIndex >= 0) {
753 c = s.charAt(charIndex);
754 if (c == delimiter) {
755 if (!delimCurrent) {
756 if (numeric) {
757 numbers++;
758 }
759 delimCurrent = true;
760 dashSeen = false;
761 numeric = true;
762 }
763 } else if (c == '+' || !numeric) {
764
765 delimCurrent = false;
766 } else if (c >= '0' && c <= '9' && !dashSeen) {
767 delimCurrent = false;
768 } else if (c == '-') {
769 delimCurrent = false;
770 dashSeen = true;
771 } else {
772
773 if (numbers > 0) {
774 return numbers;
775 }
776
777 numeric = false;
778 }
779 }
780
781
782 return numbers + 1;
783 }
784
785
786
787
788
789
790
791
792
793 public static String getTextBetweenStrings(String text, String before, String after) {
794
795 String result = "";
796
797 if (text.indexOf(before) >= 0 && text.indexOf(after) >= 0) {
798 result = text.substring(text.indexOf(before) + before.length(), text.length());
799 result = result.substring(0, result.indexOf(after));
800 }
801 return result;
802 }
803
804
805
806
807
808
809
810
811
812 public static long filetimeToUtcMs(long filetime, boolean local) {
813 return filetime / 10_000L - EPOCH_DIFF - (local ? TZ_OFFSET : 0L);
814 }
815
816
817
818
819
820
821
822 public static String parseMmDdYyyyToYyyyMmDD(String dateString) {
823 try {
824
825 return String.format(Locale.ROOT, "%s-%s-%s", dateString.substring(6, 10), dateString.substring(0, 2),
826 dateString.substring(3, 5));
827 } catch (StringIndexOutOfBoundsException e) {
828 return dateString;
829 }
830 }
831
832
833
834
835
836
837
838
839
840 public static OffsetDateTime parseCimDateTimeToOffset(String cimDateTime) {
841
842
843 try {
844
845 int tzInMinutes = Integer.parseInt(cimDateTime.substring(22));
846
847 LocalTime offsetAsLocalTime = LocalTime.MIDNIGHT.plusMinutes(tzInMinutes);
848 return OffsetDateTime.parse(
849 cimDateTime.substring(0, 22) + offsetAsLocalTime.format(DateTimeFormatter.ISO_LOCAL_TIME),
850 ParseUtil.CIM_FORMAT);
851 } catch (IndexOutOfBoundsException
852 | NumberFormatException
853 | DateTimeParseException e) {
854 LOG.trace("Unable to parse {} to CIM DateTime.", cimDateTime);
855 return Constants.UNIX_EPOCH;
856 }
857 }
858
859
860
861
862
863
864
865
866 public static boolean filePathStartsWith(List<String> prefixList, String path) {
867 for (String match : prefixList) {
868 if (path.equals(match) || path.startsWith(match + "/")) {
869 return true;
870 }
871 }
872 return false;
873 }
874
875
876
877
878
879
880
881 public static long parseMultipliedToLongs(String count) {
882 Matcher matcher = UNITS_PATTERN.matcher(count.trim());
883 String[] mem;
884 if (matcher.find() && matcher.groupCount() == 3) {
885 mem = new String[2];
886 mem[0] = matcher.group(1);
887 mem[1] = matcher.group(3);
888 } else {
889 mem = new String[] { count };
890 }
891
892 double number = ParseUtil.parseDoubleOrDefault(mem[0], 0L);
893 if (mem.length == 2 && mem[1] != null && mem[1].length() >= 1) {
894 switch (mem[1].charAt(0)) {
895 case 'T':
896 number *= 1_000_000_000_000L;
897 break;
898 case 'G':
899 number *= 1_000_000_000L;
900 break;
901 case 'M':
902 number *= 1_000_000L;
903 break;
904 case 'K':
905 case 'k':
906 number *= 1_000L;
907 break;
908 default:
909 }
910 }
911 return (long) number;
912 }
913
914
915
916
917
918
919
920
921 public static long parseDecimalMemorySizeToBinary(String size) {
922 String[] mem = ParseUtil.whitespaces.split(size);
923 if (mem.length < 2) {
924
925 Matcher matcher = BYTES_PATTERN.matcher(size.trim());
926 if (matcher.find() && matcher.groupCount() == 2) {
927 mem = new String[2];
928 mem[0] = matcher.group(1);
929 mem[1] = matcher.group(2);
930 }
931 }
932 long capacity = ParseUtil.parseLongOrDefault(mem[0], 0L);
933 if (mem.length == 2 && mem[1].length() > 1) {
934 switch (mem[1].charAt(0)) {
935 case 'T':
936 capacity <<= 40;
937 break;
938 case 'G':
939 capacity <<= 30;
940 break;
941 case 'M':
942 capacity <<= 20;
943 break;
944 case 'K':
945 case 'k':
946 capacity <<= 10;
947 break;
948 default:
949 break;
950 }
951 }
952 return capacity;
953 }
954
955
956
957
958
959
960
961
962
963 public static Triplet<String, String, String> parseDeviceIdToVendorProductSerial(String deviceId) {
964 Matcher m = VENDOR_PRODUCT_ID_SERIAL.matcher(deviceId);
965 if (m.matches()) {
966 String vendorId = "0x" + m.group(1).toLowerCase(Locale.ROOT);
967 String productId = "0x" + m.group(2).toLowerCase(Locale.ROOT);
968 String serial = m.group(4);
969 return new Triplet<>(vendorId, productId, !m.group(3).isEmpty() || serial.contains("&") ? "" : serial);
970 }
971 return null;
972 }
973
974
975
976
977
978
979
980 public static long parseLshwResourceString(String resources) {
981 long bytes = 0L;
982
983 String[] resourceArray = whitespaces.split(resources);
984 for (String r : resourceArray) {
985
986 if (r.startsWith("memory:")) {
987
988 String[] mem = r.substring(7).split("-");
989 if (mem.length == 2) {
990 try {
991
992 bytes += Long.parseLong(mem[1], 16) - Long.parseLong(mem[0], 16) + 1;
993 } catch (NumberFormatException e) {
994 LOG.trace(DEFAULT_LOG_MSG, r, e);
995 }
996 }
997 }
998 }
999 return bytes;
1000 }
1001
1002
1003
1004
1005
1006
1007
1008 public static Pair<String, String> parseLspciMachineReadable(String line) {
1009 Matcher matcher = LSPCI_MACHINE_READABLE.matcher(line);
1010 if (matcher.matches()) {
1011 return new Pair<>(matcher.group(1), matcher.group(2));
1012 }
1013 return null;
1014 }
1015
1016
1017
1018
1019
1020
1021
1022 public static long parseLspciMemorySize(String line) {
1023 Matcher matcher = LSPCI_MEMORY_SIZE.matcher(line);
1024 if (matcher.matches()) {
1025 return parseDecimalMemorySizeToBinary(matcher.group(1) + " " + matcher.group(2) + "B");
1026 }
1027 return 0;
1028 }
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038 public static List<Integer> parseHyphenatedIntList(String str) {
1039 List<Integer> result = new ArrayList<>();
1040 String[] csvTokens = str.split(",");
1041 for (String csvToken : csvTokens) {
1042 csvToken = csvToken.trim();
1043 for (String s : whitespaces.split(csvToken)) {
1044 if (s.contains("-")) {
1045 int first = getFirstIntValue(s);
1046 int last = getNthIntValue(s, 2);
1047 for (int i = first; i <= last; i++) {
1048 result.add(i);
1049 }
1050 } else {
1051 int only = ParseUtil.parseIntOrDefault(s, -1);
1052 if (only >= 0) {
1053 result.add(only);
1054 }
1055 }
1056 }
1057 }
1058 return result;
1059 }
1060
1061
1062
1063
1064
1065
1066
1067 public static byte[] parseIntToIP(int ip) {
1068 return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ip).array();
1069 }
1070
1071
1072
1073
1074
1075
1076
1077 public static byte[] parseIntArrayToIP(int[] ip6) {
1078 ByteBuffer bb = ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN);
1079 for (int i : ip6) {
1080 bb.putInt(i);
1081 }
1082 return bb.array();
1083 }
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093 public static int bigEndian16ToLittleEndian(int port) {
1094
1095
1096 return port >> 8 & 0xff | port << 8 & 0xff00;
1097 }
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107 public static String parseUtAddrV6toIP(int[] utAddrV6) {
1108 if (utAddrV6.length != 4) {
1109 throw new IllegalArgumentException("ut_addr_v6 must have exactly 4 elements");
1110 }
1111
1112 if (utAddrV6[1] == 0 && utAddrV6[2] == 0 && utAddrV6[3] == 0) {
1113
1114 if (utAddrV6[0] == 0) {
1115 return "::";
1116 }
1117
1118 byte[] ipv4 = ByteBuffer.allocate(4).putInt(utAddrV6[0]).array();
1119 try {
1120 return InetAddress.getByAddress(ipv4).getHostAddress();
1121 } catch (UnknownHostException e) {
1122
1123 return Constants.UNKNOWN;
1124 }
1125 }
1126
1127 byte[] ipv6 = ByteBuffer.allocate(16).putInt(utAddrV6[0]).putInt(utAddrV6[1]).putInt(utAddrV6[2])
1128 .putInt(utAddrV6[3]).array();
1129 try {
1130 return InetAddress.getByAddress(ipv6).getHostAddress()
1131 .replaceAll("((?:(?:^|:)0+\\b){2,8}):?(?!\\S*\\b\\1:0+\\b)(\\S*)", "::$2");
1132 } catch (UnknownHostException e) {
1133
1134 return Constants.UNKNOWN;
1135 }
1136 }
1137
1138
1139
1140
1141
1142
1143
1144
1145 public static int hexStringToInt(String hexString, int defaultValue) {
1146 if (hexString != null) {
1147 try {
1148 if (hexString.startsWith("0x")) {
1149 return new BigInteger(hexString.substring(2), 16).intValue();
1150 } else {
1151 return new BigInteger(hexString, 16).intValue();
1152 }
1153 } catch (NumberFormatException e) {
1154 LOG.trace(DEFAULT_LOG_MSG, hexString, e);
1155 }
1156 }
1157
1158 return defaultValue;
1159 }
1160
1161
1162
1163
1164
1165
1166
1167
1168 public static long hexStringToLong(String hexString, long defaultValue) {
1169 if (hexString != null) {
1170 try {
1171 if (hexString.startsWith("0x")) {
1172 return new BigInteger(hexString.substring(2), 16).longValue();
1173 } else {
1174 return new BigInteger(hexString, 16).longValue();
1175 }
1176 } catch (NumberFormatException e) {
1177 LOG.trace(DEFAULT_LOG_MSG, hexString, e);
1178 }
1179 }
1180
1181 return defaultValue;
1182 }
1183
1184
1185
1186
1187
1188
1189
1190 public static String removeLeadingDots(String dotPrefixedStr) {
1191 int pos = 0;
1192 while (pos < dotPrefixedStr.length() && dotPrefixedStr.charAt(pos) == '.') {
1193 pos++;
1194 }
1195 return pos < dotPrefixedStr.length() ? dotPrefixedStr.substring(pos) : "";
1196 }
1197
1198
1199
1200
1201
1202
1203
1204
1205 public static List<String> parseByteArrayToStrings(byte[] bytes) {
1206 List<String> strList = new ArrayList<>();
1207 int start = 0;
1208 int end = 0;
1209
1210 do {
1211
1212 if (end == bytes.length || bytes[end] == 0) {
1213
1214 if (start == end) {
1215 break;
1216 }
1217
1218
1219 strList.add(new String(bytes, start, end - start, StandardCharsets.UTF_8));
1220 start = end + 1;
1221 }
1222 } while (end++ < bytes.length);
1223 return strList;
1224 }
1225
1226
1227
1228
1229
1230
1231
1232
1233 public static Map<String, String> parseByteArrayToStringMap(byte[] bytes) {
1234
1235
1236 Map<String, String> strMap = new LinkedHashMap<>();
1237 int start = 0;
1238 int end = 0;
1239 String key = null;
1240
1241 do {
1242
1243 if (end == bytes.length || bytes[end] == 0) {
1244
1245 if (start == end && key == null) {
1246 break;
1247 }
1248
1249
1250 strMap.put(key, new String(bytes, start, end - start, StandardCharsets.UTF_8));
1251 key = null;
1252 start = end + 1;
1253 } else if (bytes[end] == '=' && key == null) {
1254 key = new String(bytes, start, end - start, StandardCharsets.UTF_8);
1255 start = end + 1;
1256 }
1257 } while (end++ < bytes.length);
1258 return strMap;
1259 }
1260
1261
1262
1263
1264
1265
1266
1267
1268 public static Map<String, String> parseCharArrayToStringMap(char[] chars) {
1269
1270
1271 Map<String, String> strMap = new LinkedHashMap<>();
1272 int start = 0;
1273 int end = 0;
1274 String key = null;
1275
1276 do {
1277
1278 if (end == chars.length || chars[end] == 0) {
1279
1280 if (start == end && key == null) {
1281 break;
1282 }
1283
1284
1285 strMap.put(key, new String(chars, start, end - start));
1286 key = null;
1287 start = end + 1;
1288 } else if (chars[end] == '=' && key == null) {
1289 key = new String(chars, start, end - start);
1290 start = end + 1;
1291 }
1292 } while (end++ < chars.length);
1293 return strMap;
1294 }
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307 public static <K extends Enum<K>> Map<K, String> stringToEnumMap(Class<K> clazz, String values, char delim) {
1308 EnumMap<K, String> map = new EnumMap<>(clazz);
1309 int start = 0;
1310 int len = values.length();
1311 EnumSet<K> keys = EnumSet.allOf(clazz);
1312 int keySize = keys.size();
1313 for (K key : keys) {
1314
1315
1316 int idx = --keySize == 0 ? len : values.indexOf(delim, start);
1317 if (idx >= 0) {
1318 map.put(key, values.substring(start, idx));
1319 start = idx;
1320 do {
1321 start++;
1322 } while (start < len && values.charAt(start) == delim);
1323 } else {
1324 map.put(key, values.substring(start));
1325 break;
1326 }
1327 }
1328 return map;
1329 }
1330
1331
1332
1333
1334
1335
1336
1337
1338 public static String getValueOrUnknown(Map<String, String> map, String key) {
1339 String value = map.getOrDefault(key, "");
1340 return value.isEmpty() ? Constants.UNKNOWN : value;
1341 }
1342 }