summaryrefslogtreecommitdiff
path: root/file.c
diff options
context:
space:
mode:
authorRuss Allbery <rra@debian.org>2008-02-16 10:41:04 -0800
committerRuss Allbery <rra@debian.org>2008-02-16 10:41:04 -0800
commit4258edd6a0fcb6cd568413984eff5731829897b2 (patch)
treef215b95d6b53e3b8af77a642e80afa9aa1e7cbaf /file.c
Imported upstream version 0.16~20080216
Diffstat (limited to 'file.c')
-rw-r--r--file.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/file.c b/file.c
new file mode 100644
index 0000000..08f9f1b
--- /dev/null
+++ b/file.c
@@ -0,0 +1,431 @@
+/*
+ * file.c
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 3 or later of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: file.c,v 1.11 2008/02/10 22:24:55 c_anthon Exp $
+ */
+
+#include "config.h"
+#include "backgammon.h"
+#include <glib.h>
+#include <glib/gi18n.h>
+#ifndef _MSC_VER
+#include <string.h>
+#include <stdlib.h>
+#endif
+#include "file.h"
+
+ExportFormat export_format[] = {
+ {EXPORT_SGF, ".sgf", N_("Gnu Backgammon File"), "sgf", {TRUE, TRUE, TRUE}}, /*must be the first element */
+ {EXPORT_HTML, ".html", N_("HTML"), "html", {TRUE, TRUE, TRUE}},
+ {EXPORT_GAM, ".gam", N_("Jellyfish Game"), "gam", {FALSE, TRUE, FALSE}},
+ {EXPORT_MAT, ".mat", N_("Jellyfish Match"), "mat", {TRUE, FALSE, FALSE}},
+ {EXPORT_POS, ".pos", N_("Jellyfish Position"), "pos", {FALSE, FALSE, TRUE}},
+ {EXPORT_LATEX, ".tex", N_("LaTeX"), "latex", {TRUE, TRUE, FALSE}},
+ {EXPORT_PDF, ".pdf", N_("PDF"), "pdf", {TRUE, TRUE, TRUE}},
+ {EXPORT_TEXT, ".txt", N_("Plain Text"), "text", {TRUE, TRUE, TRUE}},
+ {EXPORT_PNG, ".png", N_("Portable Network Graphics"), "png", {FALSE, FALSE, TRUE}},
+ {EXPORT_PS, ".ps", N_("Postscript"), "ps", {TRUE, TRUE, TRUE}},
+ {EXPORT_SNOWIETXT, ".txt", N_("Snowie Text"), "snowietxt", {FALSE, FALSE, TRUE}},
+ {EXPORT_SVG, ".svg", N_("SVG"), "svg", {FALSE, FALSE, TRUE}},
+};
+
+ImportFormat import_format[] = {
+ {IMPORT_SGF, ".sgf", N_("Gnu Backgammon File"), "sgf"}, /*must be the first element */
+ {IMPORT_SGG, ".sgg", N_("Gamesgrid Save Game"), "sgg"},
+ {IMPORT_BKG, ".bkg", N_("Hans Berliner's BKG Format"), "bkg"},
+ {IMPORT_MAT, ".mat", N_("Jellyfish Match"), "mat"},
+ {IMPORT_OLDMOVES, ".fibs", N_("FIBS oldmoves format"), "oldmoves"},
+ {IMPORT_POS, ".pos", N_("Jellyfish Position"), "pos"},
+ {IMPORT_SNOWIETXT, ".txt", N_("Snowie Text"), "snowietxt"},
+ {IMPORT_TMG, ".tmg", N_("True Moneygames"), "tmg"},
+ {IMPORT_EMPIRE, ".gam", N_("GammonEmpire Game"), "empire"},
+ {IMPORT_PARTY, ".gam", N_("PartyGammon Game"), "party"},
+ {IMPORT_BGROOM, ".bgf", N_("BackGammonRoom Game"), "bgroom"},
+ {N_IMPORT_TYPES, NULL, N_("Unknown file format"), NULL}
+};
+
+typedef struct _FileHelper {
+ FILE *fp;
+ size_t dataRead;
+ unsigned int dataPos;
+ char *data;
+} FileHelper;
+
+/* Data structures and functions for getting file type data */
+
+static FileHelper *OpenFileHelper(const char *filename)
+{
+ FileHelper *fh;
+ if (!g_file_test(filename, G_FILE_TEST_EXISTS))
+ return NULL; /* File not found */
+
+ fh = g_new(FileHelper, 1);
+ fh->fp = fopen(filename, "r");
+ if (!fh->fp) { /* Failed to open file */
+ g_free(fh);
+ return NULL;
+ }
+ fh->dataRead = 0;
+ fh->dataPos = 0;
+ fh->data = NULL;
+ return fh;
+}
+
+static void CloseFileHelper(/*lint -e{818}*/FileHelper * fh)
+{
+ fclose(fh->fp);
+ free(fh->data);
+}
+
+static void fhReset(FileHelper * fh)
+{ /* Reset data pointer to start of file */
+ fh->dataPos = 0;
+}
+
+static void fhDataGetChar(FileHelper * fh)
+{
+ size_t numRead;
+ if (fh->dataPos < fh->dataRead)
+ return;
+
+#define BLOCK_SIZE 1024
+#define MAX_READ_SIZE 5000
+ fh->data = realloc(fh->data, fh->dataRead + BLOCK_SIZE);
+ if (fh->dataRead > MAX_READ_SIZE)
+ numRead = 0; /* Too big - should have worked things out by now! */
+ else
+ numRead = fread(fh->data + fh->dataRead, 1, BLOCK_SIZE, fh->fp);
+ if (numRead < BLOCK_SIZE)
+ {
+ (fh->data + fh->dataRead)[numRead] = '\0';
+ numRead++;
+ }
+ fh->dataRead += numRead;
+}
+
+static char fhPeekNextChar(FileHelper * fh)
+{
+ fhDataGetChar(fh);
+ return fh->data[fh->dataPos];
+}
+
+static char fhReadNextChar(FileHelper * fh)
+{
+ fhDataGetChar(fh);
+ return fh->data[fh->dataPos++];
+}
+
+static int fhPeekNextIsWS(FileHelper * fh)
+{
+ char c = fhPeekNextChar(fh);
+ return (c == ' ' || c == '\t' || c == '\n');
+}
+
+static void fhSkipWS(FileHelper * fh)
+{
+ while (fhPeekNextIsWS(fh))
+ (void)fhReadNextChar(fh);
+}
+
+static int fhSkipToEOL(FileHelper * fh)
+{
+ char c;
+ do {
+ c = fhReadNextChar(fh);
+ if (c == '\n')
+ return TRUE;
+ } while (c != '\0');
+
+ return FALSE;
+}
+
+static int fhReadString(FileHelper * fh, const char *str)
+{ /* Check file has str next */
+ while (*str) {
+ if (fhReadNextChar(fh) != *str)
+ return FALSE;
+ str++;
+ }
+ return TRUE;
+}
+
+static int fhReadStringNC(FileHelper * fh, const char *str)
+{ /* Check file has str next (ignoring case) */
+ while (*str) {
+ char c = fhReadNextChar(fh);
+ if (g_ascii_tolower(c) != *str)
+ return FALSE;
+ str++;
+ }
+ return TRUE;
+}
+
+static int fhPeekStringNC(FileHelper * fh, const char *str)
+{ /* Check file has str next (ignoring case) but don't move */
+ unsigned int pos = fh->dataPos;
+ int ret = TRUE;
+ while (*str) {
+ char c = fhReadNextChar(fh);
+ if (g_ascii_tolower(c) != *str) {
+ ret = FALSE;
+ break;
+ }
+ str++;
+ }
+ fh->dataPos = pos;
+ return ret;
+}
+
+static int fhReadNumber(FileHelper * fh)
+{ /* Check file has str next */
+ int anyNumbers = FALSE;
+ do {
+ char c = fhPeekNextChar(fh);
+ if (!g_ascii_isdigit(c))
+ return anyNumbers;
+ anyNumbers = TRUE;
+ } while (fhReadNextChar(fh) != '\0');
+
+ return TRUE;
+}
+
+static int fhReadAnyAlphNumString(FileHelper * fh)
+{
+ char c = fhPeekNextChar(fh);
+ if (!g_ascii_isalnum(c))
+ return FALSE;
+ do {
+ c = fhPeekNextChar(fh);
+ if (!g_ascii_isalnum(c) && c != '_')
+ return fhPeekNextIsWS(fh);
+ } while (fhReadNextChar(fh) != '\0');
+ return TRUE;
+}
+
+static int IsSGFFile(FileHelper * fh)
+{
+ const char *elements[] =
+ { "(", ";", "FF", "[", "4", "]", "GM", "[", "6", "]", "" };
+ const char **test = elements;
+
+ fhReset(fh);
+ while (**test) {
+ fhSkipWS(fh);
+ if (!fhReadString(fh, *test))
+ return FALSE;
+ test++;
+ }
+ return TRUE;
+}
+
+static int IsSGGFile(FileHelper * fh)
+{
+ fhReset(fh);
+ fhSkipWS(fh);
+
+ if (fhReadAnyAlphNumString(fh)) {
+ fhSkipWS(fh);
+ if (!fhReadString(fh, "vs."))
+ return FALSE;
+ fhSkipWS(fh);
+ if (fhReadAnyAlphNumString(fh))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int IsMATFile(FileHelper * fh)
+{
+ fhReset(fh);
+ do {
+ char c;
+ fhSkipWS(fh);
+ c = fhPeekNextChar(fh);
+ if (g_ascii_isdigit(c)) {
+ if (fhReadNumber(fh)) {
+ fhSkipWS(fh);
+ if (fhReadStringNC(fh, "point")) {
+ fhSkipWS(fh);
+ if (fhReadStringNC(fh, "match"))
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ } while (fhSkipToEOL(fh));
+ return FALSE;
+}
+
+static int IsTMGFile(FileHelper * fh)
+{
+ fhReset(fh);
+ do {
+ fhSkipWS(fh);
+ if (fhPeekStringNC(fh, "game")) {
+ (void)fhReadStringNC(fh, "game");
+ fhSkipWS(fh);
+ return fhReadNumber(fh)
+ && (fhPeekNextChar(fh) == ':');
+ }
+ (void)fhReadAnyAlphNumString(fh);
+ if (fhPeekNextChar(fh) != ':')
+ return FALSE;
+ } while (fhSkipToEOL(fh));
+
+ return FALSE;
+}
+
+static int IsTXTFile(FileHelper * fh)
+{
+ fhReset(fh);
+ fhSkipWS(fh);
+ if (fhReadNumber(fh) && fhReadNextChar(fh) == ';') {
+ fhSkipWS(fh);
+ if (fhReadNumber(fh) && fhReadNextChar(fh) == ';')
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int IsJFPFile(FileHelper * fh)
+{
+ fhReset(fh);
+ if ((fhReadNextChar(fh) == 126) && (fhReadNextChar(fh) == '\0') &&
+ (fhReadNextChar(fh) == '\0') && (fhReadNextChar(fh) == '\0'))
+ return TRUE;
+
+ return FALSE;
+}
+
+static int IsBKGFile(FileHelper * fh)
+{
+ fhReset(fh);
+ fhSkipWS(fh);
+ if (fhReadString(fh, "Black"))
+ return TRUE;
+ fhReset(fh);
+ fhSkipWS(fh);
+ if (fhReadString(fh, "White"))
+ return TRUE;
+
+ return FALSE;
+}
+
+static int IsGAMFile(FileHelper * fh)
+{
+ fhReset(fh);
+ fhSkipWS(fh);
+
+ if (fhReadAnyAlphNumString(fh)) {
+ fhSkipWS(fh);
+ if (fhReadAnyAlphNumString(fh)) {
+ fhSkipWS(fh);
+ return fhReadString(fh, "1)");
+ }
+ }
+
+ return FALSE;
+}
+
+static int IsPARFile(FileHelper * fh)
+{
+ fhReset(fh);
+ fhSkipWS(fh);
+
+ if (fhReadStringNC(fh, "boardid=")) {
+ (void)fhSkipToEOL(fh);
+ if (fhReadStringNC(fh, "creator="))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int IsBGRFile(FileHelper *fh)
+{
+ fhReset(fh);
+ fhSkipWS(fh);
+
+ if (fhReadStringNC(fh, "bgf version"))
+ {
+ fhSkipWS(fh);
+ if (!fhReadString(fh, "1.2"))
+ printf("Unexpected version of bgroom file!\n");
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+extern FilePreviewData *ReadFilePreview(const char *filename)
+{
+ FilePreviewData *fpd = g_new0(FilePreviewData, 1);
+ FileHelper *fh = OpenFileHelper(filename);
+
+ fpd -> type = N_IMPORT_TYPES;
+
+ if (!fh)
+ return(fpd);
+
+ if (IsSGFFile(fh))
+ fpd->type = IMPORT_SGF;
+ else if (IsSGGFile(fh))
+ fpd->type = IMPORT_SGG;
+ else if (IsTXTFile(fh))
+ fpd->type = IMPORT_SNOWIETXT;
+ else if (IsTMGFile(fh))
+ fpd->type = IMPORT_TMG;
+ else if (IsMATFile(fh))
+ fpd->type = IMPORT_MAT;
+ else if (IsJFPFile(fh))
+ fpd->type = IMPORT_POS;
+ else if (IsBKGFile(fh))
+ fpd->type = IMPORT_BKG;
+ else if (IsGAMFile(fh))
+ fpd->type = IMPORT_EMPIRE;
+ else if (IsPARFile(fh))
+ fpd->type = IMPORT_PARTY;
+ else if (IsBGRFile(fh))
+ fpd->type = IMPORT_BGROOM;
+
+ CloseFileHelper(fh);
+ return fpd;
+}
+
+extern char *GetFilename(int CheckForCurrent, ExportType type)
+{
+ char *sz, tstr[15];
+ time_t t;
+
+ if (CheckForCurrent && szCurrentFileName && *szCurrentFileName)
+ sz = g_strdup_printf("%s%s", szCurrentFileName,
+ export_format[type].extension);
+ else {
+ if (mi.nYear)
+ sprintf(tstr, "%04d-%02d-%02d", mi.nYear,
+ mi.nMonth, mi.nDay);
+ else {
+ t = time(NULL);
+ if (strftime(tstr, 14, _("%Y-%m-%d-%H%M"), localtime(&t)) == 0)
+ *tstr='\0';
+ }
+ sz = g_strdup_printf("%s-%s_%dp_%s.sgf", ap[0].szName,
+ ap[1].szName, ms.nMatchTo, tstr);
+ }
+ return sz;
+}