Updated vgmstream with experimental BFWAV support
parent
3b5b53ca26
commit
cc0f04d8f9
|
@ -322,6 +322,7 @@
|
||||||
836F705718BDC2190095E648 /* util.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6F1B18BDC2190095E648 /* util.h */; };
|
836F705718BDC2190095E648 /* util.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6F1B18BDC2190095E648 /* util.h */; };
|
||||||
836F705818BDC2190095E648 /* vgmstream.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F1C18BDC2190095E648 /* vgmstream.c */; };
|
836F705818BDC2190095E648 /* vgmstream.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6F1C18BDC2190095E648 /* vgmstream.c */; };
|
||||||
836F705918BDC2190095E648 /* vgmstream.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6F1D18BDC2190095E648 /* vgmstream.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
836F705918BDC2190095E648 /* vgmstream.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6F1D18BDC2190095E648 /* vgmstream.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
83A5F75F198DF021009AF94C /* bfwav.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A5F75E198DF021009AF94C /* bfwav.c */; };
|
||||||
83F5F8831908D0A400C8E65F /* fsb5.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F5F8821908D0A400C8E65F /* fsb5.c */; };
|
83F5F8831908D0A400C8E65F /* fsb5.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F5F8821908D0A400C8E65F /* fsb5.c */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
@ -686,6 +687,7 @@
|
||||||
836F6F1B18BDC2190095E648 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; };
|
836F6F1B18BDC2190095E648 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; };
|
||||||
836F6F1C18BDC2190095E648 /* vgmstream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vgmstream.c; sourceTree = "<group>"; };
|
836F6F1C18BDC2190095E648 /* vgmstream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vgmstream.c; sourceTree = "<group>"; };
|
||||||
836F6F1D18BDC2190095E648 /* vgmstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vgmstream.h; sourceTree = "<group>"; };
|
836F6F1D18BDC2190095E648 /* vgmstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vgmstream.h; sourceTree = "<group>"; };
|
||||||
|
83A5F75E198DF021009AF94C /* bfwav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bfwav.c; sourceTree = "<group>"; };
|
||||||
83F5F8821908D0A400C8E65F /* fsb5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb5.c; sourceTree = "<group>"; };
|
83F5F8821908D0A400C8E65F /* fsb5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb5.c; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
@ -869,6 +871,7 @@
|
||||||
836F6E2718BDC2180095E648 /* meta */ = {
|
836F6E2718BDC2180095E648 /* meta */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
83A5F75E198DF021009AF94C /* bfwav.c */,
|
||||||
83F5F8821908D0A400C8E65F /* fsb5.c */,
|
83F5F8821908D0A400C8E65F /* fsb5.c */,
|
||||||
836F6E2918BDC2180095E648 /* 2dx9.c */,
|
836F6E2918BDC2180095E648 /* 2dx9.c */,
|
||||||
836F6E2A18BDC2180095E648 /* aax.c */,
|
836F6E2A18BDC2180095E648 /* aax.c */,
|
||||||
|
@ -1243,6 +1246,7 @@
|
||||||
836F700C18BDC2190095E648 /* ps2_wb.c in Sources */,
|
836F700C18BDC2190095E648 /* ps2_wb.c in Sources */,
|
||||||
836F6F7D18BDC2190095E648 /* dc_str.c in Sources */,
|
836F6F7D18BDC2190095E648 /* dc_str.c in Sources */,
|
||||||
836F701718BDC2190095E648 /* ps3_vawx.c in Sources */,
|
836F701718BDC2190095E648 /* ps3_vawx.c in Sources */,
|
||||||
|
83A5F75F198DF021009AF94C /* bfwav.c in Sources */,
|
||||||
836F702018BDC2190095E648 /* rkv.c in Sources */,
|
836F702018BDC2190095E648 /* rkv.c in Sources */,
|
||||||
836F703218BDC2190095E648 /* str_asr.c in Sources */,
|
836F703218BDC2190095E648 /* str_asr.c in Sources */,
|
||||||
836F6FB218BDC2190095E648 /* ngc_gcub.c in Sources */,
|
836F6FB218BDC2190095E648 /* ngc_gcub.c in Sources */,
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
char filename[PATH_LIMIT];
|
||||||
|
|
||||||
|
coding_t coding_type;
|
||||||
|
|
||||||
|
off_t head_offset;
|
||||||
|
/*off_t seek_offset;*/
|
||||||
|
int codec_number;
|
||||||
|
int channel_count;
|
||||||
|
int loop_flag;
|
||||||
|
|
||||||
|
off_t start_offset;
|
||||||
|
|
||||||
|
int big_endian = 1;
|
||||||
|
int ima = 0;
|
||||||
|
int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL;
|
||||||
|
int16_t(*read_16bit)(off_t, STREAMFILE*) = NULL;
|
||||||
|
read_16bit = read_16bitBE;
|
||||||
|
read_32bit = read_32bitBE;
|
||||||
|
|
||||||
|
/* check extension, case insensitive */
|
||||||
|
streamFile->get_name(streamFile, filename, sizeof(filename));
|
||||||
|
if (strcasecmp("bfwav", filename_extension(filename)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* check header */
|
||||||
|
if ((uint32_t)read_32bitBE(0, streamFile) != 0x46574156) /* "FWAV" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if ((uint32_t)read_32bitBE(4, streamFile) != 0xFEFF0040) /* "FWAV" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* get head offset, check */
|
||||||
|
if (big_endian)
|
||||||
|
head_offset = read_32bit(0x18, streamFile);
|
||||||
|
|
||||||
|
|
||||||
|
if ((uint32_t)read_32bitBE(head_offset, streamFile) != 0x494E464F) /* "INFO" (FWAV)*/
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
|
/* check type details */
|
||||||
|
codec_number = read_8bit(head_offset + 0x8, streamFile);
|
||||||
|
loop_flag = read_8bit(head_offset + 0x9, streamFile);
|
||||||
|
channel_count = read_8bit(head_offset + 0x1F, streamFile);
|
||||||
|
|
||||||
|
switch (codec_number) {
|
||||||
|
case 0:
|
||||||
|
coding_type = coding_PCM8;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (big_endian)
|
||||||
|
coding_type = coding_PCM16BE;
|
||||||
|
else
|
||||||
|
coding_type = coding_PCM16LE;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
coding_type = coding_NGC_DSP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel_count < 1) goto fail;
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
|
||||||
|
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
/* fill in the vital statistics */
|
||||||
|
vgmstream->num_samples = read_32bit(head_offset + 0x14, streamFile);
|
||||||
|
vgmstream->sample_rate = (uint16_t)read_16bit(head_offset + 0xE, streamFile);
|
||||||
|
/* channels and loop flag are set by allocate_vgmstream */
|
||||||
|
|
||||||
|
vgmstream->loop_start_sample = read_32bit(head_offset + 0x10, streamFile);
|
||||||
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
|
|
||||||
|
vgmstream->coding_type = coding_type;
|
||||||
|
if (channel_count == 1)
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ima)
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
else
|
||||||
|
vgmstream->layout_type = layout_interleave_shortblock;
|
||||||
|
}
|
||||||
|
if (big_endian)
|
||||||
|
vgmstream->meta_type = meta_FWAV;
|
||||||
|
|
||||||
|
if (big_endian)
|
||||||
|
{
|
||||||
|
// vgmstream->interleave_block_size = read_32bit(head_offset + 0x38, streamFile);
|
||||||
|
// vgmstream->interleave_smallblock_size = read_32bit(head_offset + 0x48, streamFile);
|
||||||
|
|
||||||
|
vgmstream->interleave_block_size = 0x200;
|
||||||
|
vgmstream->interleave_smallblock_size = 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (big_endian)
|
||||||
|
start_offset = read_32bitBE(0x24, streamFile) + 0x20;
|
||||||
|
|
||||||
|
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||||
|
off_t coef_offset;
|
||||||
|
/*off_t coef_offset1;
|
||||||
|
off_t coef_offset2;*/
|
||||||
|
int coef_spacing;
|
||||||
|
int i, j;
|
||||||
|
off_t coeffheader;
|
||||||
|
int foundcoef;
|
||||||
|
|
||||||
|
coef_spacing = 0x2E;
|
||||||
|
|
||||||
|
coeffheader = head_offset + 0x28;
|
||||||
|
foundcoef = 0;
|
||||||
|
while (!(foundcoef))
|
||||||
|
{
|
||||||
|
if ((uint32_t)read_32bit(coeffheader, streamFile) == 0x1F000000)
|
||||||
|
{
|
||||||
|
coef_offset = read_32bit(coeffheader + 0xC, streamFile) + coeffheader;
|
||||||
|
foundcoef = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
coeffheader++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (j = 0; j<vgmstream->channels; j++) {
|
||||||
|
for (i = 0; i<16; i++) {
|
||||||
|
vgmstream->ch[j].adpcm_coef[i] = read_16bit(coef_offset + j*coef_spacing + i * 2, streamFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* open the file for reading by each channel */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i<channel_count; i++) {
|
||||||
|
if (vgmstream->layout_type == layout_interleave_shortblock)
|
||||||
|
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
||||||
|
vgmstream->interleave_block_size);
|
||||||
|
else if (vgmstream->layout_type == layout_interleave)
|
||||||
|
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
||||||
|
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||||
|
else
|
||||||
|
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
||||||
|
0x1000);
|
||||||
|
|
||||||
|
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||||
|
|
||||||
|
vgmstream->ch[i].channel_start_offset =
|
||||||
|
vgmstream->ch[i].offset =
|
||||||
|
start_offset + i*vgmstream->interleave_block_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
/* clean up anything we may have opened */
|
||||||
|
fail:
|
||||||
|
if (vgmstream) close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include "vgmstream.h"
|
||||||
#include "streamfile.h"
|
#include "streamfile.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ typedef struct {
|
||||||
size_t validsize;
|
size_t validsize;
|
||||||
uint8_t * buffer;
|
uint8_t * buffer;
|
||||||
size_t buffersize;
|
size_t buffersize;
|
||||||
char name[260];
|
char name[PATH_LIMIT];
|
||||||
#ifdef PROFILE_STREAMFILE
|
#ifdef PROFILE_STREAMFILE
|
||||||
size_t bytes_read;
|
size_t bytes_read;
|
||||||
int error_count;
|
int error_count;
|
||||||
|
|
|
@ -16,23 +16,14 @@ enum { PATH_LIMIT = 32768 };
|
||||||
#define VGM_USE_MPEG
|
#define VGM_USE_MPEG
|
||||||
/* disabled by default, defined for builds that support it */
|
/* disabled by default, defined for builds that support it */
|
||||||
//#define VGM_USE_G7221
|
//#define VGM_USE_G7221
|
||||||
//#define VGM_USE_MP4V2
|
|
||||||
//#define VGM_USE_FDKAAC
|
|
||||||
|
|
||||||
#include "streamfile.h"
|
#include "streamfile.h"
|
||||||
#ifdef BUILD_VGMSTREAM
|
|
||||||
#include "coding/g72x_state.h"
|
#include "coding/g72x_state.h"
|
||||||
#else
|
|
||||||
#include "g72x_state.h"
|
|
||||||
#endif
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
#ifdef __APPLE__
|
|
||||||
#define __MACOSX__
|
|
||||||
#endif
|
|
||||||
#include <vorbis/vorbisfile.h>
|
#include <vorbis/vorbisfile.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef VGM_USE_MPEG
|
#ifdef VGM_USE_MPEG
|
||||||
#include <mpg123/mpg123.h>
|
#include <mpg123.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef VGM_USE_G7221
|
#ifdef VGM_USE_G7221
|
||||||
#include "g7221.h"
|
#include "g7221.h"
|
||||||
|
@ -51,13 +42,8 @@ enum { PATH_LIMIT = 32768 };
|
||||||
#include <maiatrac3plus.h>
|
#include <maiatrac3plus.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef BUILD_VGMSTREAM
|
|
||||||
#include "coding/acm_decoder.h"
|
#include "coding/acm_decoder.h"
|
||||||
#include "coding/nwa_decoder.h"
|
#include "coding/nwa_decoder.h"
|
||||||
#else
|
|
||||||
#include "acm_decoder.h"
|
|
||||||
#include "nwa_decoder.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* The encoding type specifies the format the sound data itself takes */
|
/* The encoding type specifies the format the sound data itself takes */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -254,7 +240,8 @@ typedef enum {
|
||||||
meta_RWSD, /* single-stream RWSD */
|
meta_RWSD, /* single-stream RWSD */
|
||||||
meta_RWAR, /* single-stream RWAR */
|
meta_RWAR, /* single-stream RWAR */
|
||||||
meta_RWAV, /* contents of RWAR */
|
meta_RWAV, /* contents of RWAR */
|
||||||
meta_CWAV, /* */
|
meta_CWAV, /* contents of CWAR */
|
||||||
|
meta_FWAV, /* contents of FWAR */
|
||||||
meta_RSTM_SPM, /* RSTM with 44->22khz hack */
|
meta_RSTM_SPM, /* RSTM with 44->22khz hack */
|
||||||
meta_THP,
|
meta_THP,
|
||||||
meta_RSTM_shrunken, /* Atlus' mutant shortened RSTM */
|
meta_RSTM_shrunken, /* Atlus' mutant shortened RSTM */
|
||||||
|
|
|
@ -211,7 +211,7 @@ err1:
|
||||||
|
|
||||||
+ (NSArray *)fileTypes
|
+ (NSArray *)fileTypes
|
||||||
{
|
{
|
||||||
return [NSArray arrayWithObjects:@"2dx9", @"aaap", @"aax", @"acm", @"adp", @"adpcm", @"ads", @"adx", @"afc", @"agsc", @"ahx",@"aifc", @"aiff", @"aix", @"amts", @"as4", @"asd", @"asf", @"asr", @"ass", @"ast", @"aud", @"aus", @"baf", @"baka", @"bar", @"bcstm", @"bcwav", @"bg00", @"bgw", @"bh2pcm", @"bmdx", @"bns", @"bnsf", @"bo2", @"brstm", @"caf", @"capdsp", @"ccc", @"cfn", @"cnk", @"dcs", @"dcsw", @"ddsp", @"de2", @"dmsg", @"dsp", @"dvi", @"dxh", @"eam", @"emff", @"enth", @"fag", @"filp", @"fsb", @"gca", @"gcm", @"gcsw", @"gcw", @"genh", @"gms", @"gsp", @"hgc1", @"his", @"hps", @"hwas", @"idsp", @"idvi", @"ikm", @"ild", @"int", @"isd", @"ish", @"ivaud", @"ivb", @"joe", @"kces", @"kcey", @"khv", @"kraw", @"leg", @"logg", @"lps", @"lsf", @"lwav", @"matx", @"mcg", @"mi4", @"mib", @"mic", @"mihb", @"mpdsp", @"msa", @"mss", @"msvp", @"mus", @"musc", @"musx", @"mwv", @"myspd", @"ndp", @"npsf", @"nwa", @"omu", @"otm", @"p3d", @"pcm", @"pdt", @"pnb", @"pos", @"psh", @"psw", @"raw", @"rkv", @"rnd", @"rrds", @"rsd", @"rsf", @"rstm", @"rwar", @"rwav", @"rws", @"rwsd", @"rwx", @"rxw", @"s14", @"sab", @"sad", @"sap", @"sc", @"scd", @"sd9", @"sdt", @"seg", @"sfl", @"sfs", @"sl3", @"sli", @"smp", @"smpl", @"snd", @"sng", @"sns", @"spd", @"sps", @"spsd", @"spt", @"spw", @"ss2", @"ss7", @"ssm", @"sss", @"ster", @"sth", @"stm", @"stma", @"str", @"strm", @"sts", @"stx", @"svag", @"svs", @"swav", @"swd", @"tec", @"thp", @"tk5", @"tydsp", @"um3", @"vag", @"vas", @"vgs", @"vig", @"vjdsp", @"voi", @"vpk", @"vs", @"vsf", @"waa", @"wac", @"wad", @"wam", @"was", @"wavm", @"wb", @"wii", @"wp2", @"wsd", @"wsi", @"wvs", @"xa", @"xa2", @"xa30", @"xmu", @"xss", @"xvas", @"xwav", @"xwb", @"ydsp", @"ymf", @"zsd", @"zwdsp", nil];
|
return [NSArray arrayWithObjects:@"2dx9", @"aaap", @"aax", @"acm", @"adp", @"adpcm", @"ads", @"adx", @"afc", @"agsc", @"ahx",@"aifc", @"aiff", @"aix", @"amts", @"as4", @"asd", @"asf", @"asr", @"ass", @"ast", @"aud", @"aus", @"baf", @"baka", @"bar", @"bcstm", @"bcwav", @"bfwav", @"bg00", @"bgw", @"bh2pcm", @"bmdx", @"bns", @"bnsf", @"bo2", @"brstm", @"caf", @"capdsp", @"ccc", @"cfn", @"cnk", @"dcs", @"dcsw", @"ddsp", @"de2", @"dmsg", @"dsp", @"dvi", @"dxh", @"eam", @"emff", @"enth", @"fag", @"filp", @"fsb", @"gca", @"gcm", @"gcsw", @"gcw", @"genh", @"gms", @"gsp", @"hgc1", @"his", @"hps", @"hwas", @"idsp", @"idvi", @"ikm", @"ild", @"int", @"isd", @"ish", @"ivaud", @"ivb", @"joe", @"kces", @"kcey", @"khv", @"kraw", @"leg", @"logg", @"lps", @"lsf", @"lwav", @"matx", @"mcg", @"mi4", @"mib", @"mic", @"mihb", @"mpdsp", @"msa", @"mss", @"msvp", @"mus", @"musc", @"musx", @"mwv", @"myspd", @"ndp", @"npsf", @"nwa", @"omu", @"otm", @"p3d", @"pcm", @"pdt", @"pnb", @"pos", @"psh", @"psw", @"raw", @"rkv", @"rnd", @"rrds", @"rsd", @"rsf", @"rstm", @"rwar", @"rwav", @"rws", @"rwsd", @"rwx", @"rxw", @"s14", @"sab", @"sad", @"sap", @"sc", @"scd", @"sd9", @"sdt", @"seg", @"sfl", @"sfs", @"sl3", @"sli", @"smp", @"smpl", @"snd", @"sng", @"sns", @"spd", @"sps", @"spsd", @"spt", @"spw", @"ss2", @"ss7", @"ssm", @"sss", @"ster", @"sth", @"stm", @"stma", @"str", @"strm", @"sts", @"stx", @"svag", @"svs", @"swav", @"swd", @"tec", @"thp", @"tk5", @"tydsp", @"um3", @"vag", @"vas", @"vgs", @"vig", @"vjdsp", @"voi", @"vpk", @"vs", @"vsf", @"waa", @"wac", @"wad", @"wam", @"was", @"wavm", @"wb", @"wii", @"wp2", @"wsd", @"wsi", @"wvs", @"xa", @"xa2", @"xa30", @"xmu", @"xss", @"xvas", @"xwav", @"xwb", @"ydsp", @"ymf", @"zsd", @"zwdsp", nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)mimeTypes
|
+ (NSArray *)mimeTypes
|
||||||
|
|
Loading…
Reference in New Issue