mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 15:00:11 +01:00
add extra user logs
This commit is contained in:
parent
e3c8240d5b
commit
cf36348b77
@ -83,14 +83,14 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
|
||||
coding_type = coding_CRI_ADX_enc_8;
|
||||
version = 0x0400;
|
||||
}
|
||||
VGM_ASSERT(version != 0x0400, "ADX: keystring not found\n");
|
||||
vgm_asserti(version != 0x0400, "ADX: decryption keystring not found\n");
|
||||
}
|
||||
else if (version == 0x0409) {
|
||||
if (find_adx_key(sf, 9, &xor_start, &xor_mult, &xor_add, subkey)) {
|
||||
coding_type = coding_CRI_ADX_enc_9;
|
||||
version = 0x0400;
|
||||
}
|
||||
VGM_ASSERT(version != 0x0400, "ADX: keycode not found\n");
|
||||
vgm_asserti(version != 0x0400, "ADX: decryption keycode not found\n");
|
||||
}
|
||||
|
||||
/* version + extra data */
|
||||
|
@ -166,7 +166,7 @@ static void find_bnsf_key(STREAMFILE* sf, off_t start, g7221_codec_data* data, u
|
||||
}
|
||||
|
||||
VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score);
|
||||
VGM_ASSERT(best_score < 0, "BNSF: key not found\n");
|
||||
vgm_asserti(best_score < 0 , "BNSF: decryption key not found\n");
|
||||
}
|
||||
|
||||
#define BNSF_MIN_KEY_LEN 3
|
||||
|
@ -72,7 +72,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
||||
fsb5.base_header_size = (fsb5.version==0x00) ? 0x40 : 0x3C;
|
||||
|
||||
if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(sf)) {
|
||||
VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf));
|
||||
vgm_logi("FSB5: wrong size, expected %x + %x + %x + %x vs %x (re-rip)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -217,7 +217,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
||||
fsb5.channels = fsb5.channels * fsb5.layers;
|
||||
break;
|
||||
default:
|
||||
VGM_LOG("FSB5: stream %i unknown flag 0x%x at %x + 0x04 (size 0x%x)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size);
|
||||
vgm_logi("FSB5: stream %i unknown flag 0x%x at %x + 0x04 + 0x%x (report)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -301,11 +301,11 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
||||
break;
|
||||
|
||||
case 0x03: /* FMOD_SOUND_FORMAT_PCM24 */
|
||||
VGM_LOG("FSB5: FMOD_SOUND_FORMAT_PCM24 found\n");
|
||||
vgm_logi("FSB5: FMOD_SOUND_FORMAT_PCM24 found (report)\n");
|
||||
goto fail;
|
||||
|
||||
case 0x04: /* FMOD_SOUND_FORMAT_PCM32 */
|
||||
VGM_LOG("FSB5: FMOD_SOUND_FORMAT_PCM32 found\n");
|
||||
vgm_logi("FSB5: FMOD_SOUND_FORMAT_PCM32 found (report)\n");
|
||||
goto fail;
|
||||
|
||||
case 0x05: /* FMOD_SOUND_FORMAT_PCMFLOAT [Anima: Gate of Memories (PC)] */
|
||||
@ -494,7 +494,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
||||
#endif
|
||||
#endif
|
||||
default:
|
||||
VGM_LOG("FSB5: unknown codec %x found\n", fsb5.codec);
|
||||
vgm_logi("FSB5: unknown codec 0x%x (report)\n", fsb5.codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,10 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) {
|
||||
|
||||
/* init vgmstream and library's context, will validate the HCA */
|
||||
hca_data = init_hca(sf);
|
||||
if (!hca_data) goto fail;
|
||||
if (!hca_data) {
|
||||
vgm_logi("HCA: unknown format (report)\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hca_info = hca_get_info(hca_data);
|
||||
|
||||
@ -184,7 +187,7 @@ static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t
|
||||
done:
|
||||
VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
|
||||
(uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score);
|
||||
VGM_ASSERT(best_score < 0, "HCA: key not found\n");
|
||||
vgm_asserti(best_score < 0, "HCA: decryption key not found\n");
|
||||
}
|
||||
|
||||
#ifdef HCA_BRUTEFORCE
|
||||
|
@ -279,6 +279,8 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
|
||||
}
|
||||
|
||||
default:
|
||||
/* FFmpeg may play it */
|
||||
//vgm_logi("WWISE: unknown codec 0x%04x (report)\n", fmt->format);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -418,8 +420,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
/* check for truncated RIFF */
|
||||
if (file_size != riff_size + 0x08)
|
||||
if (file_size != riff_size + 0x08) {
|
||||
vgm_logi("RIFF: wrong expected size (report/re-rip?)\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* read through chunks to verify format and find metadata */
|
||||
{
|
||||
|
@ -100,8 +100,12 @@ VGMSTREAM* init_vgmstream_sqex_scd(STREAMFILE* sf) {
|
||||
target_entry = i;
|
||||
}
|
||||
}
|
||||
if (meta_offset == 0) goto fail;
|
||||
|
||||
/* SCD can contain 0 entries too */
|
||||
if (meta_offset == 0) {
|
||||
vgm_logi("SQEX SCD: bank has no subsongs (ignore)\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/** stream header **/
|
||||
|
@ -856,9 +856,11 @@ static int parse_sead(sead_header *sead, STREAMFILE *sf) {
|
||||
}
|
||||
|
||||
/* SAB can contain 0 entries too */
|
||||
if (sead->mtrl_offset == 0)
|
||||
if (sead->mtrl_offset == 0) {
|
||||
vgm_logi("SQEX SEAD: bank has no subsongs (ignore)\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/** stream header **/
|
||||
/* 0x00: version */
|
||||
|
@ -1391,7 +1391,7 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
VGM_LOG("TXTH: error parsing key=%s, val=%s\n", key, val);
|
||||
vgm_logi("TXTH: error parsing key=%s, val=%s\n", key, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1843,7 +1843,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_
|
||||
offset += txth->base_offset;
|
||||
|
||||
if (/*offset < 0 ||*/ offset > get_streamfile_size(sf)) {
|
||||
VGM_LOG("TXTH: wrong offset %x + %x\n", offset - txth->base_offset, txth->base_offset);
|
||||
vgm_logi("TXTH: wrong offset over file size (%x + %x)\n", offset - txth->base_offset, txth->base_offset);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -634,7 +634,7 @@ static VGMSTREAM* init_vgmstream_ubi_bao_header(ubi_bao_header* bao, STREAMFILE*
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
|
||||
if (bao->total_subsongs <= 0) {
|
||||
VGM_LOG("UBI BAO: no subsongs\n");
|
||||
vgm_logi("UBI BAO: bank has no subsongs (ignore)\n");
|
||||
goto fail; /* not uncommon */
|
||||
}
|
||||
|
||||
@ -1473,7 +1473,10 @@ static STREAMFILE* setup_bao_streamfile(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||
|
||||
if (bao->stream_size - bao->prefetch_size != 0) {
|
||||
new_sf = open_streamfile_by_filename(sf, bao->resource_name);
|
||||
if (!new_sf) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
|
||||
if (!new_sf) {
|
||||
vgm_logi("UBI BAO: external file '%s' not found (put together)\n", bao->resource_name);
|
||||
goto fail;
|
||||
}
|
||||
stream_segments[1] = new_sf;
|
||||
|
||||
new_sf = open_clamp_streamfile(stream_segments[1], bao->stream_offset, (bao->stream_size - bao->prefetch_size));
|
||||
@ -1495,7 +1498,10 @@ static STREAMFILE* setup_bao_streamfile(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||
}
|
||||
else if (bao->is_external) {
|
||||
new_sf = open_streamfile_by_filename(sf, bao->resource_name);
|
||||
if (!new_sf) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
|
||||
if (!new_sf) {
|
||||
vgm_logi("UBI BAO: external file '%s' not found (put together)\n", bao->resource_name);
|
||||
goto fail;
|
||||
}
|
||||
temp_sf = new_sf;
|
||||
|
||||
new_sf = open_clamp_streamfile(temp_sf, bao->stream_offset, bao->stream_size);
|
||||
@ -1884,11 +1890,10 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||
* - 0x94: stream id? 0x9C: extra size */
|
||||
case 0x002A0300: /* Watch Dogs (Wii U) */
|
||||
/* similar to SC:B */
|
||||
default: /* others possibly using BAO: Just Dance, Watch_Dogs, Far Cry Primal, Far Cry 4 */
|
||||
VGM_LOG("UBI BAO: unknown BAO version %08x\n", bao->version);
|
||||
default: /* others possibly using BAO: Watch_Dogs, Far Cry Primal, Far Cry 4 */
|
||||
vgm_logi("UBI BAO: unknown BAO version %08x\n", bao->version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
VGM_LOG("UBI BAO: unknown BAO version %08x\n", bao->version);
|
||||
return 0;
|
||||
}
|
||||
|
@ -644,7 +644,7 @@ static VGMSTREAM *init_vgmstream_ubi_dat_main(ubi_sb_header *sb, STREAMFILE *sf_
|
||||
sf_data = open_streamfile_by_filename(sf, sb->resource_name);
|
||||
if (!sf_data) {
|
||||
/* play silence if external file is not found since Rayman 2 seems to rely on this behavior */
|
||||
VGM_LOG("UBI DAT: external stream '%s' not found\n", sb->resource_name);
|
||||
vgm_logi("UBI DAT: external file '%s' not found (put together)\n", sb->resource_name);
|
||||
strncat(sb->readable_name, " (missing)", sizeof(sb->readable_name));
|
||||
sb->duration = (float)pcm_bytes_to_samples(sb->stream_size, sb->channels, 16) / (float)sb->sample_rate;
|
||||
return init_vgmstream_ubi_sb_silence(sb);
|
||||
@ -1301,10 +1301,11 @@ static VGMSTREAM* init_vgmstream_ubi_sb_audio(ubi_sb_header* sb, STREAMFILE* sf_
|
||||
if (sb->is_external) {
|
||||
sf_data = open_streamfile_by_filename(sf, sb->resource_name);
|
||||
if (sf_data == NULL) {
|
||||
VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name);
|
||||
vgm_logi("UBI SB: external file '%s' not found (put together)\n", sb->resource_name);
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
sf_data = sf;
|
||||
}
|
||||
|
||||
@ -1341,7 +1342,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_layer(ubi_sb_header* sb, STREAMFILE* sf_
|
||||
if (sb->is_external) {
|
||||
sf_data = open_streamfile_by_filename(sf,sb->resource_name);
|
||||
if (sf_data == NULL) {
|
||||
VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name);
|
||||
vgm_logi("UBI SB: external file '%s' not found (put together)\n", sb->resource_name);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@ -1563,7 +1564,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_header(ubi_sb_header* sb, STREAMFILE* sf
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
|
||||
if (sb->total_subsongs == 0) {
|
||||
VGM_LOG("UBI SB: no subsongs\n");
|
||||
vgm_logi("UBI SB: bank has no subsongs (ignore)\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -4042,6 +4043,6 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
VGM_LOG("UBI SB: unknown SB/SM version+platform %08x\n", sb->version);
|
||||
vgm_logi("UBI SB: unknown SB/SM version+platform %08x (report)\n", sb->version);
|
||||
return 0;
|
||||
}
|
||||
|
@ -592,8 +592,8 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
case HEVAG: /* PSV */
|
||||
/* changed values, another bizarre Wwise quirk */
|
||||
//ww.block_align /* unknown (1ch=2, 2ch=4) */
|
||||
@ -644,6 +644,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case PTADPCM: /* newer ADPCM [Bayonetta 2 (Switch), Genshin Impact (PC)] */
|
||||
if (ww.bits_per_sample != 4) goto fail;
|
||||
if (ww.block_align != 0x24 * ww.channels && ww.block_align != 0x104 * ww.channels) goto fail;
|
||||
@ -885,6 +886,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||
case 0x3041: ww->codec = OPUSWW; break; /* "OPUS_WEM", added on Wwise 2019.2.3, replaces OPUS */
|
||||
case 0x8311: ww->codec = PTADPCM; break; /* added on Wwise 2019.1, replaces IMA */
|
||||
default:
|
||||
vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -893,11 +895,14 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||
if (ww->extra_size == 0x0c + ww->channels * 0x2e) {
|
||||
/* newer Wwise DSP with coefs [Epic Mickey 2 (Wii), Batman Arkham Origins Blackgate (3DS)] */
|
||||
ww->codec = DSP;
|
||||
} else if (ww->extra_size == 0x0a && ww->wiih_offset) { /* WiiH */
|
||||
}
|
||||
else if (ww->extra_size == 0x0a && ww->wiih_offset) { /* WiiH */
|
||||
/* few older Wwise DSP with num_samples in extra_size [Tony Hawk: Shred (Wii)] */
|
||||
ww->codec = DSP;
|
||||
} else if (ww->block_align == 0x104 * ww->channels) {
|
||||
ww->codec = PTADPCM; /* Bayonetta 2 (Switch) */
|
||||
}
|
||||
else if (ww->block_align == 0x104 * ww->channels) {
|
||||
/* Bayonetta 2 (Switch) */
|
||||
ww->codec = PTADPCM;
|
||||
}
|
||||
}
|
||||
|
||||
@ -911,7 +916,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||
/* catch wrong rips as truncated tracks' file_size should be much smaller than data_size,
|
||||
* but it's possible to pre-fetch small files too [Punch Out!! (Wii)] */
|
||||
if (ww->data_offset + ww->data_size - ww->file_size < 0x5000 && ww->file_size > 0x10000) {
|
||||
VGM_LOG("WWISE: wrong expected data_size\n");
|
||||
vgm_logi("WWISE: wrong expected size (re-rip?)\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -919,7 +924,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||
ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM) {
|
||||
ww->truncated = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */
|
||||
} else {
|
||||
VGM_LOG("WWISE: wrong size, maybe truncated\n");
|
||||
vgm_logi("WWISE: wrong expected size, maybe truncated (report)\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
|
||||
|
||||
sf_body = open_streamfile_by_filename(sf,filename);
|
||||
if (!sf_body) {
|
||||
VGM_LOG("XSH: can't find %s\n", filename);
|
||||
vgm_logi("XSH: external file '%s' not found (put together)\n", filename);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -116,7 +116,7 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
|
||||
snprintf(filename, sizeof(filename), "%s", "STREAMS.XSS");
|
||||
sf_body = open_streamfile_by_filename(sf,filename);
|
||||
if (!sf_body) {
|
||||
VGM_LOG("XSH: can't find %s\n", filename);
|
||||
vgm_logi("XSH: external file '%s' not found (put together)\n", filename);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
@ -75,3 +75,16 @@ void vgm_logi(const char* fmt, ...) {
|
||||
log_internal(NULL, LOG_LEVEL_INFO, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void vgm_asserti(int condition, const char* fmt, ...) {
|
||||
if (!condition)
|
||||
return;
|
||||
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
log_internal(NULL, LOG_LEVEL_INFO, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
@ -20,17 +20,21 @@ void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback);
|
||||
|
||||
#if defined(VGM_LOG_OUTPUT) || defined(VGM_DEBUG_OUTPUT)
|
||||
void vgm_logi(/*void* ctx,*/ const char* fmt, ...);
|
||||
void vgm_asserti(/*void* ctx,*/ int condition, const char* fmt, ...);
|
||||
//void vgm_logi_once(/*void* ctx, int* once_flag, */ const char* fmt, ...);
|
||||
#else
|
||||
#define vgm_logi(...) /* nothing */
|
||||
#define vgm_asserti(...) /* nothing */
|
||||
#endif
|
||||
|
||||
#ifdef VGM_DEBUG_OUTPUT
|
||||
void vgm_logd(/*void* ctx,*/ const char* fmt, ...);
|
||||
#define VGM_LOG(...) do { vgm_logd(__VA_ARGS__); } while (0)
|
||||
#define VGM_ASSERT(condition, ...) do { if (condition) {vgm_logd(__VA_ARGS__);} } while (0)
|
||||
#else
|
||||
#define vgm_logd(...) /* nothing */
|
||||
#define VGM_LOG(...) /* nothing */
|
||||
#define VGM_ASSERT(condition, ...) /* nothing */
|
||||
#endif
|
||||
|
||||
|
||||
@ -38,21 +42,11 @@ void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback);
|
||||
* Needs C99 variadic macros, uses do..while to force ";" as statement */
|
||||
#ifdef VGM_DEBUG_OUTPUT
|
||||
|
||||
/* equivalent to printf when condition is true */
|
||||
#define VGM_ASSERT(condition, ...) \
|
||||
do { if (condition) {printf(__VA_ARGS__);} } while (0)
|
||||
|
||||
#define VGM_ASSERT_ONCE(condition, ...) \
|
||||
do { static int written; if (!written) { if (condition) {printf(__VA_ARGS__); written = 1;} } } while (0)
|
||||
|
||||
/* equivalent to printf */
|
||||
//#define VGM_LOG(...) do { printf(__VA_ARGS__); } while (0)
|
||||
|
||||
#define VGM_LOG_ONCE(...) \
|
||||
do { static int written; if (!written) { printf(__VA_ARGS__); written = 1; } } while (0)
|
||||
|
||||
/* prints file/line/func */
|
||||
//#define VGM_LOGF() do { printf("%s:%i '%s'\n", __FILE__, __LINE__, __func__); } while (0)
|
||||
#define VGM_ASSERT_ONCE(condition, ...) \
|
||||
do { static int written; if (!written) { if (condition) {printf(__VA_ARGS__); written = 1;} } } while (0)
|
||||
|
||||
/* prints to a file */
|
||||
#define VGM_LOGT(txt, ...) \
|
||||
@ -71,12 +65,12 @@ void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback);
|
||||
|
||||
#else /* VGM_DEBUG_OUTPUT */
|
||||
|
||||
#define VGM_ASSERT(condition, ...) /* nothing */
|
||||
#define VGM_ASSERT_ONCE(condition, ...) /* nothing */
|
||||
//#define VGM_LOG(...) /* nothing */
|
||||
#define VGM_LOG_ONCE(...) /* nothing */
|
||||
//#define VGM_LOGF() /* nothing */
|
||||
|
||||
#define VGM_ASSERT_ONCE(condition, ...) /* nothing */
|
||||
|
||||
#define VGM_LOGT() /* nothing */
|
||||
|
||||
#define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */
|
||||
|
||||
#endif /*VGM_DEBUG_OUTPUT*/
|
||||
|
Loading…
Reference in New Issue
Block a user