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