I need to make a simple check if a dds file is of valid format. I just need to do a general check of the dds file, so I do not need to check if it is a dxt1, dxt5, dx10 etc. For example if I have a png image and I rename the extensions to .dds the dds format will ofcourse be wrong and I would then need to tell the user that he is trying to use a dds file with a wrong format. However if I have a dds that indeed has a correct file format I will not need to do any further investigation since I do not care of what type of dds file it is (at this moment). So I do only have to read the parts of the dds file that will stay the same on ALL dds files. I'm thinking I could read the dds header and magic number in some way. I have to do the same validation for a png file and there I am reading the png header like this:
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;
And I was looking if there is a similiar way to check the format of a dds file. I am new to this and the problem I am having is to know what bytes in the dds file that will always be the same for all dds files (so that I can check these bytes to see if the dds format is valid) and how I can implement the code in a simple way to check the dds format. Any help will be appreciated.
Edit: So thanks to @NaCl I have got the first part of the question answered. I now know what parts in the dds file that is required but I do not know how to locate it in the dds file. I have opened a lot of dds files with a hex editor but I am not very good at reverse engineering so I can't understand where the bytes that I need to check is located which will furthermore make me not to know how I can implement code to search for bytes at the specified positions (which I can do with the png file since I found much more document about that file) since I do not know at what position to go to.
If anybody can Point me in the right direction or help me in some other way I would appreciate it very much . Thanks.
The first thing to be done with a file that has a header is to check for its magic numbers (if any is given on documentation), in case of DDS file, the magic number is 0x44445220
which is equal to "DDS "
in "plain text".
After that, just deal with the specs. Everything (excepting magic number) is stored in little endian format, so be careful when dealing with bytes, according to Microsoft, the definition of the DDS header is (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;
Based on that, I just came with the following code for any "generic" DDS file:
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);
}
The code above just checks for the first 5 bytes of the input file (passed as argument path
), those are always the same as I have seen and should be equal to:
0x44 0x44 0x53 0x20 0x7C 0x00 0x00 0x00 (8 bytes)
The code above was tested with the .dds
files on this repository: https://github.com/toji/webgl-texture-utils/tree/master/sample/img, and both files had exactly the same 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 $
You can optimize the code above to perform a single call to fs.Read
with a size of ulong
and check the whole thing against this value: 0x444453207C000000
.
Hope this helps :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With