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