Skip to content

Commit 5c99291

Browse files
committed
Initial extraction
1 parent 99a4774 commit 5c99291

File tree

11 files changed

+652
-0
lines changed

11 files changed

+652
-0
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*.class
2+
3+
build/**
4+
dist/**
5+
.idea/**
6+
7+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
8+
hs_err_pid*

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2015 Ian Preston
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,12 @@
11
# java-multiaddr
22
Java implementation of multiaddr
3+
4+
## Usage
5+
MultiAddress m = new MultiAddress("/ip4/127.0.0.1/tcp/1234");
6+
7+
or
8+
9+
MultiAddress m = new MultiAddress("/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC");
10+
11+
## Compilation
12+
To compile just run ant.

build.xml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<project name="java-multiaddr" default="dist" basedir=".">
2+
<description>
3+
Java Multiaddr
4+
</description>
5+
6+
<property name="src" location="src"/>
7+
<property name="build" location="build"/>
8+
<property name="dist" location="dist"/>
9+
10+
<path id="dep.runtime">
11+
<fileset dir="./lib">
12+
<include name="**/*.jar" />
13+
</fileset>
14+
</path>
15+
16+
<target name="init">
17+
<mkdir dir="${build}"/>
18+
</target>
19+
20+
<target name="compile" depends="init" description="compile the source">
21+
<javac includeantruntime="false" srcdir="${src}" destdir="${build}" debug="true" debuglevel="lines,vars,source">
22+
<classpath>
23+
<fileset dir="lib">
24+
<include name="**/*.jar" />
25+
</fileset>
26+
</classpath>
27+
</javac>
28+
</target>
29+
30+
<target name="dist" depends="compile" description="generate the distribution">
31+
<mkdir dir="${dist}/lib"/>
32+
<copy todir="${dist}/lib">
33+
<fileset dir="lib"/>
34+
</copy>
35+
<manifestclasspath property="manifest_cp" jarfile="myjar.jar">
36+
<classpath refid="dep.runtime" />
37+
</manifestclasspath>
38+
<jar jarfile="${dist}/Multiaddr.jar" basedir="${build}">
39+
<manifest>
40+
<attribute name="Class-Path" value="${manifest_cp}"/>
41+
</manifest>
42+
</jar>
43+
<copy todir=".">
44+
<fileset file="${dist}/Multiaddr.jar"/>
45+
</copy>
46+
</target>
47+
48+
49+
<target name="test" depends="compile,dist">
50+
<junit printsummary="yes" fork="true" haltonfailure="yes">
51+
<jvmarg value="-Xmx1g"/>
52+
<classpath>
53+
<pathelement location="lib/junit-4.11.jar" />
54+
<pathelement location="lib/hamcrest-core-1.3.jar" />
55+
<pathelement location="Multiaddr.jar" />
56+
</classpath>
57+
<test name="org.ipfs.api.MultiaddrTests" haltonfailure="yes">
58+
<formatter type="plain"/>
59+
<formatter type="xml"/>
60+
</test>
61+
</junit>
62+
</target>
63+
64+
<target name="clean" description="clean up">
65+
<delete dir="${build}"/>
66+
<delete dir="${dist}"/>
67+
</target>
68+
</project>

lib/Multihash.jar

6.74 KB
Binary file not shown.

lib/hamcrest-core-1.3.jar

44 KB
Binary file not shown.

lib/junit-4.12.jar

308 KB
Binary file not shown.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package org.ipfs.api;
2+
3+
import java.math.*;
4+
5+
/**
6+
* Based on RFC 4648
7+
*/
8+
public class Base32 {
9+
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
10+
private static final BigInteger BASE = BigInteger.valueOf(32);
11+
12+
public static String encode(byte[] input) {
13+
// TODO: This could be a lot more efficient.
14+
BigInteger bi = new BigInteger(1, input);
15+
StringBuffer s = new StringBuffer();
16+
while (bi.compareTo(BASE) >= 0) {
17+
BigInteger mod = bi.mod(BASE);
18+
s.insert(0, ALPHABET.charAt(mod.intValue()));
19+
bi = bi.subtract(mod).divide(BASE);
20+
}
21+
s.insert(0, ALPHABET.charAt(bi.intValue()));
22+
// Convert leading zeros too.
23+
for (byte anInput : input) {
24+
if (anInput == 0)
25+
s.insert(0, ALPHABET.charAt(0));
26+
else
27+
break;
28+
}
29+
return s.toString();
30+
}
31+
32+
public static byte[] decode(String input) {
33+
byte[] bytes = decodeToBigInteger(input).toByteArray();
34+
// We may have got one more byte than we wanted, if the high bit of the next-to-last byte was not zero. This
35+
// is because BigIntegers are represented with twos-compliment notation, thus if the high bit of the last
36+
// byte happens to be 1 another 8 zero bits will be added to ensure the number parses as positive. Detect
37+
// that case here and chop it off.
38+
boolean stripSignByte = bytes.length > 1 && bytes[0] == 0 && bytes[1] < 0;
39+
// Count the leading zeros, if any.
40+
int leadingZeros = 0;
41+
for (int i = 0; input.charAt(i) == ALPHABET.charAt(0); i++) {
42+
leadingZeros++;
43+
}
44+
// Now cut/pad correctly. Java 6 has a convenience for this, but Android can't use it.
45+
byte[] tmp = new byte[bytes.length - (stripSignByte ? 1 : 0) + leadingZeros];
46+
System.arraycopy(bytes, stripSignByte ? 1 : 0, tmp, leadingZeros, tmp.length - leadingZeros);
47+
return tmp;
48+
}
49+
50+
public static BigInteger decodeToBigInteger(String input) {
51+
BigInteger bi = BigInteger.valueOf(0);
52+
// Work backwards through the string.
53+
for (int i = input.length() - 1; i >= 0; i--) {
54+
int alphaIndex = ALPHABET.indexOf(input.charAt(i));
55+
if (alphaIndex == -1) {
56+
throw new IllegalStateException("Illegal character " + input.charAt(i) + " at " + i);
57+
}
58+
bi = bi.add(BigInteger.valueOf(alphaIndex).multiply(BASE.pow(input.length() - 1 - i)));
59+
}
60+
return bi;
61+
}
62+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package org.ipfs.api;
2+
3+
import java.io.*;
4+
import java.util.*;
5+
6+
public class MultiAddress
7+
{
8+
private final byte[] raw;
9+
10+
public MultiAddress(String address) {
11+
this(decodeFromString(address));
12+
}
13+
14+
public MultiAddress(byte[] raw) {
15+
encodeToString(raw); // check validity
16+
this.raw = raw;
17+
}
18+
19+
public byte[] getBytes() {
20+
return Arrays.copyOfRange(raw, 0, raw.length);
21+
}
22+
23+
public boolean isTCPIP() {
24+
String[] parts = toString().substring(1).split("/");
25+
if (parts.length != 4)
26+
return false;
27+
if (!parts[0].startsWith("ip"))
28+
return false;
29+
if (!parts[2].equals("tcp"))
30+
return false;
31+
return true;
32+
}
33+
34+
public String getHost() {
35+
String[] parts = toString().substring(1).split("/");
36+
if (parts[0].startsWith("ip"))
37+
return parts[1];
38+
throw new IllegalStateException("This multiaddress doesn't have a host: "+toString());
39+
}
40+
41+
public int getTCPPort() {
42+
String[] parts = toString().substring(1).split("/");
43+
if (parts[2].startsWith("tcp"))
44+
return Integer.parseInt(parts[3]);
45+
throw new IllegalStateException("This multiaddress doesn't have a tcp port: "+toString());
46+
}
47+
48+
private static byte[] decodeFromString(String addr) {
49+
while (addr.endsWith("/"))
50+
addr = addr.substring(0, addr.length()-1);
51+
String[] parts = addr.split("/");
52+
if (parts[0].length() != 0)
53+
throw new IllegalStateException("MultiAddress must start with a /");
54+
55+
ByteArrayOutputStream bout = new ByteArrayOutputStream();
56+
try {
57+
for (int i = 1; i < parts.length;) {
58+
String part = parts[i++];
59+
Protocol p = Protocol.get(part);
60+
p.appendCode(bout);
61+
if (p.size() == 0)
62+
continue;
63+
64+
String component = parts[i++];
65+
if (component.length() == 0)
66+
throw new IllegalStateException("Protocol requires address, but non provided!");
67+
68+
bout.write(p.addressToBytes(component));
69+
}
70+
return bout.toByteArray();
71+
} catch (IOException e) {
72+
throw new IllegalStateException("Error decoding multiaddress: "+addr);
73+
}
74+
}
75+
76+
private static String encodeToString(byte[] raw) {
77+
StringBuilder b = new StringBuilder();
78+
InputStream in = new ByteArrayInputStream(raw);
79+
try {
80+
while (true) {
81+
int code = (int)Protocol.readVarint(in);
82+
Protocol p = Protocol.get(code);
83+
b.append("/" + p.name());
84+
if (p.size() == 0)
85+
continue;
86+
87+
String addr = p.readAddress(in);
88+
if (addr.length() > 0)
89+
b.append("/" +addr);
90+
}
91+
}
92+
catch (EOFException eof) {}
93+
catch (IOException e) {
94+
throw new RuntimeException(e);
95+
}
96+
97+
return b.toString();
98+
}
99+
100+
@Override
101+
public String toString() {
102+
return encodeToString(raw);
103+
}
104+
105+
@Override
106+
public boolean equals(Object other) {
107+
if (!(other instanceof MultiAddress))
108+
return false;
109+
return Arrays.equals(raw, ((MultiAddress) other).raw);
110+
}
111+
112+
@Override
113+
public int hashCode() {
114+
return Arrays.hashCode(raw);
115+
}
116+
}

0 commit comments

Comments
 (0)