2014-10-10 9 views
0

xxd와 같은 hexdump를 만들려고하고 있지만 해결해야 할 몇 가지 차이점이 있습니다. 현재 프로그램은 xxd의 최대 오른쪽 열 vs ​​16에서 볼 수 있듯이 한 줄당 10자를 처리합니다. 또한 2 옥텟 쌍 대신 칼럼 당 1 옥텟 만 표시합니다.hexdump 출력 대 xxd 출력

0000000: 2369 6e63 6c75 6465 203c 7374 6469 6f2e #include <stdio. 

내 출력을 xxd

0: 23 69 6E 63 6C 75 64 65 20 3C #include <  

편집 :

나는 두 가지를 달성하기 위해 노력하고, 약간의 설명을 추가 할 수 있습니다. 1)이 프로그램에서 을 정확히처럼 출력하고 싶습니다. 이를 위해 32 개의 16 진수 (4x 8x 열)를 출력해야합니다. 2) xxd에서와 같이 행의 4 열에 16 진수를 나열하는 프로그램을 원합니다.

"12"와 같은 소스에서 "10"을 편집하려고 시도했지만 출력에 오류가 발생하는 것으로 보입니다.이 파일은 magic number 인 것으로 보입니다.

자료 :

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

#define BYTE_OFFSET_INIT 8 
#define CHAR_OFFSET_INT 39 
#define LINE_LENGTH 50 

static void print_e(int e, char *program, char *file) 
{ 
    fprintf(stderr, "%s: %s: %s\n", program, file, strerror(e)); 
} 
static void print_line(char *line) 
{ 
    int i; 
/* sprintf leaves terminators mid-line, so clear them out so we can print the full line */ 
    for (i = BYTE_OFFSET_INIT; i < CHAR_OFFSET_INT; i++) 
    if (line[i] == '\0') 
     line[i] = ' '; 
    printf("%s\n", line); 
} 

int main(int argc, char *argv[]) 
{ 
    char line[LINE_LENGTH + 1]; 

    int ch; 
    int character = 0; 
    int line_offset = 0; 
    int byte_offset = BYTE_OFFSET_INIT, char_offset = CHAR_OFFSET_INT; 

    if (argc != 2) { 
    fprintf(stderr, "Usage: %s [file]\n", argv[0]); 
    exit(EXIT_FAILURE); 
    } 
    FILE *fp = fopen(argv[1], "rb"); 
    if (!fp) { 
    print_e(errno, argv[0], argv[1]); 
    exit(EXIT_FAILURE); 
    } 

    printf("Offset    Bytes    Characters\n"); 
    printf("------ ----------------------------- ----------\n"); 

    while ((ch = fgetc(fp)) != EOF) { 
    if (character == 0) { 
     sprintf(line, "%6d ", line_offset); 
     line_offset += 10; 
    } 
    sprintf(line + byte_offset, "%02X ", ch); 
    sprintf(line + char_offset, "%c", isprint(ch) ? ch : '.'); 
    character++; 
    char_offset++; 
    byte_offset += 3; 

    if (character == 10) { 
     print_line(line); 
     character = 0; 
     char_offset = CHAR_OFFSET_INT; 
     byte_offset = BYTE_OFFSET_INIT; 
    } 
    } 
    if (ferror(fp)) { 
    print_e(errno, argv[0], argv[1]); 
    exit(EXIT_FAILURE); 
    } 

    if (character > 0) 
    print_line(line); 

    if (fclose(fp) == EOF) { 
    print_e(errno, argv[0], argv[1]); 
    exit(EXIT_FAILURE); 
    } 
    return 0; 
} 
+3

있음. 그리고, 당신 문제는 무엇입니까? (힌트 : 각 바이트 값 이후의 "10"과 공백은 모두 프로그램에 있고, 이것이 실제 * 소스라면, 수정해야만합니다 ...) – DevSolar

+0

http : // powerfield-software. com /? p = 25 – paxdiablo

+1

고맙습니다. @paxdiablo – John

답변

0

은 한 번에 하나의 바이트를 스캔하고 정확한 위치에 출력 문자열로 작성 가능하지만, 반드시 필요 없습니다. 한 번에 DISPLAY_LENGTH 바이트를 읽고 이처럼 읽은 바이트 수를 두 번 반복하는 것이 더 쉬운 방법입니다. 먼저 16 진수 표현을 출력 한 다음 다시 ASCII 문자를 출력합니다. 유일한 (부전공) 경고는 파일의 끝에 무엇을 해야하는지입니다. 그러나 fread이 문자 수를 반환하기 때문에 16 진수를 채우기 위해 필요한만큼 길게 계산하고 출력 할 수 있습니다.

이것은 다음과 같은 프로그램을 만듭니다. DISPLAY_LENGTH은 한 줄에 표시 할 총 바이트 수입니다. GROUP_BYTES은 각 16 진수 그룹의 단일 바이트 수입니다 (1으로 설정하면 'regular'spaced hex 출력이 표시되고 2xxd 예와 같이 그룹화됩니다) 또한 작동해야합니다).

정확하게 마법을 사용하여 텍스트 Bytes을 가운데 맞추고 구분 기호를 표시 할 대시를 계산하는 즐거움을 느꼈습니다. 나머지는 매우 간단합니다.

한 줄짜리 예문을 제외하고는 xxd 출력이 어떻게되는지 모르겠으므로 stat을 사용하여 파일 길이를 미리 읽을 수 있습니다. "not a 파일 "- 예를 들어 폴더로 시도) 라인 카운터를 정렬 할 올바른 수의 대시 및 공백을 표시합니다. 이 값을 최소 6으로 설정하면 항상 텍스트 Offset의 여유 공간이 있습니다.

컴파일러가 현대적인 컴파일러가 아닌 경우 %zu 형식 문자열에 대해 불만을 표시 할 수 있습니다. 그렇다면 %lu을 사용하십시오. size_t의 모든 어커런스를 unsigned long으로 변경해야 할 수도 있습니다.그 자체를 표시

#include <stdio.h>  
#include <stdlib.h> 
#include <sys/stat.h> 
#include <string.h> 
#include <errno.h> 
#include <ctype.h> 

#define DISPLAY_LENGTH 21 
#define GROUP_BYTES  2 

static void print_e(int e, char *program, char *file) 
{ 
    fprintf(stderr, "%s: %s: %s\n", program, file, strerror(e)); 
} 

int main(int argc, char *argv[]) 
{ 
    size_t i; 
    struct stat fs; 
    int n_digit; 
    unsigned char read_buf[DISPLAY_LENGTH]; 
    size_t bytes_read, cpos = 0; 

    if (argc != 2) 
    { 
     fprintf(stderr, "Usage: %s [file]\n", argv[0]); 
     exit(EXIT_FAILURE); 
    } 

    FILE *fp = fopen(argv[1], "rb"); 
    if (!fp) 
    { 
     print_e (errno, argv[0], argv[1]); 
     exit(EXIT_FAILURE); 
    } 

    if (stat(argv[1], &fs) == -1) 
    { 
     print_e (errno, argv[0], argv[1]); 
     exit(EXIT_FAILURE); 
    } 

    if ((fs.st_mode & S_IFMT) != S_IFREG) /* regular file */ 
    { 
     fprintf(stderr, "Not a regular file: %s\n", argv[1]); 
     exit(EXIT_FAILURE); 
    } 

    n_digit = 0; 
    while (fs.st_size > 0) 
    { 
     fs.st_size /= 10; 
     n_digit++; 
    } 
    if (n_digit < 6) 
     n_digit = 6; 

    printf("%*s ", n_digit, "Offset"); 
    printf("%*s%-*s", ((2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES)+2)/2, "Bytes", ((2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES)+2-5)/2, ""); 
    printf (" Characters\n"); 
    for (i=0; i<n_digit; i++) 
     printf ("-"); 

    printf(" "); 

    for (i=1; i<2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES; i++) 
     printf ("-"); 
    printf (" "); 

    for (i=0; i<DISPLAY_LENGTH; i++) 
     printf ("-"); 
    printf ("\n"); 

    while ((bytes_read = fread (read_buf, 1, DISPLAY_LENGTH, fp))) 
    { 
     printf ("%*zu ", n_digit, cpos); 

     for (i=0; i<bytes_read; i++) 
     { 
      if (!(i % GROUP_BYTES)) 
       printf (" "); 
      printf ("%02X", read_buf[i]); 
     } 
     while (i < DISPLAY_LENGTH) 
     { 
      if (!(i % GROUP_BYTES)) 
       printf (" "); 
      printf (" "); 
      i++; 
     } 

     printf (" "); 

     for (i=0; i<bytes_read; i++) 
      printf ("%c", isprint(read_buf[i]) ? read_buf[i] : '.'); 

     printf ("\n"); 

     cpos += bytes_read; 
    } 
    if (ferror(fp)) 
    { 
     print_e (errno, argv[0], argv[1]); 
     exit(EXIT_FAILURE); 
    } 

    if (fclose(fp)) 
    { 
     print_e (errno, argv[0], argv[1]); 
     exit(EXIT_FAILURE); 
    } 
    return 0; 
} 

출력 샘플은 21의 디스플레이 길이 컴파일 된 실행 파일 및 2 바이트별로 그룹화 :

Offset      Bytes       Characters 
------ ---------------------------------------------------- --------------------- 
    0 CFFA EDFE 0700 0001 0300 0080 0200 0000 0D00 0000 70 ....................p 
    21 0600 0085 0020 0000 0000 0019 0000 0048 0000 005F 5F ..... .........H...__ 
    42 5041 4745 5A45 524F 0000 0000 0000 0000 0000 0000 00 PAGEZERO............. 
... (673 very similar lines omitted) ... 
14196 7075 7473 005F 7374 6174 2449 4E4F 4445 3634 005F 73 puts._stat$INODE64._s 
14217 7472 6572 726F 7200 6479 6C64 5F73 7475 625F 6269 6E trerror.dyld_stub_bin 
14238 6465 7200 0000          der... 
+0

대단히 감사합니다. xxd는 거의 모든 Linux 셸에서 실행할 수 있습니다. 돌아와 귀하의 코드에 관한 질문, 나는 당신이 상관 없어 :). 좋은 밤 되세요. – John

+0

내 Mac (OS X)에서도 볼 수 있듯이 당신 말이 맞습니다! 아 글쎄, 나는이 문제를 아직까지 아무런 문제없이 작성 해왔다. – usr2564301