2 * Copyright (C) 2006 Tilman Sauerbeck (tilman at code-monkey de)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation, version 2.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 static VALUE c_close (VALUE self);
37 static VALUE cComments, eVTError;
38 static ID id_read, id_write, id_seek, id_length;
41 on_read (void *ptr, size_t size, size_t nmemb, RbVorbisTagger *o)
44 size_t total = size * nmemb;
47 rb_str_resize (o->io_buf, size * nmemb);
49 tmp = rb_funcall (o->io, id_read, 2, LONG2NUM (total), o->io_buf);
54 memcpy (ptr, buf->ptr, buf->len);
60 on_write (const void *ptr, size_t size, size_t nmemb, RbVorbisTagger *o)
62 size_t total = size * nmemb;
64 rb_str_resize (o->io_buf, total);
65 memcpy (RSTRING (o->io_buf)->ptr, ptr, total);
67 return NUM2LONG (rb_io_write (o->io, o->io_buf));
71 c_mark (RbVorbisTagger *o)
74 rb_gc_mark (o->comments);
75 rb_gc_mark (o->io_buf);
79 c_free (RbVorbisTagger *o)
81 /* just in case the user forgot to call #close himself */
83 vcedit_state_unref (o->state);
93 return Data_Make_Struct (klass, RbVorbisTagger, c_mark, c_free, o);
98 * Ogg::Vorbis::Tagger.open(arg) -> object
99 * Ogg::Vorbis::Tagger.open(arg) { |object| block } -> nil
101 * If a block isn't specified, Ogg::Vorbis::Tagger.open is a synonym
102 * for Ogg::Vorbis::Tagger.new.
103 * If a block is given, it will be invoked with the
104 * Ogg::Vorbis::Tagger object as a parameter, and the file or IO object
105 * will be automatically closed when the block terminates.
106 * The method always returns +nil+ in this case.
109 c_open (VALUE klass, VALUE arg)
111 VALUE obj = rb_class_new_instance (1, &arg, klass);
113 if (rb_block_given_p ())
114 return rb_ensure (rb_yield, obj, c_close, obj);
121 * Ogg::Vorbis::Tagger.new(arg) -> object
123 * Returns a new Ogg::Vorbis::Tagger object for the specified argument.
124 * *arg* can either be an IO object or a filename.
126 * FIXME: add optional mode argument (read-only or read-write)
129 c_init (VALUE self, VALUE io)
135 Data_Get_Struct (self, RbVorbisTagger, o);
137 /* is this actually an IO object or a filename? */
138 if (rb_respond_to (io, id_read) &&
139 rb_respond_to (io, id_write) &&
140 rb_respond_to (io, id_seek))
141 o->need_close = false;
142 else if (!NIL_P (rb_check_string_type (io))) {
143 io = rb_file_open (StringValuePtr (io), "rb+");
144 o->need_close = true;
146 rb_raise (rb_eArgError, "invalid argument");
149 o->io_buf = rb_str_buf_new (BUFSIZ);
151 o->state = vcedit_state_new ();
153 rb_raise (eVTError, "vcedit_new_state() failed - %s",
154 vcedit_error (o->state));
156 s = vcedit_open_callbacks (o->state, o,
157 (vcedit_read_func) on_read,
158 (vcedit_write_func) on_write);
160 rb_raise (eVTError, "vcedit_open_callbacks() failed - %s",
161 vcedit_error (o->state));
163 vc = vcedit_comments (o->state);
165 rb_raise (eVTError, "vcedit_comments() failed - %s",
166 vcedit_error (o->state));
168 /* check whether all comments are well-formed */
169 for (i = 0; i < vc->comments; i++) {
170 char *ptr, *content = vc->user_comments[i];
172 ptr = strchr (content, '=');
173 if (!ptr || ptr == content)
174 rb_raise (eVTError, "malformed comment - %s", content);
177 o->comments = rb_class_new_instance (0, NULL, cComments);
179 comments_init (o->comments, o->state);
186 * object.close -> object
188 * Closes *object* and returns it.
195 Data_Get_Struct (self, RbVorbisTagger, o);
197 vcedit_state_unref (o->state);
208 * object.write -> integer
210 * Writes the comments from *object* back to the IO object and
211 * returns the numbers of comments written.
219 Data_Get_Struct (self, RbVorbisTagger, o);
221 comments_sync (o->comments);
223 /* seek back to BOF */
224 rb_funcall (o->io, id_seek, 1, INT2FIX (0));
226 s = vcedit_write (o->state, o);
228 rb_raise (rb_eIOError, "write failed - %s",
229 vcedit_error (o->state));
231 return rb_funcall (o->comments, id_length, 0);
236 * object.comments -> comments
238 * Returns the comments collection of *object*, which is an instance of
239 * Ogg::Vorbis::Comments.
242 c_comments (VALUE self)
246 Data_Get_Struct (self, RbVorbisTagger, o);
253 Init_vorbistagger_ext (void)
255 VALUE mOgg, mVorbis, eOgg, eVorbis, cVT;
257 mOgg = rb_define_module ("Ogg");
258 mVorbis = rb_define_module_under (mOgg, "Vorbis");
260 eOgg = rb_define_class_under (mOgg, "OggError", rb_eStandardError);
261 eVorbis = rb_define_class_under (mVorbis, "VorbisError", eOgg);
263 cVT = rb_define_class_under (mVorbis, "Tagger", rb_cObject);
265 rb_define_alloc_func (cVT, c_alloc);
267 rb_define_singleton_method (cVT, "open", c_open, 1);
268 rb_define_method (cVT, "initialize", c_init, 1);
269 rb_define_method (cVT, "close", c_close, 0);
270 rb_define_method (cVT, "write", c_write, 0);
271 rb_define_method (cVT, "comments", c_comments, 0);
273 eVTError = rb_define_class_under (cVT, "TaggerError", eVorbis);
275 id_read = rb_intern ("read");
276 id_write = rb_intern ("write");
277 id_seek = rb_intern ("seek");
278 id_length = rb_intern ("length");
280 cComments = Init_Comments (mVorbis);