cleanup: replace jansson

This commit is contained in:
bnnm 2024-07-28 18:24:40 +02:00
parent e6a2bec8c2
commit 3edb6e71d6
7 changed files with 246 additions and 113 deletions

View File

@ -39,6 +39,8 @@ CFLAGS += $(LIBS_CFLAGS)
LDFLAGS += $(LIBS_LDFLAGS) LDFLAGS += $(LIBS_LDFLAGS)
TARGET_EXT_LIBS += $(LIBS_TARGET_EXT_LIBS) TARGET_EXT_LIBS += $(LIBS_TARGET_EXT_LIBS)
CLI_SRCS = vgmstream_cli.c vgmstream_cli_utils.c wav_utils.c
V123_SRCS = vgmstream123.c wav_utils.c
export CFLAGS LDFLAGS export CFLAGS LDFLAGS
@ -47,11 +49,11 @@ export CFLAGS LDFLAGS
### targets ### targets
vgmstream_cli: libvgmstream.a $(TARGET_EXT_LIBS) vgmstream_cli: libvgmstream.a $(TARGET_EXT_LIBS)
$(CC) $(CFLAGS) vgmstream_cli.c vgmstream_cli_utils.c wav_utils.c $(LDFLAGS) -o $(OUTPUT_CLI) $(CC) $(CFLAGS) $(CLI_SRCS) $(LDFLAGS) -o $(OUTPUT_CLI)
$(STRIP) $(OUTPUT_CLI) $(STRIP) $(OUTPUT_CLI)
vgmstream123: libvgmstream.a $(TARGET_EXT_LIBS) vgmstream123: libvgmstream.a $(TARGET_EXT_LIBS)
$(CC) $(CFLAGS) $(LIBAO_INC) vgmstream123.c wav_utils.c $(LDFLAGS) $(LIBAO_LIB) -o $(OUTPUT_123) $(CC) $(CFLAGS) $(LIBAO_INC) $(V123_SRCS) $(LDFLAGS) $(LIBAO_LIB) -o $(OUTPUT_123)
$(STRIP) $(OUTPUT_123) $(STRIP) $(OUTPUT_123)
api_example: libvgmstream.a $(TARGET_EXT_LIBS) api_example: libvgmstream.a $(TARGET_EXT_LIBS)

View File

@ -66,10 +66,8 @@ static void print_usage(const char* progname, bool is_help) {
" -c: loop forever (continuously) to stdout\n" " -c: loop forever (continuously) to stdout\n"
" -L: append a smpl chunk and create a looping wav\n" " -L: append a smpl chunk and create a looping wav\n"
//" -w: allow .wav in original sample format rather than downmixing to PCM16\n" //" -w: allow .wav in original sample format rather than downmixing to PCM16\n"
#ifdef HAVE_JSON
" -V: print version info and supported extensions as JSON\n" " -V: print version info and supported extensions as JSON\n"
" -I: print requested file info as JSON\n" " -I: print requested file info as JSON\n"
#endif
" -h: print all commands\n" " -h: print all commands\n"
, progname); , progname);
@ -110,11 +108,7 @@ static bool parse_config(cli_config_t* cfg, int argc, char** argv) {
optind = 1; /* reset getopt's ugly globals (needed in wasm that may call same main() multiple times) */ optind = 1; /* reset getopt's ugly globals (needed in wasm that may call same main() multiple times) */
/* read config */ /* read config */
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFrgb2:s:tTk:K:hOvD:S:B:" while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFrgb2:s:tTk:K:hOvD:S:B:VI")) != -1) {
#ifdef HAVE_JSON
"VI"
#endif
)) != -1) {
switch (opt) { switch (opt) {
case 'o': case 'o':
cfg->outfilename = optarg; cfg->outfilename = optarg;
@ -229,14 +223,12 @@ static bool parse_config(cli_config_t* cfg, int argc, char** argv) {
case 'h': case 'h':
print_usage(argv[0], true); print_usage(argv[0], true);
goto fail; goto fail;
#ifdef HAVE_JSON
case 'V': case 'V':
print_json_version(VGMSTREAM_VERSION); print_json_version(VGMSTREAM_VERSION);
goto fail; goto fail;
case 'I': case 'I':
cfg->print_metajson = true; cfg->print_metajson = true;
break; break;
#endif
case '?': case '?':
fprintf(stderr, "missing argument or unknown option -%c\n", optopt); fprintf(stderr, "missing argument or unknown option -%c\n", optopt);
goto fail; goto fail;
@ -580,18 +572,14 @@ static bool convert_file(cli_config_t* cfg) {
/* prints */ /* prints */
#ifdef HAVE_JSON
if (!cfg->print_metajson) { if (!cfg->print_metajson) {
#endif
print_info(vgmstream, cfg); print_info(vgmstream, cfg);
print_tags(cfg); print_tags(cfg);
print_title(vgmstream, cfg); print_title(vgmstream, cfg);
#ifdef HAVE_JSON
} }
else { else {
print_json_info(vgmstream, cfg, VGMSTREAM_VERSION); print_json_info(vgmstream, cfg, VGMSTREAM_VERSION);
} }
#endif
/* prints done */ /* prints done */
if (cfg->print_metaonly) { if (cfg->print_metaonly) {

View File

@ -1,5 +1,5 @@
#ifndef _VGMSTREAM_CLI_H #ifndef _VGMSTREAM_CLI_H_
#define _VGMSTREAM_CLI_H #define _VGMSTREAM_CLI_H_
#include "../src/api.h" #include "../src/api.h"
#include "../src/vgmstream.h" #include "../src/vgmstream.h"
@ -43,9 +43,7 @@ typedef struct {
bool print_oggenc; bool print_oggenc;
bool print_batchvar; bool print_batchvar;
bool print_title; bool print_title;
#ifdef HAVE_JSON
bool print_metajson; bool print_metajson;
#endif
const char* tag_filename; const char* tag_filename;
// debug stuff // debug stuff
@ -69,10 +67,8 @@ void print_info(VGMSTREAM* vgmstream, cli_config_t* cfg);
void print_tags(cli_config_t* cfg); void print_tags(cli_config_t* cfg);
void print_title(VGMSTREAM* vgmstream, cli_config_t* cfg); void print_title(VGMSTREAM* vgmstream, cli_config_t* cfg);
#ifdef HAVE_JSON
void print_json_version(const char* vgmstream_version); void print_json_version(const char* vgmstream_version);
void print_json_info(VGMSTREAM* vgm, cli_config_t* cfg, const char* vgmstream_version); void print_json_info(VGMSTREAM* vgm, cli_config_t* cfg, const char* vgmstream_version);
#endif
#endif #endif

View File

@ -105,6 +105,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="vgmstream_cli.h" /> <ClInclude Include="vgmstream_cli.h" />
<ClInclude Include="vjson.h" />
<ClInclude Include="wav_utils.h" /> <ClInclude Include="wav_utils.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -22,6 +22,9 @@
<ClCompile Include="vgmstream_cli.h"> <ClCompile Include="vgmstream_cli.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="vjson.h">
<Filter>Header Files</Filter>
</ClCompile>
<ClCompile Include="wav_utils.h"> <ClCompile Include="wav_utils.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClCompile> </ClCompile>

View File

@ -6,10 +6,7 @@
#include "../src/api.h" #include "../src/api.h"
#include "../src/vgmstream.h" #include "../src/vgmstream.h"
//todo use <>? #include "vjson.h"
#ifdef HAVE_JSON
#include "jansson/jansson.h"
#endif
static void clean_filename(char* dst, int clean_paths) { static void clean_filename(char* dst, int clean_paths) {
@ -191,114 +188,106 @@ void print_title(VGMSTREAM* vgmstream, cli_config_t* cfg) {
printf("title: %s\n", title); printf("title: %s\n", title);
} }
#ifdef HAVE_JSON
void print_json_version(const char* vgmstream_version) { void print_json_version(const char* vgmstream_version) {
size_t extension_list_len; size_t extension_list_len = 0;
size_t common_extension_list_len;
const char** extension_list; const char** extension_list;
const char** common_extension_list;
vjson_t j = {0};
char buf[0x4000]; // exts need ~0x1400
vjson_init(&j, buf, sizeof(buf));
vjson_obj_open(&j);
vjson_keystr(&j, "version", vgmstream_version);
vjson_key(&j, "extensions");
vjson_obj_open(&j);
vjson_key(&j, "vgm");
vjson_arr_open(&j);
extension_list = vgmstream_get_formats(&extension_list_len); extension_list = vgmstream_get_formats(&extension_list_len);
common_extension_list = vgmstream_get_common_formats(&common_extension_list_len); for (int i = 0; i < extension_list_len; i++) {
vjson_str(&j, extension_list[i]);
json_t* ext_list = json_array();
json_t* cext_list = json_array();
for (size_t i = 0; i < extension_list_len; ++i) {
json_t* ext = json_string(extension_list[i]);
json_array_append(ext_list, ext);
} }
vjson_arr_close(&j);
for (size_t i = 0; i < common_extension_list_len; ++i) { vjson_key(&j, "common");
json_t* cext = json_string(common_extension_list[i]); vjson_arr_open(&j);
json_array_append(cext_list, cext); extension_list = vgmstream_get_common_formats(&extension_list_len);
for (int i = 0; i < extension_list_len; i++) {
vjson_str(&j, extension_list[i]);
} }
vjson_arr_close(&j);
json_t* version_string = json_string(vgmstream_version); vjson_obj_close(&j);
vjson_obj_close(&j);
json_t* final_object = json_object(); printf("%s\n", buf);
json_object_set(final_object, "version", version_string);
json_decref(version_string);
json_object_set(final_object, "extensions",
json_pack("{soso}",
"vgm", ext_list,
"common", cext_list));
json_dumpf(final_object, stdout, JSON_COMPACT);
} }
void print_json_info(VGMSTREAM* vgm, cli_config_t* cfg, const char* vgmstream_version) { void print_json_info(VGMSTREAM* vgm, cli_config_t* cfg, const char* vgmstream_version) {
json_t* version_string = json_string(vgmstream_version); char buf[0x1000]; // probably fine with ~0x400
vjson_t j = {0};
vjson_init(&j, buf, sizeof(buf));
vgmstream_info info; vgmstream_info info;
describe_vgmstream_info(vgm, &info); describe_vgmstream_info(vgm, &info);
json_t* mixing_info = NULL; vjson_obj_open(&j);
vjson_keystr(&j, "version", vgmstream_version);
// The JSON pack format string is defined here: https://jansson.readthedocs.io/en/latest/apiref.html#building-values vjson_keyint(&j, "sampleRate", info.sample_rate);
vjson_keyint(&j, "channels", info.channels);
vjson_key(&j, "mixingInfo");
if (info.mixing_info.input_channels > 0) { if (info.mixing_info.input_channels > 0) {
mixing_info = json_pack("{sisi}", vjson_obj_open(&j);
"inputChannels", info.mixing_info.input_channels, vjson_keyint(&j, "inputChannels", info.mixing_info.input_channels);
"outputChannels", info.mixing_info.output_channels); vjson_keyint(&j, "outputChannels", info.mixing_info.output_channels);
vjson_obj_close(&j);
}
else {
vjson_null(&j);
} }
json_t* loop_info = NULL; vjson_keyintnull(&j, "channelLayout", info.channel_layout);
vjson_key(&j, "loopingInfo");
if (info.loop_info.end > info.loop_info.start) { if (info.loop_info.end > info.loop_info.start) {
loop_info = json_pack("{sisi}", vjson_obj_open(&j);
"start", info.loop_info.start, vjson_keyint(&j, "start", info.loop_info.start);
"end", info.loop_info.end); vjson_keyint(&j, "end", info.loop_info.start);
vjson_obj_close(&j);
}
else {
vjson_null(&j);
} }
json_t* interleave_info = NULL; vjson_key(&j, "interleaveInfo");
if (info.interleave_info.last_block > info.interleave_info.first_block) { if (info.interleave_info.last_block > info.interleave_info.first_block) {
interleave_info = json_pack("{sisi}", vjson_obj_open(&j);
"firstBlock", info.interleave_info.first_block, vjson_keyint(&j, "firstBlock", info.interleave_info.last_block);
"lastBlock", info.interleave_info.last_block vjson_keyint(&j, "lastBlock", info.interleave_info.first_block);
); vjson_obj_close(&j);
}
else {
vjson_null(&j);
} }
json_t* stream_info = json_pack("{sisssi}", vjson_keyint(&j, "numberOfSamples", info.num_samples);
"index", info.stream_info.current, vjson_keystr(&j, "encoding", info.encoding);
"name", info.stream_info.name, vjson_keystr(&j, "layout", info.layout);
"total", info.stream_info.total vjson_keyintnull(&j, "frameSize", info.frame_size);
); vjson_keystr(&j, "metadataSource", info.metadata);
vjson_keyint(&j, "bitrate", info.bitrate);
if (info.stream_info.name[0] == '\0') { vjson_key(&j, "streamInfo");
json_object_set(stream_info, "name", json_null()); vjson_obj_open(&j);
vjson_keyint(&j, "index", info.stream_info.current);
vjson_keystr(&j, "name", info.stream_info.name);
vjson_keyint(&j, "total", info.stream_info.total);
vjson_obj_close(&j);
vjson_obj_close(&j);
printf("%s\n", buf);
} }
json_t* final_object = json_pack(
"{sssisiso?siso?so?sisssssisssiso?}",
"version", version_string,
"sampleRate", info.sample_rate,
"channels", info.channels,
"mixingInfo", mixing_info,
"channelLayout", info.channel_layout,
"loopingInfo", loop_info,
"interleaveInfo", interleave_info,
"numberOfSamples", info.num_samples,
"encoding", info.encoding,
"layout", info.layout,
"frameSize", info.frame_size,
"metadataSource", info.metadata,
"bitrate", info.bitrate,
"streamInfo", stream_info
);
if (info.frame_size == 0) {
json_object_set(final_object, "frameSize", json_null());
}
if (info.channel_layout == 0) {
json_object_set(final_object, "channelLayout", json_null());
}
json_dumpf(final_object, stdout, JSON_COMPACT);
json_decref(final_object);
printf("\n");
}
#endif

154
cli/vjson.h Normal file
View File

@ -0,0 +1,154 @@
#ifndef _VJSON_H_
#define _VJSON_H_
/* What is this crap, you may wonder? For probably non-existant use cases Jansson was added to write JSON info,
* but external libs are a pain to maintain. For now this glorified string joiner replaces it.
*
* On incorrect usage or small buf it'll create invalid JSON because who cares, try-parse-catch as usual.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#define VJSON_STACK_MAX 16
typedef struct {
char* buf;
int buf_len;
char* bufp;
int buf_left;
bool stack[VJSON_STACK_MAX];
int stack_pos;
bool is_last_key;
} vjson_t;
static void vjson_init(vjson_t* j, char* buf, int buf_len) {
j->buf = buf;
j->buf_len = buf_len;
j->bufp = buf;
j->buf_left = buf_len;
}
static void vjson_raw(vjson_t* j, const char* str) {
if (!str)
str = "null";
int done = snprintf(j->bufp, j->buf_left, "%s", str);
j->bufp += done;
j->buf_left -= done;
}
static void vjson_comma_(vjson_t* j) {
if (j->stack[j->stack_pos] && !j->is_last_key) {
vjson_raw(j, ",");
}
j->stack[j->stack_pos] = true;
j->is_last_key = false;
}
static void vjson_open_(vjson_t* j, const char* str) {
vjson_comma_(j);
vjson_raw(j, str);
if (j->stack_pos + 1 >= VJSON_STACK_MAX)
return;
j->stack_pos++;
j->stack[j->stack_pos] = false;
}
static void vjson_close_(vjson_t* j, const char* str) {
//vjson_comma_(j);
vjson_raw(j, str);
if (j->stack_pos - 1 <= 0)
return;
j->stack[j->stack_pos] = false;
j->stack_pos--;
}
static void vjson_arr_open(vjson_t* j) {
vjson_open_(j, "[");
}
static void vjson_arr_close(vjson_t* j) {
vjson_close_(j, "]");
}
static void vjson_obj_open(vjson_t* j) {
vjson_open_(j, "{");
}
static void vjson_obj_close(vjson_t* j) {
vjson_close_(j, "}");
}
static void vjson_key(vjson_t* j, const char* key) {
vjson_comma_(j);
vjson_raw(j, "\"");
vjson_raw(j, key);
vjson_raw(j, "\":");
j->is_last_key = true;
}
static void vjson_str(vjson_t* j, const char* str) {
vjson_comma_(j);
if (!str || str[0] == '\0') {
vjson_raw(j, NULL);
}
else {
vjson_raw(j, "\"");
vjson_raw(j, str);
vjson_raw(j, "\"");
}
}
static void vjson_int(vjson_t* j, int64_t num) {
vjson_comma_(j);
char tmp[32] = {0};
snprintf(tmp, sizeof(tmp), "%" PRId64, num);
vjson_raw(j, tmp);
}
#if 0
static void vjson_dbl(vjson_t* j, double num) {
vjson_comma_(j);
char tmp[32] = {0};
snprintf(tmp, sizeof(tmp), "%f", num);
vjson_raw(j, tmp);
}
#endif
void vjson_null(vjson_t* j){
vjson_comma_(j);
vjson_raw(j, "null");
}
static void vjson_intnull(vjson_t* j, int64_t num) {
if (num == 0) {
vjson_str(j, NULL);
}
else {
vjson_int(j, num);
}
}
static void vjson_keystr(vjson_t* j, const char* key, const char* val) {
vjson_key(j, key);
vjson_str(j, val);
}
static void vjson_keyint(vjson_t* j, const char* key, int64_t val) {
vjson_key(j, key);
vjson_int(j, val);
}
static void vjson_keyintnull(vjson_t* j, const char* key, int64_t val) {
vjson_key(j, key);
vjson_intnull(j, val);
}
#endif