2121import java .io .InputStream ;
2222import java .io .InvalidObjectException ;
2323import java .io .PushbackInputStream ;
24+ import java .nio .ByteBuffer ;
2425import java .nio .charset .Charset ;
2526import java .util .ArrayList ;
2627import java .util .LinkedHashMap ;
@@ -38,28 +39,55 @@ public class BencodeInputStream extends FilterInputStream {
3839 private static final int EOF = -1 ;
3940
4041 private final Charset charset ;
42+ private final boolean useBytes ;
4143 private final PushbackInputStream in ;
4244
4345 /**
44- * Creates a new BencodeInputStream that reads from the {@link InputStream} passed and uses the {@link Charset} passed for decoding the data.
46+ * Creates a new BencodeInputStream that reads from the {@link InputStream} passed and uses the {@link Charset} passed for decoding the data
47+ * and boolean passed to control String parsing.
4548 *
46- * @param in the {@link InputStream} to read from
47- * @param charset the {@link Charset} to use
49+ * If useBytes is false, then dictionary values that contain byte string data will be coerced to a {@link String}.
50+ * if useBytes is true, then dictionary values that contain byte string data will be coerced to a {@link ByteBuffer}.
51+ *
52+ * @param in the {@link InputStream} to read from
53+ * @param charset the {@link Charset} to use
54+ * @param useBytes controls coercion of dictionary values
4855 *
4956 * @throws NullPointerException if the {@link Charset} passed is null
57+ *
58+ * @since 1.3
5059 */
51- public BencodeInputStream (final InputStream in , final Charset charset ) {
60+ public BencodeInputStream (final InputStream in , final Charset charset , boolean useBytes ) {
5261 super (new PushbackInputStream (in ));
5362 this .in = (PushbackInputStream ) super .in ;
5463
5564 if (charset == null ) throw new NullPointerException ("charset cannot be null" );
5665 this .charset = charset ;
66+ this .useBytes = useBytes ;
5767 }
5868
5969 /**
60- * Creates a new BencodeInputStream that reads from the {@link InputStream} passed and uses the UTF-8 {@link Charset} for decoding the data.
70+ * Creates a new BencodeInputStream that reads from the {@link InputStream} passed and uses the {@link Charset} passed for decoding the data
71+ * and coerces dictionary values to a {@link String}.
72+ *
73+ * @param in the {@link InputStream} to read from
74+ * @param charset the {@link Charset} to use
75+ *
76+ * @throws NullPointerException if the {@link Charset} passed is null
77+ *
78+ * @see #BencodeInputStream(InputStream, Charset, boolean)
79+ */
80+ public BencodeInputStream (final InputStream in , final Charset charset ) {
81+ this (in , charset , false );
82+ }
83+
84+ /**
85+ * Creates a new BencodeInputStream that reads from the {@link InputStream} passed and uses the UTF-8 {@link Charset} for decoding the data
86+ * and coerces dictionary values to a {@link String}.
6187 *
6288 * @param in the {@link InputStream} to read from
89+ *
90+ * @see #BencodeInputStream(InputStream, Charset, boolean)
6391 */
6492 public BencodeInputStream (final InputStream in ) {
6593 this (in , Bencode .DEFAULT_CHARSET );
@@ -105,15 +133,34 @@ private Type typeForToken(int token) {
105133 }
106134
107135 /**
108- * Reads a String from the stream.
136+ * Reads a {@link String} from the stream.
109137 *
110- * @return the String read from the stream
138+ * @return the {@link String} read from the stream
111139 *
112140 * @throws IOException if the underlying stream throws
113141 * @throws EOFException if the end of the stream has been reached
114142 * @throws InvalidObjectException if the next type in the stream is not a String
115143 */
116144 public String readString () throws IOException {
145+ return new String (readStringBytesInternal (), getCharset ());
146+ }
147+
148+ /**
149+ * Reads a Byte String from the stream.
150+ *
151+ * @return the {@link ByteBuffer} read from the stream
152+ *
153+ * @throws IOException if the underlying stream throws
154+ * @throws EOFException if the end of the stream has been reached
155+ * @throws InvalidObjectException if the next type in the stream is not a String
156+ *
157+ * @since 1.3
158+ */
159+ public ByteBuffer readStringBytes () throws IOException {
160+ return ByteBuffer .wrap (readStringBytesInternal ());
161+ }
162+
163+ private byte [] readStringBytesInternal () throws IOException {
117164 int token = in .read ();
118165 validateToken (token , Type .STRING );
119166
@@ -128,7 +175,7 @@ public String readString() throws IOException {
128175 int length = Integer .parseInt (buffer .toString ());
129176 byte [] bytes = new byte [length ];
130177 read (bytes );
131- return new String ( bytes , getCharset ()) ;
178+ return bytes ;
132179 }
133180
134181 /**
@@ -206,8 +253,10 @@ private Object readObject(final int token) throws IOException {
206253
207254 Type type = typeForToken (token );
208255
209- if (type == Type .STRING )
256+ if (type == Type .STRING && ! useBytes )
210257 return readString ();
258+ if (type == Type .STRING && useBytes )
259+ return readStringBytes ();
211260 if (type == Type .NUMBER )
212261 return readNumber ();
213262 if (type == Type .LIST )
0 commit comments