pike.git / lib / modules / Protocols.pmod / Bittorrent.pmod / Bencoding.pmod

version» Context lines:

pike.git/lib/modules/Protocols.pmod/Bittorrent.pmod/Bencoding.pmod:1:   #pike __REAL_VERSION__    - //! Decodes a Bittorrent bencoded data chunk. - //! @returns - //! @array - //! @elem string|int|array|mapping data - //! The decoded data. UNDEFINED if no data could be decoded. - //! @elem string remainder - //! The trailing data that wasn't decoded. - //! @endarray - array(string|int|array|mapping) _decode(string what) + //! 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)   { -  if (what=="") return ({UNDEFINED,what}); -  if (what==0) error("Cannot decode 0 (zero)\n"); +  // Decode strings. Returns UNDEFINED if the declared size is smaller +  // than the rest of the buffer. +  if( array a = buf->sscanf("%d:") ) +  return buf->read(a[0]) || UNDEFINED;    -  int i; -  string s; -  -  switch (what[0]) +  mixed prefix; +  switch(prefix=buf->read(1))    { -  case 'i': // integer -  if (sscanf(what,"i%de%s",i,what)<2) -  return ({UNDEFINED,what}); -  return ({i,what}); +  case "": +  case 0: +  // End of buffer +  return UNDEFINED;    -  case '0'..'9': // string -  if (sscanf(what,"%d:%s",i,s)<2 || -  strlen(s)<i) -  return ({UNDEFINED,what}); -  return ({s[..i-1],s[i..]}); +  case "e": +  // End of list +  return UNDEFINED;    -  case 'l': // list -  array res=({}); -  s=what[1..]; -  while (s!="") -  { -  if (s[0]=='e') -  return ({res,s[1..]}); -  array v=_decode(s); -  if (v[1]==s) -  break; -  res+=v[..0]; -  s=v[1]; -  } -  return ({UNDEFINED,what}); +  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];    -  case 'd': // dictionary -  array keys=({}); -  array values=({}); -  s=what[1..]; -  while (s!="") +  case "l": +  // List +  array list = ({}); +  while(1)    { -  if (s[0]=='e') return ({mkmapping(keys,values),s[1..]}); +  mixed item = decode(buf); +  if( undefinedp(item) ) +  return list; +  list += ({ item }); +  };    -  array v=_decode(s); -  if (v[1]==s) break; -  keys+=v[..0]; -  s=v[1]; -  -  v=_decode(s); -  if (v[1]==s) break; -  values+=v[..0]; -  s=v[1]; +  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;    } -  return ({UNDEFINED,what}); +        default: -  error("Error in Bencoding: unknown prefix %O...\n", -  what[..10]); +  error("Error in Bencoding: unknown prefix %O...\n", prefix);    }   }    - //! Decodes a Bittorrent bencoded data chunk and ignores the remaining - //! string. Returns UNDEFINED if the data is incomplete. - string|int|array|mapping decode(string what) + variant string|int|array|mapping decode(string what)   { -  array v=_decode(what); -  if (v[1]==what) return UNDEFINED; -  return v[0]; +  return decode(Stdio.Buffer(what));   }    -  + __deprecated__ array(string|int|array|mapping) _decode(string what) + { +  Stdio.Buffer b = Stdio.Buffer(what); +  return ({ decode(b), b->read() }); + } +    //! Encodes a Bittorrent bencoded data chunk.   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":