68d7c12003-12-13Mirar (Pontus Hagland) #pike __REAL_VERSION__
4cb3c82015-10-25Martin Nilsson //! Decodes a Bittorrent bencoded data chunk and ignores the remaining //! string. Returns @expr{UNDEFINED@} if the data is incomplete. string|int|array|mapping decode(Stdio.Buffer buf)
fb397a2003-12-09Mirar (Pontus Hagland) {
780f2e2015-10-25Martin Nilsson  // Decode strings. Returns UNDEFINED if the declared size is smaller // than the rest of the buffer.
4cb3c82015-10-25Martin Nilsson  if( array a = buf->sscanf("%d:") ) return buf->read(a[0]) || UNDEFINED;
fb397a2003-12-09Mirar (Pontus Hagland) 
4cb3c82015-10-25Martin Nilsson  mixed prefix; switch(prefix=buf->read(1)) { case "": case 0: // End of buffer return UNDEFINED;
3524712015-05-26Martin Nilsson 
4cb3c82015-10-25Martin Nilsson  case "e": // End of list return UNDEFINED;
fb397a2003-12-09Mirar (Pontus Hagland) 
4cb3c82015-10-25Martin Nilsson  case "i": // Integer // 0-prefixed integers are illegal, but we don't check for // that. Also -0 is illegal, and not checked for. return buf->sscanf("%de")[0];
3524712015-05-26Martin Nilsson 
4cb3c82015-10-25Martin Nilsson  case "l": // List array list = ({}); while(1) { mixed item = decode(buf); if( undefinedp(item) ) return list; list += ({ item }); };
fb397a2003-12-09Mirar (Pontus Hagland) 
4cb3c82015-10-25Martin Nilsson  case "d": // Dictionary mapping dic = ([]); while(1) { // Keys must be strings and appear in sorted order. We don't // check for these restrictions. mixed ind = decode(buf); if( undefinedp(ind) ) return dic; mixed val = decode(buf); if( undefinedp(val) ) return dic; dic[ind] = val; }
fb397a2003-12-09Mirar (Pontus Hagland) 
4cb3c82015-10-25Martin Nilsson  default: error("Error in Bencoding: unknown prefix %O...\n", prefix); } }
fb397a2003-12-09Mirar (Pontus Hagland) 
4cb3c82015-10-25Martin Nilsson variant string|int|array|mapping decode(string what) { return decode(Stdio.Buffer(what));
fb397a2003-12-09Mirar (Pontus Hagland) }
4cb3c82015-10-25Martin Nilsson __deprecated__ array(string|int|array|mapping) _decode(string what)
fb397a2003-12-09Mirar (Pontus Hagland) {
4cb3c82015-10-25Martin Nilsson  Stdio.Buffer b = Stdio.Buffer(what); return ({ decode(b), b->read() });
fb397a2003-12-09Mirar (Pontus Hagland) }
c3e79c2003-12-16Martin Nilsson //! Encodes a Bittorrent bencoded data chunk.
fb397a2003-12-09Mirar (Pontus Hagland) string encode(string|int|array|mapping data) { switch (sprintf("%t",data)) { case "int": return sprintf("i%de",data); case "string": return sprintf("%d:%s",strlen(data),data); case "array": return "l"+map(data,encode)*""+"e"; case "mapping": string res="d"; array v=(array)data; sort(column(v,0),v); foreach (v;;[string|int|array|mapping key, string|int|array|mapping value]) { if (!stringp(key)) error("dictionaries (mappings) must have " "string keys!\n"); res+=encode(key)+encode(value); } return res+"e"; default: error("Cannot Bittorrent-Bencode type: %t\n",data); } }
9eaf1d2008-06-28Martin Nilsson private protected array(string) bits=
fb397a2003-12-09Mirar (Pontus Hagland)  sprintf("%08b",Array.enumerate(256)[*]);
9eaf1d2008-06-28Martin Nilsson private protected array(string) bobs=
fb397a2003-12-09Mirar (Pontus Hagland)  sprintf("%c",Array.enumerate(256)[*]);
c3e79c2003-12-16Martin Nilsson //! Convert an array of @expr{int(0..1)@} to a Bittorrent style //! bitstring. Input will be padded to even bytes.
fb397a2003-12-09Mirar (Pontus Hagland) string bits2string(array(int(0..1)) v) { if (sizeof(v)&7) v+=({0})*(8-sizeof(v)&7); return replace(sprintf("%@d",v),bits,bobs); }
c3e79c2003-12-16Martin Nilsson //! Convert a Bittorrent style bitstring to an array of //! @expr{int(0..1)@}.
fb397a2003-12-09Mirar (Pontus Hagland) array(int(0..1)) string2bits(string s) { return (array(int(0..1)))(replace(s,bobs,bits)/1); }
c3e79c2003-12-16Martin Nilsson //! Convert a Bittorrent style bitstring to an array of indices.
fb397a2003-12-09Mirar (Pontus Hagland) array(int) string2arr(string s) { if (last2arrbits==s) return copy_value(last2arrarr); // simple cache array v=string2bits(last2arrbits=s); array w=indices(v); sort(v,w); int i=search(v,1);
fffe9f2004-01-01Mirar (Pontus Hagland)  if (i==-1) return last2arrarr=({});
fb397a2003-12-09Mirar (Pontus Hagland)  return last2arrarr=w[i..]; }
c3e79c2003-12-16Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson protected private string last2arrbits=0; protected private array(int) last2arrarr=0;