/* BDecoder - Converts an InputStream to BEValues. Copyright (C) 2003 Mark J. Wielaard This file is part of Snark. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.klomp.snark.bencode; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; public class BEncoder { public static byte[] bencode(Object o) throws IllegalArgumentException { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bencode(o, baos); return baos.toByteArray(); } catch (IOException ioe) { throw new InternalError(ioe.toString()); } } public static void bencode(Object o, OutputStream out) throws IOException, IllegalArgumentException { if (o == null) throw new NullPointerException("Cannot bencode null"); if (o instanceof String) bencode((String)o, out); else if (o instanceof byte[]) bencode((byte[])o, out); else if (o instanceof Number) bencode((Number)o, out); else if (o instanceof List) bencode((List<?>)o, out); else if (o instanceof Map) bencode((Map<?, ?>)o, out); else if (o instanceof BEValue) bencode(((BEValue)o).getValue(), out); else throw new IllegalArgumentException("Cannot bencode: " + o.getClass()); } public static byte[] bencode(String s) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bencode(s, baos); return baos.toByteArray(); } catch (IOException ioe) { throw new InternalError(ioe.toString()); } } public static void bencode(String s, OutputStream out) throws IOException { byte[] bs = s.getBytes("UTF-8"); bencode(bs, out); } public static byte[] bencode(Number n) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bencode(n, baos); return baos.toByteArray(); } catch (IOException ioe) { throw new InternalError(ioe.toString()); } } public static void bencode(Number n, OutputStream out) throws IOException { out.write('i'); String s = n.toString(); out.write(s.getBytes("UTF-8")); out.write('e'); } public static byte[] bencode(List<?> l) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bencode(l, baos); return baos.toByteArray(); } catch (IOException ioe) { throw new InternalError(ioe.toString()); } } public static void bencode(List<?> l, OutputStream out) throws IOException { out.write('l'); Iterator<?> it = l.iterator(); while (it.hasNext()) bencode(it.next(), out); out.write('e'); } public static byte[] bencode(byte[] bs) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bencode(bs, baos); return baos.toByteArray(); } catch (IOException ioe) { throw new InternalError(ioe.toString()); } } public static void bencode(byte[] bs, OutputStream out) throws IOException { String l = Integer.toString(bs.length); out.write(l.getBytes("UTF-8")); out.write(':'); out.write(bs); } public static byte[] bencode(Map<?, ?> m) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bencode(m, baos); return baos.toByteArray(); } catch (IOException ioe) { throw new InternalError(ioe.toString()); } } public static void bencode(Map<?, ?> m, OutputStream out) throws IOException, IllegalArgumentException { out.write('d'); // Keys must be sorted. XXX - But is this the correct order? Set<?> s = m.keySet(); List<String> l = new ArrayList<String>(s.size()); for (Object k : s) { // Keys must be Strings. if (String.class.isAssignableFrom(k.getClass())) l.add((String) k); else throw new IllegalArgumentException("Cannot bencode map: contains non-String key of type " + k.getClass()); } Collections.sort(l); Iterator<String> it = l.iterator(); while(it.hasNext()) { String key = it.next(); bencode(key, out); bencode(m.get(key), out); } out.write('e'); } }