catori 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/VERSION +1 -0
  2. data/bin/catori +9 -0
  3. data/changelog.txt +3 -0
  4. data/construir +3 -0
  5. data/crear_vista.sql +8 -0
  6. data/ext/audiofile/MANIFEST +8 -0
  7. data/ext/audiofile/README +11 -0
  8. data/ext/audiofile/audiofile.c +833 -0
  9. data/ext/audiofile/audiofile.rd +265 -0
  10. data/ext/audiofile/depend +0 -0
  11. data/ext/audiofile/extconf.rb +8 -0
  12. data/ext/audiofile/fail.rb +22 -0
  13. data/ext/audiofile/mkmf.log +34 -0
  14. data/ext/audiofile/test.rb +229 -0
  15. data/ext/flac/extconf.rb +5 -0
  16. data/ext/flac/flac.c +75 -0
  17. data/ext/flac/mkmf.log +12 -0
  18. data/ext/flac/test.rb +3 -0
  19. data/ext/mahoro-0.1/INSTALL +9 -0
  20. data/ext/mahoro-0.1/extconf.rb +7 -0
  21. data/ext/mahoro-0.1/mahoro.c +187 -0
  22. data/ext/mahoro-0.1/mkmf.log +24 -0
  23. data/ext/mahoro-0.1/test.rb +41 -0
  24. data/ext/mpc/extconf.rb +5 -0
  25. data/ext/mpc/id3tag.c +245 -0
  26. data/ext/mpc/id3tag.h +5 -0
  27. data/ext/mpc/mkmf.log +12 -0
  28. data/ext/mpc/mpc.c +56 -0
  29. data/ext/mpc/mpp.h +194 -0
  30. data/ext/mpc/mppdec.h +1171 -0
  31. data/ext/mpc/test.rb +3 -0
  32. data/ext/rmac/extconf.rb +7 -0
  33. data/ext/rmac/mkmf.log +22 -0
  34. data/ext/rmac/rmac.cpp +162 -0
  35. data/ext/vorbisfile/ChangeLog +11 -0
  36. data/ext/vorbisfile/README +33 -0
  37. data/ext/vorbisfile/configure +2 -0
  38. data/ext/vorbisfile/extconf.rb +9 -0
  39. data/ext/vorbisfile/mkmf.log +68 -0
  40. data/ext/vorbisfile/test.rb +78 -0
  41. data/ext/vorbisfile/vorbisfile.c +482 -0
  42. data/instalar.txt +19 -0
  43. data/install.rb +11 -0
  44. data/lib/audioinfo.rb +321 -0
  45. data/lib/catori.rb +131 -0
  46. data/lib/catori/Catalogador.rb +71 -0
  47. data/lib/catori/Db.rb +81 -0
  48. data/lib/catori/Gui.rb +52 -0
  49. data/lib/catori/Installer.rb +16 -0
  50. data/lib/catori/Query.rb +82 -0
  51. data/lib/catori/XML.rb +42 -0
  52. data/lib/catori/catori_gui.glade +340 -0
  53. data/lib/catori/catori_gui.glade.bak +340 -0
  54. data/lib/catori/catori_gui.gladep +8 -0
  55. data/lib/catori/catori_gui.gladep.bak +8 -0
  56. data/lib/catori/taglib.rb +227 -0
  57. data/lib/pixmaps/album.png +0 -0
  58. data/lib/pixmaps/artist.png +0 -0
  59. data/lib/pixmaps/cdr.png +0 -0
  60. data/lib/pixmaps/song.png +0 -0
  61. data/lib/taglib.rb +230 -0
  62. data/sql/catori_mysql.sql +68 -0
  63. data/sql/catori_pg.sql +65 -0
  64. data/tests/saw.ape +0 -0
  65. data/tests/saw.flac +0 -0
  66. data/tests/saw.mp3 +0 -0
  67. data/tests/saw.mpc +0 -0
  68. data/tests/saw.ogg +0 -0
  69. data/tests/saw.wav +0 -0
  70. data/tests/test_audioinfo.rb +43 -0
  71. metadata +217 -0
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+ $CFLAGS+=" -Wall"
3
+ dir_config("flac")
4
+ have_library("FLAC");
5
+ create_makefile("flac");
@@ -0,0 +1,75 @@
1
+ #include "FLAC/metadata.h"
2
+ #include "ruby.h"
3
+ #include <ctype.h>
4
+ #include <string.h>
5
+ static VALUE mFlac;
6
+ static VALUE cInfo;
7
+ // static VALUE rb_cinfo_new(VALUE self);
8
+ static VALUE rb_flac_info(VALUE module, VALUE filename);
9
+ static void set_tag(FLAC__StreamMetadata_VorbisComment_Entry * tag,
10
+ VALUE info);
11
+ void
12
+ Init_flac()
13
+ {
14
+ mFlac = rb_define_module("Flac");
15
+ cInfo = rb_define_class_under(mFlac, "Info", rb_cObject);
16
+ int i = 0;
17
+ #define NA 5
18
+ const char *attr2[NA] =
19
+ { "time", "sample_rate", "channels", "bits_per_sample", "comments"
20
+ };
21
+ for (i = 0; i < NA; i++) {
22
+ rb_define_attr(cInfo, attr2[i], 1, 0);
23
+ }
24
+
25
+ rb_define_module_function(mFlac, "info", rb_flac_info, 1);
26
+ }
27
+
28
+ VALUE
29
+ rb_flac_info(VALUE self, VALUE filename)
30
+ {
31
+ FLAC__StreamMetadata si;
32
+ FLAC__StreamMetadata *tags;
33
+ // char *tag;
34
+ char *cfilename = STR2CSTR(filename);
35
+ FLAC__metadata_get_streaminfo(cfilename, &si);
36
+ int i = 0;
37
+ VALUE info = rb_class_new_instance(0, NULL, cInfo);
38
+ VALUE comments = rb_hash_new();
39
+ double time =
40
+ (double) si.data.stream_info.total_samples /
41
+ (double) si.data.stream_info.sample_rate;
42
+ rb_iv_set(info, "@sample_rate",
43
+ INT2FIX(si.data.stream_info.sample_rate));
44
+ rb_iv_set(info, "@channels", INT2FIX(si.data.stream_info.channels));
45
+ rb_iv_set(info, "@bits_per_sample",
46
+ INT2FIX(si.data.stream_info.bits_per_sample));
47
+ rb_iv_set(info, "@time", rb_float_new(time));
48
+ FLAC__metadata_get_tags(cfilename, &tags);
49
+ for (i = 0; i < tags->data.vorbis_comment.num_comments; i++) {
50
+ set_tag(&(tags->data.vorbis_comment.comments[i]), comments);
51
+ }
52
+ rb_iv_set(info, "@comments", comments);
53
+ FLAC__metadata_object_delete(tags);
54
+ return info;
55
+ }
56
+
57
+ static void
58
+ set_tag(FLAC__StreamMetadata_VorbisComment_Entry * tag, VALUE comments)
59
+ {
60
+ // printf("%s\n",tag->entry);
61
+ char *s = tag->entry;
62
+ char *equals_pos = strchr(s, '=');
63
+ VALUE key,
64
+ value;
65
+ if (0 != equals_pos) {
66
+ int i = 0;
67
+
68
+ for (; i < equals_pos - s; i++) {
69
+ s[i] = tolower(s[i]);
70
+ }
71
+ key = rb_str_new(s, equals_pos - s);
72
+ value = rb_str_new(equals_pos + 1, strlen(equals_pos + 1));
73
+ rb_hash_aset(comments, key, value);
74
+ }
75
+ }
@@ -0,0 +1,12 @@
1
+ have_library: checking for main() in -lFLAC... -------------------- yes
2
+
3
+ "i686-pc-linux-gnu-gcc -o conftest -I. -I/usr/lib/ruby/1.8/i686-linux -I. -O2 -march=athlon-xp -m3dnow -msse -mfpmath=sse -mmmx -pipe -fno-strict-aliasing -fPIC -Wall conftest.c -L'.' -L'/usr/lib' -Wl,-R'/usr/lib' -L. -rdynamic -Wl,-export-dynamic -lruby18-static -lFLAC -ldl -lcrypt -lm -lc"
4
+ checked program was:
5
+ /* begin */
6
+ 1: /*top*/
7
+ 2: int main() { return 0; }
8
+ 3: int t() { void ((*volatile p)()); p = (void ((*)()))main; return 0; }
9
+ /* end */
10
+
11
+ --------------------
12
+
@@ -0,0 +1,3 @@
1
+ require 'flac'
2
+
3
+ p Flac.info("test.flac")
@@ -0,0 +1,9 @@
1
+ INSTALL
2
+ =========
3
+
4
+ The installation is simple, install libmagic and type the following.
5
+
6
+ > ruby extconf.rb --with-magic-include=/path/to/include \
7
+ --with-magic-lib=/path/to/lib
8
+ > make
9
+ # make install
@@ -0,0 +1,7 @@
1
+ require 'mkmf'
2
+
3
+ dir_config('magic')
4
+ have_library('magic', 'magic_open')
5
+ create_makefile('mahoro')
6
+
7
+ # arch-tag: extconf
@@ -0,0 +1,187 @@
1
+ /*
2
+ * This file is Public Domain.
3
+ */
4
+
5
+ #include <ruby.h>
6
+ #include <magic.h>
7
+
8
+ struct MagicCookie
9
+ {
10
+ magic_t cookie;
11
+ };
12
+
13
+ static VALUE cMahoro;
14
+ static VALUE eMahoroError;
15
+
16
+ static void
17
+ mahoro_free(ptr)
18
+ struct MagicCookie *ptr;
19
+ {
20
+ magic_close(ptr->cookie);
21
+ free(ptr);
22
+ }
23
+
24
+ static VALUE
25
+ mahoro_allocate(klass)
26
+ VALUE klass;
27
+ {
28
+ return Data_Wrap_Struct(klass, 0, mahoro_free, 0);
29
+ }
30
+
31
+ static VALUE
32
+ mahoro_initialize(argc, argv, self)
33
+ int argc;
34
+ VALUE *argv, self;
35
+ {
36
+ int flags = MAGIC_NONE;
37
+ char *path = 0;
38
+ struct MagicCookie *ptr;
39
+ magic_t cookie;
40
+ VALUE vpath, vflags;
41
+
42
+ switch(rb_scan_args(argc, argv, "02", &vflags, &vpath)) {
43
+ case 2:
44
+ if(!NIL_P(vpath)) {
45
+ path = StringValuePtr(vpath);
46
+ }
47
+ /* fallthrough */
48
+ case 1:
49
+ flags = FIX2INT(vflags);
50
+ break;
51
+ }
52
+
53
+ if(!(cookie = magic_open(flags))) {
54
+ rb_raise(eMahoroError, "failed to initialize magic cookie");
55
+ }
56
+
57
+ if(magic_load(cookie, path)) {
58
+ rb_raise(eMahoroError, "failed to load database: %s",
59
+ magic_error(cookie));
60
+ }
61
+
62
+ ptr = ALLOC(struct MagicCookie);
63
+ ptr->cookie = cookie;
64
+ DATA_PTR(self) = ptr;
65
+
66
+ return self;
67
+ }
68
+
69
+ static VALUE
70
+ mahoro_file(self, path)
71
+ VALUE self, path;
72
+ {
73
+ const char *msg;
74
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
75
+
76
+ if(!(msg = magic_file(cookie, StringValuePtr(path)))) {
77
+ rb_raise(eMahoroError, "failed lookup: %s", magic_error(cookie));
78
+ }
79
+
80
+ return rb_str_new2(msg);
81
+ }
82
+
83
+ static VALUE
84
+ mahoro_buffer(self, input)
85
+ VALUE self, input;
86
+ {
87
+ const char *msg;
88
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
89
+
90
+ if(!(msg = magic_buffer(cookie, StringValuePtr(input),
91
+ RSTRING(StringValue(input))->len))) {
92
+ rb_raise(eMahoroError, "failed lookup: %s", magic_error(cookie));
93
+ }
94
+
95
+ return rb_str_new2(msg);
96
+ }
97
+
98
+ static VALUE
99
+ mahoro_set_flags(self, flags)
100
+ VALUE self, flags;
101
+ {
102
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
103
+
104
+ return INT2FIX(magic_setflags(cookie, FIX2INT(flags)));
105
+ }
106
+
107
+ static VALUE
108
+ mahoro_check(argc, argv, self)
109
+ int argc;
110
+ VALUE *argv, self;
111
+ {
112
+ char *path = 0;
113
+ VALUE vpath;
114
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
115
+
116
+ switch(rb_scan_args(argc, argv, "01", &vpath)) {
117
+ case 1:
118
+ if(!NIL_P(vpath)) {
119
+ path = StringValuePtr(vpath);
120
+ }
121
+ break;
122
+ }
123
+
124
+ if(!magic_check(cookie, path)) {
125
+ return Qtrue;
126
+ } else {
127
+ return Qfalse;
128
+ }
129
+ }
130
+
131
+ static VALUE
132
+ mahoro_compile(klass, path)
133
+ VALUE klass, path;
134
+ {
135
+ magic_t cookie = magic_open(MAGIC_NONE);
136
+
137
+ if(magic_compile(cookie, StringValuePtr(path))) {
138
+ rb_raise(eMahoroError, "failed compile: %s", magic_error(cookie));
139
+ }
140
+
141
+ magic_close(cookie);
142
+
143
+ return Qtrue;
144
+ }
145
+
146
+ static VALUE
147
+ mahoro_load(self, path)
148
+ VALUE self, path;
149
+ {
150
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
151
+
152
+ if(magic_load(cookie, StringValuePtr(path))) {
153
+ rb_raise(eMahoroError, "failed load: %s", magic_error(cookie));
154
+ }
155
+
156
+ return self;
157
+ }
158
+
159
+ void Init_mahoro(void)
160
+ {
161
+ cMahoro = rb_define_class("Mahoro", rb_cObject);
162
+ eMahoroError = rb_define_class_under(cMahoro, "Error", rb_eStandardError);
163
+
164
+ rb_const_set(cMahoro, rb_intern("NONE"), INT2FIX(MAGIC_NONE));
165
+ rb_const_set(cMahoro, rb_intern("DEBUG"), INT2FIX(MAGIC_DEBUG));
166
+ rb_const_set(cMahoro, rb_intern("SYMLINK"), INT2FIX(MAGIC_SYMLINK));
167
+ rb_const_set(cMahoro, rb_intern("COMPRESS"), INT2FIX(MAGIC_COMPRESS));
168
+ rb_const_set(cMahoro, rb_intern("DEVICES"), INT2FIX(MAGIC_DEVICES));
169
+ rb_const_set(cMahoro, rb_intern("MIME"), INT2FIX(MAGIC_MIME));
170
+ rb_const_set(cMahoro, rb_intern("CONTINUE"), INT2FIX(MAGIC_CONTINUE));
171
+ rb_const_set(cMahoro, rb_intern("CHECK"), INT2FIX(MAGIC_CHECK));
172
+ rb_const_set(cMahoro, rb_intern("PRESERVE_ATIME"),
173
+ INT2FIX(MAGIC_PRESERVE_ATIME));
174
+ rb_const_set(cMahoro, rb_intern("RAW"), INT2FIX(MAGIC_RAW));
175
+ rb_const_set(cMahoro, rb_intern("ERROR"), INT2FIX(MAGIC_ERROR));
176
+
177
+ rb_define_alloc_func(cMahoro, mahoro_allocate);
178
+ rb_define_method(cMahoro, "initialize", mahoro_initialize, -1);
179
+ rb_define_method(cMahoro, "file", mahoro_file, 1);
180
+ rb_define_method(cMahoro, "buffer", mahoro_buffer, 1);
181
+ rb_define_method(cMahoro, "flags=", mahoro_set_flags, 1);
182
+ rb_define_method(cMahoro, "valid?", mahoro_check, -1);
183
+ rb_define_singleton_method(cMahoro, "compile", mahoro_compile, 1);
184
+ rb_define_method(cMahoro, "load", mahoro_load, 1);
185
+ }
186
+
187
+ /* arch-tag: mahoro */
@@ -0,0 +1,24 @@
1
+ have_library: checking for magic_open() in -lmagic... -------------------- yes
2
+
3
+ "i686-pc-linux-gnu-gcc -o conftest -I. -I/usr/lib/ruby/1.8/i686-linux -I. -O2 -march=athlon-xp -m3dnow -msse -mfpmath=sse -mmmx -pipe -fno-strict-aliasing -fPIC conftest.c -L'.' -L'/usr/lib' -Wl,-R'/usr/lib' -L. -rdynamic -Wl,-export-dynamic -lruby18-static -lmagic -ldl -lcrypt -lm -lc"
4
+ conftest.c: En la función ‘t’:
5
+ conftest.c:3: error: ‘magic_open’ no se declaró aquí (primer uso en esta función)
6
+ conftest.c:3: error: (Cada identificador no declarado solamente se reporta una vez
7
+ conftest.c:3: error: ara cada funcion en la que aparece.)
8
+ checked program was:
9
+ /* begin */
10
+ 1: /*top*/
11
+ 2: int main() { return 0; }
12
+ 3: int t() { void ((*volatile p)()); p = (void ((*)()))magic_open; return 0; }
13
+ /* end */
14
+
15
+ "i686-pc-linux-gnu-gcc -o conftest -I. -I/usr/lib/ruby/1.8/i686-linux -I. -O2 -march=athlon-xp -m3dnow -msse -mfpmath=sse -mmmx -pipe -fno-strict-aliasing -fPIC conftest.c -L'.' -L'/usr/lib' -Wl,-R'/usr/lib' -L. -rdynamic -Wl,-export-dynamic -lruby18-static -lmagic -ldl -lcrypt -lm -lc"
16
+ checked program was:
17
+ /* begin */
18
+ 1: /*top*/
19
+ 2: int main() { return 0; }
20
+ 3: int t() { magic_open(); return 0; }
21
+ /* end */
22
+
23
+ --------------------
24
+
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'mahoro'
5
+
6
+ class MahoroTestCase < Test::Unit::TestCase
7
+
8
+ def initialize(*args)
9
+ super
10
+ @m = Mahoro.new
11
+ end
12
+
13
+ def test_file
14
+ @m.flags = Mahoro::NONE
15
+ assert_equal('ASCII C program text', @m.file('mahoro.c'))
16
+ end
17
+
18
+ def test_mime_file
19
+ @m.flags = Mahoro::MIME
20
+ assert_equal('text/x-c; charset=us-ascii', @m.file('mahoro.c'))
21
+ end
22
+
23
+ def test_buffer
24
+ @m.flags = Mahoro::NONE
25
+ assert_equal('ASCII C program text',
26
+ @m.buffer(File.read('mahoro.c')))
27
+ end
28
+
29
+ def test_mime_buffer
30
+ @m.flags = Mahoro::MIME
31
+ assert_equal('text/x-c; charset=us-ascii',
32
+ @m.buffer(File.read('mahoro.c')))
33
+ end
34
+
35
+ def test_valid
36
+ assert(@m.valid?, 'Default database was not valid.')
37
+ end
38
+
39
+ end
40
+
41
+ # arch-tag: test
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+ $CFLAGS+=" -Wall"
3
+ dir_config("mpcdec")
4
+ have_library("mpcdec");
5
+ create_makefile("mpc");
@@ -0,0 +1,245 @@
1
+ /*
2
+ * Musepack audio compression
3
+ * Copyright (C) 1999-2004 Buschmann/Klemm/Piecha/Wolf
4
+ *
5
+ * This library is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * This library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with this library; if not, write to the Free Software
17
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ */
19
+
20
+ #include <string.h>
21
+ #include "mppdec.h"
22
+
23
+
24
+ /*
25
+ * List of known Genres. 256 genres are possible with version 1/1.1 tags,
26
+ * but not yet used.
27
+ */
28
+
29
+ static const char* GenreList [] = {
30
+ "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
31
+ "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
32
+ "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
33
+ "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient",
34
+ "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical",
35
+ "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
36
+ "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative",
37
+ "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
38
+ "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
39
+ "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap",
40
+ "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave",
41
+ "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal",
42
+ "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll",
43
+ "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion",
44
+ "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
45
+ "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock",
46
+ "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour",
47
+ "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony",
48
+ "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club",
49
+ "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
50
+ "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
51
+ "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
52
+ "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta",
53
+ "Heavy Metal", "Black Metal", "Crossover", "Contemporary C",
54
+ "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
55
+ "SynthPop"
56
+ };
57
+
58
+
59
+ /*
60
+ * Copies src to dst. Copying is stopped at `\0' char is detected or if
61
+ * len chars are copied.
62
+ * Trailing blanks are removed and the string is `\0` terminated.
63
+ */
64
+
65
+ static void
66
+ memcpy_crop ( char* dst, const char* src, size_t len )
67
+ {
68
+ size_t i;
69
+
70
+ for ( i = 0; i < len; i++ )
71
+ if ( src[i] != '\0' )
72
+ dst[i] = src[i];
73
+ else
74
+ break;
75
+
76
+ // dst[i] points behind the string contents
77
+
78
+ while ( i > 0 && dst [i-1] == ' ' )
79
+ i--;
80
+ dst [i] = '\0';
81
+ }
82
+
83
+
84
+ /*
85
+ * Evaluate ID version 1/1.1 tags of a file given by 'fp' and fills out Tag
86
+ * information in 'tip'. Tag information also contains the effective file
87
+ * length (without the tags if tags are present). Return 1 if there is
88
+ * usable information inside the file. Note there's also the case possible
89
+ * that the file contains empty tags, the the file size is truncated by the
90
+ * 128 bytes but the function returns 0.
91
+ *
92
+ * If there're no tags, all strings containing '\0', the Genre pointer is
93
+ * NULL and GenreNo and TrackNo are -1.
94
+ */
95
+
96
+ Int
97
+ Read_ID3V1_Tags ( FILE_T fp, TagInfo_t* tip )
98
+ {
99
+ Uint8_t tmp [128];
100
+ OFF_T file_pos;
101
+
102
+ memset ( tip, 0, sizeof(*tip) );
103
+ tip->GenreNo = -1;
104
+ tip->TrackNo = -1;
105
+
106
+ if ( -1 == (file_pos = FILEPOS (fp)) )
107
+ return 0;
108
+ if ( -1 == SEEK ( fp, -128L, SEEK_END ) )
109
+ return 0;
110
+
111
+ tip->FileSize = FILEPOS (fp);
112
+ if ( 128 != READ ( fp, tmp, 128 ) )
113
+ return 0;
114
+ SEEK ( fp, file_pos, SEEK_SET );
115
+
116
+ if ( 0 != memcmp ( tmp, "TAG", 3 ) ) {
117
+ tip->FileSize += 128;
118
+ return 0;
119
+ }
120
+
121
+ if ( !tmp[3] && !tmp[33] && !tmp[63] && !tmp[93] && !tmp[97] )
122
+ return 0;
123
+
124
+ memcpy_crop ( tip->Title , tmp + 3, 30 );
125
+ memcpy_crop ( tip->Artist , tmp + 33, 30 );
126
+ memcpy_crop ( tip->Album , tmp + 63, 30 );
127
+ memcpy_crop ( tip->Year , tmp + 93, 4 );
128
+ memcpy_crop ( tip->Comment, tmp + 97, 30 );
129
+
130
+ strcpy ( tip->Genre, tmp[127] < sizeof(GenreList)/sizeof(*GenreList) ?
131
+ GenreList [tip->GenreNo = tmp[127]] : "???" );
132
+
133
+ // Index 0 may be true if file is very short
134
+ if ( tmp[125] == 0 && (tmp[126] != 0 || tip->FileSize < 66000 ) )
135
+ sprintf ( tip->Track, "[%02d]", tip->TrackNo = tmp[126] );
136
+ else
137
+ strcpy ( tip->Track, " " );
138
+
139
+ return 1;
140
+ }
141
+
142
+
143
+ struct APETagFooterStruct {
144
+ Uint8_t ID [8]; // should equal 'APETAGEX'
145
+ Uint8_t Version [4]; // currently 1000 (version 1.000)
146
+ Uint8_t Length [4]; // the complete size of the tag, including this footer
147
+ Uint8_t TagCount [4]; // the number of fields in the tag
148
+ Uint8_t Flags [4]; // the tag flags (none currently defined)
149
+ Uint8_t Reserved [8]; // reserved for later use
150
+ };
151
+
152
+
153
+ static Uint32_t
154
+ Read_LE_Uint32 ( const Uint8_t* p )
155
+ {
156
+ return ((Uint32_t)p[0] << 0) |
157
+ ((Uint32_t)p[1] << 8) |
158
+ ((Uint32_t)p[2] << 16) |
159
+ ((Uint32_t)p[3] << 24);
160
+ }
161
+
162
+
163
+ #define TAG_ANALYZE(item,elem) \
164
+ if ( 0 == memcmp (p, #item, sizeof #item ) ) { \
165
+ p += sizeof #item; \
166
+ memcpy ( tip->elem, p, len ); \
167
+ p += len; \
168
+ } else
169
+
170
+
171
+ Int
172
+ Read_APE_Tags ( FILE_T fp, TagInfo_t* tip )
173
+ {
174
+ OFF_T file_pos;
175
+ Uint32_t len;
176
+ Uint32_t flags;
177
+ unsigned char buff [8192];
178
+ unsigned char* p;
179
+ unsigned char* end;
180
+ struct APETagFooterStruct T;
181
+ Uint32_t TagLen;
182
+ Uint32_t TagCount;
183
+ Uint32_t tmp;
184
+
185
+ memset ( tip, 0, sizeof(*tip) );
186
+ tip->GenreNo = -1;
187
+ tip->TrackNo = -1;
188
+
189
+ if ( -1 == (file_pos = FILEPOS (fp)) )
190
+ goto notag;
191
+ if ( -1 == SEEK ( fp, 0L, SEEK_END ) )
192
+ goto notag;
193
+ tip->FileSize = FILEPOS (fp);
194
+ if ( -1 == SEEK ( fp, -(long)sizeof T, SEEK_END ) )
195
+ goto notag;
196
+ if ( sizeof(T) != READ ( fp, &T, sizeof T ) )
197
+ goto notag;
198
+ if ( memcmp ( T.ID, "APETAGEX", sizeof(T.ID) ) != 0 )
199
+ goto notag;
200
+ tmp = Read_LE_Uint32 (T.Version);
201
+ if ( tmp != 1000 && tmp != 2000 )
202
+ goto notag;
203
+ TagLen = Read_LE_Uint32 (T.Length);
204
+ if ( TagLen <= sizeof T )
205
+ goto notag;
206
+ if ( -1 == SEEK ( fp, -(long)TagLen, SEEK_END ) )
207
+ goto notag;
208
+ tip->FileSize = FILEPOS (fp);
209
+ memset ( buff, 0, sizeof(buff) );
210
+ if ( TagLen - sizeof T != READ ( fp, buff, TagLen - sizeof T ) )
211
+ goto notag;
212
+ SEEK ( fp, file_pos, SEEK_SET );
213
+
214
+ TagCount = Read_LE_Uint32 (T.TagCount);
215
+ end = buff + TagLen - sizeof T;
216
+ for ( p = buff; p < end && TagCount--; ) {
217
+ len = Read_LE_Uint32 ( p ); p += 4;
218
+ flags = Read_LE_Uint32 ( p ); p += 4;
219
+ TAG_ANALYZE ( Title , Title )
220
+ TAG_ANALYZE ( Album , Album )
221
+ TAG_ANALYZE ( Artist , Artist )
222
+ TAG_ANALYZE ( Album , Album )
223
+ TAG_ANALYZE ( Comment, Comment )
224
+ TAG_ANALYZE ( Track , Track )
225
+ TAG_ANALYZE ( Year , Year )
226
+ TAG_ANALYZE ( Genre , Genre )
227
+ {
228
+ p += strlen(p) + 1 + len;
229
+ }
230
+ }
231
+
232
+ if ( tip->Track[0] != '\0' )
233
+ sprintf ( tip->Track, "[%02d]", tip->TrackNo = atoi (tip->Track) );
234
+ else
235
+ strcpy ( tip->Track, " " );
236
+
237
+ /* genre is not yet entirely decoded */
238
+ return 1;
239
+
240
+ notag:
241
+ SEEK ( fp, file_pos, SEEK_SET );
242
+ return 0;
243
+ }
244
+
245
+ /* end of id3tag.c */