如何确保 DirectDraw 表面具有正确的文件格式?

How can I make sure that a DirectDraw surface has a correct file format?

我需要做一个简单的检查,看看 dds 文件的格式是否有效。我只需要对 dds 文件进行一般检查,所以我不需要检查它是否是 dxt1、dxt5、dx10 等。例如,如果我有一个 png 图像并且我将扩展名重命名为 .dds dds 格式当然会是错误的,然后我需要告诉用户他正在尝试使用格式错误的 dds 文件。但是,如果我有一个确实具有正确文件格式的 dds,我将不需要做任何进一步的调查,因为我不关心它是什么类型的 dds 文件(此时)。所以我只需要阅读 dds 文件中所有 dds 文件都保持不变的部分。 我想我可以通过某种方式读取 dds header 和幻数。 我必须对 png 文件进行相同的验证,并且我正在读取 png header,如下所示:

    var png = new byte[] { 0x89, 0x50, 0x4e, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }
    using (FileStream fs = new FileStream(fileToCheck, FileMode.Open, FileAccess.Read))
            {
               if (fs.Length > buffer.Length)
                 {
                   fs.Read(buffer, 0, buffer.Length);
                   fs.Position = (int)fs.Length - endBuffer.Length;
                   fs.Read(bufferEnd, 0, endBuffer.Length);
                 }

               fs.Close();
            } 
    for (int i = 0; i < png.Length; i++)
        {
            if (buffer[i] != png[i])
                return false;
        }

    return true;

我正在寻找是否有类似的方法来检查 dds 文件的格式。我对此很陌生,我遇到的问题是知道 dds 文件中的哪些字节对于所有 dds 文件始终相同(以便我可以检查这些字节以查看 dds 格式是否有效)以及我如何可以通过简单的方式实现代码来检查dds格式。任何帮助将不胜感激。

编辑: 所以感谢@NaCl,我已经回答了问题的第一部分。我现在知道 dds 文件中的哪些部分是必需的,但我不知道如何在 dds 文件中找到它。我用十六进制编辑器打开了很多 dds 文件,但我不太擅长逆向工程,所以我不明白我需要检查的字节在哪里,这进一步让我不知道如何实现代码在指定的位置搜索字节(我可以用 png 文件来做,因为我发现了更多关于该文件的文档),因为我不知道去哪个位置。

如果有人能指出正确的方向或以其他方式帮助我,我将不胜感激。谢谢

对具有 header 的文件要做的第一件事是检查它的幻数(如果文档中有的话),如果是 DDS file,则为幻数0x44445220 等于 "plain text".

中的 "DDS "

之后,只需处理规格即可。所有内容(幻数除外)都以小端格式存储,因此在处理字节时要小心,根据 Microsoft 的说法,DDS header 的 definition 是 (C++):

typedef struct {
  DWORD           dwSize;                 /* Always equal to 124 */
  DWORD           dwFlags;
  DWORD           dwHeight;
  DWORD           dwWidth;
  DWORD           dwPitchOrLinearSize;
  DWORD           dwDepth;
  DWORD           dwMipMapCount;
  DWORD           dwReserved1[11];
  DDS_PIXELFORMAT ddspf;
  DWORD           dwCaps;
  DWORD           dwCaps2;
  DWORD           dwCaps3;
  DWORD           dwCaps4;
  DWORD           dwReserved2;
} DDS_HEADER;

基于此,我为任何 "generic" DDS 文件提供了以下代码:

public static bool IsValidDDS(string path)
{
  if (path == null)
    throw new ArgumentNullException(nameof(path));
  if (!File.Exists(path)) // Check for existence.
    return false;

  uint magicNumber = 0; byte[] headerLength = new byte[sizeof(byte)];
  using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
  {
    byte[] magic = new byte[sizeof(uint)];

    // I'm still pretty used to C and fread, so here you go :^)
    if (fs.Read(magic, 0, sizeof(uint)) != sizeof(uint))
      return false; // Not even a valid file.

    if (fs.Read(headerLength, 0, sizeof(byte)) != sizeof(byte))
      return false; // Not enough bytes, even if the first 4 bytes were checked.

    // Convert to a big endian integer.
    magicNumber = (uint)((magic[0] << 24) | (magic[1] << 16) | (magic[2] << 8) | magic[3]);
  }
  return (headerLength[0] == 0x7C) && (magicNumber == 0x44445320);
}

上面的代码只检查输入文件的前 5 个字节(作为参数 path 传递),它们总是和我看到的一样,应该等于:

0x44 0x44 0x53 0x20 0x7C 0x00 0x00 0x00 (8 bytes)

上面的代码已使用此存储库中的 .dds 文件进行测试:https://github.com/toji/webgl-texture-utils/tree/master/sample/img,并且两个文件具有完全相同的 header:

iamnacl:~/workspace $ cd dds-test/
iamnacl:~/workspace/dds-test $ dotnet run ../test-dxt1.dds 
The file is a valid DDS file? True
iamnacl:~/workspace/dds-test $ dotnet run ../test-dxt5.dds                                                                                               
The file is a valid DDS file? True
iamnacl:~/workspace/dds-test $ 

您可以优化上面的代码以执行对大小为 ulongfs.Read 的单个调用,并根据此值检查整个事情:0x444453207C000000.

希望这对您有所帮助:)