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