ref: b259b105d7df69edf839bef1100904fbe6a688a2
parent: 16d73aa74e7c26ec2e4e900b452e7bb0c6d778fe
author: allkern <lisandroaalarcon@gmail.com>
date: Sat Aug 26 15:53:42 EDT 2023
Implement CUE parser
--- a/.gitignore
+++ b/.gitignore
@@ -15,4 +15,5 @@
*.exe
*.out
*.toml
-*.zip
\ No newline at end of file
+*.zip
+*.cue
\ No newline at end of file
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,7 @@
SOURCES := $(wildcard psx/*.c)
SOURCES += $(wildcard psx/dev/*.c)
SOURCES += $(wildcard psx/input/*.c)
+SOURCES += $(wildcard psx/disc/*.c)
SOURCES += $(wildcard frontend/*.c)
bin/psxe frontend/main.c:
--- a/build-win32.ps1
+++ b/build-win32.ps1
@@ -15,6 +15,7 @@
"psx\*.c" `
"psx\dev\*.c" `
"psx\input\*.c" `
+ "psx\disc\*.c" `
"frontend\*.c" `
-o "bin\psxe.exe" `
-DREP_VERSION="`"$($VERSION_TAG)`"" `
--- a/build-win64.ps1
+++ b/build-win64.ps1
@@ -15,6 +15,7 @@
"psx\*.c" `
"psx\dev\*.c" `
"psx\input\*.c" `
+ "psx\disc\*.c" `
"frontend\*.c" `
-o "bin\psxe.exe" `
-DREP_VERSION="`"$($VERSION_TAG)`"" `
--- a/psx/disc/cue.c
+++ b/psx/disc/cue.c
@@ -10,17 +10,73 @@
#include <ctype.h>
#include "cue.h"
+#include "../disc.h"
+#include "../log.h"
-int cue_get_keyword(char* buf) {+static const char* g_psxd_cue_tokens[] = {+ "4CH",
+ "AIFF",
+ "AUDIO",
+ "BINARY",
+ "CATALOG",
+ "CDG",
+ "CDI_2336",
+ "CDI_2352",
+ "CDTEXTFILE",
+ "DCP",
+ "FILE",
+ "FLAGS",
+ "INDEX",
+ "ISRC",
+ "MODE1_2048",
+ "MODE1_2352",
+ "MODE2_2336",
+ "MODE2_2352",
+ "MOTOROLA",
+ "MP3",
+ "PERFORMER",
+ "POSTGAP",
+ "PRE",
+ "PREGAP",
+ "REM",
+ "SCMS",
+ "SONGWRITER",
+ "TITLE",
+ "TRACK",
+ "WAVE",
+ 0
+};
+
+#define EXPECT_KEYWORD(kw) \
+ if (cue_parse_keyword(cue)) \
+ return cue->error; \
+ if (cue_get_keyword(cue) != kw) \
+ ERROR_OUT(PE_UNEXPECTED_TOKEN);
+
+void cue_add_track(psxd_cue_t* cue) {+ ++cue->numtracks;
+
+ cue->track = realloc(cue->track, cue->numtracks * sizeof(cue_track_t*));
+ cue->track[cue->numtracks - 1] = malloc(sizeof(cue_track_t));
+
+ memset(cue->track[cue->numtracks - 1], 0, sizeof(cue_track_t));
+}
+
+void cue_ignore_whitespace(psxd_cue_t* cue) {+ while (isspace(cue->c))
+ cue->c = fgetc(cue->file);
+}
+
+int cue_get_keyword(psxd_cue_t* cue) {int i = 0;
const char* token = g_psxd_cue_tokens[i];
while (token) {- if (strcmp(token, buf) == 1) {+ if (strcmp(token, cue->buf) == 1) {return i;
} else {- ++i;
+ token = g_psxd_cue_tokens[++i];
}
}
@@ -27,50 +83,197 @@
return -1;
}
-int cue_parse_keyword(FILE* file, char* c, char* buf) {- char* ptr = buf;
+#define ERROR_OUT(err) \
+ { cue->error = err; return err; }- if (!isalpha(*c))
- return PE_EXPECTED_KEYWORD;
+int cue_parse_keyword(psxd_cue_t* cue) {+ if (!isalpha(cue->c))
+ ERROR_OUT(PE_EXPECTED_KEYWORD);
- while (isalpha(*c)) {- fread(c, 1, 1, file);
+ while (isalnum(cue->c) || (cue->c == '/')) {+ *cue->ptr++ = cue->c;
- *ptr++ = *c;
+ cue->c = fgetc(cue->file);
}
- *ptr = 0;
+ *cue->ptr = 0;
+ cue->ptr = cue->buf;
+
+ cue_ignore_whitespace(cue);
+
return 0;
}
+int cue_parse_string(psxd_cue_t* cue) {+ if (cue->c != '\"')
+ ERROR_OUT(PE_EXPECTED_STRING);
+
+ cue->c = fgetc(cue->file);
+
+ while (cue->c != '\"') {+ *cue->ptr++ = cue->c;
+
+ cue->c = fgetc(cue->file);
+ }
+
+ *cue->ptr = 0;
+
+ cue->c = fgetc(cue->file);
+
+ cue->ptr = cue->buf;
+
+ cue_ignore_whitespace(cue);
+
+ return 0;
+}
+
+int cue_parse_number(psxd_cue_t* cue) {+ if (!isdigit(cue->c))
+ ERROR_OUT(PE_EXPECTED_NUMBER);
+
+ while (isdigit(cue->c)) {+ *cue->ptr++ = cue->c;
+
+ cue->c = fgetc(cue->file);
+ }
+
+ *cue->ptr = 0;
+
+ cue->ptr = cue->buf;
+
+ cue_ignore_whitespace(cue);
+
+ return 0;
+}
+
+int cue_parse_msf(psxd_cue_t* cue, msf_t* msf) {+ if (cue_parse_number(cue))
+ return cue->error;
+
+ if (cue->c != ':')
+ ERROR_OUT(PE_EXPECTED_COLON);
+
+ cue->c = fgetc(cue->file);
+
+ msf->m = atoi(cue->buf);
+
+ if (cue_parse_number(cue))
+ return cue->error;
+
+ if (cue->c != ':')
+ ERROR_OUT(PE_EXPECTED_COLON);
+
+ cue->c = fgetc(cue->file);
+
+ msf->s = atoi(cue->buf);
+
+ if (cue_parse_number(cue))
+ return cue->error;
+
+ msf->f = atoi(cue->buf);
+
+ return 0;
+}
+
int cue_parse(psxd_cue_t* cue, FILE* file) {- int state = CUE_NONE;
+ cue->file = file;
+ cue->c = fgetc(file);
- char c, buf[128];
- char* ptr = buf;
- int s;
+ void* filebuf;
+ size_t filesz;
+ msf_t msf;
+
+ EXPECT_KEYWORD(CUE_FILE);
+
+ parse_file:
+
+ if (cue_parse_string(cue))
+ return cue->error;
+
+ // Open file, get size and seek to 0
+ FILE* trackfile = fopen(cue->buf, "rb");
+
+ fseek(trackfile, 0, SEEK_END);
+
+ filesz = ftell(trackfile);
+
+ fseek(trackfile, 0, SEEK_SET);
+
+ // If we have to preload the disc image
+ // then copy data to our filebuf and close
+ // the file. Otherwise, our filebuf contains
+ // a pointer to the open FILE.
+ if (cue->preload) {+ filebuf = malloc(filesz);
+
+ fread(filebuf, 1, filesz, trackfile);
+
+ fclose(trackfile);
+ } else {+ filebuf = trackfile;
+ }
+
+ strcpy(cue->current_file, cue->buf);
+
+ EXPECT_KEYWORD(CUE_BINARY);
+ EXPECT_KEYWORD(CUE_TRACK);
+
+ if (cue_parse_number(cue))
+ return cue->error;
- c = fgetc(file);
+ int track = atoi(cue->buf) - 1;
+
+ if (track != cue->numtracks)
+ ERROR_OUT(PE_NON_SEQUENTIAL_TRACKS);
+
+ cue_add_track(cue);
- while (!feof(file)) {- s = cue_parse_keyword(file, &c, buf);
+ cue->track[track]->buf = filebuf;
+ cue->track[track]->size = filesz;
+ cue->track[track]->filename = malloc(strlen(cue->current_file));
- if (s)
- return s;
-
- switch (cue_get_keyword(buf)) {- case CUE_FILE: {-
- } break;
+ strcpy(cue->track[track]->filename, cue->current_file);
+
+ if (cue_parse_keyword(cue))
+ return cue->error;
- default: {- return PE_UNEXPECTED_TOKEN;
- } break;
- }
+ cue->track[track]->type = cue_get_keyword(cue);
+
+ // Expecting at least 1 index
+ EXPECT_KEYWORD(CUE_INDEX);
+
+ parse_index:
+
+ if (cue_parse_number(cue))
+ return cue->error;
+
+ int index = atoi(cue->buf);
+
+ if (cue_parse_msf(cue, &msf))
+ return cue->error;
+
+ cue->track[track]->index[index] = msf;
+
+ if (feof(cue->file)) {+ fclose(file);
+
+ return 0;
}
- fclose(file);
+ if (cue_parse_keyword(cue))
+ return cue->error;
+
+ switch (cue_get_keyword(cue)) {+ case CUE_INDEX:
+ goto parse_index;
+
+ case CUE_FILE:
+ goto parse_file;
+
+ default:
+ ERROR_OUT(PE_UNEXPECTED_TOKEN);
+ }
}
psxd_cue_t* psxd_cue_create() {@@ -77,12 +280,23 @@
return (psxd_cue_t*)malloc(sizeof(psxd_cue_t));
}
-void psxd_cue_init(psxd_cue_t* cue) {+void psxd_cue_init(psxd_cue_t* cue, int preload) {memset(cue, 0, sizeof(psxd_cue_t));
+
+ cue->buf = malloc(CUE_BUF_SIZE);
+ cue->ptr = cue->buf;
+ cue->preload = preload;
+ cue->current_file = malloc(CUE_BUF_SIZE);
}
void psxd_cue_load(psxd_cue_t* cue, const char* path) {-
+ FILE* file = fopen(path, "rb");
+
+ cue_parse(cue, file);
+
+ if (cue->error) {+ log_fatal("CUE error %u", cue->error);+ }
}
void psxd_cue_init_disc(psxd_cue_t* cue, psx_disc_t* disc) {@@ -90,5 +304,7 @@
}
void psxd_cue_destroy(psxd_cue_t* cue) {+ free(cue->current_file);
+ free(cue->buf);
free(cue);
}
\ No newline at end of file
--- a/psx/disc/cue.h
+++ b/psx/disc/cue.h
@@ -7,10 +7,20 @@
#ifndef CUE_H
#define CUE_H
+#define CUE_BUF_SIZE 256
+
#include "../disc.h"
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+
enum {PE_EXPECTED_KEYWORD = 1,
+ PE_EXPECTED_STRING,
+ PE_EXPECTED_NUMBER,
+ PE_EXPECTED_COLON,
+ PE_NON_SEQUENTIAL_TRACKS,
PE_UNEXPECTED_TOKEN
};
@@ -48,45 +58,28 @@
CUE_WAVE
};
-static const char* g_psxd_cue_tokens[] = {- "4CH",
- "AIFF",
- "AUDIO",
- "BINARY",
- "CATALOG",
- "CDG",
- "CDI_2336",
- "CDI_2352",
- "CDTEXTFILE",
- "DCP",
- "FILE",
- "FLAGS",
- "INDEX",
- "ISRC",
- "MODE1_2048",
- "MODE1_2352",
- "MODE2_2336",
- "MODE2_2352",
- "MOTOROLA",
- "MP3",
- "PERFORMER",
- "POSTGAP",
- "PRE",
- "PREGAP",
- "REM",
- "SCMS",
- "SONGWRITER",
- "TITLE",
- "TRACK",
- "WAVE"
-};
-
typedef struct {+ char* filename;
+ int type;
+ void* buf;
+ msf_t index[2];
+ size_t size;
+} cue_track_t;
+typedef struct {+ int preload;
+ char* buf;
+ char* ptr;
+ char c;
+ int error;
+ FILE* file;
+ int numtracks;
+ cue_track_t** track;
+ char* current_file;
} psxd_cue_t;
psxd_cue_t* psxd_cue_create();
-void psxd_cue_init(psxd_cue_t*);
+void psxd_cue_init(psxd_cue_t*, int);
void psxd_cue_load(psxd_cue_t*, const char*);
void psxd_cue_init_disc(psxd_cue_t*, psx_disc_t*);
void psxd_cue_destroy(psxd_cue_t*);
--
⑨