1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.newsclub.net.unix;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.File;
22 import java.io.FileDescriptor;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27 import java.net.DatagramSocket;
28 import java.net.InetAddress;
29 import java.net.InetSocketAddress;
30 import java.net.ServerSocket;
31 import java.net.SocketAddress;
32 import java.net.SocketException;
33 import java.net.URI;
34 import java.nio.ByteBuffer;
35 import java.nio.charset.StandardCharsets;
36 import java.util.HashMap;
37 import java.util.Locale;
38 import java.util.Map;
39 import java.util.Objects;
40
41 import org.eclipse.jdt.annotation.NonNull;
42 import org.eclipse.jdt.annotation.Nullable;
43
44 import com.google.errorprone.annotations.Immutable;
45 import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
46
47
48
49
50
51
52 @Immutable
53 @SuppressWarnings({"PMD.CouplingBetweenObjects", "PMD.CyclomaticComplexity"})
54 public abstract class AFSocketAddress extends InetSocketAddress {
55 private static final long serialVersionUID = 1L;
56
57
58
59
60
61 static final AFSocketAddress INTERNAL_DUMMY_BIND = new SentinelSocketAddress(0);
62 static final AFSocketAddress INTERNAL_DUMMY_CONNECT = new SentinelSocketAddress(1);
63 static final AFSocketAddress INTERNAL_DUMMY_DONT_CONNECT = new SentinelSocketAddress(2);
64
65 private static final int SOCKADDR_NATIVE_FAMILY_OFFSET = NativeUnixSocket.isLoaded()
66 ? NativeUnixSocket.sockAddrNativeFamilyOffset() : -1;
67
68 private static final int SOCKADDR_NATIVE_DATA_OFFSET = NativeUnixSocket.isLoaded()
69 ? NativeUnixSocket.sockAddrNativeDataOffset() : -1;
70
71 private static final int SOCKADDR_MAX_LEN = NativeUnixSocket.isLoaded()
72 ? NativeUnixSocket.sockAddrLength(0) : 256;
73
74 private static final Map<AFAddressFamily<?>, Map<Integer, Map<ByteBuffer, AFSocketAddress>>> ADDRESS_CACHE =
75 new HashMap<>();
76
77 static final ThreadLocal<ByteBuffer> SOCKETADDRESS_BUFFER_TL = new ThreadLocal<ByteBuffer>() {
78
79 @Override
80 protected ByteBuffer initialValue() {
81 return AFSocketAddress.newSockAddrDirectBuffer(SOCKADDR_MAX_LEN);
82 }
83 };
84
85 private static final boolean USE_DESERIALIZATION_FOR_INIT;
86
87 static {
88 String v = System.getProperty("org.newsclub.net.unix.AFSocketAddress.deserialize", "");
89 USE_DESERIALIZATION_FOR_INIT = v.isEmpty() ? NativeLibraryLoader.isAndroid() : Boolean
90 .parseBoolean(v);
91 }
92
93
94
95
96
97 @SuppressFBWarnings("JCIP_FIELD_ISNT_FINAL_IN_IMMUTABLE_CLASS")
98 private byte[] bytes;
99
100
101
102
103 @SuppressFBWarnings("JCIP_FIELD_ISNT_FINAL_IN_IMMUTABLE_CLASS")
104
105 private InetAddress inetAddress = null;
106
107
108
109
110 @SuppressWarnings("PMD.ImmutableField")
111 private transient ByteBuffer nativeAddress;
112
113
114
115
116 private transient AFAddressFamily<?> addressFamily;
117
118
119
120
121
122
123
124
125
126
127 @SuppressFBWarnings("CT_CONSTRUCTOR_THROW")
128 protected AFSocketAddress(int port, final byte[] socketAddress, ByteBuffer nativeAddress,
129 AFAddressFamily<?> af) throws SocketException {
130
131
132
133
134
135
136
137 super(AFInetAddress.createUnresolvedHostname(socketAddress, af), port >= 0 && port <= 0xffff
138 ? port : 0);
139 initAFSocketAddress(this, port, socketAddress, nativeAddress, af);
140 }
141
142
143
144
145
146
147
148 @SuppressWarnings("PMD.UnusedFormalParameter")
149 AFSocketAddress(Class<SentinelSocketAddress> clazz, int port) {
150 super(InetAddress.getLoopbackAddress(), port);
151 this.nativeAddress = null;
152 this.bytes = new byte[0];
153 this.addressFamily = null;
154 }
155
156 @SuppressWarnings({"cast", "this-escape"})
157 private static void initAFSocketAddress(AFSocketAddress addr, int port,
158 final byte[] socketAddress, ByteBuffer nativeAddress, AFAddressFamily<?> af)
159 throws SocketException {
160 if (socketAddress.length == 0) {
161 throw new SocketException("Illegal address length: " + socketAddress.length);
162 }
163
164 addr.nativeAddress = nativeAddress == null ? null : (ByteBuffer) (Object) nativeAddress
165 .duplicate().rewind();
166 if (port < -1) {
167 throw new IllegalArgumentException("port out of range");
168 } else if (port > 0xffff) {
169 if (!NativeUnixSocket.isLoaded()) {
170 throw (SocketException) new SocketException(
171 "Cannot set SocketAddress port - junixsocket JNI library is not available").initCause(
172 NativeUnixSocket.unsupportedException());
173 }
174 NativeUnixSocket.setPort1(addr, port);
175 }
176
177 addr.bytes = socketAddress.clone();
178 addr.addressFamily = af;
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195 protected static <A extends AFSocketAddress> A newDeserializedAFSocketAddress(int port,
196 final byte[] socketAddress, ByteBuffer nativeAddress, AFAddressFamily<A> af,
197 AFSocketAddressConstructor<A> constructor) throws SocketException {
198 String hostname = AFInetAddress.createUnresolvedHostname(socketAddress, af);
199 if (hostname == null || hostname.isEmpty()) {
200 return constructor.newAFSocketAddress(port, socketAddress, nativeAddress);
201 }
202 try (ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(AFSocketAddress
203 .craftSerializedObject(af.getSocketAddressClass(), hostname, (port >= 0 && port <= 0xffff
204 ? port : 0))))) {
205 @SuppressWarnings("unchecked")
206 A addr = (A) oin.readObject();
207 initAFSocketAddress(addr, port, socketAddress, nativeAddress, af);
208 return addr;
209 } catch (SocketException e) {
210 throw e;
211 } catch (ClassNotFoundException | IOException e) {
212 throw (SocketException) new SocketException("Unexpected deserialization problem").initCause(
213 e);
214 }
215 }
216
217
218
219
220
221
222
223
224
225
226 private static byte[] craftSerializedObject(Class<? extends AFSocketAddress> className,
227 String hostname, int port) {
228 ByteBuffer bb = ByteBuffer.allocate(768);
229 bb.putShort((short) 0xaced);
230 bb.putShort((short) 5);
231 bb.put((byte) 0x73);
232 bb.put((byte) 0x72);
233
234 putShortLengthUtf8(bb, className.getName());
235 bb.putLong(1);
236 bb.putInt(0x02000078);
237 bb.put((byte) 0x72);
238
239 putShortLengthUtf8(bb, AFSocketAddress.class.getName());
240 bb.putLong(serialVersionUID);
241 bb.putInt(0x0300025B);
242 putShortLengthUtf8(bb, "bytes");
243
244 bb.putInt(0x7400025B);
245 bb.putShort((short) 0x424C);
246
247 putShortLengthUtf8(bb, "inetAddress");
248 bb.put((byte) 0x74);
249
250 putShortLengthEncodedClassName(bb, InetAddress.class);
251
252 bb.putShort((short) 0x7872);
253 putShortLengthUtf8(bb, InetSocketAddress.class.getName());
254 bb.putLong(5076001401234631237L);
255
256 bb.putInt(0x03000349);
257 putShortLengthUtf8(bb, "port");
258
259 bb.put((byte) 0x4C);
260 putShortLengthUtf8(bb, "addr");
261
262 bb.putInt(0x71007E00);
263 bb.putShort((short) 0x034C);
264 putShortLengthUtf8(bb, "hostname");
265 bb.put((byte) 0x74);
266
267 putShortLengthEncodedClassName(bb, String.class);
268
269 bb.putShort((short) 0x7872);
270 putShortLengthUtf8(bb, SocketAddress.class.getName());
271 bb.putLong(5215720748342549866L);
272
273 bb.putInt(0x02000078);
274 bb.put((byte) 0x70);
275 bb.putInt(port);
276
277 bb.putShort((short) 0x7074);
278 putShortLengthUtf8(bb, hostname);
279
280 bb.putInt(0x78707077);
281 bb.put((byte) 0x0B);
282
283 putShortLengthUtf8(bb, "undefined");
284
285 bb.put((byte) 0x78);
286 bb.flip();
287
288 byte[] buf = new byte[bb.remaining()];
289 bb.get(buf);
290 return buf;
291 }
292
293 private static void putShortLengthEncodedClassName(ByteBuffer bb, Class<?> klazz) {
294 putShortLengthUtf8(bb, "L" + klazz.getName().replace('.', '/') + ";");
295 }
296
297 private static void putShortLengthUtf8(ByteBuffer bb, String s) {
298 byte[] utf8 = s.getBytes(StandardCharsets.UTF_8);
299 bb.putShort((short) utf8.length);
300 bb.put(utf8);
301 }
302
303
304
305
306
307
308
309
310 protected static boolean isUseDeserializationForInit() {
311 return USE_DESERIALIZATION_FOR_INIT;
312 }
313
314
315
316
317
318
319 public abstract boolean hasFilename();
320
321
322
323
324
325
326
327
328
329
330 public abstract File getFile() throws FileNotFoundException;
331
332
333
334
335
336
337 public final AFAddressFamily<?> getAddressFamily() {
338 return addressFamily;
339 }
340
341
342
343
344
345
346
347
348
349 protected static final InetAddress getInetAddress(FileDescriptor fdesc, boolean peerName,
350 AFAddressFamily<?> af) {
351 if (!fdesc.valid()) {
352 return null;
353 }
354 byte[] addr = NativeUnixSocket.sockname(af.getDomain(), fdesc, peerName);
355 if (addr == null) {
356 return null;
357 }
358 return AFInetAddress.wrapAddress(addr, af);
359 }
360
361
362
363
364
365
366
367
368
369
370
371
372 protected static final <A extends AFSocketAddress> @Nullable A getSocketAddress(
373 FileDescriptor fdesc, boolean requestPeerName, int port, AFAddressFamily<A> af) {
374 if (!fdesc.valid()) {
375 return null;
376 }
377 byte[] addr = NativeUnixSocket.sockname(af.getDomain(), fdesc, requestPeerName);
378 if (addr == null) {
379 return null;
380 }
381 try {
382
383 return AFSocketAddress.unwrap(AFInetAddress.wrapAddress(addr, af), port, af);
384 } catch (SocketException e) {
385 throw new IllegalStateException(e);
386 }
387 }
388
389 static final AFSocketAddress preprocessSocketAddress(
390 Class<? extends AFSocketAddress> supportedAddressClass, SocketAddress endpoint,
391 AFSocketAddressFromHostname<?> afh) throws SocketException {
392 Objects.requireNonNull(endpoint);
393 if (endpoint instanceof SentinelSocketAddress) {
394 return (SentinelSocketAddress) endpoint;
395 }
396
397 if (!(endpoint instanceof AFSocketAddress)) {
398 if (afh != null) {
399 if (endpoint instanceof InetSocketAddress) {
400 InetSocketAddress isa = (InetSocketAddress) endpoint;
401
402 String hostname = isa.getHostString();
403 if (afh.isHostnameSupported(hostname)) {
404 try {
405 endpoint = afh.addressFromHost(hostname, isa.getPort());
406 } catch (SocketException e) {
407 throw e;
408 }
409 }
410 }
411 }
412 }
413
414 Objects.requireNonNull(endpoint);
415
416 if (!supportedAddressClass.isAssignableFrom(endpoint.getClass())) {
417 throw new IllegalArgumentException("Can only connect to endpoints of type "
418 + supportedAddressClass.getName() + ", got: " + endpoint.getClass() + ": " + endpoint);
419 }
420
421 return (AFSocketAddress) endpoint;
422 }
423
424
425
426
427
428
429 protected final byte[] getBytes() {
430 return bytes;
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444 public final InetAddress wrapAddress() {
445 return AFInetAddress.wrapAddress(bytes, getAddressFamily());
446 }
447
448
449
450
451
452
453
454 @FunctionalInterface
455 protected interface AFSocketAddressConstructor<T extends AFSocketAddress> {
456
457
458
459
460
461
462
463
464
465 @NonNull
466 T newAFSocketAddress(int port, byte[] socketAddress, ByteBuffer nativeAddress)
467 throws SocketException;
468 }
469
470
471
472
473
474
475
476
477
478
479
480
481 @SuppressWarnings({"unchecked", "null"})
482 protected static final <A extends AFSocketAddress> A resolveAddress(final byte[] socketAddress,
483 int port, AFAddressFamily<A> af) throws SocketException {
484 if (socketAddress.length == 0) {
485 throw new SocketException("Address cannot be empty");
486 }
487
488 if (port == -1) {
489 port = 0;
490 }
491
492 ByteBuffer direct = SOCKETADDRESS_BUFFER_TL.get();
493 int limit = NativeUnixSocket.isLoaded() ? NativeUnixSocket.bytesToSockAddr(af.getDomain(),
494 direct, socketAddress) : -1;
495 if (limit == -1) {
496
497 return af.getAddressConstructor().newAFSocketAddress(port, socketAddress, null);
498 } else if (limit > SOCKADDR_MAX_LEN) {
499 throw new IllegalStateException("Unexpected address length");
500 }
501 direct.rewind();
502 direct.limit(limit);
503
504 A instance;
505 synchronized (AFSocketAddress.class) {
506 Map<ByteBuffer, AFSocketAddress> map;
507 Map<Integer, Map<ByteBuffer, AFSocketAddress>> mapPorts = ADDRESS_CACHE.get(af);
508 if (mapPorts == null) {
509 instance = null;
510 mapPorts = new HashMap<>();
511 map = new HashMap<>();
512 mapPorts.put(port, map);
513 ADDRESS_CACHE.put(af, mapPorts);
514 } else {
515 map = mapPorts.get(port);
516 if (map == null) {
517 instance = null;
518 map = new HashMap<>();
519 mapPorts.put(port, map);
520 } else {
521 instance = (A) map.get(direct);
522 }
523 }
524
525 if (instance == null) {
526 ByteBuffer key = newSockAddrKeyBuffer(limit);
527 key.put(direct);
528 key = key.asReadOnlyBuffer();
529
530 instance = af.getAddressConstructor().newAFSocketAddress(port, socketAddress, key);
531
532 map.put(key, instance);
533 }
534 }
535
536 return instance;
537 }
538
539 @SuppressWarnings("null")
540 static final <A extends AFSocketAddress> A ofInternal(ByteBuffer socketAddressBuffer,
541 AFAddressFamily<A> af) throws SocketException {
542 synchronized (AFSocketAddress.class) {
543 socketAddressBuffer.rewind();
544
545 Map<Integer, Map<ByteBuffer, AFSocketAddress>> mapPorts = ADDRESS_CACHE.get(af);
546 if (mapPorts != null) {
547 Map<ByteBuffer, AFSocketAddress> map = mapPorts.get(0);
548
549 if (map != null) {
550 @SuppressWarnings("unchecked")
551 A address = (A) map.get(socketAddressBuffer);
552 if (address != null) {
553 return address;
554 }
555 }
556 }
557
558 if (!socketAddressBuffer.isDirect()) {
559 ByteBuffer buf = getNativeAddressDirectBuffer(Math.min(socketAddressBuffer.limit(),
560 SOCKADDR_MAX_LEN));
561 buf.put(socketAddressBuffer);
562 socketAddressBuffer = buf;
563 }
564
565 byte[] sockAddrToBytes = NativeUnixSocket.sockAddrToBytes(af.getDomain(),
566 socketAddressBuffer);
567 if (sockAddrToBytes == null) {
568 return null;
569 } else {
570 return AFSocketAddress.resolveAddress(sockAddrToBytes, 0, af);
571 }
572 }
573 }
574
575
576
577
578
579
580
581 protected final synchronized InetAddress getInetAddress(AFAddressFamily<?> af) {
582 if (inetAddress == null) {
583 inetAddress = AFInetAddress.wrapAddress(bytes, af);
584 }
585 return inetAddress;
586 }
587
588
589
590
591
592
593 protected final InetAddress getInetAddress() {
594 return getInetAddress(getAddressFamily());
595 }
596
597 static final ByteBuffer newSockAddrDirectBuffer(int length) {
598 return ByteBuffer.allocateDirect(length);
599 }
600
601 static final ByteBuffer newSockAddrKeyBuffer(int length) {
602 return ByteBuffer.allocate(length);
603 }
604
605
606
607
608
609
610
611
612
613
614
615
616
617 @SuppressWarnings("null")
618 @NonNull
619 protected static final <A extends AFSocketAddress> A unwrap(InetAddress address, int port,
620 AFAddressFamily<A> af) throws SocketException {
621 Objects.requireNonNull(address);
622 return resolveAddress(AFInetAddress.unwrapAddress(address, af), port, af);
623 }
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638 @SuppressWarnings("null")
639 @NonNull
640 protected static final <A extends AFSocketAddress> A unwrap(String hostname, int port,
641 AFAddressFamily<A> af) throws SocketException {
642 Objects.requireNonNull(hostname);
643 return resolveAddress(AFInetAddress.unwrapAddress(hostname, af), port, af);
644 }
645
646 static final int unwrapAddressDirectBufferInternal(ByteBuffer socketAddressBuffer,
647 SocketAddress address) throws SocketException {
648 if (!NativeUnixSocket.isLoaded()) {
649 throw new SocketException("Unsupported operation; junixsocket native library is not loaded");
650 }
651 Objects.requireNonNull(address);
652
653 if (!(address instanceof AFSocketAddress)) {
654 AFSupplier<? extends AFSocketAddress> supp = AFUNIXSocketAddress.supportedAddressSupplier(
655 address);
656 address = supp == null ? null : supp.get();
657 if (address == null) {
658 throw new SocketException("Unsupported address");
659 }
660 }
661
662 AFSocketAddress socketAddress = (AFSocketAddress) address;
663
664 byte[] addr = socketAddress.getBytes();
665 int domain = socketAddress.getAddressFamily().getDomain();
666
667 int len = NativeUnixSocket.bytesToSockAddr(domain, socketAddressBuffer, addr);
668 if (len == -1) {
669 throw new SocketException("Unsupported domain");
670 }
671 return len;
672 }
673
674
675
676
677
678
679
680 final ByteBuffer getNativeAddressDirectBuffer() throws SocketException {
681 ByteBuffer address = nativeAddress;
682 if (address == null) {
683 throw (SocketException) new SocketException("Cannot access native address").initCause(
684 NativeUnixSocket.unsupportedException());
685 }
686 address = address.duplicate();
687
688 ByteBuffer direct = getNativeAddressDirectBuffer(address.limit());
689 address.position(0);
690 direct.put(address);
691
692 return direct;
693 }
694
695 static final ByteBuffer getNativeAddressDirectBuffer(int limit) {
696 ByteBuffer direct = SOCKETADDRESS_BUFFER_TL.get();
697 direct.position(0);
698 direct.limit(limit);
699 return direct;
700 }
701
702
703
704
705
706
707
708
709 protected static final boolean isSupportedAddress(InetAddress addr, AFAddressFamily<?> af) {
710 return AFInetAddress.isSupportedAddress(addr, af);
711 }
712
713
714
715
716
717
718
719
720
721 public final void writeNativeAddressTo(ByteBuffer buf) throws IOException {
722 if (nativeAddress == null) {
723 throw (SocketException) new SocketException("Cannot access native address").initCause(
724 NativeUnixSocket.unsupportedException());
725 }
726 buf.put(nativeAddress);
727 }
728
729
730
731
732
733
734
735 public AFSocket<?> newConnectedSocket() throws IOException {
736 AFSocket<?> socket = getAddressFamily().newSocket();
737 socket.connect(this);
738 return socket;
739 }
740
741
742
743
744
745
746
747 public AFServerSocket<?> newBoundServerSocket() throws IOException {
748 AFServerSocket<?> serverSocket = getAddressFamily().newServerSocket();
749 serverSocket.bind(this);
750 return serverSocket;
751 }
752
753
754
755
756
757
758
759
760
761 public AFServerSocket<?> newForceBoundServerSocket() throws IOException {
762 AFServerSocket<?> serverSocket = getAddressFamily().newServerSocket();
763 serverSocket.forceBindAddress(this).bind(this);
764 return serverSocket;
765 }
766
767
768
769
770
771
772
773
774
775
776
777
778 @SuppressWarnings("PMD.ShortMethodName")
779 public static AFSocketAddress of(URI u) throws SocketException {
780 return of(u, -1);
781 }
782
783
784
785
786
787
788
789
790
791
792
793
794
795 @SuppressWarnings("PMD.ShortMethodName")
796 public static AFSocketAddress of(URI u, int overridePort) throws SocketException {
797 AFAddressFamily<?> af = AFAddressFamily.getAddressFamily(u);
798 if (af == null) {
799 throw new SocketException("Cannot resolve AFSocketAddress from URI scheme: " + u.getScheme());
800 }
801 return af.parseURI(u, overridePort);
802 }
803
804
805
806
807
808
809
810
811
812
813 public URI toURI(String scheme, URI template) throws IOException {
814 throw new IOException("Unsupported operation");
815 }
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831 public @Nullable @SuppressWarnings("PMD.NPathComplexity") String toSocatAddressString(
832 AFSocketType socketType, AFSocketProtocol socketProtocol) throws IOException {
833
834 if (SOCKADDR_NATIVE_FAMILY_OFFSET == -1 || SOCKADDR_NATIVE_DATA_OFFSET == -1) {
835 return null;
836 }
837 if (nativeAddress == null) {
838 throw (SocketException) new SocketException("Cannot access native address").initCause(
839 NativeUnixSocket.unsupportedException());
840 }
841 if (socketProtocol != null && socketProtocol.getId() != 0) {
842 throw new IOException("Protocol not (yet) supported");
843 }
844
845 int family = (nativeAddress.get(SOCKADDR_NATIVE_FAMILY_OFFSET) & 0xFF);
846 int type = socketType == null ? -1 : NativeUnixSocket.sockTypeToNative(socketType.getId());
847 StringBuilder sb = new StringBuilder();
848 sb.append(family);
849 if (type != -1) {
850 sb.append(':');
851 sb.append(type);
852 }
853 if (socketProtocol != null) {
854 sb.append(':');
855 sb.append(socketProtocol.getId());
856 }
857 sb.append(":x");
858 int n = nativeAddress.limit();
859 while (n > 1 && nativeAddress.get(n - 1) == 0) {
860 n--;
861 }
862 for (int pos = SOCKADDR_NATIVE_DATA_OFFSET; pos < n; pos++) {
863 byte b = nativeAddress.get(pos);
864 sb.append(String.format(Locale.ENGLISH, "%02x", b));
865 }
866 return sb.toString();
867 }
868
869
870
871
872
873
874
875
876
877
878
879
880
881 public boolean covers(AFSocketAddress other) {
882 return this.equals(other);
883 }
884
885
886
887
888
889
890
891
892 private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
893 in.defaultReadObject();
894
895 String af = in.readUTF();
896 if ("undefined".equals(af)) {
897 this.addressFamily = null;
898 } else {
899 this.addressFamily = Objects.requireNonNull(AFAddressFamily.getAddressFamily(af),
900 "address family");
901 }
902 }
903
904
905
906
907
908
909
910 private void writeObject(ObjectOutputStream out) throws IOException {
911 out.defaultWriteObject();
912 out.writeUTF(addressFamily == null ? "undefined" : addressFamily.getJuxString());
913 }
914
915
916
917
918
919
920
921
922
923 static String toUnsignedString(int i) {
924 return Long.toString(toUnsignedLong(i));
925 }
926
927
928
929
930
931
932
933
934
935 static String toUnsignedString(int i, int radix) {
936 return Long.toUnsignedString(toUnsignedLong(i), radix);
937 }
938
939 private static long toUnsignedLong(long x) {
940 return x & 0xffffffffL;
941 }
942
943
944
945
946
947
948
949
950
951
952
953 protected static int parseUnsignedInt(String s, int radix) throws NumberFormatException {
954 if (s == null || s.isEmpty()) {
955 throw new NumberFormatException("Cannot parse null or empty string");
956 }
957
958 int len = s.length();
959 if (s.startsWith("-")) {
960 throw new NumberFormatException("Illegal leading minus sign on unsigned string " + s);
961 }
962
963 if (len <= 5 || (radix == 10 && len <= 9)) {
964 return Integer.parseInt(s, radix);
965 } else {
966 long ell = Long.parseLong(s, radix);
967 if ((ell & 0xffff_ffff_0000_0000L) == 0) {
968 return (int) ell;
969 } else {
970 throw new NumberFormatException("String value exceeds " + "range of unsigned int: " + s);
971 }
972 }
973 }
974 }