X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=ext%2Fext.c;h=46ce0d178d1090296f6a74b16e29b205e692c706;hb=f20bab80ca655b5b65a5d0d8660d2265a2410b00;hp=da2798f579495d9bdf81f0f2a8f84876335b3607;hpb=0ebbf4f00aa8b375b4a781b0a0397d0fce5466e1;p=ruby-vorbistagger.git diff --git a/ext/ext.c b/ext/ext.c index da2798f..46ce0d1 100644 --- a/ext/ext.c +++ b/ext/ext.c @@ -17,61 +17,28 @@ */ #include +#include #include +#include +#include #include "vcedit.h" #include "comments.h" -typedef struct { - VALUE io; - bool need_close; +#define CHECK_CLOSED(o) \ + if (!o->state) \ + rb_raise (eClosed, "closed stream"); +typedef struct { vcedit_state *state; - VALUE comments; } RbVorbisTagger; static VALUE c_close (VALUE self); -static VALUE cComments, eVTError, io_buf; -static ID id_read, id_write, id_seek, id_length; - -static size_t -on_read (void *ptr, size_t size, size_t nmemb, RbVorbisTagger *o) -{ - struct RString *buf; - size_t total = size * nmemb; - VALUE tmp; - - rb_str_resize (io_buf, size * nmemb); - - tmp = rb_funcall (o->io, id_read, 2, LONG2NUM (total), io_buf); - if (NIL_P (tmp)) - return 0; - - buf = RSTRING (tmp); - memcpy (ptr, buf->ptr, buf->len); - - return buf->len; -} - -static size_t -on_write (const void *ptr, size_t size, size_t nmemb, RbVorbisTagger *o) -{ - size_t total = size * nmemb; - - rb_str_resize (io_buf, total); - memcpy (RSTRING (io_buf)->ptr, ptr, total); - - return NUM2LONG (rb_io_write (o->io, io_buf)); -} - -static void -c_mark (RbVorbisTagger *o) -{ - rb_gc_mark (o->io); - rb_gc_mark (o->comments); -} +static VALUE cComments, eVT, eClosed, eOpen, eInvalidData, + eInvalidComment, eTempFile, eReopen; +static ID id_length; static void c_free (RbVorbisTagger *o) @@ -83,6 +50,12 @@ c_free (RbVorbisTagger *o) ruby_xfree (o); } +static void +c_mark (RbVorbisTagger *o) +{ + rb_gc_mark (o->comments); +} + static VALUE c_alloc (VALUE klass) { @@ -94,14 +67,12 @@ c_alloc (VALUE klass) /* * call-seq: * Ogg::Vorbis::Tagger.open(arg) -> object - * Ogg::Vorbis::Tagger.open(arg) { |object| block } -> nil + * Ogg::Vorbis::Tagger.open(arg) { |object| block } -> object * * If a block isn't specified, Ogg::Vorbis::Tagger.open is a synonym * for Ogg::Vorbis::Tagger.new. - * If a block is given, it will be invoked with the - * Ogg::Vorbis::Tagger object as a parameter, and the file or IO object - * will be automatically closed when the block terminates. - * The method always returns +nil+ in this case. + * If a block is given, it will be invoked with the * Ogg::Vorbis::Tagger + * object as a parameter. */ static VALUE c_open (VALUE klass, VALUE arg) @@ -116,51 +87,42 @@ c_open (VALUE klass, VALUE arg) /* * call-seq: - * Ogg::Vorbis::Tagger.new(arg) -> object + * Ogg::Vorbis::Tagger.new(filename) -> object * - * Returns a new Ogg::Vorbis::Tagger object for the specified argument. - * *arg* can either be an IO object or a filename. + * Returns a new Ogg::Vorbis::Tagger object for the specified file. * * FIXME: add optional mode argument (read-only or read-write) */ static VALUE -c_init (VALUE self, VALUE io) +c_init (VALUE self, VALUE filename) { RbVorbisTagger *o; vorbis_comment *vc; - int s, i; + int i; Data_Get_Struct (self, RbVorbisTagger, o); - /* is this actually an IO object or a filename? */ - if (rb_respond_to (io, id_read) && - rb_respond_to (io, id_write) && - rb_respond_to (io, id_seek)) - o->need_close = false; - else if (!NIL_P (rb_check_string_type (io))) { - io = rb_file_open (StringValuePtr (io), "rb+"); - o->need_close = true; - } else - rb_raise (rb_eArgError, "invalid argument"); - - o->io = io; + StringValue (filename); - o->state = vcedit_state_new (); + o->state = vcedit_state_new (StringValuePtr (filename)); if (!o->state) - rb_raise (eVTError, "vcedit_new_state() failed - %s", - vcedit_error (o->state)); - - s = vcedit_open_callbacks (o->state, o, - (vcedit_read_func) on_read, - (vcedit_write_func) on_write); - if (s < 0) - rb_raise (eVTError, "vcedit_open_callbacks() failed - %s", - vcedit_error (o->state)); + rb_raise (rb_eNoMemError, "Out of Memory"); + + switch (vcedit_open (o->state)) { + case VCEDIT_ERR_OPEN: + rb_raise (eOpen, "Cannot open file"); + case VCEDIT_ERR_INVAL: + rb_raise (eInvalidData, "Invalid data"); + default: + break; + } vc = vcedit_comments (o->state); - if (!vc) - rb_raise (eVTError, "vcedit_comments() failed - %s", - vcedit_error (o->state)); + + /* vcedit_open() succeeded, so vcedit_comments() cannot + * return NULL. + */ + assert (vc); /* check whether all comments are well-formed */ for (i = 0; i < vc->comments; i++) { @@ -168,7 +130,7 @@ c_init (VALUE self, VALUE io) ptr = strchr (content, '='); if (!ptr || ptr == content) - rb_raise (eVTError, "malformed comment - %s", content); + rb_raise (eInvalidComment, "invalid comment - %s", content); } o->comments = rb_class_new_instance (0, NULL, cComments); @@ -180,9 +142,11 @@ c_init (VALUE self, VALUE io) /* * call-seq: - * object.close -> object + * object.close -> nil * - * Closes *object* and returns it. + * Closes *object*. Further method calls on *object* will raise an + * Ogg::Vorbis::Tagger::ClosedStreamError exception. + * Returns +nil+. */ static VALUE c_close (VALUE self) @@ -191,13 +155,12 @@ c_close (VALUE self) Data_Get_Struct (self, RbVorbisTagger, o); + CHECK_CLOSED (o); + vcedit_state_unref (o->state); o->state = NULL; - if (o->need_close) - rb_io_close (o->io); - - return self; + return Qnil; } /* @@ -211,19 +174,23 @@ static VALUE c_write (VALUE self) { RbVorbisTagger *o; - int s; Data_Get_Struct (self, RbVorbisTagger, o); - comments_sync (o->comments, o->state); + CHECK_CLOSED (o); - /* seek back to BOF */ - rb_funcall (o->io, id_seek, 1, INT2FIX (0)); + comments_sync (o->comments, o->state); - s = vcedit_write (o->state, o); - if (s < 0) - rb_raise (rb_eIOError, "write failed - %s", - vcedit_error (o->state)); + switch (vcedit_write (o->state)) { + case VCEDIT_ERR_INVAL: + rb_raise (eInvalidData, "Invalid data"); + case VCEDIT_ERR_TMPFILE: + rb_raise (eTempFile, "Cannot create temporary file"); + case VCEDIT_ERR_REOPEN: + rb_raise (eReopen, "Cannot reopen file"); + default: + break; + } return rb_funcall (o->comments, id_length, 0); } @@ -242,6 +209,8 @@ c_comments (VALUE self) Data_Get_Struct (self, RbVorbisTagger, o); + CHECK_CLOSED (o); + return o->comments; } @@ -267,15 +236,16 @@ Init_vorbistagger_ext (void) rb_define_method (cVT, "write", c_write, 0); rb_define_method (cVT, "comments", c_comments, 0); - eVTError = rb_define_class_under (cVT, "TaggerError", eVorbis); + eVT = rb_define_class_under (cVT, "TaggerError", eVorbis); + eClosed = rb_define_class_under (cVT, "ClosedStreamError", eVT); + eOpen = rb_define_class_under (cVT, "OpenError", eVT); + eInvalidData = rb_define_class_under (cVT, "InvalidDataError", eVT); + eInvalidComment = rb_define_class_under (cVT, "InvalidCommentError", + eInvalidData); + eTempFile = rb_define_class_under (cVT, "TempFileError", eVT); + eReopen = rb_define_class_under (cVT, "ReopenError", eVT); - id_read = rb_intern ("read"); - id_write = rb_intern ("write"); - id_seek = rb_intern ("seek"); id_length = rb_intern ("length"); cComments = Init_Comments (mVorbis); - - io_buf = rb_str_buf_new (0); - rb_global_variable (&io_buf); }