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

Last change on this file since 436 was 436, checked in by dmik, 11 years ago

icedtea-web: Use unnamed pipe instead of unix-style named pipe for debug console.

Similar to r368.

File size: 37.2 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#include <fstream>
47
48/**
49 * Misc. utility functions used by the plugin
50 */
51
52/***********************************************
53 * Begin IcedTeaPluginUtilities implementation *
54************************************************/
55
56// Initialize static variables
57int IcedTeaPluginUtilities::reference = -1;
58pthread_mutex_t IcedTeaPluginUtilities::reference_mutex = PTHREAD_MUTEX_INITIALIZER;
59std::map<void*, NPP>* IcedTeaPluginUtilities::instance_map = new std::map<void*, NPP>();
60std::map<std::string, NPObject*>* IcedTeaPluginUtilities::object_map = new std::map<std::string, NPObject*>();
61std::queue<std::string> pre_jvm_message;
62
63/* Plugin async call queue */
64static std::vector< PluginThreadCall* >* pendingPluginThreadRequests = new std::vector< PluginThreadCall* >();
65
66void *flush_pre_init_messages(void* data) {
67 while (true){
68 struct timespec ts;
69 ts.tv_sec = 1;
70 ts.tv_nsec = 0;
71 nanosleep(&ts ,0);
72 if (jvm_up) {
73 while (!pre_jvm_message.empty()) {
74 pthread_mutex_lock(&debug_pipe_lock);
75 std::string message = pre_jvm_message.front();
76 pre_jvm_message.pop();
77 pthread_mutex_unlock(&debug_pipe_lock);
78 plugin_send_message_to_appletviewer_console(message.c_str());
79 }
80 flush_plugin_send_message_to_appletviewer_console();
81 }
82 }
83 return NULL;
84}
85
86void push_pre_init_messages(char * ldm){
87 pthread_mutex_lock(&debug_pipe_lock);
88 pre_jvm_message.push(std::string(ldm));
89 pthread_mutex_unlock(&debug_pipe_lock);
90}
91
92void reset_pre_init_messages(){
93 pre_jvm_message = std::queue<std::string>();
94 }
95
96/**
97 * Given a context number, constructs a message prefix to send to Java
98 *
99 * @param context The context of the request
100 * @return The string prefix (allocated on heap)
101 */
102
103void
104IcedTeaPluginUtilities::constructMessagePrefix(int context, std::string *result)
105{
106 std::string context_str = std::string();
107
108 itoa(context, &context_str);
109
110 result->append("context ");
111 result->append(context_str);
112 result->append(" reference -1");
113
114}
115
116/**
117 * Given a context number, and reference number, constructs a message prefix to
118 * send to Java
119 *
120 * @param context The context of the request
121 * @param rerefence The reference number of the request
122 * @param result The message
123 */
124
125void
126IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference, std::string* result)
127{
128 // Until security is implemented, use file:// source for _everything_
129
130 std::string context_str = std::string();
131 std::string reference_str = std::string();
132
133 itoa(context, &context_str);
134 itoa(reference, &reference_str);
135
136 *result += "context ";
137 result->append(context_str);
138 *result += " reference ";
139 result->append(reference_str);
140}
141
142/**
143 * Given a context number, reference number, and source location, constructs
144 * a message prefix to send to Java
145 *
146 * @param context The context of the request
147 * @param rerefence The reference number of the request
148 * @param address The address for the script that made the request
149 * @param result The message
150 */
151
152void
153IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference,
154 std::string address,
155 std::string* result)
156{
157 std::string context_str = std::string();
158 std::string reference_str = std::string();
159
160 itoa(context, &context_str);
161 itoa(reference, &reference_str);
162
163 *result += "context ";
164 result->append(context_str);
165 *result += " reference ";
166 result->append(reference_str);
167
168 if (address.length() > 0)
169 {
170 *result += " src ";
171 result->append(address);
172 }
173}
174
175/**
176 * Returns a string representation of a void pointer
177 *
178 * @param id The pointer
179 * @param result The string representation
180 */
181
182void
183IcedTeaPluginUtilities::JSIDToString(void* id, std::string* result)
184{
185 char id_str[NUM_STR_BUFFER_SIZE];
186
187 if (sizeof(void*) == sizeof(long long))
188 {
189 snprintf(id_str, NUM_STR_BUFFER_SIZE, "%llu", id);
190 }
191 else
192 {
193 snprintf(id_str, NUM_STR_BUFFER_SIZE, "%lu", id); // else use long
194 }
195
196 result->append(id_str);
197
198 PLUGIN_DEBUG("Converting pointer %p to %s\n", id, id_str);
199}
200
201/**
202 * Returns a void pointer from a string representation
203 *
204 * @param id_str The string representation
205 * @return The pointer
206 */
207
208void*
209IcedTeaPluginUtilities::stringToJSID(std::string id_str)
210{
211 void* ptr;
212 if (sizeof(void*) == sizeof(long long))
213 {
214 PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str.c_str(), strtoull(id_str.c_str(), NULL, 0));
215 ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str.c_str(), NULL, 0));
216 } else
217 {
218 PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str.c_str(), strtoul(id_str.c_str(), NULL, 0));
219 ptr = reinterpret_cast <void*> ((unsigned long) strtoul(id_str.c_str(), NULL, 0));
220 }
221
222 PLUGIN_DEBUG("Casted: %p\n", ptr);
223
224 return ptr;
225}
226
227/**
228 * Returns a void pointer from a string representation
229 *
230 * @param id_str The pointer to the string representation
231 * @return The pointer
232 */
233
234void*
235IcedTeaPluginUtilities::stringToJSID(std::string* id_str)
236{
237 void* ptr;
238 if (sizeof(void*) == sizeof(long long))
239 {
240 PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str->c_str(), strtoull(id_str->c_str(), NULL, 0));
241 ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str->c_str(), NULL, 0));
242 } else
243 {
244 PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str->c_str(), strtoul(id_str->c_str(), NULL, 0));
245 ptr = reinterpret_cast <void*> ((unsigned long) strtoul(id_str->c_str(), NULL, 0));
246 }
247
248 PLUGIN_DEBUG("Casted: %p\n", ptr);
249
250 return ptr;
251}
252
253/**
254 * Increments the global reference number and returns it.
255 *
256 * This function is thread-safe.
257 */
258int
259IcedTeaPluginUtilities::getReference()
260{
261 pthread_mutex_lock(&reference_mutex);
262
263 // If we are nearing the max, reset
264 if (reference < -0x7FFFFFFF + 10) {
265 reference = -1;
266 }
267
268 reference--;
269 pthread_mutex_unlock(&reference_mutex);
270
271 return reference;
272}
273
274/**
275 * Decrements the global reference number.
276 *
277 * This function is thread-safe.
278 */
279void
280IcedTeaPluginUtilities::releaseReference()
281{
282 // do nothing for now
283}
284
285/**
286 * Converts integer to char*
287 *
288 * @param i The integer to convert to ascii
289 * @param result The resulting string
290 */
291void
292IcedTeaPluginUtilities::itoa(int i, std::string* result)
293{
294 char int_str[NUM_STR_BUFFER_SIZE];
295 snprintf(int_str, NUM_STR_BUFFER_SIZE, "%d", i);
296 result->append(int_str);
297}
298
299/**
300 * Frees memory from a string* vector
301 *
302 * The vector deconstructor will only delete string pointers upon being
303 * called. This function frees the associated string memory as well.
304 *
305 * @param v The vector whose strings are to be freed
306 */
307void
308IcedTeaPluginUtilities::freeStringPtrVector(std::vector<std::string*>* v)
309{
310 if (v)
311 {
312 for (int i=0; i < v->size(); i++) {
313 delete v->at(i);
314 }
315
316 delete v;
317 }
318
319}
320
321/**
322 * Given a string, splits it on the given delimiters.
323 *
324 * @param str The string to split
325 * @param The delimiters to split on
326 * @return A string vector containing the split components
327 */
328
329std::vector<std::string*>*
330IcedTeaPluginUtilities::strSplit(const char* str, const char* delim)
331{
332 std::vector<std::string*>* v = new std::vector<std::string*>();
333 v->reserve(strlen(str)/2);
334 char* copy;
335
336 // Tokenization is done on a copy
337 copy = (char*) malloc (sizeof(char)*strlen(str) + 1);
338 strcpy(copy, str);
339
340 char* tok_ptr;
341 tok_ptr = strtok (copy, delim);
342
343 while (tok_ptr != NULL)
344 {
345 // Allocation on heap since caller has no way to knowing how much will
346 // be needed. Make sure caller cleans up!
347 std::string* s = new std::string();
348 s->append(tok_ptr);
349 v->push_back(s);
350 tok_ptr = strtok (NULL, delim);
351 }
352 free(copy);
353
354 return v;
355}
356
357/**
358 * Given a unicode byte array, converts it to a UTF8 string
359 *
360 * The actual contents in the array may be surrounded by other data.
361 *
362 * e.g. with length 5, begin = 3,
363 * unicode_byte_array = "37 28 5 48 45 4c 4c 4f 9e 47":
364 *
365 * We'd start at 3 i.e. "48" and go on for 5 i.e. upto and including "4f".
366 * So we convert "48 45 4c 4c 4f" which is "hello"
367 *
368 * @param length The length of the string
369 * @param begin Where in the array to begin conversion
370 * @param result_unicode_str The return variable in which the
371 * converted string is placed
372 */
373
374void
375IcedTeaPluginUtilities::getUTF8String(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::string* result_unicode_str)
376{
377 result_unicode_str->clear();
378 result_unicode_str->reserve(unicode_byte_array->size()/2);
379 for (int i = begin; i < begin+length; i++)
380 result_unicode_str->push_back((char) strtol(unicode_byte_array->at(i)->c_str(), NULL, 16));
381
382 PLUGIN_DEBUG("Converted UTF-8 string: %s. Length=%d\n", result_unicode_str->c_str(), result_unicode_str->length());
383}
384
385/**
386 * Given a UTF8 string, converts it to a space delimited string of hex characters
387 *
388 * The first element in the return array is the length of the string
389 *
390 * e.g. "hello" would convert to: "5 48 45 4c 4c 4f"
391 *
392 * @param str The string to convert
393 * @param urt_str The result
394 */
395
396void
397IcedTeaPluginUtilities::convertStringToUTF8(std::string* str, std::string* utf_str)
398{
399 std::ostringstream ostream;
400
401 std::string length = std::string();
402 itoa(str->length(), &length);
403
404 ostream << length;
405
406 char hex_value[NUM_STR_BUFFER_SIZE];
407
408 for (int i = 0; i < str->length(); i++)
409 {
410 snprintf(hex_value, NUM_STR_BUFFER_SIZE," %hx", str->at(i));
411 ostream << hex_value;
412 }
413
414 utf_str->clear();
415 *utf_str = ostream.str();
416
417 PLUGIN_DEBUG("Converted %s to UTF-8 string %s\n", str->c_str(), utf_str->c_str());
418}
419
420/**
421 * Given a unicode byte array, converts it to a UTF16LE/UCS-2 string
422 *
423 * This works in a manner similar to getUTF8String, except that it reads 2
424 * slots for each byte.
425 *
426 * @param length The length of the string
427 * @param begin Where in the array to begin conversion
428 * @param result_unicode_str The return variable in which the
429 * converted string is placed
430 */
431void
432IcedTeaPluginUtilities::getUTF16LEString(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::wstring* result_unicode_str)
433{
434
435 wchar_t c;
436
437 PLUGIN_DEBUG("Converted UTF-16LE string: \n");
438
439 result_unicode_str->clear();
440 for (int i = begin; i < begin+length; i+=2)
441 {
442 int low = strtol(unicode_byte_array->at(i)->c_str(), NULL, 16);
443 int high = strtol(unicode_byte_array->at(i+1)->c_str(), NULL, 16);
444
445 c = ((high << 8) | low);
446
447 if ((c >= 'a' && c <= 'z') ||
448 (c >= 'A' && c <= 'Z') ||
449 (c >= '0' && c <= '9'))
450 {
451 PLUGIN_DEBUG("%c\n", c);
452 }
453
454 result_unicode_str->push_back(c);
455 }
456
457 // not routing via debug print macros due to wide-string issues
458 PLUGIN_DEBUG(". Length=%d\n", result_unicode_str->length());
459}
460
461/*
462 * Prints the given string vector (if debug is true)
463 *
464 * @param prefix The prefix to print before printing the vector contents
465 * @param cv The string vector whose contents are to be printed
466 */
467void
468IcedTeaPluginUtilities::printStringVector(const char* prefix, std::vector<std::string>* str_vector)
469{
470
471 // This is a CPU intensive function. Run only if debugging
472 if (!plugin_debug)
473 return;
474
475 std::string* str = new std::string();
476 *str += "{ ";
477 for (int i=0; i < str_vector->size(); i++)
478 {
479 *str += str_vector->at(i);
480
481 if (i != str_vector->size() - 1)
482 *str += ", ";
483 }
484
485 *str += " }";
486
487 PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
488
489 delete str;
490}
491
492const char*
493IcedTeaPluginUtilities::getSourceFromInstance(NPP instance)
494{
495 // At the moment, src cannot be securely fetched via NPAPI
496 // See:
497 // http://www.mail-archive.com/chromium-dev@googlegroups.com/msg04872.html
498
499 // Since we use the insecure window.location.href attribute to compute
500 // source, we cannot use it to make security decisions. Therefore,
501 // instance associated source will always return empty
502
503 //ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
504 //return (data->source) ? data->source : "";
505
506 return "http://null.null";
507}
508
509/**
510 * Stores a window pointer <-> instance mapping
511 *
512 * @param member_ptr The pointer key
513 * @param instance The instance to associate with this pointer
514 */
515
516void
517IcedTeaPluginUtilities::storeInstanceID(void* member_ptr, NPP instance)
518{
519 PLUGIN_DEBUG("Storing instance %p with key %p\n", instance, member_ptr);
520 instance_map->insert(std::make_pair(member_ptr, instance));
521}
522
523/**
524 * Removes a window pointer <-> instance mapping
525 *
526 * @param member_ptr The key to remove
527 */
528
529void
530IcedTeaPluginUtilities::removeInstanceID(void* member_ptr)
531{
532 PLUGIN_DEBUG("Removing key %p from instance map\n", member_ptr);
533 instance_map->erase(member_ptr);
534}
535
536/* Clear instance_map. Useful for tests. */
537void
538IcedTeaPluginUtilities::clearInstanceIDs()
539{
540 delete instance_map;
541 instance_map = new std::map<void*, NPP>();
542}
543
544/**
545 * Removes all mappings to a given instance, and all associated objects
546 */
547void
548IcedTeaPluginUtilities::invalidateInstance(NPP instance)
549{
550 PLUGIN_DEBUG("Invalidating instance %p\n", instance);
551
552 std::map<void*,NPP>::iterator iterator;
553
554 for (iterator = instance_map->begin(); iterator != instance_map->end(); )
555 {
556 if ((*iterator).second == instance)
557 {
558 instance_map->erase(iterator++);
559 }
560 else
561 {
562 ++iterator;
563 }
564 }
565}
566
567/**
568 * Given the window pointer, returns the instance associated with it
569 *
570 * @param member_ptr The pointer key
571 * @return The associated instance
572 */
573
574NPP
575IcedTeaPluginUtilities::getInstanceFromMemberPtr(void* member_ptr)
576{
577
578 NPP instance = NULL;
579 PLUGIN_DEBUG("getInstanceFromMemberPtr looking for %p\n", member_ptr);
580
581 std::map<void*, NPP>::iterator iterator = instance_map->find(member_ptr);
582
583 if (iterator != instance_map->end())
584 {
585 instance = instance_map->find(member_ptr)->second;
586 PLUGIN_DEBUG("getInstanceFromMemberPtr found %p. Instance = %p\n", member_ptr, instance);
587 }
588
589 return instance;
590}
591
592/**
593 * Given a java id key ('classid:instanceid'), returns the associated valid NPObject, if any
594 *
595 * @param key the key
596 * @return The associated active NPObject, NULL otherwise
597 */
598
599NPObject*
600IcedTeaPluginUtilities::getNPObjectFromJavaKey(std::string key)
601{
602
603 NPObject* object = NULL;
604 PLUGIN_DEBUG("getNPObjectFromJavaKey looking for %s\n", key.c_str());
605
606 std::map<std::string, NPObject*>::iterator iterator = object_map->find(key);
607
608 if (iterator != object_map->end())
609 {
610 NPObject* mapped_object = object_map->find(key)->second;
611
612 if (getInstanceFromMemberPtr(mapped_object) != NULL)
613 {
614 object = mapped_object;
615 PLUGIN_DEBUG("getNPObjectFromJavaKey found %s. NPObject = %p\n", key.c_str(), object);
616 }
617 }
618
619 return object;
620}
621
622/**
623 * Stores a java id key <-> NPObject mapping
624 *
625 * @param key The Java ID Key
626 * @param object The object to map to
627 */
628
629void
630IcedTeaPluginUtilities::storeObjectMapping(std::string key, NPObject* object)
631{
632 PLUGIN_DEBUG("Storing object %p with key %s\n", object, key.c_str());
633 object_map->insert(std::make_pair(key, object));
634}
635
636/**
637 * Removes a java id key <-> NPObject mapping
638 *
639 * @param key The key to remove
640 */
641
642void
643IcedTeaPluginUtilities::removeObjectMapping(std::string key)
644{
645 PLUGIN_DEBUG("Removing key %s from object map\n", key.c_str());
646 object_map->erase(key);
647}
648
649/* Clear object_map. Useful for tests. */
650void
651IcedTeaPluginUtilities::clearObjectMapping()
652{
653 std::map<std::string, NPObject*>::iterator iter = object_map->begin();
654 for (; iter != object_map->end(); ++iter) {
655 browser_functions.releaseobject(iter->second);
656 }
657 delete object_map;
658 object_map = new std::map<std::string, NPObject*>();
659}
660
661/*
662 * Similar to printStringVector, but takes a vector of string pointers instead
663 *
664 * @param prefix The prefix to print before printing the vector contents
665 * @param cv The string* vector whose contents are to be printed
666 */
667
668void
669IcedTeaPluginUtilities::printStringPtrVector(const char* prefix, std::vector<std::string*>* str_ptr_vector)
670{
671 // This is a CPU intensive function. Run only if debugging
672 if (!plugin_debug)
673 return;
674
675 std::string* str = new std::string();
676 *str += "{ ";
677 for (int i=0; i < str_ptr_vector->size(); i++)
678 {
679 *str += *(str_ptr_vector->at(i));
680
681 if (i != str_ptr_vector->size() - 1)
682 *str += ", ";
683 }
684
685 *str += " }";
686
687 PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
688
689 delete str;
690}
691
692void
693IcedTeaPluginUtilities::printNPVariant(NPVariant variant)
694{
695 // This is a CPU intensive function. Run only if debugging
696 if (!plugin_debug)
697 return;
698
699 if (NPVARIANT_IS_VOID(variant))
700 {
701 PLUGIN_DEBUG("VOID %d\n", variant);
702 }
703 else if (NPVARIANT_IS_NULL(variant))
704 {
705 PLUGIN_DEBUG("NULL\n", variant);
706 }
707 else if (NPVARIANT_IS_BOOLEAN(variant))
708 {
709 PLUGIN_DEBUG("BOOL: %d\n", NPVARIANT_TO_BOOLEAN(variant));
710 }
711 else if (NPVARIANT_IS_INT32(variant))
712 {
713 PLUGIN_DEBUG("INT32: %d\n", NPVARIANT_TO_INT32(variant));
714 }
715 else if (NPVARIANT_IS_DOUBLE(variant))
716 {
717 PLUGIN_DEBUG("DOUBLE: %f\n", NPVARIANT_TO_DOUBLE(variant));
718 }
719 else if (NPVARIANT_IS_STRING(variant))
720 {
721 std::string str = IcedTeaPluginUtilities::NPVariantAsString(variant);
722 PLUGIN_DEBUG("STRING: %s (length=%d)\n", str.c_str(), str.size());
723 }
724 else
725 {
726 PLUGIN_DEBUG("OBJ: %p\n", NPVARIANT_TO_OBJECT(variant));
727 }
728}
729
730void
731IcedTeaPluginUtilities::NPVariantToString(NPVariant variant, std::string* result)
732{
733 char conv_str[NUM_STR_BUFFER_SIZE]; // conversion buffer
734 bool was_string_already = false;
735
736 if (NPVARIANT_IS_STRING(variant))
737 {
738 result->append(IcedTeaPluginUtilities::NPVariantAsString(variant));
739 was_string_already = true;
740 }
741 else if (NPVARIANT_IS_VOID(variant))
742 {
743 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "%p", variant);
744 }
745 else if (NPVARIANT_IS_NULL(variant))
746 {
747 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "NULL");
748 }
749 else if (NPVARIANT_IS_BOOLEAN(variant))
750 {
751 if (NPVARIANT_TO_BOOLEAN(variant))
752 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "true");
753 else
754 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "false");
755 }
756 else if (NPVARIANT_IS_INT32(variant))
757 {
758 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "%d", NPVARIANT_TO_INT32(variant));
759 }
760 else if (NPVARIANT_IS_DOUBLE(variant))
761 {
762 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "%f", NPVARIANT_TO_DOUBLE(variant));
763 }
764 else
765 {
766 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "[Object %p]", variant);
767 }
768
769 if (!was_string_already){
770 result->append(conv_str);
771 }
772}
773
774/**
775 * Convert either a void, boolean, or a number
776 */
777static void
778javaPrimitiveResultToNPVariant(const std::string& value, NPVariant* variant)
779{
780 if (value == "void")
781 {
782 PLUGIN_DEBUG("Method call returned void\n");
783 VOID_TO_NPVARIANT(*variant);
784 } else if (value == "null")
785 {
786 PLUGIN_DEBUG("Method call returned null\n");
787 NULL_TO_NPVARIANT(*variant);
788 } else if (value == "true")
789 {
790 PLUGIN_DEBUG("Method call returned a boolean (true)\n");
791 BOOLEAN_TO_NPVARIANT(true, *variant);
792 } else if (value == "false")
793 {
794 PLUGIN_DEBUG("Method call returned a boolean (false)\n");
795 BOOLEAN_TO_NPVARIANT(false, *variant);
796 } else
797 {
798 double d = strtod(value.c_str(), NULL);
799
800 // See if it is convertible to int
801 if (value.find(".") != std::string::npos || d < -(0x7fffffffL - 1L) || d > 0x7fffffffL)
802 {
803 PLUGIN_DEBUG("Method call returned a double %f\n", d);
804 DOUBLE_TO_NPVARIANT(d, *variant);
805 } else
806 {
807 int32_t i = (int32_t) d;
808 PLUGIN_DEBUG("Method call returned an int %d\n", i);
809 INT32_TO_NPVARIANT(i, *variant);
810 }
811 }
812}
813
814static bool
815javaStringResultToNPVariant(const std::string& jobject_id, NPVariant* variant)
816{
817 JavaRequestProcessor jrequest_processor;
818 JavaResultData* jstring_result = jrequest_processor.getString(jobject_id);
819
820 if (jstring_result->error_occurred)
821 {
822 return false;
823 }
824
825 std::string str = *jstring_result->return_string;
826
827 PLUGIN_DEBUG( "Method call returned a string:\"%s\"\n", str.c_str());
828
829 *variant = IcedTeaPluginUtilities::NPVariantStringCopy(str);
830
831 return true;
832}
833
834static bool
835javaJSObjectResultToNPVariant(const std::string& js_id, NPVariant* variant)
836{
837 NPVariant* result_variant = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(js_id);
838 *variant = *result_variant;
839 return true;
840}
841
842static bool
843javaObjectResultToNPVariant(NPP instance, const std::string& jobject_id, NPVariant* variant)
844{
845 // Reference the class object so we can construct an NPObject with it and the instance
846
847 JavaRequestProcessor jrequest_processor;
848 JavaResultData* jclass_result = jrequest_processor.getClassID(jobject_id);
849
850 if (jclass_result->error_occurred)
851 {
852 return false;
853 }
854
855 std::string jclass_id = *jclass_result->return_string;
856
857 NPObject* obj;
858 if (jclass_id.at(0) == '[') // array
859 {
860 obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(instance, jclass_id,
861 jobject_id, true);
862 } else
863 {
864 obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(instance, jclass_id,
865 jobject_id, false);
866 }
867
868 OBJECT_TO_NPVARIANT(obj, *variant);
869
870 return true;
871}
872
873bool
874IcedTeaPluginUtilities::javaResultToNPVariant(NPP instance,
875 std::string* java_value, NPVariant* variant)
876{
877 int literal_n = sizeof("literalreturn"); // Accounts for one space char
878 int jsobject_n = sizeof("jsobject"); // Accounts for one space char
879
880 if (strncmp("literalreturn ", java_value->c_str(), literal_n) == 0)
881 {
882 javaPrimitiveResultToNPVariant(java_value->substr(literal_n), variant);
883 } else if (strncmp("jsobject ", java_value->c_str(), jsobject_n) == 0)
884 {
885 javaJSObjectResultToNPVariant(java_value->substr(jsobject_n), variant);
886 } else
887 {
888 std::string jobject_id = *java_value;
889
890 JavaRequestProcessor jrequest_processor;
891 JavaResultData* jclassname_result = jrequest_processor.getClassName(jobject_id);
892
893 if (jclassname_result->error_occurred)
894 {
895 return false;
896 }
897
898 // Special-case for NPString if string
899 if (*jclassname_result->return_string == "java.lang.String")
900 {
901 return javaStringResultToNPVariant(jobject_id, variant);
902 } else // Else this needs a java object wrapper
903 {
904 return javaObjectResultToNPVariant(instance, jobject_id, variant);
905 }
906 }
907
908 return true;
909}
910
911bool
912IcedTeaPluginUtilities::isObjectJSArray(NPP instance, NPObject* object)
913{
914
915 NPVariant constructor_v = NPVariant();
916 NPIdentifier constructor_id = browser_functions.getstringidentifier("constructor");
917 browser_functions.getproperty(instance, object, constructor_id, &constructor_v);
918 IcedTeaPluginUtilities::printNPVariant(constructor_v);
919
920 // void constructor => not an array
921 if (NPVARIANT_IS_VOID(constructor_v))
922 return false;
923
924 NPObject* constructor = NPVARIANT_TO_OBJECT(constructor_v);
925
926 NPVariant constructor_str;
927 NPIdentifier toString = browser_functions.getstringidentifier("toString");
928 browser_functions.invoke(instance, constructor, toString, NULL, 0, &constructor_str);
929 IcedTeaPluginUtilities::printNPVariant(constructor_str);
930
931 std::string constructor_name = IcedTeaPluginUtilities::NPVariantAsString(constructor_str);
932
933 PLUGIN_DEBUG("Constructor for NPObject is %s\n", constructor_name.c_str());
934
935 return constructor_name.find("function Array") == 0;
936}
937
938void
939IcedTeaPluginUtilities::decodeURL(const gchar* url, gchar** decoded_url)
940{
941
942 PLUGIN_DEBUG("GOT URL: %s -- %s\n", url, *decoded_url);
943 int length = strlen(url);
944 for (int i=0; i < length; i++)
945 {
946 if (url[i] == '%' && i < length - 2)
947 {
948 unsigned char code1 = (unsigned char) url[i+1];
949 unsigned char code2 = (unsigned char) url[i+2];
950
951 if (!IS_VALID_HEX(&code1) || !IS_VALID_HEX(&code2))
952 continue;
953
954 // Convert hex value to integer
955 int converted1 = HEX_TO_INT(&code1);
956 int converted2 = HEX_TO_INT(&code2);
957
958 // bitshift 4 to simulate *16
959 int value = (converted1 << 4) + converted2;
960 char decoded = value;
961
962 strncat(*decoded_url, &decoded, 1);
963
964 i += 2;
965 } else
966 {
967 strncat(*decoded_url, &url[i], 1);
968 }
969 }
970
971 PLUGIN_DEBUG("SENDING URL: %s\n", *decoded_url);
972}
973
974/* Copies a variant data type into a C++ string */
975std::string
976IcedTeaPluginUtilities::NPVariantAsString(NPVariant variant)
977{
978 return std::string(
979 NPVARIANT_TO_STRING(variant).UTF8Characters,
980 NPVARIANT_TO_STRING(variant).UTF8Length);
981}
982
983/**
984 * Posts a function for execution on the plug-in thread and wait for result.
985 *
986 * @param instance The NPP instance
987 * @param func The function to post
988 * @param data Arguments to *func
989 */
990NPString IcedTeaPluginUtilities::NPStringCopy(const std::string& result) {
991 char* utf8 = (char*)browser_functions.memalloc(result.size() + 1);
992 strncpy(utf8, result.c_str(), result.size() + 1);
993
994 NPString npstr = {utf8, result.size()};
995 return npstr;
996}
997
998NPVariant IcedTeaPluginUtilities::NPVariantStringCopy(const std::string& result) {
999 NPString npstr = NPStringCopy(result);
1000 NPVariant npvar;
1001 STRINGN_TO_NPVARIANT(npstr.UTF8Characters, npstr.UTF8Length, npvar);
1002 return npvar;
1003}
1004
1005void
1006IcedTeaPluginUtilities::callAndWaitForResult(NPP instance, void (*func) (void *), AsyncCallThreadData* data)
1007{
1008
1009 struct timespec t;
1010 struct timespec curr_t;
1011#ifdef __OS2__
1012 t.tv_sec = time(NULL);
1013 t.tv_nsec = 0;
1014 curr_t.tv_sec = curr_t.tv_nsec = 0;
1015#else
1016 clock_gettime(CLOCK_REALTIME, &t);
1017#endif
1018 t.tv_sec += REQUESTTIMEOUT; // timeout
1019
1020 // post request
1021 postPluginThreadAsyncCall(instance, func, data);
1022
1023 do
1024 {
1025#ifdef __OS2__
1026 curr_t.tv_sec = time(NULL);
1027#else
1028 clock_gettime(CLOCK_REALTIME, &curr_t);
1029#endif
1030 if (data != NULL && !data->result_ready && (curr_t.tv_sec < t.tv_sec))
1031 {
1032 usleep(2000);
1033 } else
1034 {
1035 break;
1036 }
1037 } while (1);
1038}
1039
1040
1041/**
1042 * Posts a request that needs to be handled in a plugin thread.
1043 *
1044 * @param instance The plugin instance
1045 * @param func The function to execute
1046 * @param userData The userData for the function to consume/write to
1047 * @return if the call was posted successfully
1048 */
1049
1050bool
1051IcedTeaPluginUtilities::postPluginThreadAsyncCall(NPP instance, void (*func) (void *), void* data)
1052{
1053 if (instance)
1054 {
1055 PluginThreadCall* call = new PluginThreadCall();
1056 call->instance = instance;
1057 call->func = func;
1058 call->userData = data;
1059
1060 pthread_mutex_lock(&pluginAsyncCallMutex);
1061 pendingPluginThreadRequests->push_back(call);
1062 pthread_mutex_unlock(&pluginAsyncCallMutex);
1063
1064 browser_functions.pluginthreadasynccall(instance, &processAsyncCallQueue, NULL); // Always returns immediately
1065
1066 PLUGIN_DEBUG("Pushed back call evt %p\n", call);
1067
1068 return true;
1069 }
1070
1071 // Else
1072 PLUGIN_DEBUG("Instance is not active. Call rejected.\n");
1073 return false;
1074}
1075
1076/**
1077 * Returns a vector of gchar* pointing to the elements of the vector string passed in.
1078 * @param stringVec The vector of strings reference.
1079 */
1080std::vector<gchar*>
1081IcedTeaPluginUtilities::vectorStringToVectorGchar(const std::vector<std::string>* stringVec)
1082{
1083 std::vector<gchar*> charVec;
1084
1085 for (int i = 0; i < stringVec->size(); i++)
1086 {
1087 gchar* element = (gchar*) stringVec->at(i).c_str(); //cast from const char
1088 charVec.push_back(element);
1089 }
1090 charVec.push_back(NULL);
1091 return charVec;
1092}
1093
1094/**
1095 * Runs through the async call wait queue and executes all calls
1096 *
1097 * @param param Ignored -- required to conform to NPN_PluginThreadAsynCall API
1098 */
1099void
1100processAsyncCallQueue(void* param /* ignored */)
1101{
1102 do {
1103 PluginThreadCall* call = NULL;
1104
1105 pthread_mutex_lock(&pluginAsyncCallMutex);
1106 if (pendingPluginThreadRequests->size() > 0)
1107 {
1108 call = pendingPluginThreadRequests->front();
1109 pendingPluginThreadRequests->erase(pendingPluginThreadRequests->begin());
1110 }
1111 pthread_mutex_unlock(&pluginAsyncCallMutex);
1112
1113 if (call)
1114 {
1115 PLUGIN_DEBUG("Processing call evt %p\n", call);
1116 call->func(call->userData);
1117 PLUGIN_DEBUG("Call evt %p processed\n", call);
1118
1119 delete call;
1120 } else
1121 {
1122 break;
1123 }
1124 } while(1);
1125}
1126
1127void IcedTeaPluginUtilities::trim(std::string& str) {
1128 size_t start = str.find_first_not_of(" \t\n"), end = str.find_last_not_of(" \t\n");
1129 if (start == std::string::npos) {
1130 return;
1131 }
1132 str = str.substr(start, end - start + 1);
1133}
1134
1135std::string IcedTeaPluginUtilities::NPIdentifierAsString(NPIdentifier id) {
1136 NPUTF8* cstr = browser_functions.utf8fromidentifier(id);
1137 if (cstr == NULL) {
1138 /* Treat not-existing strings as empty. To tell if it was a valid string,
1139 * use browser_functions.identifierisstring. */
1140 return std::string();
1141 }
1142 std::string str = cstr;
1143 browser_functions.memfree(cstr);
1144 return str;
1145}
1146
1147bool IcedTeaPluginUtilities::file_exists(std::string filename)
1148{
1149 std::ifstream infile(filename.c_str());
1150 return infile.good();
1151}
1152
1153void IcedTeaPluginUtilities::initFileLog(){
1154 if (plugin_file_log != NULL ) {
1155 //reusing
1156 return;
1157 }
1158 plugin_file_log_name = get_log_dir() + "/" + IcedTeaPluginUtilities::generateLogFileName();
1159 int plugin_file_log_fd = open(plugin_file_log_name.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600);
1160 if (plugin_file_log_fd <=0 ) {
1161 plugin_debug_to_file = false;
1162 } else {
1163 plugin_file_log = fdopen(plugin_file_log_fd, "w");
1164 }
1165 if (plugin_file_log == NULL ) {
1166 plugin_debug_to_file = false;
1167 }
1168}
1169
1170
1171
1172std::string IcedTeaPluginUtilities::generateLogFileName(){
1173 char times[96];
1174 char result[100];
1175 time_t t = time(NULL);
1176 struct tm p;
1177 localtime_r(&t, &p);
1178 struct timeval current_time; \
1179 gettimeofday (&current_time, NULL);\
1180 strftime(times, 96, "%Y-%m-%d_%H:%M:%S", &p);
1181 snprintf(result, 100, "%s.%i",times, current_time.tv_usec/1000);
1182 return "itw-cplugin-"+std::string(result)+".log";
1183}
1184
1185void IcedTeaPluginUtilities::printDebugStatus(){
1186 if (plugin_debug){
1187 PLUGIN_DEBUG("plugin_debug: true, initialised\n");
1188 if (plugin_debug_headers){
1189 PLUGIN_DEBUG("plugin_debug_headers: true\n");
1190 } else {
1191 PLUGIN_DEBUG("plugin_debug_headers: false\n");
1192 }
1193 if (plugin_debug_to_file){
1194 PLUGIN_DEBUG("plugin_debug_to_file: true, using %s\n", plugin_file_log_name.c_str());
1195 } else {
1196 PLUGIN_DEBUG("plugin_debug_to_file: false\n");
1197 }
1198 if (plugin_debug_to_streams){
1199 PLUGIN_DEBUG("plugin_debug_to_streams: true\n");
1200 } else {
1201 PLUGIN_DEBUG("plugin_debug_to_streams: false\n");
1202 }
1203 if (plugin_debug_to_system){
1204 PLUGIN_DEBUG("plugin_debug_to_system: true\n");
1205 } else {
1206 PLUGIN_DEBUG("plugin_debug_to_system: false\n");
1207 }
1208 if (plugin_debug_to_console){
1209#ifdef __OS2__
1210 if (debug_pipe[0] != -1){
1211 PLUGIN_DEBUG("plugin_debug_to_console: true, pipe %d\n", debug_pipe[0]);
1212 }
1213#else
1214 if (debug_pipe_name){
1215 PLUGIN_DEBUG("plugin_debug_to_console: true, pipe %s\n", debug_pipe_name);
1216 } else {
1217 PLUGIN_DEBUG("plugin_debug_to_console: true, pipe not yet known or broken\n");
1218 }
1219#endif
1220 } else {
1221 PLUGIN_DEBUG("plugin_debug_to_console: false\n");
1222 }
1223 }
1224 }
1225
1226
1227std::string IcedTeaPluginUtilities::getTmpPath(){
1228 const char* tmpdir_env = getenv("TMPDIR");
1229 if (tmpdir_env != NULL && g_file_test (tmpdir_env,
1230 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
1231 {
1232 return std::string(tmpdir_env);
1233 }
1234 else if (g_file_test (P_tmpdir,
1235 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
1236 {
1237 return std::string(P_tmpdir);
1238 }
1239 else
1240 {
1241 // If TMPDIR and P_tmpdir do not exist, try /tmp directly
1242 return "/tmp";
1243 }
1244}
1245
1246std::string IcedTeaPluginUtilities::getRuntimePath(){
1247 const char* rntdir_env = getenv("XDG_RUNTIME_DIR");
1248 if (rntdir_env != NULL && g_file_test (rntdir_env,
1249 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
1250 {
1251 return std::string(rntdir_env);
1252 }
1253 return IcedTeaPluginUtilities::getTmpPath();
1254}
1255
1256
1257/******************************************
1258 * Begin JavaMessageSender implementation *
1259 ******************************************
1260 *
1261 * This implementation is very simple and is therefore folded into this file
1262 * rather than a new one.
1263 */
1264
1265/**
1266 * Sends to the Java side
1267 *
1268 * @param message The message to send.
1269 * @param returns whether the message was consumable (always true)
1270 */
1271
1272bool
1273JavaMessageSender::newMessageOnBus(const char* message)
1274{
1275 char* msg = (char*) malloc(sizeof(char)*strlen(message) + 1);
1276 strcpy(msg, message);
1277 plugin_send_message_to_appletviewer(msg);
1278
1279 free(msg);
1280 msg = NULL;
1281
1282 // Always successful
1283 return true;
1284}
1285
1286/***********************************
1287 * Begin MessageBus implementation *
1288 ***********************************/
1289
1290/**
1291 * Constructor.
1292 *
1293 * Initializes the mutexes needed by the other functions.
1294 */
1295MessageBus::MessageBus()
1296{
1297 int ret;
1298
1299 ret = pthread_mutex_init(&subscriber_mutex, NULL);
1300
1301 if(ret)
1302 PLUGIN_DEBUG("Error: Unable to initialize subscriber mutex: %d\n", ret);
1303
1304 ret = pthread_mutex_init(&msg_queue_mutex, NULL);
1305 if(ret)
1306 PLUGIN_DEBUG("Error: Unable to initialize message queue mutex: %d\n", ret);
1307
1308 PLUGIN_DEBUG("Mutexes %p and %p initialized\n", &subscriber_mutex, &msg_queue_mutex);
1309}
1310
1311/**
1312 * Destructor.
1313 *
1314 * Destroy the mutexes initialized by the constructor.
1315 */
1316
1317MessageBus::~MessageBus()
1318{
1319 PLUGIN_DEBUG("MessageBus::~MessageBus\n");
1320
1321 int ret;
1322
1323 ret = pthread_mutex_destroy(&subscriber_mutex);
1324 if(ret)
1325 PLUGIN_DEBUG("Error: Unable to destroy subscriber mutex: %d\n", ret);
1326
1327 ret = pthread_mutex_destroy(&msg_queue_mutex);
1328 if(ret)
1329 PLUGIN_DEBUG("Error: Unable to destroy message queue mutex: %d\n", ret);
1330}
1331
1332/**
1333 * Adds the given BusSubscriber as a subscriber to self
1334 *
1335 * @param b The BusSubscriber to subscribe
1336 */
1337void
1338MessageBus::subscribe(BusSubscriber* b)
1339{
1340 // Applets may initialize in parallel. So lock before pushing.
1341
1342 PLUGIN_DEBUG("Subscribing %p to bus %p\n", b, this);
1343 pthread_mutex_lock(&subscriber_mutex);
1344 subscribers.push_back(b);
1345 pthread_mutex_unlock(&subscriber_mutex);
1346}
1347
1348/**
1349 * Removes the given BusSubscriber from the subscriber list
1350 *
1351 * @param b The BusSubscriber to ubsubscribe
1352 */
1353void
1354MessageBus::unSubscribe(BusSubscriber* b)
1355{
1356 // Applets may initialize in parallel. So lock before pushing.
1357
1358 PLUGIN_DEBUG("Un-subscribing %p from bus %p\n", b, this);
1359 pthread_mutex_lock(&subscriber_mutex);
1360 subscribers.remove(b);
1361 pthread_mutex_unlock(&subscriber_mutex);
1362}
1363
1364/**
1365 * Notifies all subscribers with the given message
1366 *
1367 * @param message The message to send to the subscribers
1368 */
1369void
1370MessageBus::post(const char* message)
1371{
1372 bool message_consumed = false;
1373
1374 PLUGIN_DEBUG("Trying to lock %p...\n", &msg_queue_mutex);
1375 pthread_mutex_lock(&subscriber_mutex);
1376
1377 PLUGIN_DEBUG("Message %s received on bus. Notifying subscribers.\n", message);
1378
1379 std::list<BusSubscriber*>::const_iterator i;
1380 for( i = subscribers.begin(); i != subscribers.end() && !message_consumed; ++i ) {
1381 PLUGIN_DEBUG("Notifying subscriber %p of %s\n", *i, message);
1382 message_consumed = ((BusSubscriber*) *i)->newMessageOnBus(message);
1383 }
1384
1385 pthread_mutex_unlock(&subscriber_mutex);
1386
1387 if (!message_consumed)
1388 PLUGIN_DEBUG("Warning: No consumer found for message %s\n", message);
1389
1390 PLUGIN_DEBUG("%p unlocked...\n", &msg_queue_mutex);
1391}
1392
Note: See TracBrowser for help on using the repository browser.