Skip to content

Commit

Permalink
add hexdump
Browse files Browse the repository at this point in the history
  • Loading branch information
archibate committed Mar 1, 2024
1 parent d94b709 commit ad9f208
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 2 deletions.
2 changes: 2 additions & 0 deletions foundation/cpphexdumptool/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.cache/
build/
18 changes: 18 additions & 0 deletions foundation/cpphexdumptool/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.18)

if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_CXX_STANDARD 20)

project(main LANGUAGES CXX)

add_executable(main main.cpp)

include(FetchContent)
FetchContent_Declare(range-v3 GIT_REPOSITORY https://github.com/ericniebler/range-v3)
FetchContent_MakeAvailable(range-v3)
target_link_libraries(main PRIVATE range-v3)
FetchContent_Declare(cxxopts GIT_REPOSITORY https://github.com/jarro2783/cxxopts.git)
FetchContent_MakeAvailable(cxxopts)
target_link_libraries(main PRIVATE cxxopts)
87 changes: 87 additions & 0 deletions foundation/cpphexdumptool/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <cstdint>
#include <cstring>
#include <fstream>
#include <iostream>
#include <random>
#include <cctype>
#include <iomanip>
#include <range/v3/view/chunk.hpp>
#include <cxxopts.hpp>
#include <ranges>

void hexdump(std::ranges::input_range auto const &range, std::size_t width = 16) {
using T = std::ranges::range_value_t<decltype(range)>;
// 00096e90 6d 5f 64 65 76 69 63 65 20 72 64 3b 0a 20 20 20 |m_device rd;. |
std::size_t addr = 0;
std::vector<char> saved;
for (auto chunk: range | ranges::views::chunk(width)) {
std::cout << std::setw(8) << std::setfill('0') << std::hex << addr << ' ';
for (auto c: chunk) {
std::cout << ' ' << std::right << std::hex << std::setw(2 * sizeof(T)) << std::setfill('0');
std::cout << (std::uint64_t)(std::make_unsigned_t<T>)c;
++addr;
if constexpr (sizeof(T) == sizeof(char) && std::convertible_to<T, char>) {
saved.push_back(static_cast<char>(c));
}
}
if constexpr (sizeof(T) == sizeof(char) && std::convertible_to<T, char>) {
if (addr % width != 0) {
for (std::size_t i = 0; i < (width - addr % width) * 3; i++) {
std::cout << ' ';
}
}
std::cout << " |";
for (auto c: saved) {
if (!std::isprint(c)) {
c = '.';
}
std::cout << c;
}
std::cout << "|";
saved.clear();
}
std::cout << '\n';
}
}

struct IstreamRange {
std::istreambuf_iterator<char> b, e;

IstreamRange(std::istream &is)
: b(std::istreambuf_iterator<char>(is))
, e(std::istreambuf_iterator<char>()) {}

auto begin() const {
return b;
}

auto end() const {
return e;
}
};

int main(int argc, char **argv) {
cxxopts::Options options("hexdump", "A command line utility for printing the hexadecimal and ASCII representation of a file.");
options.add_options()("f,file", "Input file", cxxopts::value<std::string>()->default_value("-"));
options.add_options()("w,width", "Number of bytes per line", cxxopts::value<std::size_t>()->default_value("16"));
// add help
options.add_options()("h,help", "Print usage");
auto args = options.parse(argc, argv);
if (args.count("help")) {
std::cout << options.help() << '\n';
return 0;
}
auto path = args["file"].as<std::string>();
auto width = args["width"].as<std::size_t>();
if (path == "-") {
hexdump(IstreamRange(std::cin), width);
return 0;
}
std::ifstream ifs(path);
if (!ifs.good()) {
std::cerr << std::strerror(errno) << ": " << path << '\n';
return errno;
}
hexdump(IstreamRange(ifs), width);
return 0;
}
18 changes: 16 additions & 2 deletions foundation/cppwchartest/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ std::basic_string_view<To> reinterpret_string(std::basic_string_view<From> in) {
return std::basic_string_view<To>{reinterpret_cast<const To *>(in.data()), in.size()};
}

template <class To, class From>
const To *reinterpret_string(const From *in) {
static_assert(sizeof(To) == sizeof(From));
return reinterpret_cast<const To *>(in);
}

inline std::wstring utf8_to_wide(std::u8string_view in) {
if constexpr (sizeof(wchar_t) == 1) {
return std::wstring{reinterpret_string<wchar_t>(in)};
Expand Down Expand Up @@ -150,6 +156,12 @@ inline std::u16string utf8_to_utf16(std::u8string_view in) {
return widen<char16_t, char8_t>(in, std::locale::classic());
}

#define ansi_literial(s) s
#define unicode_literial(s) L##s
#define utf8_literial(s) u8##s
#define utf16_literial(s) u##s
#define utf32_literial(s) U##s

int main() {
using namespace std;
auto s_ansi = "我🤔"s;
Expand All @@ -164,9 +176,11 @@ int main() {
cout << "utf32: " << as_hex(s_utf32) << endl;
auto s_gb18030 = narrowing<wchar_t, char>(widen<wchar_t, char>("我🤔"s, std::locale("")), std::locale("zh_CN.GB18030"));
cout << "gb18030: " << as_hex(s_gb18030) << endl;
auto s_test = widen<wchar_t, char>("\xE6\x88\x91\xF0\x9F\xA4\x94"s, std::locale(""));
auto s_test = ansi_to_wide("我🤔"s, std::locale(""));
cout << "test: " << as_hex(s_test) << endl;
auto s_test2 = ansi_to_utf8("\xCE\xD2\x95\x30\xCD\x34"s, std::locale("zh_CN.GB18030"));
auto s_test2 = wide_to_ansi(L"我🤔"s, std::locale("zh_CN.GBK"));
cout << "test2: " << as_hex(s_test2) << endl;
auto s_test3 = wide_to_ansi(L"我🤔"s, std::locale("zh_CN.GB18030"));
cout << "test3: " << as_hex(s_test3) << endl;
return 0;
}

0 comments on commit ad9f208

Please sign in to comment.