btparser/cparser/tests/exp_lex/MP3Template.bt

499 lines
12 KiB
Plaintext

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50: local uint32 bitrate , frame_size , sampling_freq , frames_count = 0 ;
51: local quad frame_header_offset , seek_pos , sum_bitrate = 0 ;
52: local short data ;
53: local byte was_bad_sync , id3v1_tag_found = 0 ;
54: local ubyte buf [ 3 ] ;
55:
56:
57: enum < ubyte > ID3_GENRES
58: {
59: Blues , Classic_Rock , Country , Dance , Disco , Funk , Grunge , Hip_Hop ,
60: Jazz , Metal , New_Age , Oldies , Other , Pop , R_and_B , Rap ,
61: Reggae , Rock , Techno , Industrial , Alternative , Ska , Death_Metal , Pranks ,
62: Soundtrack , Euro_Techno , Ambient , Trip_Hop , Vocal , Jazz_Funk , Fusion , Trance ,
63: Classical , Instrumental , Acid , House , Game , Sound_Clip , Gospel , Noise ,
64: AlternRock , Bass , Soul , Punk , Space , Meditative , Instrumental_Pop , Instrumental_Rock ,
65: Ethnic , Gothic , Darkwave , Techno_Industrial , Electronic , Pop_Folk , Eurodance , Dream ,
66: Southern_Rock , Comedy , Cult , Gangsta , Top_40 , Christian_Rap , Pop_Funk , Jungle ,
67: Native_American , Cabaret , New_Wave , Psychadelic , Rave , Showtunes , Trailer , Lo_Fi ,
68: Tribal , Acid_Punk , Acid_Jazz , Polka , Retro , Musical , Rock_n_Roll , Hard_Rock ,
69: Folk , Folk_Rock , National_Folk , Swing , Fast_Fusion , Bebob , Latin , Revival ,
70: Celtic , Bluegrass , Avantgarde , Gothic_Rock ,
71: Progressive_Rock , Psychedelic_Rock , Symphonic_Rock , Slow_Rock ,
72: Big_Band , Chorus , Easy_Listening , Acoustic , Humour , Speech , Chanson , Opera ,
73: Chamber_Music , Sonata , Symphony , Booty_Bass , Primus , Porn_Groove , Satire , Slow_Jam ,
74: Club , Tango , Samba , Folklore , Ballad , Power_Ballad , Rhythmic_Soul , Freestyle ,
75: Duet , Punk_Rock , Drum_Solo , A_capella , Euro_House , Dance_Hall , Goa , Drum_and_Bass ,
76: Club_House , Hardcore , Terror , Indie , BritPop , Negerpunk , Polsk_Punk , Beat ,
77: Christian , Heavy_Metal , Black_Metal , Crossover ,
78: Contemporary , Christian_Rock , Merengue , Salsa , Thrash_Metal , Anime , JPop , Synthpop
79: } ;
80:
81:
82: struct ID3v1_TAG
83: {
84: DisplayFormatDecimal ( ) ;
85:
86: SetBackColor ( 0x33BC55 ) ;
87: char id [ 3 ] ;
88:
89: SetBackColor ( 0x48E048 ) ;
90: char title [ 30 ] ;
91:
92: SetBackColor ( 0x5DE45D ) ;
93: char artist [ 30 ] ;
94:
95: SetBackColor ( 0x72E872 ) ;
96: char album [ 30 ] ;
97:
98: SetBackColor ( 0x87EC87 ) ;
99: char year [ 4 ] ;
100:
101: if ( ReadByte ( FTell ( ) + 28 ) == 0 && ReadByte ( FTell ( ) + 29 ) != 0 )
102: {
103:
104:
105: SetBackColor ( 0x9CF09C ) ;
106: char comment [ 28 ] ;
107:
108: SetBackColor ( 0xB1F4B1 ) ;
109: byte zero ;
110:
111: SetBackColor ( 0xC6F8C6 ) ;
112: ubyte track ;
113: }
114: else
115: {
116:
117:
118: SetBackColor ( 0x9CF09C ) ;
119: char comment [ 30 ] ;
120: }
121:
122: SetBackColor ( 0xDBFCDB ) ;
123: ID3_GENRES genre ;
124: } ;
125:
126:
127: struct ID3v2_HEADER
128: {
129: SetBackColor ( 0x91C4FF ) ;
130:
131: char head [ 3 ] ;
132:
133: DisplayFormatDecimal ( ) ;
134:
135: ubyte ver_major ;
136: ubyte ver_revision ;
137:
138: struct FLAGS {
139: ubyte UNSYNCHRONISATION_USED : 1 ;
140: ubyte EXTENDED_HEADER_PRESENT : 1 ;
141: ubyte EXPERIMENTAL_TAG : 1 ;
142: ubyte : 5 ;
143: } flags ;
144:
145: DisplayFormatHex ( ) ;
146:
147: ubyte size [ 4 ] ;
148:
149:
150:
151: } ;
152:
153:
154: struct ID3v2_EXTENDED_HEADER
155: {
156: SetBackColor ( 0xA1D4FF ) ;
157:
158: DisplayFormatDecimal ( ) ;
159:
160: uint32 size ;
161:
162: uint16 FLAG_CRC_PRESENT : 1 ;
163: uint16 : 15 ;
164:
165: uint32 padding_sz ;
166:
167: if ( FLAG_CRC_PRESENT )
168: {
169: DisplayFormatHex ( ) ;
170: uint32 crc ;
171: }
172: } ;
173:
174:
175: struct ID3v2_FRAME
176: {
177: char id [ 4 ] ;
178:
179: DisplayFormatDecimal ( ) ;
180:
181: uint32 size ;
182:
183: struct FRAME_FLAGS {
184: uint16 TAG_ALTER_PRESERV : 1 ;
185: uint16 FILE_ALTER_PRESERV : 1 ;
186: uint16 READ_ONLY_FRAME : 1 ;
187: uint16 : 5 ;
188: uint16 COMPRESSED_FRAME : 1 ;
189: uint16 ENCRYPTED_FRAME : 1 ;
190: uint16 GROUP_MEMBER_FRAME : 1 ;
191: uint16 : 5 ;
192: } flags ;
193:
194: if ( id [ 0 ] == 'T' )
195: {
196:
197: if ( ReadByte ( FTell ( ) ) == 0 && size > 1 )
198: {
199: byte id_asciiz_str ;
200: char frame_data [ size - 1 ] ;
201: }
202: else
203: char frame_data [ size ] ;
204: }
205: else
206: {
207: DisplayFormatHex ( ) ;
208: ubyte frame_data [ size ] ;
209: }
210: } ;
211:
212:
213: struct ID3v2_TAG
214: {
215: ID3v2_HEADER hdr ;
216:
217:
218: local uint32 tag_sz = hdr . size [ 0 ] ;
219: tag_sz <<= 7 ;
220: tag_sz |= hdr . size [ 1 ] ;
221: tag_sz <<= 7 ;
222: tag_sz |= hdr . size [ 2 ] ;
223: tag_sz <<= 7 ;
224: tag_sz |= hdr . size [ 3 ] ;
225:
226:
227:
228:
229:
230:
231: if ( hdr . ver_major == 0xFF || hdr . ver_revision == 0xFF ||
232: hdr . size [ 0 ] >= 0x80 || hdr . size [ 1 ] >= 0x80 ||
233: hdr . size [ 2 ] >= 0x80 || hdr . size [ 3 ] >= 0x80 )
234: {
235: Printf ( "MP3: warning: invalid ID3v2 tag header\n" ) ;
236: }
237: else
238: {
239: if ( hdr . ver_major != 3 || hdr . flags . UNSYNCHRONISATION_USED || hdr . flags . EXPERIMENTAL_TAG )
240: {
241: Printf ( "MP3: warning: skipping unsupported ID3v2.%d tag\n" , hdr . ver_major ) ;
242: SetBackColor ( 0xA9DCFF ) ;
243: DisplayFormatHex ( ) ;
244: ubyte id3v2_data [ tag_sz ] ;
245: }
246: else
247: {
248: if ( hdr . flags . EXTENDED_HEADER_PRESENT )
249: ID3v2_EXTENDED_HEADER ext_hdr ;
250:
251:
252:
253:
254:
255: local uint32 frame_color = 0xC9FCFF ;
256: do
257: {
258: SetBackColor ( frame_color ) ;
259: ID3v2_FRAME tf ;
260: frame_color -= 0x20200 ;
261: }
262: while ( FTell ( ) < tag_sz + sizeof ( hdr ) && ReadByte ( FTell ( ) ) != 0 ) ;
263:
264: SetBackColor ( 0x99CCFF ) ;
265: ubyte id3v2_padding [ tag_sz + sizeof ( hdr ) - FTell ( ) ] ;
266: }
267: }
268: } ;
269:
270:
271:
272:
273:
274: struct MPEG_HEADER
275: {
276: SetBackColor ( 0xCC99FF ) ;
277:
278: DisplayFormatHex ( ) ;
279:
280: uint32 frame_sync : 12 ;
281:
282: DisplayFormatDecimal ( ) ;
283:
284: uint32 mpeg_id : 1 ;
285: uint32 layer_id : 2 ;
286: uint32 protection_bit : 1 ;
287: uint32 bitrate_index : 4 ;
288: uint32 frequency_index : 2 ;
289: uint32 padding_bit : 1 ;
290: uint32 private_bit : 1 ;
291: uint32 channel_mode : 2 ;
292: uint32 mode_extension : 2 ;
293: uint32 copyright : 1 ;
294: uint32 original : 1 ;
295: uint32 emphasis : 2 ;
296:
297: if ( protection_bit == 0 )
298: {
299: DisplayFormatHex ( ) ;
300: uint16 checksum ;
301: }
302: } ;
303:
304:
305: struct MPEG_FRAME
306: {
307: MPEG_HEADER mpeg_hdr ;
308:
309:
310: bitrate = 0 ;
311:
312:
313: if ( mpeg_hdr . frame_sync < 0xFFE || mpeg_hdr . layer_id == 0 ||
314: mpeg_hdr . bitrate_index == 0 || mpeg_hdr . bitrate_index == 15 ||
315: mpeg_hdr . frequency_index == 3 )
316: {
317: Printf ( "MP3: warning: invalid MPEG header in frame at offset 0x%X\n" ,
318: FTell ( ) - 4 - ( mpeg_hdr . protection_bit == 0 ? 2 : 0 ) ) ;
319:
320:
321: FSeek ( FTell ( ) - 2 ) ;
322: }
323: else
324: {
325: if ( mpeg_hdr . layer_id == 3 )
326: {
327: bitrate = ( uint32 ) mpeg_hdr . bitrate_index << 5 ;
328: }
329: else
330: {
331: if ( mpeg_hdr . layer_id == 2 )
332: {
333: bitrate = ( uint32 ) mpeg_hdr . bitrate_index == 1 ? 32 :
334: ( 1 << 5 + ( uint32 ) mpeg_hdr . bitrate_index / 4 ) +
335: ( ( ( uint32 ) mpeg_hdr . bitrate_index & 3 ) <<
336: 3 + ( uint32 ) mpeg_hdr . bitrate_index / 4 ) ;
337: }
338: else
339: {
340: if ( mpeg_hdr . mpeg_id == 1 )
341: {
342: bitrate = ( 1 << 5 + ( ( uint32 ) mpeg_hdr . bitrate_index - 1 ) / 4 ) +
343: ( ( ( uint32 ) mpeg_hdr . bitrate_index - 1 & 3 ) <<
344: 3 + ( ( uint32 ) mpeg_hdr . bitrate_index - 1 ) / 4 ) ;
345: }
346: else
347: {
348: bitrate = ( uint32 ) mpeg_hdr . bitrate_index < 4 ?
349:
350: 8 * ( uint32 ) mpeg_hdr . bitrate_index :
351:
352: ( 1 << 4 + ( uint32 ) mpeg_hdr . bitrate_index / 4 ) +
353: (
354: ( ( uint32 ) mpeg_hdr . bitrate_index & 3 ) == 0 ? 0 :
355:
356: ( ( uint32 ) mpeg_hdr . bitrate_index & 3 ) == 1 ?
357: ( 1 << 4 + ( uint32 ) mpeg_hdr . bitrate_index / 4 ) :
358:
359: ( ( uint32 ) mpeg_hdr . bitrate_index & 3 ) == 2 ?
360: ( 1 << 4 + ( uint32 ) mpeg_hdr . bitrate_index / 4 ) +
361: ( ( 1 << 4 + ( uint32 ) mpeg_hdr . bitrate_index / 4 ) >> 1 ) :
362:
363: ( 1 << 4 + ( uint32 ) mpeg_hdr . bitrate_index / 4 ) -
364: ( ( 1 << 4 + ( uint32 ) mpeg_hdr . bitrate_index / 4 ) >> 2 )
365: ) ;
366: }
367: }
368: }
369: }
370:
371: if ( bitrate != 0 )
372: {
373: local uint16 freq [ 3 ] ;
374: freq [ 0 ] = 2205 ;
375: freq [ 1 ] = 2400 ;
376: freq [ 2 ] = 1600 ;
377:
378: sampling_freq = freq [ mpeg_hdr . frequency_index ] ;
379:
380: if ( mpeg_hdr . mpeg_id == 1 )
381: sampling_freq <<= 1 ;
382:
383: frame_size = ( bitrate * 14400 ) / sampling_freq ;
384:
385: if ( mpeg_hdr . channel_mode == 3 )
386: frame_size >>= 1 ;
387:
388: frame_size -= 4 + ( mpeg_hdr . protection_bit == 0 ? 2 : 0 ) - mpeg_hdr . padding_bit ;
389:
390: frame_header_offset = FTell ( ) - 4 - ( mpeg_hdr . protection_bit == 0 ? 2 : 0 ) ;
391:
392:
393: if ( FTell ( ) + frame_size > FileSize ( ) )
394: {
395: Printf ( "MP3: warning: cut MPEG frame at end of file (frame header offset = 0x%LX, data length = %u)\n" ,
396: frame_header_offset , frame_size ) ;
397:
398: Printf ( "MP3: file parsing completed!\nMP3: valid MPEG frames found: %d\n" , frames_count ) ;
399:
400: if ( frames_count != 0 )
401: Printf ( "MP3: average frame bitrate: %d kbit\n" , sum_bitrate / frames_count ) ;
402:
403: return ;
404: }
405: else
406: {
407: DisplayFormatHex ( ) ;
408: SetBackColor ( 0xCCCCFF ) ;
409: ubyte mpeg_frame_data [ frame_size ] ;
410: }
411:
412: sum_bitrate += bitrate ;
413:
414: frames_count ++ ;
415: }
416: } ;
417:
418:
419:
420:
421:
422: BigEndian ( ) ;
423:
424: ReadBytes ( buf , 0 , 3 ) ;
425:
426: if ( ! Strcmp ( buf , "ID3" ) )
427: {
428: Printf ( "MP3: ID3v2 tag found\n" ) ;
429: ID3v2_TAG id3v2_tag ;
430: }
431:
432: while ( ! FEof ( ) && ! id3v1_tag_found )
433: {
434:
435: seek_pos = FTell ( ) ;
436: was_bad_sync = 0 ;
437: do
438: {
439: data = ReadShort ( seek_pos ) ;
440:
441: if ( ( uint16 ) data == 0x5441 && ( uchar ) ReadByte ( seek_pos + 2 ) == 0x47 )
442: id3v1_tag_found = 1 ;
443:
444: if ( ! was_bad_sync && ( uint16 ) data < 0xFFE0 && ! id3v1_tag_found )
445: {
446: Printf ( "MP3: warning: invalid MPEG frame synchronization at offset 0x%LX\n" , seek_pos ) ;
447: was_bad_sync = 1 ;
448: }
449:
450: seek_pos ++ ;
451: }
452: while ( ( uint16 ) data < 0xFFE0 && seek_pos < ( FileSize ( ) - 1 ) && ! id3v1_tag_found ) ;
453:
454: if ( ( uint16 ) data >= 0xFFE0 || id3v1_tag_found )
455: {
456: FSeek ( seek_pos - 1 ) ;
457: }
458: else
459: {
460: Printf ( "MP3: file parsing completed!\nMP3: valid MPEG frames found: %d\n" , frames_count ) ;
461:
462: if ( frames_count != 0 )
463: Printf ( "MP3: average frame bitrate: %d kbit\n" , sum_bitrate / frames_count ) ;
464:
465: return ;
466: }
467:
468: if ( ! id3v1_tag_found )
469: {
470: MPEG_FRAME mf ;
471:
472: if ( frames_count == 1 && bitrate )
473: Printf ( "MP3: first found MPEG frame parameters:\nMP3:\t- header ofsset: 0x%LX\nMP3:\t- bitrate: %d kbit\nMP3:\t- MPEG-%d layer %d\nMP3:\t- sampling frequency: %d Hz\nMP3:\t- channel mode: %s\nMP3:\t- CRC protected: %s\n" ,
474: frame_header_offset ,
475: bitrate ,
476: mf . mpeg_hdr . mpeg_id == 1 ? 1 : 2 ,
477: mf . mpeg_hdr . layer_id == 1 ? 3 : mf . mpeg_hdr . layer_id == 2 ? 2 : 1 ,
478: sampling_freq * 10 ,
479: mf . mpeg_hdr . channel_mode == 3 ? "mono" :
480: mf . mpeg_hdr . channel_mode == 0 ? "stereo" :
481: mf . mpeg_hdr . channel_mode == 1 ? "joint stereo" : "dual channel" ,
482: mf . mpeg_hdr . protection_bit == 0 ? "Yes" : "No" ) ;
483: }
484: }
485:
486: if ( id3v1_tag_found )
487: {
488: Printf ( "MP3: ID3v1 tag found\n" ) ;
489: ID3v1_TAG id3v1_tag ;
490: }
491:
492: if ( ! FEof ( ) )
493: Printf ( "MP3: warning: there is some unknown extra-data after ID3v1 tag at end of file\n" ) ;
494:
495: Printf ( "MP3: file parsing completed!\nMP3: valid MPEG frames found: %d\n" , frames_count ) ;
496:
497: if ( frames_count != 0 )
498: Printf ( "MP3: average frame bitrate: %d kbit\n" , sum_bitrate / frames_count ) ;
499: tok_eof