Может ли простая программа на C имитировать стандартную команду 'xxd' так, чтобы ее вывод diff возвращал 0? - PullRequest
0 голосов
/ 03 февраля 2019

Я пытаюсь написать исполняемый файл C, который будет выдавать результат, идентичный выводу команды xxd по умолчанию.Например, допустим, у меня есть довольно небольшой текстовый файл с именем test.txt и исполняемый файл с именем myxxd

Итак, сначала я сделаю тест для сравнения, используя:

$ touch correct-xxdoutput.txt test-output.txt
$ xxd test.txt > correct-xxdoutput.txt

Затем, используя мой исполняемый файл для той же операции, но для другого выходного файла:

$ ./myxxd test.txt > test-output.txt
$ diff correct-xxdoutput.txt test-output.txt
$

Я довольно близко подошел к некоторым догадкам, но мое форматирование всегда как-то не так, и я не совсем понимаю конкретнокак xxd генерирует hexDump.Такое ощущение, что я просто выбрал совершенно неправильный подход, но, может быть, задача просто не соответствует моему потенциалу с моим текущим уровнем знания языка C.

Мой код (см. Также: https://pastebin.com/Vjkm8Wb4):

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

#define SIZE 256

//Prototypes
void hexDump(void*, int);

int main(int argc, char *argv[])
{
    //Create and open filestream
    FILE *myfile;
    myfile =fopen(argv[1],"rb");

    for ( ; ; )
    {
        unsigned char buffer[SIZE];
        size_t n = fread(buffer, 1, SIZE, myfile);

        if (n > 0)
            hexDump(buffer, n);
        if (n < SIZE)
            break;
    }

    fclose(myfile);
    return 0;
}


void hexDump (void *addr, int len)
{
    int i;
    unsigned char bufferLine[17];
    unsigned char *pc = (unsigned char*)addr;

    for (i = 0; i < len; i++)
    {
        if ((i % 16) == 0)
        {
            if (i != 0)
                printf (" %s\n", bufferLine);

            if (pc[i] == 0x00) exit(0);
            printf ("%08x: ", i);
        }

        // Prints Hexcdoes that represent each chars.
        printf ("%02x", pc[i]);
        if ((i % 2) == 1)
            printf (" ");

        if ((pc[i] < 0x20) || (pc[i] > 0x7e))
        {
            bufferLine[i % 16] = '.';
        }

        else
        {
           bufferLine[i % 16] = pc[i];
        }    

        bufferLine[(i % 16) + 1] = '\0'; //Clears the next array buffLine
    }

    while ((i % 16) != 0)
    {
        printf ("  ");
        i++;
    }

    printf ("     %s\n", bufferLine);
}

1 Ответ

0 голосов
/ 03 февраля 2019

Существует несколько проблем с вашим кодом, в том числе:

  • Вы не проверяете, есть ли у вас имя файла для открытия.
  • Вы не проверяете, открыли ли выфайл с именем.
  • У вас нет механизма для обработки смещения на выходе, поэтому адреса в начале строк после первого блока неверны.
  • Вашкод проверяет нулевой байт и молча завершает работу при его обнаружении.Это плохо - дважды.Однажды, потому что программа, предназначенная для обработки двоичных данных, должна также обрабатывать ноль байтов, а также значения из 1..255;и однажды, потому что выход молча (и требование успеха с exit(0) для загрузки) плох.Вы должны сообщить о проблеме (при стандартной ошибке, а не при стандартном выводе) и выйти со статусом ошибки - ненулевым статусом.

Форматирование ядра в основном нормально;Также существует проблема с заполнением короткой строки данных в конце файла.

Я придумал этот код, который тесно основан на вашем (но переформатирован, чтобы соответствовать хотя бы некоторым моим стилем)предрассудки - но мой стиль не сильно отличается от вашего в большинстве случаев):

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

#define SIZE 256

void hexDump(size_t, void *, int);

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s file\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    FILE *myfile = fopen(argv[1], "rb");
    if (myfile == 0)
    {
        fprintf(stderr, "%s: failed to open file '%s' for reading\n", argv[0], argv[1]);
        exit(EXIT_FAILURE);
    }

    unsigned char buffer[SIZE];
    size_t n;
    size_t offset = 0;
    while ((n = fread(buffer, 1, SIZE, myfile)) > 0)
    {
        hexDump(offset, buffer, n);
        if (n < SIZE)
            break;
        offset += n;
    }

    fclose(myfile);
    return 0;
}

void hexDump(size_t offset, void *addr, int len)
{
    int i;
    unsigned char bufferLine[17];
    unsigned char *pc = (unsigned char *)addr;

    for (i = 0; i < len; i++)
    {
        if ((i % 16) == 0)
        {
            if (i != 0)
                printf(" %s\n", bufferLine);
            // Bogus test for zero bytes!
            //if (pc[i] == 0x00)
            //    exit(0);
            printf("%08zx: ", offset);
            offset += (i % 16 == 0) ? 16 : i % 16;
        }

        printf("%02x", pc[i]);
        if ((i % 2) == 1)
            printf(" ");

        if ((pc[i] < 0x20) || (pc[i] > 0x7e))
        {
            bufferLine[i % 16] = '.';
        }
        else
        {
            bufferLine[i % 16] = pc[i];
        }

        bufferLine[(i % 16) + 1] = '\0';
    }

    while ((i % 16) != 0)
    {
        printf("  ");
        if (i % 2 == 1)
            putchar(' ');
        i++;
    }
    printf(" %s\n", bufferLine);

}

При запуске с исходным исходным кодом и сравнении с выводом из системы xxd различий нет.Я также проверил это по файлу всего с 16 символами (abcdefghijklmno плюс перевод строки);выход там был такой же.И я проверил это на его собственном двоичном файле - и нашел и исправил нулевой байт и необъявленную проблему раннего выхода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...