After reading the specs on the STL file format, I want to write a few tests to ensure that a file is, in fact, a valid binary or ASCII file.
An ASCII-based STL file
If the file does not begin with "solid ", and if the file size is exactly 84 + (numTriangles * 50) bytes, where numTriangles is read from offset 80, then the file is binary.
If the file size is at least 15 bytes (absolute minimum for an ASCII file with no triangles) and begins with "solid ", read the name that follows it until a line break is reached. Check if the next line either begins with "facet " or is "endsolid [name]" (no other value is allowed). If "facet ", seek to the end of the file and make sure it ends with a line that says "endsolid [name]". If all of these are true, the file is ASCII.
Treat any other combination as invalid.
So, something like this:
STL_STATUS getStlFileFormat(const QString &path)
{
QFile file(path);
if (!file.open(QIODevice::ReadOnly))
{
qDebug("\n\tUnable to open \"%s\"", qPrintable(path));
return STL_INVALID;
}
QFileInfo fileInfo(path);
size_t fileSize = fileInfo.size();
// Look for text "solid " in first 6 bytes, indicating the possibility that this is an ASCII STL format.
if (fileSize < 15)
{
// "solid " and "endsolid " markers for an ASCII file
qDebug("\n\tThe STL file is not long enough (%u bytes).", uint(fileSize));
return STL_INVALID;
}
// binary files should never start with "solid ", but
// just in case, check for ASCII, and if not valid then
// check for binary...
QByteArray sixBytes = file.read(6);
if (sixBytes.startsWith("solid "))
{
QByteArray name = file.readLine();
QByteArray endLine = name.prepend("endsolid ");
QByteArray nextLine = file.readLine();
if (line.startsWith("facet "))
{
// TODO: seek to the end of the file, read the last line,
// and make sure it is "endsolid [name]"...
/*
line = ...;
if (!line.startsWith(endLine))
return STL_INVALID;
*/
return STL_ASCII;
}
if (line.startsWith(endLine))
return STL_ASCII;
// reset and check for binary...
if (!file.reset())
{
qDebug("\n\tCannot seek to the 0th byte (before the header)");
return STL_INVALID;
}
}
if (fileSize < 84)
{
// 80-byte header + 4-byte "number of triangles" for a binary file
qDebug("\n\tThe STL file is not long enough (%u bytes).", uint(fileSize));
return STL_INVALID;
}
// Header is from bytes 0-79; numTriangleBytes starts at byte offset 80.
if (!file.seek(80))
{
qDebug("\n\tCannot seek to the 80th byte (after the header)");
return STL_INVALID;
}
// Read the number of triangles, uint32_t (4 bytes), little-endian
QByteArray nTrianglesBytes = file.read(4);
if (nTrianglesBytes.size() != 4)
{
qDebug("\n\tCannot read the number of triangles (after the header)");
return STL_INVALID;
}
uint32_t nTriangles = *((uint32_t*)nTrianglesBytes.data());
// Verify that file size equals the sum of header + nTriangles value + all triangles
if (fileSize == (84 + (nTriangles * 50)))
return STL_BINARY;
return STL_INVALID;
}