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

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

vendor: Add icedtea-web v1.1.2 to current.

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