Verifying that an STL file is ASCII or binary

前端 未结 2 2042
梦谈多话
梦谈多话 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;
    }
    

提交回复
热议问题