]> git.sesse.net Git - vlc/blob - projects/mozilla/control/npolibvlc.cpp
Add isPluginRunning() and getPrivate<>(), and use them instead of the raw code.
[vlc] / projects / mozilla / control / npolibvlc.cpp
1 /*****************************************************************************
2  * npolibvlc.cpp: official Javascript APIs
3  *****************************************************************************
4  * Copyright (C) 2002-2006 the VideoLAN team
5  *
6  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 /* Mozilla stuff */
30 #ifdef HAVE_MOZILLA_CONFIG_H
31 #   include <mozilla-config.h>
32 #endif
33
34 #include "vlcplugin.h"
35 #include "npolibvlc.h"
36
37 /*
38 ** Local helper macros and function
39 */
40 #define COUNTNAMES(a,b,c) const int a::b = sizeof(a::c)/sizeof(NPUTF8 *)
41 #define RETURN_ON_EXCEPTION(this,ex) \
42     do { if( libvlc_exception_raised(&ex) ) \
43     { \
44         NPN_SetException(this, libvlc_exception_get_message(&ex)); \
45         libvlc_exception_clear(&ex); \
46         return INVOKERESULT_GENERIC_ERROR; \
47     } } while(false)
48
49 /*
50 ** implementation of libvlc root object
51 */
52
53 LibvlcRootNPObject::~LibvlcRootNPObject()
54 {
55     /*
56     ** When the plugin is destroyed, firefox takes it upon itself to
57     ** destroy all 'live' script objects and ignores refcounting.
58     ** Therefore we cannot safely assume that refcounting will control
59     ** lifespan of objects. Hence they are only lazily created on
60     ** request, so that firefox can take ownership, and are not released
61     ** when the plugin is destroyed.
62     */
63     if( isValid() )
64     {
65         if( audioObj    ) NPN_ReleaseObject(audioObj);
66         if( inputObj    ) NPN_ReleaseObject(inputObj);
67         if( logObj      ) NPN_ReleaseObject(logObj);
68         if( playlistObj ) NPN_ReleaseObject(playlistObj);
69         if( videoObj    ) NPN_ReleaseObject(videoObj);
70     }
71 }
72
73 const NPUTF8 * const LibvlcRootNPObject::propertyNames[] = 
74 {
75     "audio",
76     "input",
77     "log",
78     "playlist",
79     "video",
80     "VersionInfo",
81 };
82 COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames);
83
84 enum LibvlcRootNPObjectPropertyIds
85 {
86     ID_root_audio = 0,
87     ID_root_input,
88     ID_root_log,
89     ID_root_playlist,
90     ID_root_video,
91     ID_root_VersionInfo,
92 };
93
94 RuntimeNPObject::InvokeResult
95 LibvlcRootNPObject::getProperty(int index, NPVariant &result)
96 {
97     /* is plugin still running */
98     if( isPluginRunning() )
99     {
100         switch( index )
101         {
102             case ID_root_audio:
103                 // create child object in lazyman fashion to avoid
104                 // ownership problem with firefox
105                 if( ! audioObj )
106                     audioObj = NPN_CreateObject(_instance,
107                              RuntimeNPClass<LibvlcAudioNPObject>::getClass());
108                 OBJECT_TO_NPVARIANT(NPN_RetainObject(audioObj), result);
109                 return INVOKERESULT_NO_ERROR;
110             case ID_root_input:
111                 // create child object in lazyman fashion to avoid
112                 // ownership problem with firefox
113                 if( ! inputObj )
114                     inputObj = NPN_CreateObject(_instance,
115                              RuntimeNPClass<LibvlcInputNPObject>::getClass());
116                 OBJECT_TO_NPVARIANT(NPN_RetainObject(inputObj), result);
117                 return INVOKERESULT_NO_ERROR;
118             case ID_root_log:
119                 // create child object in lazyman fashion to avoid
120                 // ownership problem with firefox
121                 if( ! logObj )
122                     logObj = NPN_CreateObject(_instance,
123                                RuntimeNPClass<LibvlcLogNPObject>::getClass());
124                 OBJECT_TO_NPVARIANT(NPN_RetainObject(logObj), result);
125                 return INVOKERESULT_NO_ERROR;
126             case ID_root_playlist:
127                 // create child object in lazyman fashion to avoid
128                 // ownership problem with firefox
129                 if( ! playlistObj )
130                     playlistObj = NPN_CreateObject(_instance,
131                           RuntimeNPClass<LibvlcPlaylistNPObject>::getClass());
132                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistObj), result);
133                 return INVOKERESULT_NO_ERROR;
134             case ID_root_video:
135                 // create child object in lazyman fashion to avoid
136                 // ownership problem with firefox
137                 if( ! videoObj )
138                     videoObj = NPN_CreateObject(_instance,
139                              RuntimeNPClass<LibvlcVideoNPObject>::getClass());
140                 OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);
141                 return INVOKERESULT_NO_ERROR;
142             case ID_root_VersionInfo:
143             {
144                 int len = strlen(libvlc_get_version());
145                 NPUTF8 *retval =(NPUTF8*)NPN_MemAlloc(len);
146                 if( retval )
147                 {
148                     memcpy(retval, libvlc_get_version(), len);
149                     STRINGN_TO_NPVARIANT(retval, len, result);
150                 }
151                 else
152                 {
153                     NULL_TO_NPVARIANT(result);
154                 }
155                 return INVOKERESULT_NO_ERROR;
156             }
157             default:
158                 ;
159         }
160     }
161     return INVOKERESULT_GENERIC_ERROR;
162 }
163
164 const NPUTF8 * const LibvlcRootNPObject::methodNames[] =
165 {
166     "versionInfo",
167 };
168 COUNTNAMES(LibvlcRootNPObject,methodCount,methodNames);
169
170 enum LibvlcRootNPObjectMethodIds
171 {
172     ID_root_versionInfo,
173 };
174
175 RuntimeNPObject::InvokeResult LibvlcRootNPObject::invoke(int index,
176                   const NPVariant *args, uint32_t argCount, NPVariant &result)
177 {
178     /* is plugin still running */
179     if( isPluginRunning() )
180     {
181         libvlc_exception_t ex;
182         libvlc_exception_init(&ex);
183
184         switch( index )
185         {
186             case ID_root_versionInfo:
187                 if( argCount == 0 )
188                 {
189                     int len = strlen(libvlc_get_version());
190                     NPUTF8 *retval =(NPUTF8*)NPN_MemAlloc(len);
191                     if( retval )
192                     {
193                         memcpy(retval, libvlc_get_version(), len);
194                         STRINGN_TO_NPVARIANT(retval, len, result);
195                     }
196                     else
197                     {
198                         NULL_TO_NPVARIANT(result);
199                     }
200                     return INVOKERESULT_NO_ERROR;
201                 }
202                 return INVOKERESULT_NO_SUCH_METHOD;
203             default:
204                 ;
205         }
206     }
207     return INVOKERESULT_GENERIC_ERROR;
208 }
209
210 /*
211 ** implementation of libvlc audio object
212 */
213
214 const NPUTF8 * const LibvlcAudioNPObject::propertyNames[] = 
215 {
216     "mute",
217     "volume",
218     "track",
219     "channel",
220 };
221 COUNTNAMES(LibvlcAudioNPObject,propertyCount,propertyNames);
222
223 enum LibvlcAudioNPObjectPropertyIds
224 {
225     ID_audio_mute,
226     ID_audio_volume,
227     ID_audio_track,
228     ID_audio_channel,
229 };
230
231 RuntimeNPObject::InvokeResult
232 LibvlcAudioNPObject::getProperty(int index, NPVariant &result)
233 {
234     /* is plugin still running */
235     if( isPluginRunning() )
236     {
237         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
238         libvlc_exception_t ex;
239         libvlc_exception_init(&ex);
240
241         switch( index )
242         {
243             case ID_audio_mute:
244             {
245                 bool muted = libvlc_audio_get_mute(p_plugin->getVLC(), &ex);
246                 RETURN_ON_EXCEPTION(this,ex);
247                 BOOLEAN_TO_NPVARIANT(muted, result);
248                 return INVOKERESULT_NO_ERROR;
249             }
250             case ID_audio_volume:
251             {
252                 int volume = libvlc_audio_get_volume(p_plugin->getVLC(), &ex);
253                 RETURN_ON_EXCEPTION(this,ex);
254                 INT32_TO_NPVARIANT(volume, result);
255                 return INVOKERESULT_NO_ERROR;
256             }
257             case ID_audio_track:
258             {
259                 libvlc_media_player_t *p_md =
260                     libvlc_playlist_get_media_player(p_plugin->getVLC(), &ex);
261                 RETURN_ON_EXCEPTION(this,ex);
262                 int track = libvlc_audio_get_track(p_md, &ex);
263                 libvlc_media_player_release(p_md);
264                 RETURN_ON_EXCEPTION(this,ex);
265                 INT32_TO_NPVARIANT(track, result);
266                 return INVOKERESULT_NO_ERROR;
267             }
268             case ID_audio_channel:
269             {
270                 int channel = libvlc_audio_get_channel(p_plugin->getVLC(), &ex);
271                 RETURN_ON_EXCEPTION(this,ex);
272                 INT32_TO_NPVARIANT(channel, result);
273                 return INVOKERESULT_NO_ERROR;
274             }
275             default:
276                 ;
277         }
278     }
279     return INVOKERESULT_GENERIC_ERROR;
280 }
281
282 RuntimeNPObject::InvokeResult
283 LibvlcAudioNPObject::setProperty(int index, const NPVariant &value)
284 {
285     /* is plugin still running */
286     if( isPluginRunning() )
287     {
288         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
289         libvlc_exception_t ex;
290         libvlc_exception_init(&ex);
291
292         switch( index )
293         {
294             case ID_audio_mute:
295                 if( NPVARIANT_IS_BOOLEAN(value) )
296                 {
297                     libvlc_audio_set_mute(p_plugin->getVLC(),
298                                           NPVARIANT_TO_BOOLEAN(value), &ex);
299                     RETURN_ON_EXCEPTION(this,ex);
300                     return INVOKERESULT_NO_ERROR;
301                 }
302                 return INVOKERESULT_INVALID_VALUE;
303             case ID_audio_volume:
304                 if( isNumberValue(value) )
305                 {
306                     libvlc_audio_set_volume(p_plugin->getVLC(),
307                                             numberValue(value), &ex);
308                     RETURN_ON_EXCEPTION(this,ex);
309                     return INVOKERESULT_NO_ERROR;
310                 }
311                 return INVOKERESULT_INVALID_VALUE;
312             case ID_audio_track:
313                 if( isNumberValue(value) )
314                 {
315                     libvlc_media_player_t *p_md =
316                       libvlc_playlist_get_media_player(p_plugin->getVLC(), &ex);
317                     RETURN_ON_EXCEPTION(this,ex);
318                     libvlc_audio_set_track(p_md, numberValue(value), &ex);
319                     libvlc_media_player_release(p_md);
320                     RETURN_ON_EXCEPTION(this,ex);
321                     return INVOKERESULT_NO_ERROR;
322                 }
323                 return INVOKERESULT_INVALID_VALUE;
324             case ID_audio_channel:
325                 if( isNumberValue(value) )
326                 {
327                     libvlc_audio_set_channel(p_plugin->getVLC(),
328                                              numberValue(value), &ex);
329                     RETURN_ON_EXCEPTION(this,ex);
330                     return INVOKERESULT_NO_ERROR;
331                 }
332                 return INVOKERESULT_INVALID_VALUE;
333             default:
334                 ;
335         }
336     }
337     return INVOKERESULT_GENERIC_ERROR;
338 }
339
340 const NPUTF8 * const LibvlcAudioNPObject::methodNames[] =
341 {
342     "toggleMute",
343 };
344 COUNTNAMES(LibvlcAudioNPObject,methodCount,methodNames);
345
346 enum LibvlcAudioNPObjectMethodIds
347 {
348     ID_audio_togglemute,
349 };
350
351 RuntimeNPObject::InvokeResult
352 LibvlcAudioNPObject::invoke(int index, const NPVariant *args,
353                             uint32_t argCount, NPVariant &result)
354 {
355     /* is plugin still running */
356     if( isPluginRunning() )
357     {
358         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
359         libvlc_exception_t ex;
360         libvlc_exception_init(&ex);
361
362         switch( index )
363         {
364             case ID_audio_togglemute:
365                 if( argCount == 0 )
366                 {
367                     libvlc_audio_toggle_mute(p_plugin->getVLC(), &ex);
368                     RETURN_ON_EXCEPTION(this,ex);
369                     VOID_TO_NPVARIANT(result);
370                     return INVOKERESULT_NO_ERROR;
371                 }
372                 return INVOKERESULT_NO_SUCH_METHOD;
373             default:
374                 ;
375         }
376     }
377     return INVOKERESULT_GENERIC_ERROR;
378 }
379
380 /*
381 ** implementation of libvlc input object
382 */
383
384 const NPUTF8 * const LibvlcInputNPObject::propertyNames[] = 
385 {
386     "length",
387     "position",
388     "time",
389     "state",
390     "rate",
391     "fps",
392     "hasVout",
393 };
394 COUNTNAMES(LibvlcInputNPObject,propertyCount,propertyNames);
395
396 enum LibvlcInputNPObjectPropertyIds
397 {
398     ID_input_length,
399     ID_input_position,
400     ID_input_time,
401     ID_input_state,
402     ID_input_rate,
403     ID_input_fps,
404     ID_input_hasvout,
405 };
406
407 RuntimeNPObject::InvokeResult
408 LibvlcInputNPObject::getProperty(int index, NPVariant &result)
409 {
410     /* is plugin still running */
411     if( isPluginRunning() )
412     {
413         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
414         libvlc_exception_t ex;
415         libvlc_exception_init(&ex);
416
417         libvlc_media_player_t *p_md =
418                     libvlc_playlist_get_media_player(p_plugin->getVLC(), &ex);
419         if( libvlc_exception_raised(&ex) )
420         {
421             if( index != ID_input_state )
422             {
423                 NPN_SetException(this, libvlc_exception_get_message(&ex));
424                 libvlc_exception_clear(&ex);
425                 return INVOKERESULT_GENERIC_ERROR;
426             }
427             else
428             {
429                 /* for input state, return CLOSED rather than an exception */
430                 INT32_TO_NPVARIANT(0, result);
431                 libvlc_exception_clear(&ex);
432                 return INVOKERESULT_NO_ERROR;
433             }
434         }
435
436         switch( index )
437         {
438             case ID_input_length:
439             {
440                 double val = (double)libvlc_media_player_get_length(p_md, &ex);
441                 libvlc_media_player_release(p_md);
442                 RETURN_ON_EXCEPTION(this,ex);
443                 DOUBLE_TO_NPVARIANT(val, result);
444                 return INVOKERESULT_NO_ERROR;
445             }
446             case ID_input_position:
447             {
448                 double val = libvlc_media_player_get_position(p_md, &ex);
449                 libvlc_media_player_release(p_md);
450                 RETURN_ON_EXCEPTION(this,ex);
451                 DOUBLE_TO_NPVARIANT(val, result);
452                 return INVOKERESULT_NO_ERROR;
453             }
454             case ID_input_time:
455             {
456                 double val = (double)libvlc_media_player_get_time(p_md, &ex);
457                 libvlc_media_player_release(p_md);
458                 RETURN_ON_EXCEPTION(this,ex);
459                 DOUBLE_TO_NPVARIANT(val, result);
460                 return INVOKERESULT_NO_ERROR;
461             }
462             case ID_input_state:
463             {
464                 int val = libvlc_media_player_get_state(p_md, &ex);
465                 libvlc_media_player_release(p_md);
466                 RETURN_ON_EXCEPTION(this,ex);
467                 INT32_TO_NPVARIANT(val, result);
468                 return INVOKERESULT_NO_ERROR;
469             }
470             case ID_input_rate:
471             {
472                 float val = libvlc_media_player_get_rate(p_md, &ex);
473                 libvlc_media_player_release(p_md);
474                 RETURN_ON_EXCEPTION(this,ex);
475                 DOUBLE_TO_NPVARIANT(val, result);
476                 return INVOKERESULT_NO_ERROR;
477             }
478             case ID_input_fps:
479             {
480                 double val = libvlc_media_player_get_fps(p_md, &ex);
481                 libvlc_media_player_release(p_md);
482                 RETURN_ON_EXCEPTION(this,ex);
483                 DOUBLE_TO_NPVARIANT(val, result);
484                 return INVOKERESULT_NO_ERROR;
485             }
486             case ID_input_hasvout:
487             {
488                 bool val = libvlc_media_player_has_vout(p_md, &ex);
489                 libvlc_media_player_release(p_md);
490                 RETURN_ON_EXCEPTION(this,ex);
491                 BOOLEAN_TO_NPVARIANT(val, result);
492                 return INVOKERESULT_NO_ERROR;
493             }
494             default:
495                 ;
496         }
497         libvlc_media_player_release(p_md);
498     }
499     return INVOKERESULT_GENERIC_ERROR;
500 }
501
502 RuntimeNPObject::InvokeResult
503 LibvlcInputNPObject::setProperty(int index, const NPVariant &value)
504 {
505     /* is plugin still running */
506     if( isPluginRunning() )
507     {
508         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
509         libvlc_exception_t ex;
510         libvlc_exception_init(&ex);
511
512         libvlc_media_player_t *p_md =
513                     libvlc_playlist_get_media_player(p_plugin->getVLC(), &ex);
514         RETURN_ON_EXCEPTION(this,ex);
515
516         switch( index )
517         {
518             case ID_input_position:
519             {
520                 if( ! NPVARIANT_IS_DOUBLE(value) )
521                 {
522                     libvlc_media_player_release(p_md);
523                     return INVOKERESULT_INVALID_VALUE;
524                 }
525
526                 float val = (float)NPVARIANT_TO_DOUBLE(value);
527                 libvlc_media_player_set_position(p_md, val, &ex);
528                 libvlc_media_player_release(p_md);
529                 RETURN_ON_EXCEPTION(this,ex);
530                 return INVOKERESULT_NO_ERROR;
531             }
532             case ID_input_time:
533             {
534                 int64_t val;
535                 if( NPVARIANT_IS_INT32(value) )
536                     val = (int64_t)NPVARIANT_TO_INT32(value);
537                 else if( NPVARIANT_IS_DOUBLE(value) )
538                     val = (int64_t)NPVARIANT_TO_DOUBLE(value);
539                 else
540                 {
541                     libvlc_media_player_release(p_md);
542                     return INVOKERESULT_INVALID_VALUE;
543                 }
544
545                 libvlc_media_player_set_time(p_md, val, &ex);
546                 libvlc_media_player_release(p_md);
547                 RETURN_ON_EXCEPTION(this,ex);
548                 return INVOKERESULT_NO_ERROR;
549             }
550             case ID_input_rate:
551             {
552                 float val;
553                 if( NPVARIANT_IS_INT32(value) )
554                     val = (float)NPVARIANT_TO_INT32(value);
555                 else if( NPVARIANT_IS_DOUBLE(value) )
556                     val = (float)NPVARIANT_TO_DOUBLE(value);
557                 else
558                 {
559                     libvlc_media_player_release(p_md);
560                     return INVOKERESULT_INVALID_VALUE;
561                 }
562
563                 libvlc_media_player_set_rate(p_md, val, &ex);
564                 libvlc_media_player_release(p_md);
565                 RETURN_ON_EXCEPTION(this,ex);
566                 return INVOKERESULT_NO_ERROR;
567             }
568             default:
569                 ;
570         }
571         libvlc_media_player_release(p_md);
572     }
573     return INVOKERESULT_GENERIC_ERROR;
574 }
575
576 const NPUTF8 * const LibvlcInputNPObject::methodNames[] =
577 {
578     /* no methods */
579 };
580
581 COUNTNAMES(LibvlcInputNPObject,methodCount,methodNames);
582
583 /*
584 ** implementation of libvlc message object
585 */
586
587 const NPUTF8 * const LibvlcMessageNPObject::propertyNames[] = 
588 {
589     "severity",
590     "type",
591     "name",
592     "header",
593     "message",
594 };
595 COUNTNAMES(LibvlcMessageNPObject,propertyCount,propertyNames);
596
597 enum LibvlcMessageNPObjectPropertyIds
598 {
599     ID_message_severity,
600     ID_message_type,
601     ID_message_name,
602     ID_message_header,
603     ID_message_message,
604 };
605
606 RuntimeNPObject::InvokeResult
607 LibvlcMessageNPObject::getProperty(int index, NPVariant &result)
608 {
609     /* is plugin still running */
610     if( isPluginRunning() )
611     {
612         switch( index )
613         {
614             case ID_message_severity:
615             {
616                 INT32_TO_NPVARIANT(_msg.i_severity, result);
617                 return INVOKERESULT_NO_ERROR;
618             }
619             case ID_message_type:
620             {
621                 if( _msg.psz_type )
622                 {
623                     int len = strlen(_msg.psz_type);
624                     NPUTF8* retval = (NPUTF8*)NPN_MemAlloc(len);
625                     if( retval )
626                     {
627                         memcpy(retval, _msg.psz_type, len);
628                         STRINGN_TO_NPVARIANT(retval, len, result);
629                     }
630                 }
631                 else
632                 {
633                     NULL_TO_NPVARIANT(result);
634                 }
635                 return INVOKERESULT_NO_ERROR;
636             }
637             case ID_message_name:
638             {
639                 if( _msg.psz_name )
640                 {
641                     int len = strlen(_msg.psz_name);
642                     NPUTF8* retval = (NPUTF8*)NPN_MemAlloc(len);
643                     if( retval )
644                     {
645                         memcpy(retval, _msg.psz_name, len);
646                         STRINGN_TO_NPVARIANT(retval, len, result);
647                     }
648                 }
649                 else
650                 {
651                     NULL_TO_NPVARIANT(result);
652                 }
653                 return INVOKERESULT_NO_ERROR;
654             }
655             case ID_message_header:
656             {
657                 if( _msg.psz_header )
658                 {
659                     int len = strlen(_msg.psz_header);
660                     NPUTF8* retval = (NPUTF8*)NPN_MemAlloc(len);
661                     if( retval )
662                     {
663                         memcpy(retval, _msg.psz_header, len);
664                         STRINGN_TO_NPVARIANT(retval, len, result);
665                     }
666                 }
667                 else
668                 {
669                     NULL_TO_NPVARIANT(result);
670                 }
671                 return INVOKERESULT_NO_ERROR;
672             }
673             case ID_message_message:
674             {
675                 if( _msg.psz_message )
676                 {
677                     int len = strlen(_msg.psz_message);
678                     NPUTF8* retval = (NPUTF8*)NPN_MemAlloc(len);
679                     if( retval )
680                     {
681                         memcpy(retval, _msg.psz_message, len);
682                         STRINGN_TO_NPVARIANT(retval, len, result);
683                     }
684                 }
685                 else
686                 {
687                     NULL_TO_NPVARIANT(result);
688                 }
689                 return INVOKERESULT_NO_ERROR;
690             }
691             default:
692                 ;
693         }
694     }
695     return INVOKERESULT_GENERIC_ERROR;
696 }
697
698 const NPUTF8 * const LibvlcMessageNPObject::methodNames[] =
699 {
700     /* no methods */
701 };
702 COUNTNAMES(LibvlcMessageNPObject,methodCount,methodNames);
703
704 /*
705 ** implementation of libvlc message iterator object
706 */
707
708 LibvlcMessageIteratorNPObject::LibvlcMessageIteratorNPObject(NPP instance,
709                                                       const NPClass *aClass) :
710     RuntimeNPObject(instance, aClass),
711     _p_iter(NULL)
712 {
713     // XXX FIXME use _instance or instance in this method?
714
715     /* is plugin still running */
716     if( instance->pdata )
717     {
718         VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(instance->pdata);
719         libvlc_log_t *p_log = p_plugin->getLog();
720         if( p_log )
721         {
722             _p_iter = libvlc_log_get_iterator(p_log, NULL);
723         }
724     }
725 };
726
727 LibvlcMessageIteratorNPObject::~LibvlcMessageIteratorNPObject()
728 {
729     if( _p_iter )
730         libvlc_log_iterator_free(_p_iter, NULL);
731 }
732
733 const NPUTF8 * const LibvlcMessageIteratorNPObject::propertyNames[] = 
734 {
735     "hasNext",
736 };
737 COUNTNAMES(LibvlcMessageIteratorNPObject,propertyCount,propertyNames);
738
739 enum LibvlcMessageIteratorNPObjectPropertyIds
740 {
741     ID_messageiterator_hasNext,
742 };
743
744 RuntimeNPObject::InvokeResult
745 LibvlcMessageIteratorNPObject::getProperty(int index, NPVariant &result)
746 {
747     /* is plugin still running */
748     if( isPluginRunning() )
749     {
750         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
751         switch( index )
752         {
753             case ID_messageiterator_hasNext:
754             {
755                 if( _p_iter && p_plugin->getLog() )
756                 {
757                     libvlc_exception_t ex;
758                     libvlc_exception_init(&ex);
759
760                     BOOLEAN_TO_NPVARIANT(
761                          libvlc_log_iterator_has_next(_p_iter, &ex), result );
762                     RETURN_ON_EXCEPTION(this,ex);
763                 }
764                 else
765                 {
766                     BOOLEAN_TO_NPVARIANT(0, result);
767                 }
768                 return INVOKERESULT_NO_ERROR;
769             }
770             default:
771                 ;
772         }
773     }
774     return INVOKERESULT_GENERIC_ERROR;
775 }
776
777 const NPUTF8 * const LibvlcMessageIteratorNPObject::methodNames[] =
778 {
779     "next",
780 };
781 COUNTNAMES(LibvlcMessageIteratorNPObject,methodCount,methodNames);
782
783 enum LibvlcMessageIteratorNPObjectMethodIds
784 {
785     ID_messageiterator_next,
786 };
787
788 RuntimeNPObject::InvokeResult
789 LibvlcMessageIteratorNPObject::invoke(int index, const NPVariant *args,
790                                       uint32_t argCount, NPVariant &result)
791 {
792     /* is plugin still running */
793     if( isPluginRunning() )
794     {
795         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
796         libvlc_exception_t ex;
797         libvlc_exception_init(&ex);
798
799         switch( index )
800         {
801             case ID_messageiterator_next:
802                 if( argCount == 0 )
803                 {
804                     if( _p_iter && p_plugin->getLog() )
805                     {
806                         struct libvlc_log_message_t buffer;
807
808                         buffer.sizeof_msg = sizeof(buffer);
809
810                         libvlc_log_iterator_next(_p_iter, &buffer, &ex);
811                         RETURN_ON_EXCEPTION(this,ex);
812
813                         LibvlcMessageNPObject* message =
814                             static_cast<LibvlcMessageNPObject*>(
815                             NPN_CreateObject(_instance, RuntimeNPClass<
816                             LibvlcMessageNPObject>::getClass()));
817                         if( message )
818                         {
819                             message->setMessage(buffer);
820                             OBJECT_TO_NPVARIANT(message, result);
821                             return INVOKERESULT_NO_ERROR;
822                         }
823                         return INVOKERESULT_OUT_OF_MEMORY;
824                     }
825                     return INVOKERESULT_GENERIC_ERROR;
826                 }
827                 return INVOKERESULT_NO_SUCH_METHOD;
828             default:
829                 ;
830         }
831     }
832     return INVOKERESULT_GENERIC_ERROR;
833 }
834  
835 /*
836 ** implementation of libvlc message object
837 */
838
839 const NPUTF8 * const LibvlcMessagesNPObject::propertyNames[] = 
840 {
841     "count",
842 };
843 COUNTNAMES(LibvlcMessagesNPObject,propertyCount,propertyNames);
844
845 enum LibvlcMessagesNPObjectPropertyIds
846 {
847     ID_messages_count,
848 };
849
850 RuntimeNPObject::InvokeResult
851 LibvlcMessagesNPObject::getProperty(int index, NPVariant &result)
852 {
853     /* is plugin still running */
854     if( isPluginRunning() )
855     {
856         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
857         switch( index )
858         {
859             case ID_messages_count:
860             {
861                 libvlc_log_t *p_log = p_plugin->getLog();
862                 if( p_log )
863                 {
864                     libvlc_exception_t ex;
865                     libvlc_exception_init(&ex);
866
867                     INT32_TO_NPVARIANT(libvlc_log_count(p_log, &ex), result);
868                     RETURN_ON_EXCEPTION(this,ex);
869                 }
870                 else
871                 {
872                     INT32_TO_NPVARIANT(0, result);
873                 }
874                 return INVOKERESULT_NO_ERROR;
875             }
876             default:
877                 ;
878         }
879     }
880     return INVOKERESULT_GENERIC_ERROR;
881 }
882
883 const NPUTF8 * const LibvlcMessagesNPObject::methodNames[] =
884 {
885     "clear",
886     "iterator",
887 };
888 COUNTNAMES(LibvlcMessagesNPObject,methodCount,methodNames);
889
890 enum LibvlcMessagesNPObjectMethodIds
891 {
892     ID_messages_clear,
893     ID_messages_iterator,
894 };
895
896 RuntimeNPObject::InvokeResult
897 LibvlcMessagesNPObject::invoke(int index, const NPVariant *args,
898                                uint32_t argCount, NPVariant &result)
899 {
900     /* is plugin still running */
901     if( isPluginRunning() )
902     {
903         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
904         libvlc_exception_t ex;
905         libvlc_exception_init(&ex);
906
907         switch( index )
908         {
909             case ID_messages_clear:
910                 if( argCount == 0 )
911                 {
912                     libvlc_log_t *p_log = p_plugin->getLog();
913                     if( p_log )
914                     {
915                         libvlc_log_clear(p_log, &ex);
916                         RETURN_ON_EXCEPTION(this,ex);
917                     }
918                     return INVOKERESULT_NO_ERROR;
919                 }
920                 return INVOKERESULT_NO_SUCH_METHOD;
921
922             case ID_messages_iterator:
923                 if( argCount == 0 )
924                 {
925                     LibvlcMessageIteratorNPObject* iter =
926                         static_cast<LibvlcMessageIteratorNPObject*>(
927                         NPN_CreateObject(_instance, RuntimeNPClass<
928                         LibvlcMessageIteratorNPObject>::getClass()));
929                     if( iter )
930                     {
931                         OBJECT_TO_NPVARIANT(iter, result);
932                         return INVOKERESULT_NO_ERROR;
933                     }
934                     return INVOKERESULT_OUT_OF_MEMORY;
935                 }
936                 return INVOKERESULT_NO_SUCH_METHOD;
937
938             default:
939                 ;
940         }
941     }
942     return INVOKERESULT_GENERIC_ERROR;
943 }
944
945  
946 /*
947 ** implementation of libvlc message object
948 */
949
950
951 LibvlcLogNPObject::~LibvlcLogNPObject()
952 {
953     if( isValid() )
954     {
955         if( messagesObj ) NPN_ReleaseObject(messagesObj);
956     }
957 };
958
959 const NPUTF8 * const LibvlcLogNPObject::propertyNames[] = 
960 {
961     "messages",
962     "verbosity",
963 };
964 COUNTNAMES(LibvlcLogNPObject,propertyCount,propertyNames);
965
966 enum LibvlcLogNPObjectPropertyIds
967 {
968     ID_log_messages,
969     ID_log_verbosity,
970 };
971
972 RuntimeNPObject::InvokeResult
973 LibvlcLogNPObject::getProperty(int index, NPVariant &result)
974 {
975     /* is plugin still running */
976     if( isPluginRunning() )
977     {
978         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
979         libvlc_exception_t ex;
980         libvlc_exception_init(&ex);
981
982         switch( index )
983         {
984             case ID_log_messages:
985             {
986                 // create child object in lazyman fashion to avoid
987                 // ownership problem with firefox
988                 if( ! messagesObj )
989                     messagesObj = NPN_CreateObject(_instance,
990                           RuntimeNPClass<LibvlcMessagesNPObject>::getClass());
991                 OBJECT_TO_NPVARIANT(NPN_RetainObject(messagesObj), result);
992                 return INVOKERESULT_NO_ERROR;
993             }
994             case ID_log_verbosity:
995             {
996                 if( p_plugin->getLog() )
997                 {
998                     INT32_TO_NPVARIANT( libvlc_get_log_verbosity(
999                                         p_plugin->getVLC(), &ex), result);
1000                     RETURN_ON_EXCEPTION(this,ex);
1001                 }
1002                 else
1003                 {
1004                     /* log is not enabled, return -1 */
1005                     DOUBLE_TO_NPVARIANT(-1.0, result);
1006                 }
1007                 return INVOKERESULT_NO_ERROR;
1008             }
1009             default:
1010                 ;
1011         }
1012     }
1013     return INVOKERESULT_GENERIC_ERROR;
1014 }
1015
1016 RuntimeNPObject::InvokeResult
1017 LibvlcLogNPObject::setProperty(int index, const NPVariant &value)
1018 {
1019     /* is plugin still running */
1020     if( isPluginRunning() )
1021     {
1022         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1023         libvlc_exception_t ex;
1024         libvlc_exception_init(&ex);
1025
1026         switch( index )
1027         {
1028             case ID_log_verbosity:
1029                 if( isNumberValue(value) )
1030                 {
1031                     libvlc_instance_t* p_libvlc = p_plugin->getVLC();
1032                     libvlc_log_t *p_log = p_plugin->getLog();
1033                     int verbosity = numberValue(value);
1034                     if( verbosity >= 0 )
1035                     {
1036                         if( !p_log )
1037                         {
1038                             p_log = libvlc_log_open(p_libvlc, &ex);
1039                             RETURN_ON_EXCEPTION(this,ex);
1040                             p_plugin->setLog(p_log);
1041                         }
1042                         libvlc_set_log_verbosity(p_libvlc, (unsigned)verbosity, &ex);
1043                         RETURN_ON_EXCEPTION(this,ex);
1044                     }
1045                     else if( p_log )
1046                     {
1047                         /* close log  when verbosity is set to -1 */
1048                         p_plugin->setLog(NULL);
1049                         libvlc_log_close(p_log, &ex);
1050                         RETURN_ON_EXCEPTION(this,ex);
1051                     }
1052                     return INVOKERESULT_NO_ERROR;
1053                 }
1054                 return INVOKERESULT_INVALID_VALUE;
1055             default:
1056                 ;
1057         }
1058     }
1059     return INVOKERESULT_GENERIC_ERROR;
1060 }
1061
1062 const NPUTF8 * const LibvlcLogNPObject::methodNames[] =
1063 {
1064     /* no methods */
1065 };
1066 COUNTNAMES(LibvlcLogNPObject,methodCount,methodNames);
1067
1068 /*
1069 ** implementation of libvlc playlist items object
1070 */
1071
1072 const NPUTF8 * const LibvlcPlaylistItemsNPObject::propertyNames[] = 
1073 {
1074     "count",
1075 };
1076 COUNTNAMES(LibvlcPlaylistItemsNPObject,propertyCount,propertyNames);
1077
1078 enum LibvlcPlaylistItemsNPObjectPropertyIds
1079 {
1080     ID_playlistitems_count,
1081 };
1082
1083 RuntimeNPObject::InvokeResult
1084 LibvlcPlaylistItemsNPObject::getProperty(int index, NPVariant &result)
1085 {
1086     /* is plugin still running */
1087     if( isPluginRunning() )
1088     {
1089         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1090         libvlc_exception_t ex;
1091         libvlc_exception_init(&ex);
1092
1093         switch( index )
1094         {
1095             case ID_playlistitems_count:
1096             {
1097                 libvlc_playlist_lock(p_plugin->getVLC());
1098                 int val = libvlc_playlist_items_count(p_plugin->getVLC(), &ex);
1099                 libvlc_playlist_unlock(p_plugin->getVLC());
1100                 RETURN_ON_EXCEPTION(this,ex);
1101                 INT32_TO_NPVARIANT(val, result);
1102                 return INVOKERESULT_NO_ERROR;
1103             }
1104             default:
1105                 ;
1106         }
1107     }
1108     return INVOKERESULT_GENERIC_ERROR;
1109 }
1110
1111 const NPUTF8 * const LibvlcPlaylistItemsNPObject::methodNames[] =
1112 {
1113     "clear",
1114     "remove",
1115 };
1116 COUNTNAMES(LibvlcPlaylistItemsNPObject,methodCount,methodNames);
1117
1118 enum LibvlcPlaylistItemsNPObjectMethodIds
1119 {
1120     ID_playlistitems_clear,
1121     ID_playlistitems_remove,
1122 };
1123
1124 RuntimeNPObject::InvokeResult
1125 LibvlcPlaylistItemsNPObject::invoke(int index, const NPVariant *args,
1126                                     uint32_t argCount, NPVariant &result)
1127 {
1128     /* is plugin still running */
1129     if( isPluginRunning() )
1130     {
1131         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1132         libvlc_exception_t ex;
1133         libvlc_exception_init(&ex);
1134
1135         switch( index )
1136         {
1137             case ID_playlistitems_clear:
1138                 if( argCount == 0 )
1139                 {
1140                     libvlc_playlist_clear(p_plugin->getVLC(), &ex);
1141                     RETURN_ON_EXCEPTION(this,ex);
1142                     VOID_TO_NPVARIANT(result);
1143                     return INVOKERESULT_NO_ERROR;
1144                 }
1145                 return INVOKERESULT_NO_SUCH_METHOD;
1146             case ID_playlistitems_remove:
1147                 if( (argCount == 1) && isNumberValue(args[0]) )
1148                 {
1149                     libvlc_playlist_delete_item(p_plugin->getVLC(),
1150                                                 numberValue(args[0]), &ex);
1151                     RETURN_ON_EXCEPTION(this,ex);
1152                     VOID_TO_NPVARIANT(result);
1153                     return INVOKERESULT_NO_ERROR;
1154                 }
1155                 return INVOKERESULT_NO_SUCH_METHOD;
1156             default:
1157                 ;
1158         }
1159     }
1160     return INVOKERESULT_GENERIC_ERROR;
1161 }
1162
1163 /*
1164 ** implementation of libvlc playlist object
1165 */
1166
1167
1168 LibvlcPlaylistNPObject::~LibvlcPlaylistNPObject()
1169 {
1170     if( isValid() )
1171     {
1172         if( playlistItemsObj ) NPN_ReleaseObject(playlistItemsObj);
1173     }
1174 };
1175
1176 const NPUTF8 * const LibvlcPlaylistNPObject::propertyNames[] = 
1177 {
1178     "itemCount", /* deprecated */
1179     "isPlaying",
1180     "items",
1181 };
1182 COUNTNAMES(LibvlcPlaylistNPObject,propertyCount,propertyNames);
1183
1184 enum LibvlcPlaylistNPObjectPropertyIds
1185 {
1186     ID_playlist_itemcount,
1187     ID_playlist_isplaying,
1188     ID_playlist_items,
1189 };
1190
1191 RuntimeNPObject::InvokeResult
1192 LibvlcPlaylistNPObject::getProperty(int index, NPVariant &result)
1193 {
1194     /* is plugin still running */
1195     if( isPluginRunning() )
1196     {
1197         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1198         libvlc_exception_t ex;
1199         libvlc_exception_init(&ex);
1200
1201         switch( index )
1202         {
1203             case ID_playlist_itemcount: /* deprecated */
1204             {
1205                 libvlc_playlist_lock(p_plugin->getVLC());
1206                 int val = libvlc_playlist_items_count(p_plugin->getVLC(), &ex);
1207                 libvlc_playlist_unlock(p_plugin->getVLC());
1208                 RETURN_ON_EXCEPTION(this,ex);
1209                 INT32_TO_NPVARIANT(val, result);
1210                 return INVOKERESULT_NO_ERROR;
1211             }
1212             case ID_playlist_isplaying:
1213             {
1214                 libvlc_playlist_lock(p_plugin->getVLC());
1215                 int val = libvlc_playlist_isplaying(p_plugin->getVLC(), &ex);
1216                 libvlc_playlist_unlock(p_plugin->getVLC());
1217                 RETURN_ON_EXCEPTION(this,ex);
1218                 BOOLEAN_TO_NPVARIANT(val, result);
1219                 return INVOKERESULT_NO_ERROR;
1220             }
1221             case ID_playlist_items:
1222             {
1223                 // create child object in lazyman fashion to avoid
1224                 // ownership problem with firefox
1225                 if( ! playlistItemsObj )
1226                     playlistItemsObj =
1227                         NPN_CreateObject(_instance, RuntimeNPClass<
1228                         LibvlcPlaylistItemsNPObject>::getClass());
1229                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistItemsObj), result);
1230                 return INVOKERESULT_NO_ERROR;
1231             }
1232             default:
1233                 ;
1234         }
1235     }
1236     return INVOKERESULT_GENERIC_ERROR;
1237 }
1238
1239 const NPUTF8 * const LibvlcPlaylistNPObject::methodNames[] =
1240 {
1241     "add",
1242     "play",
1243     "playItem",
1244     "togglePause",
1245     "stop",
1246     "next",
1247     "prev",
1248     "clear", /* deprecated */
1249     "removeItem", /* deprecated */
1250 };
1251 COUNTNAMES(LibvlcPlaylistNPObject,methodCount,methodNames);
1252
1253 enum LibvlcPlaylistNPObjectMethodIds
1254 {
1255     ID_playlist_add,
1256     ID_playlist_play,
1257     ID_playlist_playItem,
1258     ID_playlist_togglepause,
1259     ID_playlist_stop,
1260     ID_playlist_next,
1261     ID_playlist_prev,
1262     ID_playlist_clear,
1263     ID_playlist_removeitem
1264 };
1265
1266 RuntimeNPObject::InvokeResult
1267 LibvlcPlaylistNPObject::invoke(int index, const NPVariant *args,
1268                                uint32_t argCount, NPVariant &result)
1269 {
1270     /* is plugin still running */
1271     if( isPluginRunning() )
1272     {
1273         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1274         libvlc_exception_t ex;
1275         libvlc_exception_init(&ex);
1276
1277         switch( index )
1278         {
1279             case ID_playlist_add:
1280             {
1281                 if( (argCount < 1) || (argCount > 3) )
1282                     return INVOKERESULT_NO_SUCH_METHOD;
1283
1284                 char *url = NULL;
1285
1286                 // grab URL
1287                 if( NPVARIANT_IS_STRING(args[0]) )
1288                 {
1289                     char *s = stringValue(NPVARIANT_TO_STRING(args[0]));
1290                     if( s )
1291                     {
1292                         url = p_plugin->getAbsoluteURL(s);
1293                         if( url )
1294                             free(s);
1295                         else
1296                             // problem with combining url, use argument
1297                             url = s;
1298                     }
1299                     else
1300                         return INVOKERESULT_OUT_OF_MEMORY;
1301                 }
1302                 else
1303                     return INVOKERESULT_NO_SUCH_METHOD;
1304
1305                 char *name = NULL;
1306
1307                 // grab name if available
1308                 if( argCount > 1 )
1309                 {
1310                     if( NPVARIANT_IS_NULL(args[1]) )
1311                     {
1312                         // do nothing
1313                     }
1314                     else if( NPVARIANT_IS_STRING(args[1]) )
1315                     {
1316                         name = stringValue(NPVARIANT_TO_STRING(args[1]));
1317                     }
1318                     else
1319                     {
1320                         free(url);
1321                         return INVOKERESULT_INVALID_VALUE;
1322                     }
1323                 }
1324
1325                 int i_options = 0;
1326                 char** ppsz_options = NULL;
1327
1328                 // grab options if available
1329                 if( argCount > 2 )
1330                 {
1331                     if( NPVARIANT_IS_NULL(args[2]) )
1332                     {
1333                         // do nothing
1334                     }
1335                     else if( NPVARIANT_IS_STRING(args[2]) )
1336                     {
1337                         parseOptions(NPVARIANT_TO_STRING(args[2]),
1338                                      &i_options, &ppsz_options);
1339
1340                     }
1341                     else if( NPVARIANT_IS_OBJECT(args[2]) )
1342                     {
1343                         parseOptions(NPVARIANT_TO_OBJECT(args[2]),
1344                                      &i_options, &ppsz_options);
1345                     }
1346                     else
1347                     {
1348                         free(url);
1349                         free(name);
1350                         return INVOKERESULT_INVALID_VALUE;
1351                     }
1352                 }
1353
1354                 int item = libvlc_playlist_add_extended_untrusted(
1355                                p_plugin->getVLC(), url, name, i_options,
1356                                const_cast<const char **>(ppsz_options), &ex);
1357                 free(url);
1358                 free(name);
1359                 for( int i=0; i< i_options; ++i )
1360                 {
1361                     free(ppsz_options[i]);
1362                 }
1363                 free(ppsz_options);
1364
1365                 RETURN_ON_EXCEPTION(this,ex);
1366                 INT32_TO_NPVARIANT(item, result);
1367                 return INVOKERESULT_NO_ERROR;
1368             }
1369             case ID_playlist_play:
1370                 if( argCount == 0 )
1371                 {
1372                     libvlc_playlist_play(p_plugin->getVLC(), -1, 0, NULL, &ex);
1373                     RETURN_ON_EXCEPTION(this,ex);
1374                     VOID_TO_NPVARIANT(result);
1375                     return INVOKERESULT_NO_ERROR;
1376                 }
1377                 return INVOKERESULT_NO_SUCH_METHOD;
1378             case ID_playlist_playItem:
1379                 if( (argCount == 1) && isNumberValue(args[0]) )
1380                 {
1381                     libvlc_playlist_play(p_plugin->getVLC(),
1382                                          numberValue(args[0]), 0, NULL, &ex);
1383                     RETURN_ON_EXCEPTION(this,ex);
1384                     VOID_TO_NPVARIANT(result);
1385                     return INVOKERESULT_NO_ERROR;
1386                 }
1387                 return INVOKERESULT_NO_SUCH_METHOD;
1388             case ID_playlist_togglepause:
1389                 if( argCount == 0 )
1390                 {
1391                     libvlc_playlist_pause(p_plugin->getVLC(), &ex);
1392                     RETURN_ON_EXCEPTION(this,ex);
1393                     VOID_TO_NPVARIANT(result);
1394                     return INVOKERESULT_NO_ERROR;
1395                 }
1396                 return INVOKERESULT_NO_SUCH_METHOD;
1397             case ID_playlist_stop:
1398                 if( argCount == 0 )
1399                 {
1400                     libvlc_playlist_stop(p_plugin->getVLC(), &ex);
1401                     RETURN_ON_EXCEPTION(this,ex);
1402                     VOID_TO_NPVARIANT(result);
1403                     return INVOKERESULT_NO_ERROR;
1404                 }
1405                 return INVOKERESULT_NO_SUCH_METHOD;
1406             case ID_playlist_next:
1407                 if( argCount == 0 )
1408                 {
1409                     libvlc_playlist_next(p_plugin->getVLC(), &ex);
1410                     RETURN_ON_EXCEPTION(this,ex);
1411                     VOID_TO_NPVARIANT(result);
1412                     return INVOKERESULT_NO_ERROR;
1413                 }
1414                 return INVOKERESULT_NO_SUCH_METHOD;
1415             case ID_playlist_prev:
1416                 if( argCount == 0 )
1417                 {
1418                     libvlc_playlist_prev(p_plugin->getVLC(), &ex);
1419                     RETURN_ON_EXCEPTION(this,ex);
1420                     VOID_TO_NPVARIANT(result);
1421                     return INVOKERESULT_NO_ERROR;
1422                 }
1423                 return INVOKERESULT_NO_SUCH_METHOD;
1424             case ID_playlist_clear: /* deprecated */
1425                 if( argCount == 0 )
1426                 {
1427                     libvlc_playlist_clear(p_plugin->getVLC(), &ex);
1428                     RETURN_ON_EXCEPTION(this,ex);
1429                     VOID_TO_NPVARIANT(result);
1430                     return INVOKERESULT_NO_ERROR;
1431                 }
1432                 return INVOKERESULT_NO_SUCH_METHOD;
1433             case ID_playlist_removeitem: /* deprecated */
1434                 if( (argCount == 1) && isNumberValue(args[0]) )
1435                 {
1436                     libvlc_playlist_delete_item(p_plugin->getVLC(),
1437                                                 numberValue(args[0]), &ex);
1438                     RETURN_ON_EXCEPTION(this,ex);
1439                     VOID_TO_NPVARIANT(result);
1440                     return INVOKERESULT_NO_ERROR;
1441                 }
1442                 return INVOKERESULT_NO_SUCH_METHOD;
1443             default:
1444                 ;
1445         }
1446     }
1447     return INVOKERESULT_GENERIC_ERROR;
1448 }
1449
1450 void LibvlcPlaylistNPObject::parseOptions(const NPString &nps,
1451                                          int *i_options, char*** ppsz_options)
1452 {
1453     if( nps.utf8length )
1454     {
1455         char *s = stringValue(nps);
1456         char *val = s;
1457         if( val )
1458         {
1459             long capacity = 16;
1460             char **options = (char **)malloc(capacity*sizeof(char *));
1461             if( options )
1462             {
1463                 int nOptions = 0;
1464
1465                 char *end = val + nps.utf8length;
1466                 while( val < end )
1467                 {
1468                     // skip leading blanks
1469                     while( (val < end)
1470                         && ((*val == ' ' ) || (*val == '\t')) )
1471                         ++val;
1472
1473                     char *start = val;
1474                     // skip till we get a blank character
1475                     while( (val < end)
1476                         && (*val != ' ' )
1477                         && (*val != '\t') )
1478                     {
1479                         char c = *(val++);
1480                         if( ('\'' == c) || ('"' == c) )
1481                         {
1482                             // skip till end of string
1483                             while( (val < end) && (*(val++) != c ) );
1484                         }
1485                     }
1486
1487                     if( val > start )
1488                     {
1489                         if( nOptions == capacity )
1490                         {
1491                             capacity += 16;
1492                             char **moreOptions = (char **)realloc(options, capacity*sizeof(char*)); 
1493                             if( ! moreOptions )
1494                             {
1495                                 /* failed to allocate more memory */
1496                                 free(s);
1497                                 /* return what we got so far */
1498                                 *i_options = nOptions;
1499                                 *ppsz_options = options;
1500                                 return;
1501                             }
1502                             options = moreOptions;
1503                         }
1504                         *(val++) = '\0';
1505                         options[nOptions++] = strdup(start);
1506                     }
1507                     else
1508                         // must be end of string
1509                         break;
1510                 }
1511                 *i_options = nOptions;
1512                 *ppsz_options = options;
1513             }
1514             free(s);
1515         }
1516     }
1517 }
1518
1519 void LibvlcPlaylistNPObject::parseOptions(NPObject *obj, int *i_options,
1520                                           char*** ppsz_options)
1521 {
1522     /* WARNING: Safari does not implement NPN_HasProperty/NPN_HasMethod */
1523
1524     NPVariant value;
1525
1526     /* we are expecting to have a Javascript Array object */
1527     NPIdentifier propId = NPN_GetStringIdentifier("length");
1528     if( NPN_GetProperty(_instance, obj, propId, &value) )
1529     {
1530         int count = numberValue(value);
1531         NPN_ReleaseVariantValue(&value);
1532
1533         if( count )
1534         {
1535             long capacity = 16;
1536             char **options = (char **)malloc(capacity*sizeof(char *));
1537             if( options )
1538             {
1539                 int nOptions = 0;
1540
1541                 while( nOptions < count )
1542                 {
1543                     propId = NPN_GetIntIdentifier(nOptions);
1544                     if( ! NPN_GetProperty(_instance, obj, propId, &value) )
1545                         /* return what we got so far */
1546                         break;
1547
1548                     if( ! NPVARIANT_IS_STRING(value) )
1549                     {
1550                         /* return what we got so far */
1551                         NPN_ReleaseVariantValue(&value);
1552                         break;
1553                     }
1554
1555                     if( nOptions == capacity )
1556                     {
1557                         capacity += 16;
1558                         char **moreOptions = (char **)realloc(options, capacity*sizeof(char*)); 
1559                         if( ! moreOptions )
1560                         {
1561                             /* failed to allocate more memory */
1562                             NPN_ReleaseVariantValue(&value);
1563                             /* return what we got so far */
1564                             *i_options = nOptions;
1565                             *ppsz_options = options;
1566                             break;
1567                         }
1568                         options = moreOptions;
1569                     }
1570
1571                     options[nOptions++] = stringValue(value);
1572                 }
1573                 *i_options = nOptions;
1574                 *ppsz_options = options;
1575             }
1576         }
1577     }
1578 }
1579
1580 /*
1581 ** implementation of libvlc video object
1582 */
1583
1584 const NPUTF8 * const LibvlcVideoNPObject::propertyNames[] = 
1585 {
1586     "fullscreen",
1587     "height",
1588     "width",
1589     "aspectRatio",
1590     "subtitle",
1591     "crop",
1592     "teletext"
1593 };
1594
1595 enum LibvlcVideoNPObjectPropertyIds
1596 {
1597     ID_video_fullscreen,
1598     ID_video_height,
1599     ID_video_width,
1600     ID_video_aspectratio,
1601     ID_video_subtitle,
1602     ID_video_crop,
1603     ID_video_teletext
1604 };
1605 COUNTNAMES(LibvlcVideoNPObject,propertyCount,propertyNames);
1606
1607 RuntimeNPObject::InvokeResult
1608 LibvlcVideoNPObject::getProperty(int index, NPVariant &result)
1609 {
1610     /* is plugin still running */
1611     if( isPluginRunning() )
1612     {
1613         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1614         libvlc_exception_t ex;
1615         libvlc_exception_init(&ex);
1616
1617         libvlc_media_player_t *p_md = libvlc_playlist_get_media_player(p_plugin->getVLC(), &ex);
1618         RETURN_ON_EXCEPTION(this,ex);
1619
1620         switch( index )
1621         {
1622             case ID_video_fullscreen:
1623             {
1624                 int val = libvlc_get_fullscreen(p_md, &ex);
1625                 libvlc_media_player_release(p_md);
1626                 RETURN_ON_EXCEPTION(this,ex);
1627                 BOOLEAN_TO_NPVARIANT(val, result);
1628                 return INVOKERESULT_NO_ERROR;
1629             }
1630             case ID_video_height:
1631             {
1632                 int val = libvlc_video_get_height(p_md, &ex);
1633                 libvlc_media_player_release(p_md);
1634                 RETURN_ON_EXCEPTION(this,ex);
1635                 INT32_TO_NPVARIANT(val, result);
1636                 return INVOKERESULT_NO_ERROR;
1637             }
1638             case ID_video_width:
1639             {
1640                 int val = libvlc_video_get_width(p_md, &ex);
1641                 libvlc_media_player_release(p_md);
1642                 RETURN_ON_EXCEPTION(this,ex);
1643                 INT32_TO_NPVARIANT(val, result);
1644                 return INVOKERESULT_NO_ERROR;
1645             }
1646             case ID_video_aspectratio:
1647             {
1648                 NPUTF8 *psz_aspect = libvlc_video_get_aspect_ratio(p_md, &ex);
1649                 libvlc_media_player_release(p_md);
1650                 RETURN_ON_EXCEPTION(this,ex);
1651                 if( !psz_aspect )
1652                     return INVOKERESULT_GENERIC_ERROR;
1653
1654                 STRINGZ_TO_NPVARIANT(psz_aspect, result);
1655                 return INVOKERESULT_NO_ERROR;
1656             }
1657             case ID_video_subtitle:
1658             {
1659                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1660                 libvlc_media_player_release(p_md);
1661                 RETURN_ON_EXCEPTION(this,ex);
1662                 INT32_TO_NPVARIANT(i_spu, result);
1663                 return INVOKERESULT_NO_ERROR;
1664             }
1665             case ID_video_crop:
1666             {
1667                 NPUTF8 *psz_geometry = libvlc_video_get_crop_geometry(p_md, &ex);
1668                 libvlc_media_player_release(p_md);
1669                 RETURN_ON_EXCEPTION(this,ex);
1670                 if( !psz_geometry )
1671                     return INVOKERESULT_GENERIC_ERROR;
1672
1673                 STRINGZ_TO_NPVARIANT(psz_geometry, result);
1674                 return INVOKERESULT_NO_ERROR;
1675             }
1676             case ID_video_teletext:
1677             {
1678                 int i_page = libvlc_video_get_teletext(p_md, &ex);
1679                 libvlc_media_player_release(p_md);
1680                 RETURN_ON_EXCEPTION(this,ex);
1681                 INT32_TO_NPVARIANT(i_page, result);
1682                 return INVOKERESULT_NO_ERROR;
1683             }
1684         }
1685         libvlc_media_player_release(p_md);
1686     }
1687     return INVOKERESULT_GENERIC_ERROR;
1688 }
1689
1690 RuntimeNPObject::InvokeResult
1691 LibvlcVideoNPObject::setProperty(int index, const NPVariant &value)
1692 {
1693     /* is plugin still running */
1694     if( isPluginRunning() )
1695     {
1696         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1697         libvlc_exception_t ex;
1698         libvlc_exception_init(&ex);
1699
1700         libvlc_media_player_t *p_md = libvlc_playlist_get_media_player(p_plugin->getVLC(), &ex);
1701         RETURN_ON_EXCEPTION(this,ex);
1702
1703         switch( index )
1704         {
1705             case ID_video_fullscreen:
1706             {
1707                 if( ! NPVARIANT_IS_BOOLEAN(value) )
1708                 {
1709                     libvlc_media_player_release(p_md);
1710                     return INVOKERESULT_INVALID_VALUE;
1711                 }
1712
1713                 int val = NPVARIANT_TO_BOOLEAN(value);
1714                 libvlc_set_fullscreen(p_md, val, &ex);
1715                 libvlc_media_player_release(p_md);
1716
1717                 RETURN_ON_EXCEPTION(this,ex);
1718                 return INVOKERESULT_NO_ERROR;
1719             }
1720             case ID_video_aspectratio:
1721             {
1722                 char *psz_aspect = NULL;
1723
1724                 if( ! NPVARIANT_IS_STRING(value) )
1725                 {
1726                     libvlc_media_player_release(p_md);
1727                     return INVOKERESULT_INVALID_VALUE;
1728                 }
1729
1730                 psz_aspect = stringValue(NPVARIANT_TO_STRING(value));
1731                 if( !psz_aspect )
1732                 {
1733                     libvlc_media_player_release(p_md);
1734                     return INVOKERESULT_GENERIC_ERROR;
1735                 }
1736
1737                 libvlc_video_set_aspect_ratio(p_md, psz_aspect, &ex);
1738                 free(psz_aspect);
1739                 libvlc_media_player_release(p_md);
1740                 RETURN_ON_EXCEPTION(this,ex);
1741
1742                 return INVOKERESULT_NO_ERROR;
1743             }
1744             case ID_video_subtitle:
1745             {
1746                 if( isNumberValue(value) )
1747                 {
1748                     libvlc_video_set_spu(p_md,
1749                                          numberValue(value), &ex);
1750                     libvlc_media_player_release(p_md);
1751                     RETURN_ON_EXCEPTION(this,ex);
1752
1753                     return INVOKERESULT_NO_ERROR;
1754                 }
1755                 libvlc_media_player_release(p_md);
1756                 return INVOKERESULT_INVALID_VALUE;
1757             }
1758             case ID_video_crop:
1759             {
1760                 char *psz_geometry = NULL;
1761
1762                 if( ! NPVARIANT_IS_STRING(value) )
1763                 {
1764                     libvlc_media_player_release(p_md);
1765                     return INVOKERESULT_INVALID_VALUE;
1766                 }
1767
1768                 psz_geometry = stringValue(NPVARIANT_TO_STRING(value));
1769                 if( !psz_geometry )
1770                 {
1771                     libvlc_media_player_release(p_md);
1772                     return INVOKERESULT_GENERIC_ERROR;
1773                 }
1774
1775                 libvlc_video_set_crop_geometry(p_md, psz_geometry, &ex);
1776                 free(psz_geometry);
1777                 libvlc_media_player_release(p_md);
1778                 RETURN_ON_EXCEPTION(this,ex);
1779
1780                 return INVOKERESULT_NO_ERROR;
1781             }
1782             case ID_video_teletext:
1783             {
1784                 if( isNumberValue(value) )
1785                 {
1786                     libvlc_video_set_teletext(p_md,
1787                                          numberValue(value), &ex);
1788                     libvlc_media_player_release(p_md);
1789                     RETURN_ON_EXCEPTION(this,ex);
1790
1791                     return INVOKERESULT_NO_ERROR;
1792                 }
1793                 libvlc_media_player_release(p_md);
1794                 return INVOKERESULT_INVALID_VALUE;
1795             }
1796         }
1797         libvlc_media_player_release(p_md);
1798     }
1799     return INVOKERESULT_GENERIC_ERROR;
1800 }
1801
1802 const NPUTF8 * const LibvlcVideoNPObject::methodNames[] =
1803 {
1804     "toggleFullscreen",
1805     "toggleTeletext"
1806 };
1807 COUNTNAMES(LibvlcVideoNPObject,methodCount,methodNames);
1808
1809 enum LibvlcVideoNPObjectMethodIds
1810 {
1811     ID_video_togglefullscreen,
1812     ID_video_toggleteletext
1813 };
1814
1815 RuntimeNPObject::InvokeResult
1816 LibvlcVideoNPObject::invoke(int index, const NPVariant *args,
1817                             uint32_t argCount, NPVariant &result)
1818 {
1819     /* is plugin still running */
1820     if( isPluginRunning() )
1821     {
1822         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1823         libvlc_exception_t ex;
1824         libvlc_exception_init(&ex);
1825
1826         libvlc_media_player_t *p_md = libvlc_playlist_get_media_player(p_plugin->getVLC(), &ex);
1827         RETURN_ON_EXCEPTION(this,ex);
1828
1829         switch( index )
1830         {
1831             case ID_video_togglefullscreen:
1832                 if( argCount == 0 )
1833                 {
1834                     libvlc_toggle_fullscreen(p_md, &ex);
1835                     libvlc_media_player_release(p_md);
1836                     RETURN_ON_EXCEPTION(this,ex);
1837                     VOID_TO_NPVARIANT(result);
1838                     return INVOKERESULT_NO_ERROR;
1839                 }
1840                 return INVOKERESULT_NO_SUCH_METHOD;
1841             case ID_video_toggleteletext:
1842                 if( argCount == 0 )
1843                 {
1844                     libvlc_toggle_teletext(p_md, &ex);
1845                     libvlc_media_player_release(p_md);
1846                     RETURN_ON_EXCEPTION(this,ex);
1847                     VOID_TO_NPVARIANT(result);
1848                     return INVOKERESULT_NO_ERROR;
1849                 }
1850                 return INVOKERESULT_NO_SUCH_METHOD;
1851             default:
1852                 return INVOKERESULT_NO_SUCH_METHOD;
1853         }
1854     }
1855     return INVOKERESULT_GENERIC_ERROR;
1856 }