catori 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 */