Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 120 lines (99 sloc) 3.778 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
/// @file
/// Embedded bencode support, header definitions.
// 2012-09-29 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

/// Encoder class to generate Bencode on the fly (no buffer storage needed).
class EmBencode {
public:
  EmBencode () {}
  
  /// Push a string out in Bencode format.
  /// @param str The zero-terminated string to send out (without trailing \0).
  static void push (const char* str) {
    push(str, strlen(str));
  }

  /// Push arbitrary bytes in Bencode format.
  /// @param ptr Pointer to the data to send out.
  /// @param len Number of data bytes to send out.
  static void push (const void* ptr, uint8_t len) {
    PushCount(len);
    PushChar(':');
    PushData(ptr, len);
  }

  /// Push a signed integer in Bencode format.
  /// @param val The integer to send (this implementation supports 32 bits).
  static void push (long val) {
    PushChar('i');
    if (val < 0) {
      PushChar('-');
      val = -val;
    }
    PushCount(val);
    PushEnd();
  }

  /// Start a new new list. Must be matched with a call to endList().
  /// Entries can be nested with more calls to startList(), startDict(), etc.
  static void startList () {
    PushChar('l');
  }

  /// Terminate a list, started earlier with a call to startList().
  static void endList () {
    PushEnd();
  }

  /// Start a new new dictionary. Must be matched with a call to endDict().
  /// Dictionary entries must consist of a string key plus an arbitrary value.
  /// Entries can be nested with more calls to startList(), startDict(), etc.
  static void startDict () {
    PushChar('d');
  }

  /// Terminate a dictionary, started earlier with a call to startDict().
  static void endDict () {
    PushEnd();
  }

protected:
  static void PushCount (uint32_t num) {
    char buf[11];
    PushData(ultoa(num, buf, 10), strlen(buf));
  }

  static void PushEnd () {
    PushChar('e');
  }

  static void PushData (const void* ptr, uint8_t len) {
    for (const char* p = (const char*) ptr; len-- > 0; ++p)
      PushChar(*p);
  }

  /// This function is not implemented in the library. It must be supplied by
  /// the caller to implement the actual writing of caharacters.
  static void PushChar (char ch);
};

/// Decoder class, needs an external buffer to collect the incoming data.
class EmBdecode {
public:
  /// Types of tokens, as returned by nextToken().
  enum { T_STRING = 0, T_NUMBER = 251, T_DICT, T_LIST, T_POP, T_END };

  /// Initialize a decoder instance with the specified buffer space.
  /// @param buf Pointer to the buffer which will be used by the decoder.
  /// @param len Size of the buffer, must be in the range 50 to 255.
  EmBdecode (char* buf, uint8_t len)
    : bufPtr (buf), bufLen (len) { reset(); }

  /// Reset the decoder - can be called to prepare for a new round of decoding.
  uint8_t reset ();

  /// Process a single incoming caharacter.
  /// @return Returns a count > 0 when the buffer contains a complete packet.
  uint8_t process (char ch);

  /// Call this after process() is done, to extract each of the data tokens.
  /// @returns Returns one of the T_STRING .. T_END enumeration codes.
  uint8_t nextToken ();
  /// Extract the last token as string (works for T_STRING and T_NUMBER).
  /// @param plen This variable will receive the size, if present.
  /// @return Returns pointer to a zero-terminated string in the decode buffer.
  const char* asString (uint8_t* plen =0);
  /// Extract the last token as number (also works for strings if numeric).
  /// @return Returns the decoded integer, max 32-bit signed in this version.
  long asNumber ();
  
protected:
  void AddToBuf (char ch);

  char level, *bufPtr;
  uint8_t bufLen, count, next, last, state;
};
Something went wrong with that request. Please try again.