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)
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
@ -47,11 +49,11 @@ export CFLAGS LDFLAGS
### targets
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)
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)
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"
" -L: append a smpl chunk and create a looping wav\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"
" -I: print requested file info as JSON\n"
#endif
" -h: print all commands\n"
, 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) */
/* read config */
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFrgb2:s:tTk:K:hOvD:S:B:"
#ifdef HAVE_JSON
"VI"
#endif
)) != -1) {
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFrgb2:s:tTk:K:hOvD:S:B:VI")) != -1) {
switch (opt) {
case 'o':
cfg->outfilename = optarg;
@ -229,14 +223,12 @@ static bool parse_config(cli_config_t* cfg, int argc, char** argv) {
case 'h':
print_usage(argv[0], true);
goto fail;
#ifdef HAVE_JSON
case 'V':
print_json_version(VGMSTREAM_VERSION);
goto fail;
case 'I':
cfg->print_metajson = true;
break;
#endif
case '?':
fprintf(stderr, "missing argument or unknown option -%c\n", optopt);
goto fail;
@ -580,18 +572,14 @@ static bool convert_file(cli_config_t* cfg) {
/* prints */
#ifdef HAVE_JSON
if (!cfg->print_metajson) {
#endif
print_info(vgmstream, cfg);
print_tags(cfg);
print_title(vgmstream, cfg);
#ifdef HAVE_JSON
}
else {
print_json_info(vgmstream, cfg, VGMSTREAM_VERSION);
}
#endif
/* prints done */
if (cfg->print_metaonly) {

View File

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

View File

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

View File

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

View File

@ -6,10 +6,7 @@
#include "../src/api.h"
#include "../src/vgmstream.h"
//todo use <>?
#ifdef HAVE_JSON
#include "jansson/jansson.h"
#endif
#include "vjson.h"
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);
}
#ifdef HAVE_JSON
void print_json_version(const char* vgmstream_version) {
size_t extension_list_len;
size_t common_extension_list_len;
size_t extension_list_len = 0;
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);
common_extension_list = vgmstream_get_common_formats(&common_extension_list_len);
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);
for (int i = 0; i < extension_list_len; i++) {
vjson_str(&j, extension_list[i]);
}
vjson_arr_close(&j);
for (size_t i = 0; i < common_extension_list_len; ++i) {
json_t* cext = json_string(common_extension_list[i]);
json_array_append(cext_list, cext);
vjson_key(&j, "common");
vjson_arr_open(&j);
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();
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);
printf("%s\n", buf);
}
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;
describe_vgmstream_info(vgm, &info);
json_t* mixing_info = NULL;
// The JSON pack format string is defined here: https://jansson.readthedocs.io/en/latest/apiref.html#building-values
vjson_obj_open(&j);
vjson_keystr(&j, "version", vgmstream_version);
vjson_keyint(&j, "sampleRate", info.sample_rate);
vjson_keyint(&j, "channels", info.channels);
vjson_key(&j, "mixingInfo");
if (info.mixing_info.input_channels > 0) {
mixing_info = json_pack("{sisi}",
"inputChannels", info.mixing_info.input_channels,
"outputChannels", info.mixing_info.output_channels);
vjson_obj_open(&j);
vjson_keyint(&j, "inputChannels", info.mixing_info.input_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) {
loop_info = json_pack("{sisi}",
"start", info.loop_info.start,
"end", info.loop_info.end);
vjson_obj_open(&j);
vjson_keyint(&j, "start", info.loop_info.start);
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) {
interleave_info = json_pack("{sisi}",
"firstBlock", info.interleave_info.first_block,
"lastBlock", info.interleave_info.last_block
);
vjson_obj_open(&j);
vjson_keyint(&j, "firstBlock", 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}",
"index", info.stream_info.current,
"name", info.stream_info.name,
"total", info.stream_info.total
);
vjson_keyint(&j, "numberOfSamples", info.num_samples);
vjson_keystr(&j, "encoding", info.encoding);
vjson_keystr(&j, "layout", info.layout);
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') {
json_object_set(stream_info, "name", json_null());
vjson_key(&j, "streamInfo");
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