Skip to content

Latest commit

 

History

History
289 lines (219 loc) · 8.45 KB

README_zh.md

File metadata and controls

289 lines (219 loc) · 8.45 KB

Contributors Forks Stargazers Issues License Deploy


bencode

A header-only Bencode parser and generator for C++20. It supports both SAX and DOM style API.
Explore the docs »

特性 · 示例 · 构建 · 集成 . 许可

Translations: English | 简体中文

特性

  • 简单、快速. bencode 库只包含头文件, 不依赖于 Boost。你可以随意 "组装" bencode 库的 Handler。
  • 简洁的 API. bencode 库同时支持 DOM 和 SAX 风格的 API, SAX 可以自定义 Handler 实现流式处理。
  • 多种输入输出流. bencode 库内置了字符串输入输出流和文件输入输出流, 并充分利用内存缓冲区提高读写速度。
  • 内置 std 流包装类. bencode 库提供了正式的 std::istream 和 std::ostream 包装类, 可以与 bencode 库的内置输入输出流组合

示例

用法一目了然

此简单例子解析一个 Bencode 字符串至一个 document (DOM), 对 DOM 作出简单修改, 最终把 DOM 转换(stringify)至 Bencode 字符串。

#include <cstdio>
#include <cstdlib>

#include "bencode/document.h"
#include "bencode/exception.h"
#include "bencode/string_write_stream.h"
#include "bencode/writer.h"
#include "sample.h"

int main(const int argc, char *argv[]) {
  (void)argc;
  (void)argv;

  // 1. Parse a Bencode string into DOM.
  bencode::Document doc;
  if (const auto err = doc.Parse(kSample[0]); err != bencode::error::OK) {
    puts(bencode::ParseErrorStr(err));
    return EXIT_FAILURE;
  }

  // 2. Modify it by DOM.
  auto &s = doc["creation date"];
  s.SetInteger(0);

  // 3. Stringify the DOM
  bencode::StringWriteStream os;
  bencode::Writer writer(os);
  doc.WriteTo(writer);

  // Output
  fprintf(stdout, "%.*s", static_cast<int>(os.get().length()), os.get().data());

  return 0;
}

输出:

d8:announce41:http://bttracker.debian.org:6969/announce7:comment35:"Debian CD from cdimage.debian.org"10:created by13:mktorrent 1.113:creation datei0e4:infod6:lengthi3909091328e4:name29:debian-11.6.0-amd64-DVD-1.iso12:piece lengthi262144e6:pieces41:(binary blob of the hashes of each piece)ee

Bencode 与 JSON 之间的相互转换

得益于 bencode 库优秀的设计。bencode 库可以很容易地与 neujson 结合使用, 实现 JSON 与 Bencode 之间的相互转换。同时, 这也是 SAX 的一个示例。与 DOM 不同, SAX 不会将数据存储到内存中, 而是直接从输入流写到输出流中。

Bencode 转 JSON

#include <memory>
#include <string_view>

#include "bencode/non_copyable.h"
#include "bencode/reader.h"
#include "bencode/string_read_stream.h"
#include "sample.h"

#include "neujson/file_write_stream.h"
#include "neujson/pretty_writer.h"

template <typename Handler> class BencodeToJSON : bencode::NonCopyable {
  Handler &handler_;

public:
  explicit BencodeToJSON(Handler &handler) : handler_(handler) {}

  bool Null() { return true; }
  bool Integer(int64_t i64) { return handler_.Int64(i64); }
  bool String(std::string_view str) { return handler_.String(str); }
  bool Key(std::string_view str) { return handler_.Key(str); }
  bool StartList() { return handler_.StartArray(); }
  bool EndList() { return handler_.EndArray(); }
  bool StartDict() { return handler_.StartObject(); }
  bool EndDict() { return handler_.EndObject(); }
};

int main(const int argc, char *argv[]) {
  (void)argc;
  (void)argv;

  bencode::StringReadStream in(kSample[0]);

  neujson::FileWriteStream out(stdout);
  neujson::PrettyWriter pretty_writer(out);
  pretty_writer.SetIndent(' ', 2);
  BencodeToJSON to_json(pretty_writer);

  if (const auto err = bencode::Reader::Parse(in, to_json);
      err != bencode::error::OK) {
    puts(bencode::ParseErrorStr(err));
    return EXIT_FAILURE;
  }

  return 0;
}

输出:

{
  "announce": "http://bttracker.debian.org:6969/announce",
  "comment": "\"Debian CD from cdimage.debian.org\"",
  "created by": "mktorrent 1.1",
  "creation date": 1671279452,
  "info": {
    "length": 3909091328,
    "name": "debian-11.6.0-amd64-DVD-1.iso",
    "piece length": 262144,
    "pieces": "(binary blob of the hashes of each piece)"
  }
}

JSON 转 Bencode

#include <memory>
#include <string_view>

#include "bencode/file_write_stream.h"
#include "bencode/writer.h"
#include "sample.h"

#include "neujson/internal/ieee754.h"
#include "neujson/non_copyable.h"
#include "neujson/reader.h"
#include "neujson/string_read_stream.h"

template <typename Handler> class JSONToBencode : neujson::NonCopyable {
  Handler &handler_;

public:
  explicit JSONToBencode(Handler &handler) : handler_(handler) {}

  bool Null() { return handler_.Null(); }
  bool Bool(const bool b) {
    (void)b;
    return true;
  }
  bool Int32(int32_t i32) { return handler_.Integer(i32); }
  bool Int64(int64_t i64) { return handler_.Integer(i64); }
  bool Double(const neujson::internal::Double d) {
    (void)d;
    return true;
  }
  bool String(std::string_view str) { return handler_.String(str); }
  bool Key(std::string_view str) { return handler_.Key(str); }
  bool StartArray() { return handler_.StartList(); }
  bool EndArray() { return handler_.EndList(); }
  bool StartObject() { return handler_.StartDict(); }
  bool EndObject() { return handler_.EndDict(); }
};

int main(const int argc, char *argv[]) {
  (void)argc;
  (void)argv;

  neujson::StringReadStream in(kSample[1]);

  bencode::FileWriteStream out(stdout);
  bencode::Writer writer(out);
  JSONToBencode to_json(writer);

  if (const auto err = neujson::Reader::Parse(in, to_json);
      err != neujson::error::OK) {
    puts(neujson::ParseErrorStr(err));
    return EXIT_FAILURE;
  }

  return 0;
}

输出:

d8:announce41:http://bttracker.debian.org:6969/announce7:comment35:"Debian CD from cdimage.debian.org"10:created by13:mktorrent 1.113:creation datei1671279452e4:infod6:lengthi3909091328e4:name29:debian-11.6.0-amd64-DVD-1.iso12:piece lengthi262144e6:pieces41:(binary blob of the hashes of each piece)ee

构建

项目需要 C++17 的支持, 同时使用了这些库:

构建测试时:

构建示例时:

在构建过程中, 所有依赖都会自动从 github 中获取, 您不需要配置它们。

使用 CMake build types, 您可以控制是否构建示例和测试。

cmake -H. -Bbuild \
	-DCMAKE_BUILD_TYPE=Release \
	-DCMAKE_INSTALL_PREFIX=/Users/hominsu/utils/install \
	-DNEUJSON_BUILD_EXAMPLES=ON \
	-DNEUJSON_BUILD_TESTS=ON
cmake --build ./build --parallel $(nproc)
ctest -VV --test-dir ./build/ --output-on-failure
cmake --install ./build

或者只作为 CMake 包安装。

cmake -H. -Bbuild \
	-DNEUJSON_BUILD_EXAMPLES=OFF \
	-DNEUJSON_BUILD_TESTS=OFF
cmake --install ./build

卸载

cd build
make uninstall

集成

在 CMake 中使用 find_package 定位 bencode 库。

find_package(bencode REQUIRED)
target_include_directories(foo PUBLIC ${bencode_INCLUDE_DIRS})

许可

在 MIT 许可下发布。更多信息请参见 LICENSE