9 #include "metadata_common.h"
10 #include "metadata_parsers.h"
11 #include "rbunicode.h"
13 /* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
15 typedef unsigned char byte
;
17 enum { header_size
= 0x40 };
18 enum { max_field
= 64 };
28 byte track_duration
[4];
30 byte loop_duration
[4];
32 byte noise_feedback
[2];
41 static byte
const* skip_gd3_str( byte
const* in
, byte
const* end
)
43 while ( end
- in
>= 2 )
46 if ( !(in
[-2] | in
[-1]) )
52 static byte
const* get_gd3_str( byte
const* in
, byte
const* end
, char* field
)
54 byte
const* mid
= skip_gd3_str( in
, end
);
55 int len
= (mid
- in
) / 2 - 1;
56 if ( field
&& len
> 0 )
58 len
= len
< (int) max_field
? len
: (int) max_field
;
62 utf16LEdecode( in
, field
, len
);
64 /* Copy string back to id3v2buf */
65 strcpy( (char*) in
, field
);
70 static byte
const* get_gd3_pair( byte
const* in
, byte
const* end
, char* field
)
72 return skip_gd3_str( get_gd3_str( in
, end
, field
), end
);
75 static void parse_gd3( byte
const* in
, byte
const* end
, struct mp3entry
* id3
)
78 id3
->title
= (char *) in
;
79 in
= get_gd3_pair( in
, end
, p
); /* Song */
81 id3
->album
= (char *) in
;
82 in
= get_gd3_pair( in
, end
, p
); /* Game */
84 in
= get_gd3_pair( in
, end
, NULL
); /* System */
86 id3
->artist
= (char *) in
;
87 in
= get_gd3_pair( in
, end
, p
); /* Author */
90 in
= get_gd3_str ( in
, end
, NULL
); /* Copyright */
91 in
= get_gd3_pair( in
, end
, NULL
); /* Dumper */
93 id3
->comment
= (char *) in
;
94 in
= get_gd3_str ( in
, end
, p
); /* Comment */
98 int const gd3_header_size
= 12;
100 static long check_gd3_header( byte
* h
, long remain
)
102 if ( remain
< gd3_header_size
) return 0;
103 if ( memcmp( h
, "Gd3 ", 4 ) ) return 0;
104 if ( get_long_le( h
+ 4 ) >= 0x200 ) return 0;
106 long gd3_size
= get_long_le( h
+ 8 );
107 if ( gd3_size
> remain
- gd3_header_size
)
108 gd3_size
= remain
- gd3_header_size
;
113 static void get_vgm_length( struct header_t
* h
, struct mp3entry
* id3
)
115 long length
= get_long_le( h
->track_duration
) * 10 / 441;
118 long loop_length
= 0, intro_length
= 0;
119 long loop
= get_long_le( h
->loop_duration
);
120 if ( loop
> 0 && get_long_le( h
->loop_offset
) )
122 loop_length
= loop
* 10 / 441;
123 intro_length
= length
- loop_length
;
127 intro_length
= length
; /* make it clear that track is no longer than length */
131 id3
->length
= intro_length
+ 2 * loop_length
; /* intro + 2 loops */
135 id3
->length
= 150 * 1000; /* 2.5 minutes */
138 bool get_vgm_metadata(int fd
, struct mp3entry
* id3
)
140 /* Use the id3v2 part of the id3 structure as a temporary buffer */
141 unsigned char* buf
= (unsigned char *)id3
->id3v2buf
;
144 memset(buf
, 0, ID3V2_BUF_SIZE
);
145 if ((lseek(fd
, 0, SEEK_SET
) < 0)
146 || ((read_bytes
= read(fd
, buf
, header_size
)) < header_size
))
152 id3
->filesize
= filesize(fd
);
155 id3
->frequency
= 44100;
157 /* If file is gzipped, will get metadata later */
158 if (memcmp(buf
, "Vgm ", 4))
160 /* We must set a default song length here because
161 the codec can't do it anymore */
162 id3
->length
= 150 * 1000; /* 2.5 minutes */
166 /* Get song length from header */
167 struct header_t
* header
= (struct header_t
*) buf
;
168 get_vgm_length( header
, id3
);
170 long gd3_offset
= get_long_le( header
->gd3_offset
) - 0x2C;
172 /* No gd3 tag found */
173 if ( gd3_offset
< 0 )
176 /* Seek to gd3 offset and read as
177 many bytes posible */
178 gd3_offset
= id3
->filesize
- (header_size
+ gd3_offset
);
179 if ((lseek(fd
, -gd3_offset
, SEEK_END
) < 0)
180 || ((read_bytes
= read(fd
, buf
, ID3V2_BUF_SIZE
)) <= 0))
184 long gd3_size
= check_gd3_header( gd3
, read_bytes
);
186 /* GD3 tag is zero */
190 /* Finally, parse gd3 tag */
192 parse_gd3( gd3
+ gd3_header_size
, gd3
+ read_bytes
, id3
);