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

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

Merge icedtea-web v1.3 to trunk.

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