source: trunk/icedtea-web/plugin/icedteanp/IcedTeaPluginUtils.cc@ 357

Last change on this file since 357 was 357, checked in by dmik, 13 years ago

icedtea-web: Port plugin to OS/2.

File size: 31.1 KB
Line 
1/* IcedTeaPluginUtils.cc
2
3 Copyright (C) 2009, 2010 Red Hat
4
5This file is part of IcedTea.
6
7IcedTea is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12IcedTea is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with IcedTea; see the file COPYING. If not, write to the
19Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
2002110-1301 USA.
21
22Linking this library statically or dynamically with other modules is
23making a combined work based on this library. Thus, the terms and
24conditions of the GNU General Public License cover the whole
25combination.
26
27As a special exception, the copyright holders of this library give you
28permission to link this library with independent modules to produce an
29executable, regardless of the license terms of these independent
30modules, and to copy and distribute the resulting executable under
31terms of your choice, provided that you also meet, for each linked
32independent module, the terms and conditions of the license of that
33module. An independent module is a module which is not derived from
34or based on this library. If you modify this library, you may extend
35this exception to your version of the library, but you are not
36obligated to do so. If you do not wish to do so, delete this
37exception statement from your version. */
38
39#ifdef __EMX__
40#include <unistd.h> // usleep
41#endif
42
43#include "IcedTeaNPPlugin.h"
44#include "IcedTeaScriptablePluginObject.h"
45#include "IcedTeaPluginUtils.h"
46
47/**
48 * Misc. utility functions used by the plugin
49 */
50
51/***********************************************
52 * Begin IcedTeaPluginUtilities implementation *
53************************************************/
54
55// Initialize static variables
56int IcedTeaPluginUtilities::reference = -1;
57pthread_mutex_t IcedTeaPluginUtilities::reference_mutex = PTHREAD_MUTEX_INITIALIZER;
58std::map<void*, NPP>* IcedTeaPluginUtilities::instance_map = new std::map<void*, NPP>();
59std::map<std::string, NPObject*>* IcedTeaPluginUtilities::object_map = new std::map<std::string, NPObject*>();
60
61/* Plugin async call queue */
62static std::vector< PluginThreadCall* >* pendingPluginThreadRequests = new std::vector< PluginThreadCall* >();
63
64/**
65 * Given a context number, constructs a message prefix to send to Java
66 *
67 * @param context The context of the request
68 * @return The string prefix (allocated on heap)
69 */
70
71void
72IcedTeaPluginUtilities::constructMessagePrefix(int context, std::string *result)
73{
74 std::string context_str = std::string();
75
76 itoa(context, &context_str);
77
78 result->append("context ");
79 result->append(context_str);
80 result->append(" reference -1");
81
82}
83
84/**
85 * Given a context number, and reference number, constructs a message prefix to
86 * send to Java
87 *
88 * @param context The context of the request
89 * @param rerefence The reference number of the request
90 * @param result The message
91 */
92
93void
94IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference, std::string* result)
95{
96 // Until security is implemented, use file:// source for _everything_
97
98 std::string context_str = std::string();
99 std::string reference_str = std::string();
100
101 itoa(context, &context_str);
102 itoa(reference, &reference_str);
103
104 *result += "context ";
105 result->append(context_str);
106 *result += " reference ";
107 result->append(reference_str);
108}
109
110/**
111 * Given a context number, reference number, and source location, constructs
112 * a message prefix to send to Java
113 *
114 * @param context The context of the request
115 * @param rerefence The reference number of the request
116 * @param address The address for the script that made the request
117 * @param result The message
118 */
119
120void
121IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference,
122 std::string address,
123 std::string* result)
124{
125 std::string context_str = std::string();
126 std::string reference_str = std::string();
127
128 itoa(context, &context_str);
129 itoa(reference, &reference_str);
130
131 *result += "context ";
132 result->append(context_str);
133 *result += " reference ";
134 result->append(reference_str);
135
136 if (address.length() > 0)
137 {
138 *result += " src ";
139 result->append(address);
140 }
141}
142
143/**
144 * Returns a string representation of a void pointer
145 *
146 * @param id The pointer
147 * @param result The string representation
148 */
149
150void
151IcedTeaPluginUtilities::JSIDToString(void* id, std::string* result)
152{
153
154 char* id_str = (char*) malloc(sizeof(char)*20); // max = long long = 8446744073709551615 == 19 chars
155
156 if (sizeof(void*) == sizeof(long long))
157 {
158 sprintf(id_str, "%llu", id);
159 }
160 else
161 {
162 sprintf(id_str, "%lu", id); // else use long
163 }
164
165 result->append(id_str);
166
167 PLUGIN_DEBUG("Converting pointer %p to %s\n", id, id_str);
168 free(id_str);
169}
170
171/**
172 * Returns a void pointer from a string representation
173 *
174 * @param id_str The string representation
175 * @return The pointer
176 */
177
178void*
179IcedTeaPluginUtilities::stringToJSID(std::string id_str)
180{
181 void* ptr;
182 if (sizeof(void*) == sizeof(long long))
183 {
184 PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str.c_str(), strtoull(id_str.c_str(), NULL, 0));
185 ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str.c_str(), NULL, 0));
186 } else
187 {
188 PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str.c_str(), strtoul(id_str.c_str(), NULL, 0));
189 ptr = reinterpret_cast <void*> ((unsigned long) strtoul(id_str.c_str(), NULL, 0));
190 }
191
192 PLUGIN_DEBUG("Casted: %p\n", ptr);
193
194 return ptr;
195}
196
197/**
198 * Returns a void pointer from a string representation
199 *
200 * @param id_str The pointer to the string representation
201 * @return The pointer
202 */
203
204void*
205IcedTeaPluginUtilities::stringToJSID(std::string* id_str)
206{
207 void* ptr;
208 if (sizeof(void*) == sizeof(long long))
209 {
210 PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str->c_str(), strtoull(id_str->c_str(), NULL, 0));
211 ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str->c_str(), NULL, 0));
212 } else
213 {
214 PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str->c_str(), strtoul(id_str->c_str(), NULL, 0));
215 ptr = reinterpret_cast <void*> ((unsigned long) strtoul(id_str->c_str(), NULL, 0));
216 }
217
218 PLUGIN_DEBUG("Casted: %p\n", ptr);
219
220 return ptr;
221}
222
223/**
224 * Increments the global reference number and returns it.
225 *
226 * This function is thread-safe.
227 */
228int
229IcedTeaPluginUtilities::getReference()
230{
231 pthread_mutex_lock(&reference_mutex);
232
233 // If we are nearing the max, reset
234 if (reference < -0x7FFFFFFF + 10) {
235 reference = -1;
236 }
237
238 reference--;
239 pthread_mutex_unlock(&reference_mutex);
240
241 return reference;
242}
243
244/**
245 * Decrements the global reference number.
246 *
247 * This function is thread-safe.
248 */
249void
250IcedTeaPluginUtilities::releaseReference()
251{
252 // do nothing for now
253}
254
255/**
256 * Converts integer to char*
257 *
258 * @param i The integer to convert to ascii
259 * @param result The resulting string
260 */
261void
262IcedTeaPluginUtilities::itoa(int i, std::string* result)
263{
264 // largest possible integer is 10 digits long
265 char* int_str = (char*) malloc(sizeof(char)*11);
266 sprintf(int_str, "%d", i);
267 result->append(int_str);
268
269 free(int_str);
270}
271
272/**
273 * Frees memory from a string* vector
274 *
275 * The vector deconstructor will only delete string pointers upon being
276 * called. This function frees the associated string memory as well.
277 *
278 * @param v The vector whose strings are to be freed
279 */
280void
281IcedTeaPluginUtilities::freeStringPtrVector(std::vector<std::string*>* v)
282{
283 if (v)
284 {
285 for (int i=0; i < v->size(); i++) {
286 delete v->at(i);
287 }
288
289 delete v;
290 }
291
292}
293
294/**
295 * Given a string, splits it on the given delimiters.
296 *
297 * @param str The string to split
298 * @param The delimiters to split on
299 * @return A string vector containing the aplit components
300 */
301
302std::vector<std::string*>*
303IcedTeaPluginUtilities::strSplit(const char* str, const char* delim)
304{
305 std::vector<std::string*>* v = new std::vector<std::string*>();
306 v->reserve(strlen(str)/2);
307 char* copy;
308
309 // Tokening is done on a copy
310 copy = (char*) malloc (sizeof(char)*strlen(str) + 1);
311 strcpy(copy, str);
312
313 char* tok_ptr;
314 tok_ptr = strtok (copy, delim);
315
316 while (tok_ptr != NULL)
317 {
318 // Allocation on heap since caller has no way to knowing how much will
319 // be needed. Make sure caller cleans up!
320 std::string* s = new std::string();
321 s->append(tok_ptr);
322 v->push_back(s);
323 tok_ptr = strtok (NULL, " ");
324 }
325
326 return v;
327}
328
329/**
330 * Given a unicode byte array, converts it to a UTF8 string
331 *
332 * The actual contents in the array may be surrounded by other data.
333 *
334 * e.g. with length 5, begin = 3,
335 * unicode_byte_array = "37 28 5 48 45 4c 4c 4f 9e 47":
336 *
337 * We'd start at 3 i.e. "48" and go on for 5 i.e. upto and including "4f".
338 * So we convert "48 45 4c 4c 4f" which is "hello"
339 *
340 * @param length The length of the string
341 * @param begin Where in the array to begin conversion
342 * @param result_unicode_str The return variable in which the
343 * converted string is placed
344 */
345
346void
347IcedTeaPluginUtilities::getUTF8String(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::string* result_unicode_str)
348{
349 result_unicode_str->clear();
350 result_unicode_str->reserve(unicode_byte_array->size()/2);
351 for (int i = begin; i < begin+length; i++)
352 result_unicode_str->push_back((char) strtol(unicode_byte_array->at(i)->c_str(), NULL, 16));
353
354 PLUGIN_DEBUG("Converted UTF-8 string: %s. Length=%d\n", result_unicode_str->c_str(), result_unicode_str->length());
355}
356
357/**
358 * Given a UTF8 string, converts it to a space delimited string of hex characters
359 *
360 * The first element in the return array is the length of the string
361 *
362 * e.g. "hello" would convert to: "5 48 45 4c 4c 4f"
363 *
364 * @param str The string to convert
365 * @param urt_str The result
366 */
367
368void
369IcedTeaPluginUtilities::convertStringToUTF8(std::string* str, std::string* utf_str)
370{
371 std::ostringstream ostream;
372
373 std::string length = std::string();
374 itoa(str->length(), &length);
375
376 ostream << length;
377
378 // UTF-8 characters are 4-bytes max + space + '\0'
379 char* hex_value = (char*) malloc(sizeof(char)*10);
380
381 for (int i = 0; i < str->length(); i++)
382 {
383 sprintf(hex_value, " %hx", str->at(i));
384 ostream << hex_value;
385 }
386
387 utf_str->clear();
388 *utf_str = ostream.str();
389
390 free(hex_value);
391 PLUGIN_DEBUG("Converted %s to UTF-8 string %s\n", str->c_str(), utf_str->c_str());
392}
393
394/**
395 * Given a unicode byte array, converts it to a UTF16LE/UCS-2 string
396 *
397 * This works in a manner similar to getUTF8String, except that it reads 2
398 * slots for each byte.
399 *
400 * @param length The length of the string
401 * @param begin Where in the array to begin conversion
402 * @param result_unicode_str The return variable in which the
403 * converted string is placed
404 */
405void
406IcedTeaPluginUtilities::getUTF16LEString(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::wstring* result_unicode_str)
407{
408
409 wchar_t c;
410
411 if (plugin_debug) printf("Converted UTF-16LE string: ");
412
413 result_unicode_str->clear();
414 for (int i = begin; i < begin+length; i+=2)
415 {
416 int low = strtol(unicode_byte_array->at(i)->c_str(), NULL, 16);
417 int high = strtol(unicode_byte_array->at(i+1)->c_str(), NULL, 16);
418
419 c = ((high << 8) | low);
420
421 if ((c >= 'a' && c <= 'z') ||
422 (c >= 'A' && c <= 'Z') ||
423 (c >= '0' && c <= '9'))
424 {
425 if (plugin_debug) printf("%c", c);
426 }
427
428 result_unicode_str->push_back(c);
429 }
430
431 // not routing via debug print macros due to wide-string issues
432 if (plugin_debug) printf(". Length=%d\n", result_unicode_str->length());
433}
434
435/*
436 * Prints the given string vector (if debug is true)
437 *
438 * @param prefix The prefix to print before printing the vector contents
439 * @param cv The string vector whose contents are to be printed
440 */
441void
442IcedTeaPluginUtilities::printStringVector(const char* prefix, std::vector<std::string>* str_vector)
443{
444
445 // This is a CPU intensive function. Run only if debugging
446 if (!plugin_debug)
447 return;
448
449 std::string* str = new std::string();
450 *str += "{ ";
451 for (int i=0; i < str_vector->size(); i++)
452 {
453 *str += str_vector->at(i);
454
455 if (i != str_vector->size() - 1)
456 *str += ", ";
457 }
458
459 *str += " }";
460
461 PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
462
463 delete str;
464}
465
466const gchar*
467IcedTeaPluginUtilities::getSourceFromInstance(NPP instance)
468{
469 // At the moment, src cannot be securely fetched via NPAPI
470 // See:
471 // http://www.mail-archive.com/chromium-dev@googlegroups.com/msg04872.html
472
473 // Since we use the insecure window.location.href attribute to compute
474 // source, we cannot use it to make security decisions. Therefore,
475 // instance associated source will always return empty
476
477 //ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
478 //return (data->source) ? data->source : "";
479
480 return "http://null.null";
481}
482
483/**
484 * Stores a window pointer <-> instance mapping
485 *
486 * @param member_ptr The pointer key
487 * @param instance The instance to associate with this pointer
488 */
489
490void
491IcedTeaPluginUtilities::storeInstanceID(void* member_ptr, NPP instance)
492{
493 PLUGIN_DEBUG("Storing instance %p with key %p\n", instance, member_ptr);
494 instance_map->insert(std::make_pair(member_ptr, instance));
495}
496
497/**
498 * Removes a window pointer <-> instance mapping
499 *
500 * @param member_ptr The key to remove
501 */
502
503void
504IcedTeaPluginUtilities::removeInstanceID(void* member_ptr)
505{
506 PLUGIN_DEBUG("Removing key %p from instance map\n", member_ptr);
507 instance_map->erase(member_ptr);
508}
509
510/**
511 * Removes all mappings to a given instance, and all associated objects
512 */
513void
514IcedTeaPluginUtilities::invalidateInstance(NPP instance)
515{
516 PLUGIN_DEBUG("Invalidating instance %p\n", instance);
517
518 std::map<void*,NPP>::iterator iterator;
519
520 for (iterator = instance_map->begin(); iterator != instance_map->end(); )
521 {
522 if ((*iterator).second == instance)
523 {
524 instance_map->erase(iterator++);
525 }
526 else
527 {
528 ++iterator;
529 }
530 }
531}
532
533/**
534 * Given the window pointer, returns the instance associated with it
535 *
536 * @param member_ptr The pointer key
537 * @return The associated instance
538 */
539
540NPP
541IcedTeaPluginUtilities::getInstanceFromMemberPtr(void* member_ptr)
542{
543
544 NPP instance = NULL;
545 PLUGIN_DEBUG("getInstanceFromMemberPtr looking for %p\n", member_ptr);
546
547 std::map<void*, NPP>::iterator iterator = instance_map->find(member_ptr);
548
549 if (iterator != instance_map->end())
550 {
551 instance = instance_map->find(member_ptr)->second;
552 PLUGIN_DEBUG("getInstanceFromMemberPtr found %p. Instance = %p\n", member_ptr, instance);
553 }
554
555 return instance;
556}
557
558/**
559 * Given a java id key ('classid:instanceid'), returns the associated valid NPObject, if any
560 *
561 * @param key the key
562 * @return The associated active NPObject, NULL otherwise
563 */
564
565NPObject*
566IcedTeaPluginUtilities::getNPObjectFromJavaKey(std::string key)
567{
568
569 NPObject* object = NULL;
570 PLUGIN_DEBUG("getNPObjectFromJavaKey looking for %s\n", key.c_str());
571
572 std::map<std::string, NPObject*>::iterator iterator = object_map->find(key);
573
574 if (iterator != object_map->end())
575 {
576 NPObject* mapped_object = object_map->find(key)->second;
577
578 if (getInstanceFromMemberPtr(mapped_object) != NULL)
579 {
580 object = mapped_object;
581 PLUGIN_DEBUG("getNPObjectFromJavaKey found %s. NPObject = %p\n", key.c_str(), object);
582 }
583 }
584
585 return object;
586}
587
588/**
589 * Stores a java id key <-> NPObject mapping
590 *
591 * @param key The Java ID Key
592 * @param object The object to map to
593 */
594
595void
596IcedTeaPluginUtilities::storeObjectMapping(std::string key, NPObject* object)
597{
598 PLUGIN_DEBUG("Storing object %p with key %s\n", object, key.c_str());
599 object_map->insert(std::make_pair(key, object));
600}
601
602/**
603 * Removes a java id key <-> NPObject mapping
604 *
605 * @param key The key to remove
606 */
607
608void
609IcedTeaPluginUtilities::removeObjectMapping(std::string key)
610{
611 PLUGIN_DEBUG("Removing key %s from object map\n", key.c_str());
612 object_map->erase(key);
613}
614
615/*
616 * Similar to printStringVector, but takes a vector of string pointers instead
617 *
618 * @param prefix The prefix to print before printing the vector contents
619 * @param cv The string* vector whose contents are to be printed
620 */
621
622void
623IcedTeaPluginUtilities::printStringPtrVector(const char* prefix, std::vector<std::string*>* str_ptr_vector)
624{
625 // This is a CPU intensive function. Run only if debugging
626 if (!plugin_debug)
627 return;
628
629 std::string* str = new std::string();
630 *str += "{ ";
631 for (int i=0; i < str_ptr_vector->size(); i++)
632 {
633 *str += *(str_ptr_vector->at(i));
634
635 if (i != str_ptr_vector->size() - 1)
636 *str += ", ";
637 }
638
639 *str += " }";
640
641 PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
642
643 delete str;
644}
645
646void
647IcedTeaPluginUtilities::printNPVariant(NPVariant variant)
648{
649 // This is a CPU intensive function. Run only if debugging
650 if (!plugin_debug)
651 return;
652
653 if (NPVARIANT_IS_VOID(variant))
654 {
655 PLUGIN_DEBUG("VOID %d\n", variant);
656 }
657 else if (NPVARIANT_IS_NULL(variant))
658 {
659 PLUGIN_DEBUG("NULL\n", variant);
660 }
661 else if (NPVARIANT_IS_BOOLEAN(variant))
662 {
663 PLUGIN_DEBUG("BOOL: %d\n", NPVARIANT_TO_BOOLEAN(variant));
664 }
665 else if (NPVARIANT_IS_INT32(variant))
666 {
667 PLUGIN_DEBUG("INT32: %d\n", NPVARIANT_TO_INT32(variant));
668 }
669 else if (NPVARIANT_IS_DOUBLE(variant))
670 {
671 PLUGIN_DEBUG("DOUBLE: %f\n", NPVARIANT_TO_DOUBLE(variant));
672 }
673 else if (NPVARIANT_IS_STRING(variant))
674 {
675#if MOZILLA_VERSION_COLLAPSED < 1090200
676 PLUGIN_DEBUG("STRING: %s\n", NPVARIANT_TO_STRING(variant).utf8characters);
677#else
678 PLUGIN_DEBUG("STRING: %s\n", NPVARIANT_TO_STRING(variant).UTF8Characters);
679#endif
680 }
681 else
682 {
683 PLUGIN_DEBUG("OBJ: %p\n", NPVARIANT_TO_OBJECT(variant));
684 }
685}
686
687void
688IcedTeaPluginUtilities::NPVariantToString(NPVariant variant, std::string* result)
689{
690 char* str = (char*) malloc(sizeof(char)*32); // enough for everything except string
691
692 if (NPVARIANT_IS_VOID(variant))
693 {
694 sprintf(str, "%p", variant);
695 }
696 else if (NPVARIANT_IS_NULL(variant))
697 {
698 sprintf(str, "NULL");
699 }
700 else if (NPVARIANT_IS_BOOLEAN(variant))
701 {
702 if (NPVARIANT_TO_BOOLEAN(variant))
703 sprintf(str, "true");
704 else
705 sprintf(str, "false");
706 }
707 else if (NPVARIANT_IS_INT32(variant))
708 {
709 sprintf(str, "%d", NPVARIANT_TO_INT32(variant));
710 }
711 else if (NPVARIANT_IS_DOUBLE(variant))
712 {
713 sprintf(str, "%f", NPVARIANT_TO_DOUBLE(variant));;
714 }
715 else if (NPVARIANT_IS_STRING(variant))
716 {
717 free(str);
718#if MOZILLA_VERSION_COLLAPSED < 1090200
719 str = (char*) malloc(sizeof(char)*NPVARIANT_TO_STRING(variant).utf8length);
720 sprintf(str, "%s", NPVARIANT_TO_STRING(variant).utf8characters);
721#else
722 str = (char*) malloc(sizeof(char)*NPVARIANT_TO_STRING(variant).UTF8Length);
723 sprintf(str, "%s", NPVARIANT_TO_STRING(variant).UTF8Characters);
724#endif
725 }
726 else
727 {
728 sprintf(str, "[Object %p]", variant);
729 }
730
731 result->append(str);
732 free(str);
733}
734
735bool
736IcedTeaPluginUtilities::javaResultToNPVariant(NPP instance,
737 std::string* java_value,
738 NPVariant* variant)
739{
740 JavaRequestProcessor java_request = JavaRequestProcessor();
741 JavaResultData* java_result;
742
743 if (java_value->find("literalreturn") == 0)
744 {
745 // 'literalreturn ' == 14 to skip
746 std::string value = java_value->substr(14);
747
748 // VOID/BOOLEAN/NUMBER
749
750 if (value == "void")
751 {
752 PLUGIN_DEBUG("Method call returned void\n");
753 VOID_TO_NPVARIANT(*variant);
754 } else if (value == "null")
755 {
756 PLUGIN_DEBUG("Method call returned null\n");
757 NULL_TO_NPVARIANT(*variant);
758 }else if (value == "true")
759 {
760 PLUGIN_DEBUG("Method call returned a boolean (true)\n");
761 BOOLEAN_TO_NPVARIANT(true, *variant);
762 } else if (value == "false")
763 {
764 PLUGIN_DEBUG("Method call returned a boolean (false)\n");
765 BOOLEAN_TO_NPVARIANT(false, *variant);
766 } else
767 {
768 double d = strtod(value.c_str(), NULL);
769
770 // See if it is convertible to int
771 if (value.find(".") != std::string::npos ||
772 d < -(0x7fffffffL - 1L) ||
773 d > 0x7fffffffL)
774 {
775 PLUGIN_DEBUG("Method call returned a double %f\n", d);
776 DOUBLE_TO_NPVARIANT(d, *variant);
777 } else
778 {
779 int32_t i = (int32_t) d;
780 PLUGIN_DEBUG("Method call returned an int %d\n", i);
781 INT32_TO_NPVARIANT(i, *variant);
782 }
783 }
784 } else {
785 // Else this is a complex java object
786
787 // To keep code a little bit cleaner, we create variables with proper descriptive names
788 std::string return_obj_instance_id = std::string();
789 std::string return_obj_class_id = std::string();
790 std::string return_obj_class_name = std::string();
791 return_obj_instance_id.append(*java_value);
792
793 // Find out the class name first, because string is a special case
794 java_result = java_request.getClassName(return_obj_instance_id);
795
796 if (java_result->error_occurred)
797 {
798 return false;
799 }
800
801 return_obj_class_name.append(*(java_result->return_string));
802
803 if (return_obj_class_name == "java.lang.String")
804 {
805 // String is a special case as NPVariant can handle it directly
806 java_result = java_request.getString(return_obj_instance_id);
807
808 if (java_result->error_occurred)
809 {
810 return false;
811 }
812
813 // needs to be on the heap
814 NPUTF8* return_str = (NPUTF8*) malloc(sizeof(NPUTF8)*java_result->return_string->size() + 1);
815 strcpy(return_str, java_result->return_string->c_str());
816
817 PLUGIN_DEBUG("Method call returned a string: \"%s\"\n", return_str);
818 STRINGZ_TO_NPVARIANT(return_str, *variant);
819
820 } else {
821
822 // Else this is a regular class. Reference the class object so
823 // we can construct an NPObject with it and the instance
824 java_result = java_request.getClassID(return_obj_instance_id);
825
826 if (java_result->error_occurred)
827 {
828 return false;
829 }
830
831 return_obj_class_id.append(*(java_result->return_string));
832
833 NPObject* obj;
834
835 if (return_obj_class_name.find('[') == 0) // array
836 obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
837 instance,
838 return_obj_class_id, return_obj_instance_id, true);
839 else
840 obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
841 instance,
842 return_obj_class_id, return_obj_instance_id, false);
843
844 OBJECT_TO_NPVARIANT(obj, *variant);
845 }
846 }
847
848 return true;
849}
850
851bool
852IcedTeaPluginUtilities::isObjectJSArray(NPP instance, NPObject* object)
853{
854
855 NPVariant constructor_v = NPVariant();
856 NPIdentifier constructor_id = browser_functions.getstringidentifier("constructor");
857 browser_functions.getproperty(instance, object, constructor_id, &constructor_v);
858 IcedTeaPluginUtilities::printNPVariant(constructor_v);
859
860 // void constructor => not an array
861 if (NPVARIANT_IS_VOID(constructor_v))
862 return false;
863
864 NPObject* constructor = NPVARIANT_TO_OBJECT(constructor_v);
865
866 NPVariant constructor_str;
867 NPIdentifier toString = browser_functions.getstringidentifier("toString");
868 browser_functions.invoke(instance, constructor, toString, NULL, 0, &constructor_str);
869 IcedTeaPluginUtilities::printNPVariant(constructor_str);
870
871 std::string constructor_name = std::string();
872
873#if MOZILLA_VERSION_COLLAPSED < 1090200
874 constructor_name.append(NPVARIANT_TO_STRING(constructor_str).utf8characters);
875#else
876 constructor_name.append(NPVARIANT_TO_STRING(constructor_str).UTF8Characters);
877#endif
878
879 PLUGIN_DEBUG("Constructor for NPObject is %s\n", constructor_name.c_str());
880
881 return constructor_name.find("function Array") == 0;
882}
883
884void
885IcedTeaPluginUtilities::decodeURL(const gchar* url, gchar** decoded_url)
886{
887
888 PLUGIN_DEBUG("GOT URL: %s -- %s\n", url, *decoded_url);
889 int length = strlen(url);
890 for (int i=0; i < length; i++)
891 {
892 if (url[i] == '%' && i < length - 2)
893 {
894 unsigned char code1 = (unsigned char) url[i+1];
895 unsigned char code2 = (unsigned char) url[i+2];
896
897 if (!IS_VALID_HEX(&code1) || !IS_VALID_HEX(&code2))
898 continue;
899
900 // Convert hex value to integer
901 int converted1 = HEX_TO_INT(&code1);
902 int converted2 = HEX_TO_INT(&code2);
903
904 // bitshift 4 to simulate *16
905 int value = (converted1 << 4) + converted2;
906 char decoded = value;
907
908 strncat(*decoded_url, &decoded, 1);
909
910 i += 2;
911 } else
912 {
913 strncat(*decoded_url, &url[i], 1);
914 }
915 }
916
917 PLUGIN_DEBUG("SENDING URL: %s\n", *decoded_url);
918}
919
920
921/**
922 * Posts a function for execution on the plug-in thread and wait for result.
923 *
924 * @param instance The NPP instance
925 * @param func The function to post
926 * @param data Arguments to *func
927 */
928void
929IcedTeaPluginUtilities::callAndWaitForResult(NPP instance, void (*func) (void *), AsyncCallThreadData* data)
930{
931
932 struct timespec t;
933 struct timespec curr_t;
934 clock_gettime(CLOCK_REALTIME, &t);
935 t.tv_sec += REQUESTTIMEOUT; // timeout
936
937 // post request
938 postPluginThreadAsyncCall(instance, func, data);
939
940 do
941 {
942 clock_gettime(CLOCK_REALTIME, &curr_t);
943 if (data != NULL && !data->result_ready && (curr_t.tv_sec < t.tv_sec))
944 {
945 usleep(2000);
946 } else
947 {
948 break;
949 }
950 } while (1);
951}
952
953
954/**
955 * Posts a request that needs to be handled in a plugin thread.
956 *
957 * @param instance The plugin instance
958 * @param func The function to execute
959 * @param userData The userData for the function to consume/write to
960 * @return if the call was posted successfully
961 */
962
963bool
964IcedTeaPluginUtilities::postPluginThreadAsyncCall(NPP instance, void (*func) (void *), void* data)
965{
966 if (instance)
967 {
968 PluginThreadCall* call = new PluginThreadCall();
969 call->instance = instance;
970 call->func = func;
971 call->userData = data;
972
973 pthread_mutex_lock(&pluginAsyncCallMutex);
974 pendingPluginThreadRequests->push_back(call);
975 pthread_mutex_unlock(&pluginAsyncCallMutex);
976
977 browser_functions.pluginthreadasynccall(instance, &processAsyncCallQueue, NULL); // Always returns immediately
978
979 PLUGIN_DEBUG("Pushed back call evt %p\n", call);
980
981 return true;
982 }
983
984 // Else
985 PLUGIN_DEBUG("Instance is not active. Call rejected.\n");
986 return false;
987}
988
989/**
990 * Runs through the async call wait queue and executes all calls
991 *
992 * @param param Ignored -- required to conform to NPN_PluginThreadAsynCall API
993 */
994void
995processAsyncCallQueue(void* param /* ignored */)
996{
997 do {
998 PluginThreadCall* call = NULL;
999
1000 pthread_mutex_lock(&pluginAsyncCallMutex);
1001 if (pendingPluginThreadRequests->size() > 0)
1002 {
1003 call = pendingPluginThreadRequests->front();
1004 pendingPluginThreadRequests->erase(pendingPluginThreadRequests->begin());
1005 }
1006 pthread_mutex_unlock(&pluginAsyncCallMutex);
1007
1008 if (call)
1009 {
1010 PLUGIN_DEBUG("Processing call evt %p\n", call);
1011 call->func(call->userData);
1012 PLUGIN_DEBUG("Call evt %p processed\n", call);
1013
1014 delete call;
1015 } else
1016 {
1017 break;
1018 }
1019 } while(1);
1020}
1021
1022/******************************************
1023 * Begin JavaMessageSender implementation *
1024 ******************************************
1025 *
1026 * This implementation is very simple and is therefore folded into this file
1027 * rather than a new one.
1028 */
1029
1030/**
1031 * Sends to the Java side
1032 *
1033 * @param message The message to send.
1034 * @param returns whether the message was consumable (always true)
1035 */
1036
1037bool
1038JavaMessageSender::newMessageOnBus(const char* message)
1039{
1040 char* msg = (char*) malloc(sizeof(char)*strlen(message) + 1);
1041 strcpy(msg, message);
1042 plugin_send_message_to_appletviewer(msg);
1043
1044 free(msg);
1045 msg = NULL;
1046
1047 // Always successful
1048 return true;
1049}
1050
1051/***********************************
1052 * Begin MessageBus implementation *
1053 ***********************************/
1054
1055/**
1056 * Constructor.
1057 *
1058 * Initializes the mutexes needed by the other functions.
1059 */
1060MessageBus::MessageBus()
1061{
1062 int ret;
1063
1064 ret = pthread_mutex_init(&subscriber_mutex, NULL);
1065
1066 if(ret)
1067 PLUGIN_DEBUG("Error: Unable to initialize subscriber mutex: %d\n", ret);
1068
1069 ret = pthread_mutex_init(&msg_queue_mutex, NULL);
1070 if(ret)
1071 PLUGIN_DEBUG("Error: Unable to initialize message queue mutex: %d\n", ret);
1072
1073 PLUGIN_DEBUG("Mutexs %p and %p initialized\n", &subscriber_mutex, &msg_queue_mutex);
1074}
1075
1076/**
1077 * Destructor.
1078 *
1079 * Destroy the mutexes initialized by the constructor.
1080 */
1081
1082MessageBus::~MessageBus()
1083{
1084 PLUGIN_DEBUG("MessageBus::~MessageBus\n");
1085
1086 int ret;
1087
1088 ret = pthread_mutex_destroy(&subscriber_mutex);
1089 if(ret)
1090 PLUGIN_DEBUG("Error: Unable to destroy subscriber mutex: %d\n", ret);
1091
1092 ret = pthread_mutex_destroy(&msg_queue_mutex);
1093 if(ret)
1094 PLUGIN_DEBUG("Error: Unable to destroy message queue mutex: %d\n", ret);
1095}
1096
1097/**
1098 * Adds the given BusSubscriber as a subscriber to self
1099 *
1100 * @param b The BusSubscriber to subscribe
1101 */
1102void
1103MessageBus::subscribe(BusSubscriber* b)
1104{
1105 // Applets may initialize in parallel. So lock before pushing.
1106
1107 PLUGIN_DEBUG("Subscribing %p to bus %p\n", b, this);
1108 pthread_mutex_lock(&subscriber_mutex);
1109 subscribers.push_back(b);
1110 pthread_mutex_unlock(&subscriber_mutex);
1111}
1112
1113/**
1114 * Removes the given BusSubscriber from the subscriber list
1115 *
1116 * @param b The BusSubscriber to ubsubscribe
1117 */
1118void
1119MessageBus::unSubscribe(BusSubscriber* b)
1120{
1121 // Applets may initialize in parallel. So lock before pushing.
1122
1123 PLUGIN_DEBUG("Un-subscribing %p from bus %p\n", b, this);
1124 pthread_mutex_lock(&subscriber_mutex);
1125 subscribers.remove(b);
1126 pthread_mutex_unlock(&subscriber_mutex);
1127}
1128
1129/**
1130 * Notifies all subscribers with the given message
1131 *
1132 * @param message The message to send to the subscribers
1133 */
1134void
1135MessageBus::post(const char* message)
1136{
1137 char* msg = (char*) malloc(sizeof(char)*strlen(message) + 1);
1138 bool message_consumed = false;
1139
1140 // consumer frees this memory
1141 strcpy(msg, message);
1142
1143 PLUGIN_DEBUG("Trying to lock %p...\n", &msg_queue_mutex);
1144 pthread_mutex_lock(&subscriber_mutex);
1145
1146 PLUGIN_DEBUG("Message %s received on bus. Notifying subscribers.\n", msg);
1147
1148 std::list<BusSubscriber*>::const_iterator i;
1149 for( i = subscribers.begin(); i != subscribers.end() && !message_consumed; ++i ) {
1150 PLUGIN_DEBUG("Notifying subscriber %p of %s\n", *i, msg);
1151 message_consumed = ((BusSubscriber*) *i)->newMessageOnBus(msg);
1152 }
1153
1154 pthread_mutex_unlock(&subscriber_mutex);
1155
1156 if (!message_consumed)
1157 PLUGIN_DEBUG("Warning: No consumer found for message %s\n", msg);
1158
1159 PLUGIN_DEBUG("%p unlocked...\n", &msg_queue_mutex);
1160}
Note: See TracBrowser for help on using the repository browser.