mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Add plugin helper functions for tagfile handling
This commit is contained in:
parent
0245832256
commit
2eba5abc26
@ -147,10 +147,14 @@
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\plugins.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\streamtypes.h"
|
||||
>
|
||||
@ -172,6 +176,10 @@
|
||||
<File
|
||||
RelativePath=".\formats.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\plugins.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\streamfile.c"
|
||||
|
@ -89,6 +89,7 @@
|
||||
<ClInclude Include="coding\vorbis_custom_data_fsb.h" />
|
||||
<ClInclude Include="coding\vorbis_custom_data_wwise.h" />
|
||||
<ClInclude Include="coding\vorbis_custom_decoder.h" />
|
||||
<ClInclude Include="plugins.h" />
|
||||
<ClInclude Include="streamfile.h" />
|
||||
<ClInclude Include="streamtypes.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
@ -189,6 +190,7 @@
|
||||
<ClCompile Include="meta\x360_cxs.c" />
|
||||
<ClCompile Include="meta\x360_tra.c" />
|
||||
<ClCompile Include="formats.c" />
|
||||
<ClCompile Include="plugins.c" />
|
||||
<ClCompile Include="meta\ps2_va3.c" />
|
||||
<ClCompile Include="streamfile.c" />
|
||||
<ClCompile Include="util.c" />
|
||||
|
@ -47,6 +47,9 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="plugins.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="streamfile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -160,6 +163,9 @@
|
||||
<ClCompile Include="formats.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="plugins.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="streamfile.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
129
src/plugins.c
Normal file
129
src/plugins.c
Normal file
@ -0,0 +1,129 @@
|
||||
#include "vgmstream.h"
|
||||
#include "plugins.h"
|
||||
|
||||
|
||||
static void tags_clean(VGMSTREAM_TAGS* tag) {
|
||||
int i;
|
||||
int val_len = strlen(tag->val);
|
||||
|
||||
/* remove trailing spaces */
|
||||
for (i = val_len - 1; i > 0; i--) {
|
||||
if (tag->val[i] != ' ')
|
||||
break;
|
||||
tag->val[i] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Tags are divided in two: "global" @TAGS and "file" %TAGS for target filename. To extract both
|
||||
* we find the filename's tag "section": (other_filename) ..(#tag section).. (target_filename).
|
||||
* When a new "other_filename" is found that offset is marked as section_start, and when target_filename
|
||||
* is found it's marked as section_end. Then we can begin extracting tags within that section, until
|
||||
* all tags are exhausted. Global tags are extracted while searching, so they always go first, and
|
||||
* also meaning any tags after the section is found are ignored. */
|
||||
int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tag, STREAMFILE* tagfile) {
|
||||
off_t file_size = get_streamfile_size(tagfile);
|
||||
char currentname[TAG_LINE_MAX] = {0};
|
||||
char line[TAG_LINE_MAX] = {0};
|
||||
int ok, bytes_read, line_done;
|
||||
|
||||
|
||||
/* prepare file start and skip BOM if needed */
|
||||
if (tag->offset == 0) {
|
||||
if ((uint16_t)read_16bitLE(0x00, tagfile) == 0xFFFE ||
|
||||
(uint16_t)read_16bitLE(0x00, tagfile) == 0xFEFF) {
|
||||
tag->offset = 0x02;
|
||||
if (tag->section_start == 0)
|
||||
tag->section_start = 0x02;
|
||||
}
|
||||
else if (((uint32_t)read_32bitBE(0x00, tagfile) & 0xFFFFFF00) == 0xEFBBBF00) {
|
||||
tag->offset = 0x03;
|
||||
if (tag->section_start == 0)
|
||||
tag->section_start = 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
/* read lines */
|
||||
while (tag->offset < file_size) {
|
||||
/* no more tags to extract */
|
||||
if (tag->section_found && tag->offset >= tag->section_end) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bytes_read = get_streamfile_text_line(TAG_LINE_MAX,line, tag->offset,tagfile, &line_done);
|
||||
if (!line_done) goto fail;
|
||||
|
||||
tag->offset += bytes_read;
|
||||
|
||||
|
||||
if (tag->section_found) {
|
||||
/* find possible file tag */
|
||||
ok = sscanf(line, "# %%%[^ \t] %[^\r\n] ", tag->key,tag->val);
|
||||
if (ok == 2) {
|
||||
tags_clean(tag);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* find possible global tag */
|
||||
if (line[0] == '#') {
|
||||
ok = sscanf(line, "# @%[^ \t] %[^\r\n]", tag->key,tag->val);
|
||||
if (ok == 2) {
|
||||
tags_clean(tag);
|
||||
return 1;
|
||||
}
|
||||
|
||||
continue; /* next line */
|
||||
}
|
||||
|
||||
/* find possible filename and section start/end */
|
||||
ok = sscanf(line, " %[^\r\n] ", currentname);
|
||||
if (ok == 1) {
|
||||
if (strcasecmp(tag->targetname,currentname) == 0) { /* looks ok even for UTF-8 */
|
||||
/* section ok, start would be set before this (or be 0) */
|
||||
tag->section_end = tag->offset;
|
||||
tag->section_found = 1;
|
||||
tag->offset = tag->section_start;
|
||||
}
|
||||
else {
|
||||
/* mark new possible section */
|
||||
tag->section_start = tag->offset;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* empty/bad line, probably */
|
||||
}
|
||||
}
|
||||
|
||||
/* may reach here if read up to file_size but no section was found */
|
||||
|
||||
fail:
|
||||
tag->key[0] = '\0';
|
||||
tag->val[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void vgmstream_tags_reset(VGMSTREAM_TAGS* tag, const char* target_filename) {
|
||||
const char *path;
|
||||
|
||||
memset(tag, 0, sizeof(VGMSTREAM_TAGS));
|
||||
|
||||
|
||||
/* get base name */
|
||||
|
||||
//todo Windows CMD accepts both \\ and /, better way to handle this?
|
||||
path = strrchr(target_filename,'\\');
|
||||
if (!path)
|
||||
path = strrchr(target_filename,'/');
|
||||
if (path != NULL)
|
||||
path = path+1;
|
||||
|
||||
//todo validate sizes and copy sensible max
|
||||
if (path) {
|
||||
strcpy(tag->targetname, path);
|
||||
} else {
|
||||
strcpy(tag->targetname, target_filename);
|
||||
}
|
||||
}
|
36
src/plugins.h
Normal file
36
src/plugins.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* plugins.h - helper for plugins
|
||||
*/
|
||||
#ifndef _PLUGINS_H_
|
||||
#define _PLUGINS_H_
|
||||
|
||||
#include "streamfile.h"
|
||||
#define TAG_LINE_MAX 2048
|
||||
|
||||
//todo improve API and make opaque
|
||||
//typedef struct VGMSTREAM_TAGS VGMSTREAM_TAGS;
|
||||
typedef struct {
|
||||
/* extracted output */
|
||||
char key[TAG_LINE_MAX];
|
||||
char val[TAG_LINE_MAX];
|
||||
|
||||
/* file to find tags for */
|
||||
char targetname[TAG_LINE_MAX];
|
||||
|
||||
/* tag section for filename (see comments below) */
|
||||
int section_found;
|
||||
off_t section_start;
|
||||
off_t section_end;
|
||||
off_t offset;
|
||||
} VGMSTREAM_TAGS;
|
||||
|
||||
|
||||
|
||||
/* Extracts next valid tag in tagfile to *tag. Returns 0 if no more tags are found (meant to be
|
||||
* called repeatedly until 0). Key are lowercase and values can be treated as UTF-8. */
|
||||
int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tag, STREAMFILE* tagfile);
|
||||
|
||||
/* resets tagfile to restart reading from the beginning for a new filename */
|
||||
void vgmstream_tags_reset(VGMSTREAM_TAGS* tag, const char* target_filename);
|
||||
|
||||
#endif /* _PLUGINS_H_ */
|
Loading…
x
Reference in New Issue
Block a user