Verifying that an STL file is ASCII or binary

前端 未结 2 2037
梦谈多话
梦谈多话 2020-12-15 08:21

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

相关标签:
2条回答
  • 2020-12-15 08:54

    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;
    }
    
    0 讨论(0)
  • 2020-12-15 09:04

    Are there additional steps that would prove useful in validating whether I can be "absolutely sure" that a file is either ASCII or binary?

    Since there is no format tag in the stl specs, you can't be absolutely sure about the file format.

    Checking for "solid" in the beginning of the file should be enough in most cases. Additionally you could check for further keywords like "facet" or "vertex" to be sure it's ASCII. These words should only occur in the ASCII format (or in the useless binary header), but there is a little chance that the binary floats coincidentally form these words. So you could also check if the keywords are in the right order.

    And of course check if the length in the binary header matches the file length.

    But: Your code would work faster if you'd read the file linear and hope that nobody puts the words "solid" in the binary header. Maybe you should prefer ASCII-parsing if the file starts with "solid" and use the binary parser as a fallback if the ASCII parsing fails.

    0 讨论(0)
提交回复
热议问题