[mw-devel] MW3 r955 - trunk/src

psycodom at sucs.org psycodom at sucs.org
Thu Apr 26 14:58:18 BST 2007


Author: psycodom
Date: 2007-04-26 14:58:18 +0100 (Thu, 26 Apr 2007)
New Revision: 955

Modified:
   trunk/src/iconv.c
   trunk/src/iconv.h
   trunk/src/js.c
Log:
Stops the javascript dbquery() from segving.
Fixes javascript dbquery() for UTF-8 compatibility.
Implements a new convert_string_charset function in iconv.c that removes lots of code duplication in iconv functions.
Cleans up the javscript UTF-8 conversion code using new convert_string_charset to remove a mass of code duplication.



Modified: trunk/src/iconv.c
===================================================================
--- trunk/src/iconv.c	2007-04-26 13:39:31 UTC (rev 954)
+++ trunk/src/iconv.c	2007-04-26 13:58:18 UTC (rev 955)
@@ -6,6 +6,8 @@
 #include <iconv.h>
 #include <locale.h>
 
+#include "iconv.h"
+
 #ifdef TEST_ICONV
 #  define DEBUG_ICONV
 #endif
@@ -16,9 +18,233 @@
 
 static char * local_charset = NULL;
 
+/**** convert_string_charset ****
+	a generic iconv function to convert a string from any charset to another 
+	expects memory to be allocated for output_buffer 
+   
+	returns: 0 if successful. 
+			 +ve if something was converted but errors occured in the conversion 
+			 -ve if the conversion fails.
+	input_buffer: pointer to the string you want to convert.
+	input_charset: the iconv encoding description string of the input string
+	input_length: the length in bytes of the input string
+	output_buffer: pointer to the memory to put the converted string into (must be allocated)
+	output_charset: the iconv encoding description string of the output string
+	output_buffer_length: the number of bytes allocated for output_buffer
+	unconverted_bytes: on _toolong_ the number of bytes in input buffer that were not converted.
+	output_bytes_used: on success/toolong/invalchars the number of bytes used in output_buffer
+	invalid_count: on invalchars the number of invalid chars that were discovered in the string
+	irreversible_count: on _success_ the number of chars that were converted in an irreversible way
+	substitute: if an invalid char is discovered replace it with this ***UTF-8*** string
+					(the utf8 string is converted into your desired charset)
+	
+	for sanities sake this function always attempts to put '\0' (in the converted charset)
+	at the end of the output buffer even if there was not a '\0' in the input string.
+	
+	it is assumed this function is used on a system that understands UTF-8!
+	if not you will get EOUTPUTNOTSUPPORTED.
+*/	
+int convert_string_charset(char *input_buffer, char *input_charset, size_t input_length,
+							char *output_buffer, char *output_charset, size_t output_buffer_length,
+							size_t *output_bytes_used,  size_t *irreversible_count,
+							size_t *unconverted_bytes, size_t *invalid_count, char *substitute)
+{
+	char *input_ptr, *output_ptr;
+	iconv_t conversion_descriptor;
+	size_t input_bytes_left, output_bytes_left, not_conv_count=0;
+	
+	char converted_null[8], null_string[1]="";
+	char *converted_substitute=NULL;
+	size_t converted_substitute_length=output_buffer_length, converted_null_length;
+	size_t nconv;
+	int local_invalid_count=0;
+	int i, too_big=0, iconv_failed=0, retval=0;
+	
+	
+	if(output_charset==NULL) {
+		return ENOOUTPUTCS;
+	}
+	if(input_charset==NULL) {
+		return ENOINPUTCS;
+	}
+	if(output_buffer==NULL) {
+		return ENOINPUTBUFF;
+	}
+	if(input_buffer==NULL) {
+		return ENOINPUTBUFF;
+	}
+	if(input_length<1) {
+		return EZEROLENTGHINPUT;
+	}
+	
+	if( strcmp(output_charset,"LOCAL")==0 ) {
+		if(local_charset!=NULL) {
+			output_charset = local_charset;
+		} else {
+			output_charset = null_string;
+		}
+	}
+	
+	if( strcmp(input_charset,"LOCAL")==0 ) {
+		if(local_charset!=NULL) {
+			input_charset = local_charset;
+		} else {
+			input_charset = null_string;
+		}
+	}
+	
+	conversion_descriptor = iconv_open(output_charset, "UTF-8");
+	if(conversion_descriptor == (iconv_t)-1) {
+		if(errno == EINVAL) {
+			return EOUTPUTNOTSUPPORTED;
+		} else {
+			return EUTFCONVERTFAILED;
+		}
+	}
+	/* convert '\0' to local charsets representation */
+	input_bytes_left=1;
+	output_bytes_left=8;
+	input_ptr=null_string;
+	output_ptr=converted_null;
+	nconv = iconv( conversion_descriptor,
+				   &input_ptr, &input_bytes_left,
+				   &output_ptr, &output_bytes_left );
+	if(nconv!=0) {
+		iconv_close(conversion_descriptor);
+		return ECONVERTNULLFAILED;
+	}
+	converted_null_length = 8-output_bytes_left;
+	if(converted_null_length > output_buffer_length)
+	{
+		iconv_close(conversion_descriptor);
+		return EOUTPUTBUFFMUCHTOOSHORT;
+	}
+	
+	/* if the caller specified a invalid char substitute string convert that to the output format */
+	if(substitute!=NULL) {
+		output_bytes_left = sizeof(char) * strlen(substitute) * converted_null_length;
+		converted_substitute = malloc(output_bytes_left);
+		if(converted_substitute==NULL) {
+			iconv_close(conversion_descriptor);
+			return EMALLOCSUBS;
+		}
+		input_bytes_left = strlen(substitute);
+		input_ptr=substitute;
+		output_ptr=converted_substitute;
+		nconv = iconv( conversion_descriptor,
+					   &input_ptr, &input_bytes_left,
+					   &output_ptr, &output_bytes_left );
+		if(nconv!=0) {
+			free(converted_substitute);
+			iconv_close(conversion_descriptor);
+			return ECONVERTSUBSFAILED;
+		}
+		converted_substitute_length = (size_t)(output_ptr - converted_substitute);
+	}
+	iconv_close(conversion_descriptor);
+	
+	/* open an iconv convertor for the main conversion */
+	conversion_descriptor = iconv_open(output_charset, input_charset);
+	if(conversion_descriptor == (iconv_t)-1) {
+		if(errno == EINVAL) {
+			free(converted_substitute);
+			return EINPUTNOTSUPPORTED;
+		} else {
+			free(converted_substitute);
+			return EOPENCONVERTFAILED;
+		}
+	}
+	
+	input_ptr = input_buffer;
+	output_ptr = output_buffer;
+	input_bytes_left = input_length;
+	/* we tell iconv the buffer is shorter than it really is so we always have space to put a null on the end of it */
+	output_bytes_left = output_buffer_length - converted_null_length;
+	
+	while(input_bytes_left > 0) {
+		nconv = iconv( conversion_descriptor,
+					   &input_ptr, &input_bytes_left,
+					   &output_ptr, &output_bytes_left );
+		if(nconv == -1) {
+			if(errno == EILSEQ || errno == EINVAL) {
+				/* invalid input sequence, we skip over its in the input buffer */
+				local_invalid_count++;
+				input_ptr++;
+				input_bytes_left--;
+				if(converted_substitute!=NULL) {
+					/* if the caller specified a substitute string we add it here */
+					if(output_bytes_left >= converted_substitute_length) {
+						for(i=0; i<converted_substitute_length ; i++) {
+							output_ptr[0]=converted_substitute[i];
+							output_ptr++;
+							output_bytes_left--;
+						} 
+					} else {
+						too_big=1;
+					}
+				}
+			
+			} else if (errno == E2BIG) {
+				/* this happens if the output buffer if not big enough, we truncate to this point but warn the caller */
+				too_big=1;
+				not_conv_count=input_bytes_left;
+				input_bytes_left=0;
+			}
+			else {
+				/* some other error occured, we truncate to this point but warn the user */
+				iconv_failed=1;
+				not_conv_count=input_bytes_left;
+				input_bytes_left=0;
+				
+			}
+			errno=0;
+		}
+	}
+	/* put a null on the end of the converted string */
+	for(i=0; i<converted_null_length; i++) {
+		output_ptr[0]=converted_null[i];
+		output_ptr++;
+	}
+	if(local_invalid_count>0) {
+		retval += WINVALIDCHARS;
+	}
+
+	if(invalid_count!=NULL) {
+		*invalid_count = local_invalid_count;
+	}
+
+	if(too_big) {
+		retval += WOUTPUTTOOSHORT;
+	}
+	
+	if(unconverted_bytes!=NULL) {
+		*unconverted_bytes=not_conv_count;
+	}
+	
+	if(iconv_failed) {
+		retval += WICONVFAIL;
+	}
+	
+	if(output_bytes_used!=NULL) {
+		*output_bytes_used = output_buffer_length - output_bytes_left;
+	}
+	
+	if(irreversible_count!=NULL) {
+		if(retval==0) {
+			*irreversible_count=nconv;
+		} else {
+			*irreversible_count=0;
+		}
+	}
+
+	free(converted_substitute);
+	iconv_close(conversion_descriptor);
+	
+	return retval;
+}
+
 /* convert string in given encoding to wide string */
-wchar_t *
-any2wcs(char * s, char * charset, int report_error)
+wchar_t * any2wcs(char * s, char * charset, int report_error)
 {
     char * local, * localcpy;
     char * wcs; /* needs to be char * for passing to iconv */

Modified: trunk/src/iconv.h
===================================================================
--- trunk/src/iconv.h	2007-04-26 13:39:31 UTC (rev 954)
+++ trunk/src/iconv.h	2007-04-26 13:58:18 UTC (rev 955)
@@ -1,33 +1,57 @@
 #include <wchar.h>
 
+int convert_string_charset(char *input_buffer, char *input_charset, size_t input_length,
+							char *output_buffer, char *output_charset, size_t output_buffer_length,
+							size_t *output_bytes_used,  size_t *irreversible_count,
+							size_t *unconverted_bytes, size_t *invalid_count, char *substitute);
+
+
 /* convert string in given encoding to wide string */
-wchar_t * any2wcs(char * s, char * charset);
+//wchar_t * any2wcs(char * s, char * charset);
 
 /* convert wide string to string in given encoding */
-char * wcs2any(wchar_t * ws, char * charset);
+//char * wcs2any(wchar_t * ws, char * charset);
 
 /* convert string in local encoding to wide string */
-extern wchar_t * local2wcs(char * s);
+// wchar_t * local2wcs(char * s);
 
 /* convert wide string to local encoding */
-extern char * wcs2local(wchar_t * ws);
+// char * wcs2local(wchar_t * ws);
 
 /* convert UTF-8 encoded string to wide string */
-wchar_t * utf82wcs(char * s);
+//wchar_t * utf82wcs(char * s);
 
 /* convert wide string to UTF-8 encoded string */
-char * wcs2utf8(wchar_t * ws);
+//char * wcs2utf8(wchar_t * ws);
 
 /* set local charset independently of locale */
-extern int set_local_charset(char * set);
+ int set_local_charset(char * set);
 
 /* query local charset */
-extern char * get_local_charset(void);
+ char * get_local_charset(void);
 
 /* wrapper around set_locale printing failure messages */
 int locale_mesgs(char * locale);
 
 /* set locale */
-extern int set_locale(char * locale);
+ int set_locale(char * locale);
 
-extern void init_locale(void);
+ void init_locale(void);
+
+#define ENOOUTPUTCS -1
+#define ENOINPUTCS -2
+#define ENOOUTPUTBUFF -3
+#define ENOINPUTBUFF -4
+#define EZEROLENTGHINPUT -5
+#define EOUTPUTNOTSUPPORTED -6
+#define EUTFCONVERTFAILED -7
+#define ECONVERTNULLFAILED -8
+#define EMALLOCSUBS -9
+#define ECONVERTSUBSFAILED -10
+#define EINPUTNOTSUPPORTED -11
+#define EOPENCONVERTFAILED -12
+#define EOUTPUTBUFFMUCHTOOSHORT -13
+
+#define WOUTPUTTOOSHORT 1
+#define WINVALIDCHARS 2
+#define WICONVFAIL 4

Modified: trunk/src/js.c
===================================================================
--- trunk/src/js.c	2007-04-26 13:39:31 UTC (rev 954)
+++ trunk/src/js.c	2007-04-26 13:58:18 UTC (rev 955)
@@ -18,6 +18,7 @@
 #include "chattable.h"
 #include "script.h"
 #include "talker_privs.h"
+#include "iconv.h"
 
 extern struct person *user;
 extern long userposn;
@@ -51,184 +52,53 @@
 	JSCLASS_NO_OPTIONAL_MEMBERS
 };
 
-// currently assuming all scripts and script arguments will be in utf8
-// if the users client is not utf8 then that issue needs to be dealt with elsewhere
-char *jsstring_to_utf8(jschar *the_jsstring, size_t len)
+// turns a jsval into a utf-8 string that mw can handle
+// expects the utf8_buffer to have been allocated and be at least buffer_length long
+// used to reduce mass code duplication
+int jsval_to_utf8string(JSContext *cx, jsval the_jsval, char *utf8_buffer, size_t buffer_length)
 {
-	char * utf8_string;
-	char * utf8_string_tmp;
-
-	char * jsstring_ptr;
-	char * utf8_ptr;
-
-	iconv_t conv;
-	size_t nconv;
-
-	size_t utf8_bytes_left;
-	size_t jsstring_bytes_left;
-	size_t utf8_length;
-		
-	conv = iconv_open("UTF-8", "UCS-2");
-	if (conv == (iconv_t)-1) {
-		fprintf(stderr, "jsstring_to_utf8: iconv_open() failed.\n");
-		return NULL;
-	}
+	JSString *the_jsstring;
+	size_t ucs2_length;
+	jschar *ucs2_string;
+	int retval;
 	
-	utf8_bytes_left = (len) * sizeof(char) * 4; /* Urgh, x4 is kludge (x2 isn't big enough, some utf8 chars require 4 bytes and in a worst case scenario we'd run out) */
-	jsstring_bytes_left = (len) * sizeof(jschar);
-	utf8_string_tmp = (char *)malloc(utf8_bytes_left);
+	the_jsstring = JS_ValueToString(cx, the_jsval);
+	ucs2_length=JS_GetStringLength(the_jsstring);
+	ucs2_string=JS_GetStringChars(the_jsstring);
 	
-	if (utf8_string_tmp == NULL) {
-		fprintf(stderr, "jsstring_to_utf8: Could not allocate memory for iconv\n");
-		return NULL;
-	}
+	retval=convert_string_charset((char *)ucs2_string, "UCS-2", ucs2_length*sizeof(jschar), utf8_buffer, "UTF-8", buffer_length, NULL, NULL, NULL, NULL, NULL);
 	
-	utf8_ptr = utf8_string_tmp;
-	jsstring_ptr = (char *)the_jsstring;
-
-	while (jsstring_bytes_left > 0) {
-/*		printf("Before: localbytesleft: %d utf16bytesleft: %d\n",
-			(int)localbytesleft, (int)utf16bytesleft); */
-		nconv = iconv(conv, 
-			&jsstring_ptr, &jsstring_bytes_left, 
-			&utf8_ptr, &utf8_bytes_left);
-/*		printf("After: localbytesleft: %d utf16bytesleft: %d\n", 
-			(int)localbytesleft, (int)jsstring_bytes_left); */
-		if (nconv == (size_t)-1) {
-			fprintf(stderr, "jsstring_to_utf8: iconv() barfed with error %d - ", errno);
-			/* iconv barfed, but why? */
-			if (errno == EILSEQ || errno == EINVAL) {
-				/* invalid input sequence, skip it */
-				fprintf(stderr, "Invalid input sequence\n");
-				jsstring_ptr++;
-				jsstring_bytes_left--;
-				errno = 0;
-				continue;
-			} else {
-				/* some other error, recover what we can */
-				*(char *)utf8_ptr = '\0';
-				perror("iconv");
-				errno = 0;
-				break;
-			}
-		}
+	if(retval<0) {
+		fprintf(stderr, "jsval_to_utf8string: convert_string_charset failed with error: %d\n", retval);
 	}
-	iconv_close(conv);
-	utf8_length=(len*4)-utf8_bytes_left;
-	
-	utf8_string=(char *)malloc(sizeof(char)*(utf8_length+1));
-	if(utf8_string==NULL) {
-		fprintf(stderr, "jsstring_to_utf8: Could not allocate memory for the utf8_string\n");
-		return NULL;
-	}
-	strncpy(utf8_string, utf8_string_tmp, utf8_length);
-	utf8_string[utf8_length]='\0';
-	free(utf8_string_tmp);
-	
-	return utf8_string;
+	return retval;
 }
 
-jschar *utf8_to_jsstring(char *utf8_string, size_t *length, int *utferror)
-{
-	char * the_jsstring; // iconv uses char*, we'll cast to jschar* at the end.
 
-	char * jsstring_ptr;
-	char * utf8_ptr;
 
-	iconv_t conv;
-	size_t nconv;
-
-	size_t utf8_bytes_left;
-	size_t jsstring_bytes_left;
-	
-	*utferror=0;
-	conv = iconv_open("UCS-2", "UTF-8");
-	if (conv == (iconv_t)-1) {
-		fprintf(stderr, "utf8_to_jsstring: iconv_open() failed.\n");
-		return NULL;
-	}
-	
-	utf8_bytes_left = (strlen(utf8_string)+1) * sizeof(char); 
-	jsstring_bytes_left = (strlen(utf8_string)+1) * sizeof(jschar);
-	the_jsstring = (char *)malloc(jsstring_bytes_left);
-
-	if (the_jsstring == NULL) {
-		fprintf(stderr, "utf8_to_jsstring: Could not allocate memory for iconv\n");
-		return NULL;
-	}
-	
-	utf8_ptr = utf8_string;
-	jsstring_ptr = the_jsstring;
-
-	while (utf8_bytes_left > 0) {
-/*		printf("Before: localbytesleft: %d utf16bytesleft: %d\n",
-			(int)localbytesleft, (int)utf16bytesleft); */
-		nconv = iconv(conv, 
-			&utf8_ptr, &utf8_bytes_left, 
-			&jsstring_ptr, &jsstring_bytes_left);
-/*		printf("After: localbytesleft: %d utf16bytesleft: %d\n", 
-			(int)localbytesleft, (int)jsstring_bytes_left); */
-		if (nconv == (size_t)-1) {
-			fprintf(stderr, "utf8_to_jsstring: iconv() barfed with error %d - ", errno);
-			/* iconv barfed, but why? */
-			if (errno == EILSEQ || errno == EINVAL) {
-				/* invalid input sequence, skip it */
-				fprintf(stderr, "Invalid input sequence\n");
-				utf8_ptr++;
-				utf8_bytes_left--;
-				errno = 0;
-				*utferror=1;
-				continue;
-			} else {
-				/* some other error, recover what we can */
-				/**(char *)jsstring_ptr = '\0';
-				jsstring_ptr++;
-				*(char *)jsstring_ptr = '\0';*/
-				perror("iconv");
-				errno = 0;
-				break;
-			}
-		}
-	}
-	iconv_close(conv);
-	
-	*length=strlen(utf8_string)-(jsstring_bytes_left/(sizeof(jschar)));
-	
-	return (jschar *)the_jsstring;
-}
-
-
-
 /* Function for printing to standard out from javascript (helpful for
  * debugging and demonstrates how to call C from js)
  */
-static JSBool
-js_print(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval) {
-	JSString *jsmsg;
-	jschar *ucmsg;
-	size_t len;
+static JSBool js_print(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval) 
+{
 	uintN i;
-	
-//	jschar * ucmsg;
-	char * msg;
+	int conversion_result;
+	char msg[MAXTEXTLENGTH];
 	if (argc < 1) {
 		return JS_TRUE;
 	}
 	
 	for (i = 0; i<argc; i++) {
 		if (JSVAL_IS_STRING(argv[i])) {
-			jsmsg = JS_ValueToString(cx,argv[i]);
-			len = JS_GetStringLength(jsmsg);
-			ucmsg = JS_GetStringChars(jsmsg);
-			msg = jsstring_to_utf8(ucmsg, len);
-			if(msg==NULL) {
-				printf("js_print: failed to convert jsstring to utf8\n");
+			conversion_result=jsval_to_utf8string(cx, argv[0], msg, MAXTEXTLENGTH);
+			if( conversion_result >= 0) {
+				if( conversion_result & WOUTPUTTOOSHORT ) {
+					printf("JavaScript print() command produced too much text.  It was truncated\n");
+				}
+				display_message(msg, 0, 1);
+			} else {
 				return JS_FALSE;
 			}
-			//msg = JS_GetStringBytes(jsmsg);
-			display_message(msg, 0, 1);
-			free(msg);
-			//printf("%s",msg);
 		} else 
 		if (JSVAL_IS_NULL(argv[i])) {
 			display_message("jsval is NULL",0,1);
@@ -244,42 +114,32 @@
 }
 
 /* execute a talker command */
-static JSBool
-js_mwexec(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval) {
-	JSString *jsmsg;
-	jschar *ucmsg;
-	size_t len;
-	char * msg;
+static JSBool js_mwexec(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval) 
+{
+	char msg[MAXTEXTLENGTH];
+	int conversion_result;
 	if (argc < 1) {
 		return JS_FALSE;
 	}
 	
 	if (JSVAL_IS_STRING(argv[0])) {
-		jsmsg = JS_ValueToString(cx,argv[0]);
-		len = JS_GetStringLength(jsmsg);
-		ucmsg = JS_GetStringChars(jsmsg);
-		msg = jsstring_to_utf8(ucmsg, len);
-		if(msg==NULL) {
-			printf("js_mwexec: failed to convert jsstring to utf8\n");
-			return JS_FALSE;
+		conversion_result=jsval_to_utf8string(cx, argv[0], msg, MAXTEXTLENGTH);
+		if( conversion_result >= 0) {
+			if( conversion_result & WOUTPUTTOOSHORT ) {
+				printf("JavaScript exec() command produced too much text.  It was truncated\n");
+			}
+			DoCommand(msg, chattable);
+			return JS_TRUE;
 		}
-		//msg = strdup(JS_GetStringBytes(jsmsg));
-		DoCommand(msg, chattable);
-		free(msg);
-		return JS_TRUE;
 	}
 	return JS_FALSE;
 }
 
 /* say to the talker */
-static JSBool
-js_say(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval) {
-	JSString *jsmsg;
-	jschar *ucmsg;
-	size_t len;
-	char * msg;
-	char saymsg[MAXTEXTLENGTH];
-	
+static JSBool js_say(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval) 
+{
+	char msg[MAXTEXTLENGTH];
+	int conversion_result;
 	if (argc < 1) {
 		return JS_FALSE;
 	}
@@ -291,89 +151,20 @@
 	}
 	
 	if (JSVAL_IS_STRING(argv[0])) {
-		jsmsg = JS_ValueToString(cx,argv[0]);
-		len = JS_GetStringLength(jsmsg);
-		ucmsg = JS_GetStringChars(jsmsg);
-		
-		msg = jsstring_to_utf8(ucmsg, len);
-		if(msg==NULL) {
-			printf("js_say: failed to convert jsstring to utf8\n");
-			return JS_FALSE;
+		conversion_result=jsval_to_utf8string(cx, argv[0], msg, MAXTEXTLENGTH);
+		if( conversion_result >= 0) {
+			if( conversion_result & WOUTPUTTOOSHORT ) {
+				printf("JavaScript say() command produced too much text.  It was truncated\n");
+			}
+			chat_say(msg);
+			return JS_TRUE;
 		}
-		//msg = strdup(JS_GetStringBytes(jsmsg));
-		
-		// things passed to chatsay may end up being passed to apply_gag which expects a buffer MAXTEXTLENGTH long.
-		strncpy(saymsg,msg,MAXTEXTLENGTH-1);
-		saymsg[MAXTEXTLENGTH]='\0';
-		chat_say(saymsg);
-		free(msg);
-		return JS_TRUE;
 	}
 	return JS_FALSE;
 }
 
-// Create a javascript array of strings from a struct db_data
-JSObject *
-dbdata_to_jsarray(JSContext *cx, struct db_data *data, int ncols) {
-	JSObject *jsdata;
-	JSString *jsstr;
-	jsval jv;
-	int i;
-
-	if (data == NULL || ncols < 1) return NULL;
-
-	jsdata = JS_NewArrayObject(cx, 0, NULL);
-	JS_AddRoot(cx, jsdata);
-
-	for (i = 0; i < ncols; i++) {
-		printf("dbdata_to_jsarray: data @ %p", (void *)data->field[i]);
-		jsstr = JS_NewStringCopyZ(cx, data->field[i]);
-		JS_AddRoot(cx, jsstr);
-		printf(" -> JSString @ %p\n", (void *)jsstr);
-		jv = STRING_TO_JSVAL(jsstr);
-		JS_SetElement(cx, jsdata, i, &jv);
-	}
-	JS_RemoveRoot(cx, jsdata);
-
-	return jsdata;
-}
-
-// Create a javascript array of arrays (see dbdata_to_jsarray()) from
-// a struct db_result
-JSObject *
-dbresult_to_jsarray(JSContext *cx, struct db_result *data) {
-	JSObject *jsarray;
-	JSObject *jsnode;
-	jsval jv;
-	struct db_data *node;
-	int i;
-
-	if (data == NULL) return NULL;
-
-	jsarray = JS_NewArrayObject(cx, 0, NULL);
-	JS_AddRoot(cx, jsarray);
-	JS_SetArrayLength(cx, jsarray, data->cols);
-
-/*	printf("Making Array(%d)\n", data->cols); */
-	i = 0;
-	node = data->data;
-	while (node) {
-		printf("dbresult_to_jsarray: node @ %p\n", (void *)node);
-		jsnode = dbdata_to_jsarray(cx, node, data->cols);
-		jv = OBJECT_TO_JSVAL(jsnode);
-		JS_SetElement(cx, jsarray, i, &jv);
-
-		node = node->next;
-		i++;
-	}
-	JS_RemoveRoot(cx, jsarray);
-
-	return jsarray;
-}
-
 // Provides a javascript function to query the wholist
-static JSBool
-js_wholist(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval *rval) {
+static JSBool js_wholist(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval *rval) {
 	struct person u;
 	struct who w;
 	int ufile, wfile;
@@ -435,16 +226,95 @@
 	return JS_TRUE;
 }
 
+// Create a javascript array of strings from a struct db_data
+JSObject *dbdata_to_jsarray(JSContext *cx, struct db_data *data, int ncols) {
+	JSObject *jsdata;
+	JSString *jsstr;
+	jsval jv;
+	jschar *ucsstr;
+	int i, conv_error;
+	size_t data_length;
+	
+	if (data == NULL || ncols < 1) return NULL;
 
+	jsdata = JS_NewArrayObject(cx, 0, NULL);
+	JS_AddRoot(cx, jsdata);
+
+	for (i = 0; i < ncols; i++) {
+//		printf("dbdata_to_jsarray: data @ %p -", (void *)data->field[i]);
+//		printf("%s", data->field[i]);
+		data_length = sizeof(jschar) * (strlen(data->field[i]) + 1);
+		
+		ucsstr = malloc( data_length );
+		if(ucsstr!=NULL) {
+			
+			conv_error=convert_string_charset(data->field[i], "UTF-8", strlen(data->field[i]),
+												(char *)ucsstr, "UCS-2", data_length, 
+												NULL, NULL, NULL, NULL, NULL);
+			if(conv_error>=0) {
+				jsstr = JS_NewUCStringCopyZ(cx, ucsstr);
+			} else {
+				jsstr = JS_NewStringCopyZ(cx, "(garbled string)");
+			}	
+			free(ucsstr);
+		} else {
+			jsstr = JS_NewStringCopyZ(cx, "(garbled string)");
+		}
+		//JS_AddRoot(cx, jsstr);
+//		printf(" -> JSString @ %p\n", (void *)jsstr);
+		jv = STRING_TO_JSVAL(jsstr);
+		JS_SetElement(cx, jsdata, i, &jv);
+	}
+	JS_RemoveRoot(cx, jsdata);
+
+	return jsdata;
+}
+
+// Create a javascript array of arrays (see dbdata_to_jsarray()) from
+// a struct db_result
+JSObject *dbresult_to_jsarray(JSContext *cx, struct db_result *data) {
+	JSObject *jsarray;
+	JSObject *jsnode;
+	jsval jv;
+	struct db_data *node;
+	int i;
+
+	if (data == NULL) return NULL;
+
+	jsarray = JS_NewArrayObject(cx, 0, NULL);
+	JS_AddRoot(cx, jsarray);
+//	JS_SetArrayLength(cx, jsarray, data->cols);
+
+/*	printf("Making Array(%d)\n", data->cols); */
+	i = 0;
+	node = data->data;
+	while (node) {
+//		printf("dbresult_to_jsarray: node @ %p\n", (void *)node);
+		jsnode = dbdata_to_jsarray(cx, node, data->cols);
+		jv = OBJECT_TO_JSVAL(jsnode);
+		JS_SetElement(cx, jsarray, i, &jv);
+
+		node = node->next;
+		i++;
+	}
+	JS_RemoveRoot(cx, jsarray);
+
+	return jsarray;
+}
+
+
+
 // Provides a javascript function to query an sqlite3 database
-static JSBool
-js_doquery(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval *rval) {
+// This probably wants updating to not return JS_FALSE as that halts js execution
+// far better to return an error code in rsval which the javascript can handle
+static JSBool js_doquery(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval *rval) {
 	struct db_result *dbres;
 	char *dbname;
-	char *query;
-	JSObject *result; // result object were creating
+	char query[MAXTEXTLENGTH*2]; // for now queries will be at most 4096 bytes or will fail.
+								 // if this becomes a problem dynamic allocation of the utf8 buffer might be needed although getting the right size is a pita
+	//JSObject *result; // result object were creating
 	JSObject *resarray;
-	int myid;
+	int myid, conversion_result;
 	char path[1024];
 	struct passwd *pw;
 
@@ -467,8 +337,12 @@
 	}
 
 	dbname = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
-	query = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
-
+	conversion_result=jsval_to_utf8string(cx, argv[1], query, MAXTEXTLENGTH*2);
+	//query = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
+	if(conversion_result != 0) {
+		return JS_FALSE;
+	}
+	
 	if (dbname[0] == '/'
 	||  strncmp(dbname, "../", 3)==0
 	||  strstr(dbname, "/../")) {
@@ -495,14 +369,18 @@
 	if (!resarray) {
 		return JS_FALSE;
 	}
-	result = JS_NewObject(cx, &js_dbresultclass, NULL, NULL);
-
+/*	result = JS_NewObject(cx, &js_dbresultclass, NULL, NULL);
+	// seems pointless to create an object with a data array and a numrows when the array itself has a .length.
+	// also something here was making mw segv so it's being done wrong.
+	// so now we just return the array.
+	
 	JS_DefineProperty(cx, result, "numrows", INT_TO_JSVAL(dbres->rows), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT);
 	JS_DefineProperty(cx, result, "data", OBJECT_TO_JSVAL(resarray), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE);
 
-	JS_SetPrivate(cx, result, dbres);
-
-	*rval = OBJECT_TO_JSVAL(result);
+	//JS_SetPrivate(cx, result, dbres);
+*/
+	db_free(dbres);
+	*rval = OBJECT_TO_JSVAL(resarray);
 	return JS_TRUE;
 }
 
@@ -532,15 +410,16 @@
 /* Execute some javascript commands */
 int js_exec(char * name, int argc, char **argvc) {
 	int i;
-	jschar * js_string;
+//	jschar * js_string;
 	jsval rval;
 	jsval *argv;
 	JSBool ret;
-	jschar *ucarg;
-	size_t uclen;
+	//jschar *ucarg;
+	jschar unicode_arg[MAXTEXTLENGTH];
+	//size_t uclen;
 	int utferror;
 	
-	js_string = NULL;
+//	js_string = NULL;
 	argv=calloc(argc,sizeof(jsval));
 
 	for (i=0;i<argc;i++) {
@@ -548,33 +427,37 @@
 			fprintf(stderr, "js_exec: argc %d was NULL!\n",i);
 			continue;
 		}
-		js_string = (jschar *)JS_malloc(jscx, sizeof(jschar) * strlen(argvc[i]));
-			if (!js_string || js_string == NULL) {
-				fprintf(stderr, "Could not allocate memory for string. Aborting slang_exec(%s)\n", name);
-				return -1;
+		//ucarg=utf8_to_jsstring(argvc[i], &uclen, &utferror);
+		utferror=convert_string_charset(argvc[i], "UTF-8", strlen(argvc[i]), (char *)unicode_arg, "UCS-2", sizeof(jschar) * MAXTEXTLENGTH, NULL, NULL, NULL, NULL, "?");
+		if(utferror>=0) {
+			if(utferror & WOUTPUTTOOSHORT) {
+				printf("Argument %d for javascript function '%s' was too long and has been truncated.\n", i, name);
 			}
-		//	js_string = local2jschars(argvc[i]);
-			if (js_string != NULL) {
-				ucarg=utf8_to_jsstring(argvc[i], &uclen, &utferror);
-				argv[i] = STRING_TO_JSVAL(JS_NewUCStringCopyZ(jscx, ucarg));
-		//		argv[i] = STRING_TO_JSVAL(JS_NewStringCopyZ(jscx, argvc[i]));
-			} else {
-				argv[i] = STRING_TO_JSVAL(JS_NewStringCopyZ(jscx, "(Garbled string)"));
+			if(utferror & WINVALIDCHARS) {
+				printf("Argument %d for javascript function '%s' contained invalid characters which have been replaced by '?'\n", i, name);
 			}
-		if (js_string) JS_free(jscx, js_string);
+			if(utferror & WICONVFAIL) {
+				printf("An iconv error occured processing argument %d for javascript function '%s' and the argument may have been truncated.\n", i, name);
+			}
+			
+			argv[i] = STRING_TO_JSVAL(JS_NewUCStringCopyZ(jscx, unicode_arg));
+		} else {
+			printf("A major error %d occured converting argument %d for javascript function '%s' to unicode.\n", utferror, i, name);
+			argv[i] = STRING_TO_JSVAL(JS_NewStringCopyZ(jscx, "(error argument)"));
+		}
+			
 	}
 	
 	ret = JS_CallFunctionName(jscx, jsroot, name, argc, argv, &rval);
-	if (!ret) {
-		printf("JS function '%s' (args: %d) not found.\n", name, argc);
+	if (ret) {
+		if (JSVAL_IS_BOOLEAN(rval) && JSVAL_TO_BOOLEAN(rval)==0) {
+			script_output=0;
+		}
 	}
 	//show_type("js_exec(rval)", rval);
-	if (JSVAL_IS_BOOLEAN(rval) && JSVAL_TO_BOOLEAN(rval)==0) {
-		script_output=0;
-	}
 	free(argv);
 	JS_GC(jscx); // do we still need to do this now the actual bug has been found?
-	return ret ? 1 : 0;
+	return ret;
 }
 
 /* Prints error reports to stdout when a javascript error occurs */
@@ -648,17 +531,27 @@
 	fread(body, 1, len, f);
 	body[len]=0;
 	/*convert the script into jsstring, scripts assumed to be utf8*/
-	unicode_body=utf8_to_jsstring(body, &length, &utferror);
 	
-	if(unicode_body==NULL)
-	{
-		fprintf(stderr, "load_jsfile: failed to convert script into javascript compatible unicode\n");
+	unicode_body=malloc(sizeof(jschar) * (len+1));
+	
+	/*unicode_body=utf8_to_jsstring(body, &length, &utferror);*/
+	
+	if(unicode_body==NULL) {
+		fprintf(stderr, "load_jsfile: failed to allocate memory for javascript file\n");
 		return 0;
 	}
-	if(utferror)
+	utferror = convert_string_charset( body, "UTF-8", len, (char *)unicode_body, "UCS-2", sizeof(jschar) * (len+1), &length, NULL, NULL, NULL, NULL);
+	if(utferror<0)
 	{
+		fprintf(stderr, "load_jsfile: failed to convert script to jschar string. Error %d\n", utferror);
+		return 0;
+	}
+	
+	if(utferror & WINVALIDCHARS) {
 		printf("The script '%s' does not appear to be utf-8.  Some characters may have been discared.  Please ensure this file is saved as UTF-8\n", filename);
 	}
+	
+	length=(length/sizeof(jschar))-1;
 	/* Compile the js file specified */
 	/* script = JS_CompileScript(jscx, jsroot, body, len, filename, lineno); */
 	script = JS_CompileUCScript(jscx, jsroot, unicode_body, length, filename, lineno);





More information about the mw-devel mailing list