#include <stdlib.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <string.h>
#include <stdio.h>
+#include <wchar.h>
#include <sys/stat.h>
#include <assert.h>
#include "surfacefile.h"
#include "exif.h"
#include "jpegrdr.h"
+#include <ctype.h>
+
#ifdef WIN32
#include <direct.h>
#include <tchar.h>
#else
#include "compat/tchar.h"
#endif /* !WIN32 */
+#include "compat/platform.h"
+
+typedef struct options_t {
+ bool info;
+ const char *export;
+ const char *filename;
+ logfunc_t log;
+} options_t;
-static void _cdecl logger(const char *format, ...)
+static void CDECL log_debug(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+static void CDECL log_null(const char *format, ...)
{
va_list args;
va_start(args, format);
return total;
}
+// FIXME: do surrogate pairs?
+static size_t utf16_to_utf8(char* buffer, int* offset, uint16_t wc)
+{
+ int r = 0;
+ if (wc <= 0x7F)
+ {
+ r = 1;
+ if (buffer)
+ buffer[(*offset)++] = (char)wc;
+ }
+ else if (wc <= 0x7FF)
+ {
+ r = 2;
+ if (buffer)
+ {
+ buffer[(*offset)++] = 0xC0 | (wc >> 6);
+ buffer[(*offset)++] = 0x80 | ((wc >> 0) & 0x3F);
+ }
+ }
+ else if (wc <= 0xFFFF)
+ {
+ r = 3;
+ if (buffer)
+ {
+ buffer[(*offset)++] = 0xE0 | (wc >> 12);
+ buffer[(*offset)++] = 0x80 | ((wc >> 6) & 0x3F);
+ buffer[(*offset)++] = 0x80 | ((wc >> 0) & 0x3F);
+ }
+ }
+ return r;
+}
+
// Read a BSTR record from the current file position/.
// Reads a uint32_t to get the size in bytes
-// Then allocates and returns a Unicode string with terminating NUL
-static wchar_t* read_name(FILE* fp)
+// Then converts the UTF-16 string to UTF-8 with terminating NUL
+static char* read_name(FILE* fp)
{
uint32_t length = 0;
fread(&length, sizeof(uint32_t), 1, fp);
- wchar_t* name = NULL;
+ char* name = NULL;
if (length)
{
- name = (wchar_t*)calloc(1, length + sizeof(wchar_t));
- fread(name, 1, length, fp);
+ uint16_t *bstr = (uint16_t*)calloc(length, 1);
+ fread(bstr, 1, length, fp);
+
+ size_t len = 0;
+ for (uint32_t n = 0; n < length / sizeof(uint16_t); ++n)
+ {
+ len += utf16_to_utf8(NULL, NULL, bstr[n]);
+ }
+
+ int offset = 0;
+ name = (char *)calloc(len + 1, 1);
+ for (uint32_t n = 0; n < length / sizeof(uint16_t); ++n)
+ {
+ utf16_to_utf8(name, &offset, bstr[n]);
+ }
+ free(bstr);
}
return name;
}
uint32_t *table = NULL;
if (hdrPtr->num_images > 0)
{
- table = (uint32_t *)calloc(sizeof(uint32_t), (hdrPtr->num_images + 1));
+ table = (uint32_t *)calloc((hdrPtr->num_images + 1), sizeof(uint32_t));
if (table == NULL)
{
_tperror("calloc table");
return points;
}
-static int SrfDump(const char *filename)
+static int SrfDump(const options_t *options)
{
- FILE *fp = fopen(filename, "rb");
+ FILE *fp = fopen(options->filename, "rb");
if (fp == NULL) {
perror("fopen");
return 1;
for (uint32_t n = 0; n < hdr.num_images + 1; ++n)
printf(" %u: %#08x\n", n, offsets[n]);
}
-#if 0
+ if (hdr.revision < 7 && options->export != NULL)
+ {
#ifdef WIN32
- _tmkdir(_T("images"));
+ mkdir(options->export);
#else
- mkdir("images", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ mkdir(options->export, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
#endif // !WIN32
-#endif
+ }
for (uint32_t n = 0; n < hdr.num_images; ++n)
{
SurfaceImageInfo info = { 0 };
uint32_t image_size = 0;
exif_item_t *items = NULL;
+ int pos = fseek(fp, 0, SEEK_CUR);
if (hdr.revision < 7)
{
fread(&image_size, sizeof(uint32_t), 1, fp);
- items = jpegrdr_get_exif(fp, logger);
+ items = jpegrdr_get_exif(fp, options->log);
}
else
{
info.imagepath = read_name(fp);
info.backuppath = read_name(fp);
- wchar_t wfilename[260] = {0};
+ char path[256] = {0};
+ strcpy(path, options->filename);
+ char *sep = strrchr(path, PATHSEP);
+ assert(sep != NULL);
+ sep[1] = '\0';
+ strcat(path, hdr.dirname);
+ const char separator[2] = {PATHSEP, 0};
+ strcat(path, separator);
+ strcat(path, info.imagepath);
- mbstowcs(wfilename, filename, strlen(filename));
- wchar_t *ext = wcsrchr(wfilename, L'\\');
- assert(ext != NULL);
- ext[1] = L'\0';
- wcscat(wfilename, hdr.dirname);
- wcscat(wfilename, L"\\");
- wcscat(wfilename, info.imagepath);
- FILE *imagefp = _wfopen(wfilename, L"rb");
+ FILE *imagefp = fopen(path, "r");
assert(imagefp != NULL);
- items = jpegrdr_get_exif(imagefp, logger);
- fclose(imagefp);
+ if (imagefp != NULL)
+ {
+ items = jpegrdr_get_exif(imagefp, options->log);
+ fclose(imagefp);
+ }
}
-#if 0
- TCHAR name[32 + 16] = {0};
- _stprintf(name, _T("images/img%u.jpg"), n);
-
- FILE *fp2 = _tfopen(name, "wb");
- if (fp2 == NULL) {
- _tperror("fopen image file");
- exit(1);
- }
- size_t len = fcopy(fp, fp2, image_size);
- fclose(fp2);
- // For revision > 2 we have the size of the 'original' image if present and the image data.
- if (hdr.revision > 2)
+ if (hdr.revision < 7 && options->export != NULL)
{
- uint32_t backup_size = 0;
- fread(&backup_size, sizeof(uint32_t), 1, fp);
- fseek(fp, backup_size, SEEK_CUR);
- len += sizeof(backup_size) + backup_size; // account for 'backup image' and its size
- printf(" orig:%u: %u\n", n, backup_size);
+ char name[256] = {0};
+ sprintf(name, "%s/img%u.jpg", options->export, n);
+
+ FILE *fp2 = fopen(name, "wb");
+ if (fp2 == NULL) {
+ perror("fopen image file");
+ exit(1);
+ }
+ fseek(fp, pos, SEEK_SET);
+ size_t len = fcopy(fp, fp2, image_size);
+ fclose(fp2);
+ // For revision > 2 we have the size of the 'original' image if present and the image data.
+ if (hdr.revision > 2)
+ {
+ uint32_t backup_size = 0;
+ fread(&backup_size, sizeof(uint32_t), 1, fp);
+ fseek(fp, backup_size, SEEK_CUR);
+ len += sizeof(backup_size) + backup_size; // account for 'backup image' and its size
+ printf(" orig:%u: %u\n", n, backup_size);
+ }
}
-#endif
+
printf(" img %u: %u@%#08x @(%.3f,%.3f,%.3f) fov:%.3f,%.3f res:%u,%u off:%d,%d\n",
n, image_size, offsets[n],
info.point.x, info.point.y, info.point.z,
info.xoffset, info.yoffset);
if (hdr.revision >= 7)
{
- char path[256] = { 0 };
- wcstombs(path, info.imagepath, sizeof(path));
- printf(" image: %s\n", path);
- if (info.backuppath != NULL && info.backuppath[0] != L'\0')
+ printf(" image: %s\n", info.imagepath);
+ if (info.backuppath != NULL && info.backuppath[0] != '\0')
{
- wcstombs(path, info.backuppath, sizeof(path));
- printf(" original: %s\n", path);
+ printf(" original: %s\n", info.backuppath);
}
}
if (items)
int main(int argc, char *const argv[])
{
+ options_t options = {false, NULL, NULL, log_null};
+
// add `-debug` to enable more log output
// add `-info` to just read the main header and output csv
// add `-export dirname` to output the images for rev < 7 surfaces
- if (argc != 2) {
- fputs("usage: srfdump filename", stderr);
+ int opt = 1;
+ for (; opt < argc - 1; ++opt)
+ {
+ if (strncmp("-d", argv[opt], 2) == 0
+ || strncmp("--debug", argv[opt], 7) == 0)
+ {
+ options.log = log_debug;
+ }
+ else if (strncmp("-i", argv[opt], 2) == 0
+ || strncmp("--info", argv[opt], 6) == 0)
+ {
+ options.info = true;
+ }
+ else if (strncmp("-e", argv[opt], 2 == 0)
+ || strncmp("--export", argv[opt], 8) == 0)
+ {
+ ++opt;
+ options.export = argv[opt];
+ }
+ }
+ if (opt != argc - 1) {
+ fputs("usage: srfdump [-di] [--debug] [--info] [--export dir] filename", stderr);
return 1;
}
+ options.filename = argv[opt];
- int r = SrfDump(argv[1]);
- return r;
+ return SrfDump(&options);
}