Initial version of an srfdump surface file dump utility.
authorPat Thoyts <patthoyts@users.sourceforge.net>
Wed, 10 Oct 2018 20:25:29 +0000 (21:25 +0100)
committerPat Thoyts <patthoyts@users.sourceforge.net>
Wed, 10 Oct 2018 20:25:29 +0000 (21:25 +0100)
.editorconfig [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.vscode/settings.json [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
compat/tchar.h [new file with mode: 0644]
srfdump.c [new file with mode: 0644]
surfacefile.h [new file with mode: 0644]

diff --git a/.editorconfig b/.editorconfig
new file mode 100644 (file)
index 0000000..092e06e
--- /dev/null
@@ -0,0 +1,12 @@
+root = true
+[*.{c,h}]
+charset = utf-8
+indent_style = space
+indent_size = 4
+tab_width = 4
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[CMakeLists.txt]
+charset = utf-8
+indent_style = space
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..23520ae
--- /dev/null
@@ -0,0 +1,4 @@
+.vscode/
+build/
+images/
+*.srf
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644 (file)
index 0000000..84ff98b
--- /dev/null
@@ -0,0 +1,16 @@
+{
+    "files.exclude": {
+        "**/.git": true,
+        "**/.svn": true,
+        "**/.hg": true,
+        "**/CVS": true,
+        "**/.DS_Store": true,
+        "**/images": true,
+        "**/build": true
+    },
+    "cppcheck.standard": [
+        "c11",
+        "c++14"
+    ],
+    "cppcheck.language": "c"
+}
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..264d9c6
--- /dev/null
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.0)
+project(srfdump VERSION 1.0)
+
+if (MSVC)
+  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+else()
+  add_definitions(-pedantic)
+endif()
+
+set(CMAKE_C_STANDARD 11)
+
+set(SOURCE srfdump.c)
+add_executable(${PROJECT_NAME}  ${SOURCE})
+set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11)
diff --git a/compat/tchar.h b/compat/tchar.h
new file mode 100644 (file)
index 0000000..f4e14a6
--- /dev/null
@@ -0,0 +1,17 @@
+/* Compatability definitions for building Windows TCHAR type
+ * code on Linux.
+ */
+
+#ifndef _compat_tchar_h_INCLUDE
+#define _compat_tchar_h_INCLUDE
+
+#define _T(x) (x)
+#define TCHAR char
+#define _tmain main
+#define _tprintf printf
+#define _stprintf sprintf
+#define _fputts fputs
+#define _tfopen fopen
+#define _tperror perror
+
+#endif /* _compat_tchar_h_INCLUDE */
diff --git a/srfdump.c b/srfdump.c
new file mode 100644 (file)
index 0000000..78e68fc
--- /dev/null
+++ b/srfdump.c
@@ -0,0 +1,202 @@
+/* Copyright (c) 2018 Pat Thoyts <patthoyts@users.sourceforge.net>
+ *
+ * Examine a Renishaw .srf surface file and dump the contents.
+ * All images are exported to an images/ subdirectory with an accompanying
+ * data file containing the additional data stored for each image.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include "surfacefile.h"
+
+#ifdef WIN32
+#include <tchar.h>
+#else
+#include "compat/tchar.h"
+#endif /* !WIN32 */
+
+static size_t fcopy(FILE *src, FILE *dst, size_t count)
+{
+    size_t total = 0, n = 0;
+    char buf[4096];
+    do {
+        n = fread(buf, 1, sizeof(buf), src);
+        total += fwrite(buf, 1, n, dst);
+    } while (n == sizeof(buf));
+    return total;
+}
+
+static uint32_t * ReadImageTable(SurfaceFileHeader *hdrPtr, FILE *fp)
+{
+    uint32_t *table = NULL;
+    if (hdrPtr->num_images > 0)
+    {
+        table = (uint32_t *)malloc(sizeof(uint32_t) * (hdrPtr->num_images + 1));
+        fread(table + 1, sizeof(uint32_t), hdrPtr->num_images, fp);
+        // set first image to the end of the table.
+        table[0] = ftell(fp);
+        // convert offsets from relative to table to file absolute positions
+        for (int n = 1; n < hdrPtr->num_images+1; ++n)
+            table[n] += table[0];
+    }
+    return table;
+}
+
+static SurfaceTriangle * ReadTriangles(SurfaceFileHeader *hdrPtr, FILE *fp)
+{
+    SurfaceTriangle *triangles = NULL;
+    if (hdrPtr->num_triangles > 0)
+    {
+        triangles = (SurfaceTriangle *)malloc(sizeof(SurfaceTriangle) * hdrPtr->num_triangles);
+        fread(triangles, sizeof(SurfaceTriangle), hdrPtr->num_triangles, fp);
+    }
+    return triangles;
+}
+
+static SurfacePoint * ReadPoints(SurfaceFileHeader *hdrPtr, FILE *fp)
+{
+    SurfacePoint *points = NULL;
+    if (hdrPtr->num_points > 0)
+    {
+        points = (SurfacePoint *)malloc(sizeof(SurfacePoint) * hdrPtr->num_points);
+        double *buffer = (double *)malloc(sizeof(double) * hdrPtr->num_points);
+        fread(buffer, sizeof(double), hdrPtr->num_points, fp);
+        for (int n = 0; n < hdrPtr->num_points; ++n)
+            points[n].x = buffer[n];
+        fread(buffer, sizeof(double), hdrPtr->num_points, fp);
+        for (int n = 0; n < hdrPtr->num_points; ++n)
+            points[n].y = buffer[n];
+        fread(buffer, sizeof(double), hdrPtr->num_points, fp);
+        for (int n = 0; n < hdrPtr->num_points; ++n)
+            points[n].z = buffer[n];
+        free(buffer);
+    }
+    return points;
+}
+
+static int SrfDump(FILE *fp)
+{
+    int r = 0;
+    SurfaceFileHeader hdr = {0};
+    fread(&hdr, sizeof(SurfaceFileHeaderRev0), 1, fp);
+    size_t hdrsize = sizeof(SurfaceFileHeaderRev0);
+    if (hdr.revision > 1)
+        hdrsize += sizeof(SurfaceFileHeaderRev2);
+    if (hdr.revision > 2)
+        hdrsize += sizeof(SurfaceFileHeaderRev3);
+    if (hdr.revision > 3)
+        hdrsize += sizeof(SurfaceFileHeaderRev4);
+    if (hdr.revision > 4)
+        hdrsize += sizeof(SurfaceFileHeaderRev5);
+    fseek(fp, 0, SEEK_SET);
+    fread(&hdr, hdrsize, 1, fp);
+
+    char ver[5] = {0};
+    memcpy(ver, &hdr.fileversion, 4);
+    printf("ver: %s rev: %d points: %u tri: %u images: %u\n", ver, hdr.revision, hdr.num_points, hdr.num_triangles, hdr.num_images);
+    if (hdr.revision > 1)
+        printf(_T("translation: %.6f, %.6f, %.6f\n"), hdr.translation.xtrans, hdr.translation.ytrans, hdr.translation.ztrans);
+    if (hdr.revision > 2)
+    {
+        printf("image extents: (%.6g,%.6g) -> (%.6g,%.6g)\n",
+            hdr.image_extents.min_x, hdr.image_extents.min_y,
+            hdr.image_extents.max_x, hdr.image_extents.max_y);
+        printf("surface extents: (%.6g,%.6g) -> (%.6g,%.6g)\n",
+            hdr.surface_extents.min_x, hdr.surface_extents.min_y,
+            hdr.surface_extents.max_x, hdr.surface_extents.max_y);
+    }
+    if (hdr.revision > 3)
+        printf("use background removal: %s\n", hdr.use_background_removal ? "true" : "false");
+    if (hdr.revision > 4)
+        printf("extrapolation mode: %d\n", (int)hdr.extrapolation_mode);
+
+    SurfacePoint *points = ReadPoints(&hdr, fp);
+    if (points)
+    {
+        for (int n = 0; n < hdr.num_points; ++n)
+        {
+            printf("  point %d: %.6g %.6g %.6g\n",
+                n, points[n].x, points[n].y, points[n].z);
+        }
+        free(points);
+    }
+
+    SurfaceTriangle *triangles = ReadTriangles(&hdr, fp);
+    if (triangles)
+    {
+        printf("  TRIANGLES: FIX ME\n");
+        free(triangles);
+    }
+
+    uint32_t *offsets = ReadImageTable(&hdr, fp);
+    uint32_t table_base = ftell(fp);
+    if (offsets)
+    {
+        printf("  image base: %#08x\n", table_base);
+        mkdir("images", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+        for (int n = 0; n < hdr.num_images; ++n)
+        {
+            uint32_t image_size = offsets[n+1] - offsets[n] - 60;
+            printf("  image %d: %#08x size %#04x\n",
+                n, offsets[n], image_size);
+
+            TCHAR name[32 + 16] = {0};
+            _stprintf(name, _T("images/img%d.jpg"), n);
+            FILE *fp2 = _tfopen(name, "w");
+            if (fp2 == NULL) {
+                _tperror("fopen");
+                exit(1);
+            }
+            // TODO: deal with the 60 bytes of additional data per image....
+            // first 24 bytes are the image point position
+            // {
+            //     SurfacePoint point; // in um
+            //     double image_width_microns; // field of view x
+            //     double image_height_microns; // field of view y
+            //     uint32_t image_width; // in pixels ?
+            //     uint32_t image_height; // in pixels ?
+            //     uint32_t unknown[3];
+            // }
+            fseek(fp, offsets[n], SEEK_SET);
+
+            char data[60] = {0};
+            fread(data, 1, 60, fp);
+            fcopy(fp, fp2, image_size);
+            fclose(fp2);
+
+            _stprintf(name, _T("images/img%d.dat"), n);
+            fp2 = _tfopen(name, "w");
+            if (fp2 == NULL) {
+                _tperror("fopen data");
+                exit(1);
+            }
+            fwrite(data, 1, 60, fp2);
+            fclose(fp2);
+        }
+        free(offsets);
+    }
+
+    return r;
+}
+
+int _tmain(int argc, TCHAR *argv[])
+{
+    if (argc != 2) {
+        _fputts(_T("usage: srfdump filename"), stderr);
+        return 1;
+    }
+
+    FILE *fp = _tfopen(argv[1], _T("r"));
+    if (fp == NULL) {
+        _tperror(_T("fopen"));
+        return 1;
+    }
+
+    int r = SrfDump(fp);
+
+    fclose(fp);
+    return r;
+}
diff --git a/surfacefile.h b/surfacefile.h
new file mode 100644 (file)
index 0000000..1582ec4
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef _SurfaceFile_h_INCLUDE
+#define _SurfaceFile_h_INCLUDE
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#define SURFACE_FILE_VERSION 0x46525553UL /* 'S' 'U' 'R' 'F' */
+#define SURFACE_FILE_REVISION 5
+
+#pragma pack(push,1)
+
+typedef struct SurfaceExtents {
+    double min_x;
+    double max_x;
+    double min_y;
+    double max_y;
+} SurfaceExtents;
+
+typedef struct SurfacePoint {
+    double x;
+    double y;
+    double z;
+} SurfacePoint;
+
+typedef struct SurfaceTriangle {
+    int a;
+    int b;
+    int c;
+    int ab;
+    int bc;
+    int ca;
+} SurfaceTriangle;
+
+typedef struct SurfaceTranslationCoords {
+    float xtrans;
+    float ytrans;
+    float ztrans;
+} SurfaceTranslationCoords;
+
+typedef struct SurfaceFileHeaderRev0 {
+    uint32_t fileversion;
+    uint16_t revision;
+    uint32_t num_points;
+    uint32_t num_triangles;
+    uint32_t num_images;
+} SurfaceFileHeaderRev0;
+
+typedef struct SurfaceFileHeaderRev2 {
+    struct SurfaceTranslationCoords translation;
+} SurfaceFileHeaderRev2;
+
+typedef struct SurfaceFileHeaderRev3 {
+    struct SurfaceExtents image_extents;
+    struct SurfaceExtents surface_extents;
+} SurfaceFileHeaderRev3;
+
+typedef struct SurfaceFileHeaderRev4 {
+    uint8_t use_background_removal; // boolean
+} SurfaceFileHeaderRev4;
+
+typedef struct SurfaceFileHeaderRev5 {
+    uint8_t extrapolation_mode;
+} SurfaceFileHeaderRev5;
+
+typedef struct SurfaceFileHeader {
+    struct {
+        uint32_t fileversion;
+        uint16_t revision;
+        uint32_t num_points;
+        uint32_t num_triangles;
+        uint32_t num_images;
+    };
+    struct {
+        struct SurfaceTranslationCoords translation;
+    };
+    struct {
+        struct SurfaceExtents image_extents;
+        struct SurfaceExtents surface_extents;
+    };
+    struct {
+        uint8_t use_background_removal;
+    };
+    struct {
+        uint8_t extrapolation_mode;
+    };
+} SurfaceFileHeader;
+
+#pragma pack(pop)
+
+#if defined(__cplusplus)
+}
+#endif
+#endif // _SurfaceFile_h_INCLUDE