【问题标题】:Search for Binary Pattern in C (Read buffered binary file)在 C 中搜索二进制模式(读取缓冲的二进制文件)
【发布时间】:2010-12-05 05:38:01
【问题描述】:

你好。我正在尝试编写一个小程序,它将在最后一次出现“0xFF 0xC0 0x00 0x11”之后读取以下四个字节,这些字节可以轻松转换为二进制或十进制。目的是最后一次出现该十六进制模式之后的 2-5 个字节表示 JPEG 文件的宽度和高度。

#include <stdio.h>

 int main () {
  FILE * pFile;
  long lSize;
  char * buffer;
  size_t result;

  pFile = fopen ( "pano8sample.jpg" , "rb" );
  if(pFile==NULL){
   fputs ("File error",stderr);
   exit (1);
  }

  fseek (pFile , 0 , SEEK_END);
  lSize = ftell (pFile);
  rewind (pFile);

  printf("\n\nFile is %d bytes big\n\n", lSize);

  buffer = (char*) malloc (sizeof(char)*lSize);
  if(buffer == NULL){
   fputs("Memory error",stderr);
   exit (2);
  }

  result = fread (buffer,1,lSize,pFile);
  if(result != lSize){
   fputs("Reading error",stderr);
   exit (3);
  }

  //0xFF 0xC0 0x00 0x11 (0x08)

  //Logic to check for hex/binary/dec

  fclose (pFile);
  free (buffer);
  return 0;
 }

问题是我不知道如何递归地从缓冲内存中读取数据并将最近读取的变量用作 int 来与我的二进制/十六进制/十进制进行比较。

我该怎么做?

【问题讨论】:

    标签: c binary design-patterns match buffered


    【解决方案1】:
    byte needle[4] = {0xff, 0xc0, 0x00, 0x11};
    byte *last_needle = NULL;
    while (true) {
      byte *p = memmem(buffer, lSize, needle, 4); 
      if (!p) break;
      last_needle = p;
      lSize -= (p + 4) - buffer;
      buffer = p + 4;
    }
    

    如果last_needle不为空,可以打印出last_needle+4...

    【讨论】:

    • memmem() 函数未由 POSIX 标准化,但在 Linux 和 AIX 上可用,但在 MacOS X (10.5) 或 Solaris 10 上不可用。
    • 对于那些没有 memmem 实现的人,我把它留给读者作为练习......
    • memmem() 似乎在 OSX 上可用 developer.apple.com/legacy/library/documentation/Darwin/… 我也看到它使用 man memmem (OSX 10.11.6)
    【解决方案2】:

    我不会将整个文件读入内存,而是使用一些状态机。我的 C 有点生锈了,但是:

    char searchChars[] = {0xFF,0xC0,0x00,0x11};
    char lastBytes[5];
    int pos = 0; int curSearch = 0;
    while(pos <= lSize) {
        curChar = getc(pfile); pos++;            /*readone char*/
    
        if(curChar == searchChars[curSearch]) { /* found a match */
            curSearch++;                        /* search for next char */
            if(curSearch > 3) {                 /* found the whole string! */
                curSearch = 0;                  /* start searching again */
                read = fread(lastBytes,1,5,pfile); /* read 5 bytes */
                pos += read;                      /* advance position by how much we read */
            }
        } else { /* didn't find a match */
            curSearch = 0;                     /* go back to searching for first char */
        }
     }
    

    最后,你在 lastBytes 中剩下 5 个字节,这是你最后一次找到 searchChars 之后的五个字节

    【讨论】:

      【解决方案3】:

      就个人而言,我会使用一次吞下一个字符的函数。该函数将使用有限状态机进行简单的正则表达式匹配,将详细信息保存在静态局部变量或参数块结构中。您需要两个子块 - 一个用于部分匹配状态,一个用于最后一个完整匹配 - 每个都根据需要指示相关位置或值。

      在这种情况下,您应该可以手动设计。如需更复杂的要求,请查看Ragel

      【讨论】:

        【解决方案4】:

        如果数据以 ascii 编码,您可以在 C/C++ 中使用 fscanf 函数。如果不是,您将不得不编写自己的函数来执行此操作。简单的方法是从文件中读取 N 个字节,在字节字符串中搜索您想要的模式,然后继续直到 EOF。

        您的代码实际上一次读取整个文件(如果您要查找的行靠近文件顶部,则不必要。)您的代码将文件作为字节数组存储在堆上(char 相当于一个字节在 C++ 中)使用缓冲区指向内存中连续数组的开头的指针。像操作任何其他数组一样操作缓冲区数组。

        此外,如果您打算在读取大小后执行任何操作,请确保释放分配的缓冲区对象以避免泄漏。

        【讨论】:

        • 对.. r+b 文件上的 fgetc 将返回二进制整数值是吗?
        • 因为它似乎返回垃圾值。如何将最后一个 fgetc 结果与二进制 8 位字节进行比较?
        • 我不怎么用 fgetc 但我认为它从内部文件位置的当前位置返回一个字节。
        • 您想将从 fgetc 获得的结果转换为无符号字符(这意味着从 0-255 的值)然后比较它。 char 也有负值表示,这可能会让你搞砸。
        • 或者您也可以与十六进制值进行比较。只需将要比较的内容与 0x 放在一起,编译器就会知道您要比较十六进制值。
        【解决方案5】:

        使用magic_open() 和magic_print() 更安全,更易于使用

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-05
          • 1970-01-01
          • 2023-02-09
          • 2014-11-02
          • 2016-09-16
          • 2016-09-30
          相关资源
          最近更新 更多