#(bytes) $
cat test.bin | hexdump -ve '/1 "%02x"' ### обратная функция: cat hexstring.txt | xxd -r -p > output.bin
#(words) $
cat test.bin | hexdump -ve '/2 "%04x"'
---------
Символы формата:
/1 — говорит, что читать и форматировать следует по одному байту,
/2 — по два байта как единое целое,
"%02x" — формат вывода одного байта с лидирующими нулями,
"%04x" — формат вывода двухбайтового слова с лидирующими нулями.
Таким образом, первый пример выводит dump построчно байт за байтом, а второй — группами из двух байт (в том числе меняя порядок байтов на little-endian, если используется hexdump по умолчанию).
Если нужно корректно читать слова в вашем файле как они идут (big-endian или little-endian), нужно знать порядок байтов в данных. Но с точки зрения формата вывода /1 "%02x" — байт за байтом, /2 "%04x" — слова по 2 байта как слово.
Это стандартное поведение команды hexdump с параметром формата вывода.
** или ***
$ cat hexbin.c
/*
* hexbin.c — самодостаточная замена связки
* cat file.bin | hexdump -ve '/1 "%02x"' (кодирование bin -> hex)
* cat hex.txt | xxd -r -p > file.bin (декодирование hex -> bin)
*
* Использование:
* hexbin -e < input.bin > hex.txt кодирование (bin -> сплошной hex, lowercase)
* hexbin -d < hex.txt > output.bin декодирование (hex -> bin)
*
* Компиляция для полной автономности (статический бинарник, без внешних
* зависимостей — можно скопировать на любой linux x86_64 и запустить):
*
* gcc -O2 -Wall -Wextra -static -o hexbin hexbin.c
*
* Если статическая линковка недоступна (нет libc.a), собрать динамически:
* gcc -O2 -Wall -Wextra -o hexbin hexbin.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 65536
static const char HEX[] = "0123456789abcdef";
/* bin -> hex (аналог hexdump -ve '/1 "%02x"') */
static int encode(void)
{
unsigned char in[BUF_SIZE];
char out[BUF_SIZE * 2];
size_t n;
while ((n = fread(in, 1, sizeof(in), stdin)) > 0) {
for (size_t i = 0; i < n; i++) {
out[i * 2] = HEX[(in[i] >> 4) & 0xF];
out[i * 2 + 1] = HEX[in[i] & 0xF];
}
if (fwrite(out, 1, n * 2, stdout) != n * 2) {
perror("fwrite");
return 1;
}
}
if (ferror(stdin)) {
perror("fread");
return 1;
}
return 0;
}
static int hexval(int c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return -1;
}
/* hex -> bin (аналог xxd -r -p), пробелы/переводы строк игнорируются */
static int decode(void)
{
int c;
int have_high = 0;
int high = 0;
long pos = 0;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
continue;
int v = hexval(c);
if (v < 0) {
fprintf(stderr, "hexbin: недопустимый символ hex '%c' на позиции %ld\n", c, pos);
return 1;
}
pos++;
if (!have_high) {
high = v;
have_high = 1;
} else {
unsigned char byte = (unsigned char)((high << 4) | v);
if (putchar(byte) == EOF) {
perror("putchar");
return 1;
}
have_high = 0;
}
}
if (have_high) {
fprintf(stderr, "hexbin: нечётное количество hex-символов (незавершённая пара)\n");
return 1;
}
return 0;
}
static void usage(const char *prog)
{
fprintf(stderr,
"Использование: %s -e|-d\n"
" -e кодировать stdin (бинарные данные) в hex-строку -> stdout\n"
" -d декодировать stdin (hex-строку) в бинарные данные -> stdout\n",
prog);
}
int main(int argc, char **argv)
{
if (argc != 2) {
usage(argv[0]);
return 2;
}
if (strcmp(argv[1], "-e") == 0 || strcmp(argv[1], "--encode") == 0)
return encode();
if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--decode") == 0)
return decode();
usage(argv[0]);
return 2;
}