Bug 397215: Runtime option to switch to UTF-8 encoding in byte <-> jschar conversiions. Patch from Sam Ruby with some changes by me. r,a=brendan
authorigor@mir2.org
Tue, 11 Dec 2007 02:09:58 -0800
changeset 8893 3cc18e881a439411e957930818b6b94ba931a2e1
parent 8892 084074dcd2510ea91c25fab9d21ad391c7db3240
child 8894 121927fc848a623bccef4945088ad0e166768d79
push idunknown
push userunknown
push dateunknown
reviewersbrendan
bugs397215
milestone1.9b2pre
Bug 397215: Runtime option to switch to UTF-8 encoding in byte <-> jschar conversiions. Patch from Sam Ruby with some changes by me. r,a=brendan
js/src/js.c
js/src/jsapi.c
js/src/jsapi.h
js/src/jsobj.c
js/src/jsprf.c
js/src/jsprf.h
js/src/jsprvtd.h
js/src/jspubtd.h
js/src/jsstr.c
--- a/js/src/js.c
+++ b/js/src/js.c
@@ -713,22 +713,27 @@ ReadLine(JSContext *cx, uintN argc, jsva
     return JS_TRUE;
 }
 
 static JSBool
 Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     uintN i;
     JSString *str;
+    char *bytes;
 
     for (i = 0; i < argc; i++) {
         str = JS_ValueToString(cx, argv[i]);
         if (!str)
             return JS_FALSE;
-        fprintf(gOutFile, "%s%s", i ? " " : "", JS_GetStringBytes(str));
+        bytes = JS_EncodeString(cx, str);
+        if (!bytes)
+            return JS_FALSE;
+        fprintf(gOutFile, "%s%s", i ? " " : "", bytes);
+        JS_free(cx, bytes);
     }
     fputc('\n', gOutFile);
     return JS_TRUE;
 }
 
 static JSBool
 Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
 
--- a/js/src/jsapi.c
+++ b/js/src/jsapi.c
@@ -646,25 +646,32 @@ JS_GetTypeName(JSContext *cx, JSType typ
 {
     if ((uintN)type >= (uintN)JSTYPE_LIMIT)
         return NULL;
     return JS_TYPE_STR(type);
 }
 
 /************************************************************************/
 
+/*
+ * Has a new runtime ever been created?  This flag is used to detect unsafe
+ * changes to js_CStringsAreUTF8 after a runtime has been created, and to
+ * ensure that "first checks" on runtime creation are run only once.
+ */
+#ifdef DEBUG
+static JSBool js_NewRuntimeWasCalled = JS_FALSE;
+#endif
+
 JS_PUBLIC_API(JSRuntime *)
 JS_NewRuntime(uint32 maxbytes)
 {
     JSRuntime *rt;
 
 #ifdef DEBUG
-    static JSBool didFirstChecks;
-
-    if (!didFirstChecks) {
+    if (!js_NewRuntimeWasCalled) {
         /*
          * This code asserts that the numbers associated with the error names
          * in jsmsg.def are monotonically increasing.  It uses values for the
          * error names enumerated in jscntxt.c.  It's not a compile-time check
          * but it's better than nothing.
          */
         int errorNumber = 0;
 #define MSG_DEF(name, number, count, exception, format)                       \
@@ -680,17 +687,17 @@ JS_NewRuntime(uint32 maxbytes)
             if (*fmt == '{' && isdigit(fmt[1]))                               \
                 ++numfmtspecs;                                                \
         }                                                                     \
         JS_ASSERT(count == numfmtspecs);                                      \
     JS_END_MACRO;
 #include "js.msg"
 #undef MSG_DEF
 
-        didFirstChecks = JS_TRUE;
+        js_NewRuntimeWasCalled = JS_TRUE;
     }
 #endif /* DEBUG */
 
     rt = (JSRuntime *) malloc(sizeof(JSRuntime));
     if (!rt)
         return NULL;
 
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
@@ -5227,23 +5234,44 @@ JS_EncodeCharacters(JSContext *cx, const
 
 JS_PUBLIC_API(JSBool)
 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
                size_t *dstlenp)
 {
     return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
 }
 
+JS_PUBLIC_API(char *)
+JS_EncodeString(JSContext *cx, JSString *str)
+{
+    return js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
+}
+
+/*
+ * The following determines whether C Strings are to be treated as UTF-8
+ * or ISO-8859-1.  For correct operation, it must be set prior to the
+ * first call to JS_NewRuntime.
+ */
+#ifndef JS_C_STRINGS_ARE_UTF8
+JSBool js_CStringsAreUTF8 = JS_FALSE;
+#endif
+
 JS_PUBLIC_API(JSBool)
 JS_CStringsAreUTF8()
 {
-#ifdef JS_C_STRINGS_ARE_UTF8
-    return JS_TRUE;
-#else
-    return JS_FALSE;
+    return js_CStringsAreUTF8;
+}
+
+JS_PUBLIC_API(void)
+JS_SetCStringsAreUTF8()
+{
+    JS_ASSERT(!js_NewRuntimeWasCalled);
+
+#ifndef JS_C_STRINGS_ARE_UTF8
+    js_CStringsAreUTF8 = JS_TRUE;
 #endif
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(void)
 JS_ReportError(JSContext *cx, const char *format, ...)
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2241,52 +2241,65 @@ JS_UndependString(JSContext *cx, JSStrin
  * Convert a mutable string (either growable or dependent) into an immutable,
  * thread-safe one.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_MakeStringImmutable(JSContext *cx, JSString *str);
 
 /*
  * Return JS_TRUE if C (char []) strings passed via the API and internally
- * are UTF-8. The source must be compiled with JS_C_STRINGS_ARE_UTF8 defined
- * to get UTF-8 support.
+ * are UTF-8.
  */
 JS_PUBLIC_API(JSBool)
 JS_CStringsAreUTF8(void);
 
 /*
+ * Update the value to be returned by JS_CStringsAreUTF8().  Once set,
+ * it can not be changed.  Must be called before the first call to 
+ * JS_NewRuntime.
+ */
+JS_PUBLIC_API(void)
+JS_SetCStringsAreUTF8();
+
+/*
  * Character encoding support.
  *
  * For both JS_EncodeCharacters and JS_DecodeBytes, set *dstlenp to the size
  * of the destination buffer before the call; on return, *dstlenp contains the
  * number of bytes (JS_EncodeCharacters) or jschars (JS_DecodeBytes) actually
  * stored.  To determine the necessary destination buffer size, make a sizing
  * call that passes NULL for dst.
  *
  * On errors, the functions report the error. In that case, *dstlenp contains
  * the number of characters or bytes transferred so far.  If cx is NULL, no
  * error is reported on failure, and the functions simply return JS_FALSE.
  *
  * NB: Neither function stores an additional zero byte or jschar after the
  * transcoded string.
  *
- * If the source has been compiled with the #define JS_C_STRINGS_ARE_UTF8 to
- * enable UTF-8 interpretation of C char[] strings, then JS_EncodeCharacters
- * encodes to UTF-8, and JS_DecodeBytes decodes from UTF-8, which may create
- * addititional errors if the character sequence is malformed.  If UTF-8
- * support is disabled, the functions deflate and inflate, respectively.
+ * If JS_CStringsAreUTF8() is true then JS_EncodeCharacters encodes to
+ * UTF-8, and JS_DecodeBytes decodes from UTF-8, which may create additional
+ * errors if the character sequence is malformed.  If UTF-8 support is
+ * disabled, the functions deflate and inflate, respectively.
  */
 JS_PUBLIC_API(JSBool)
 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
                     size_t *dstlenp);
 
 JS_PUBLIC_API(JSBool)
 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
                size_t *dstlenp);
 
+/*
+ * A variation on JS_EncodeCharacters where a null terminated string is
+ * returned that you are expected to call JS_free on when done.
+ */
+JS_PUBLIC_API(char *)
+JS_EncodeString(JSContext *cx, JSString *str);
+
 /************************************************************************/
 
 /*
  * Locale specific string conversion and error message callbacks.
  */
 struct JSLocaleCallbacks {
     JSLocaleToUpperCase     localeToUpperCase;
     JSLocaleToLowerCase     localeToLowerCase;
--- a/js/src/jsobj.c
+++ b/js/src/jsobj.c
@@ -2739,16 +2739,17 @@ js_SetClassObject(JSContext *cx, JSObjec
 }
 
 JSBool
 js_FindClassObject(JSContext *cx, JSObject *start, jsid id, jsval *vp)
 {
     JSObject *obj, *cobj, *pobj;
     JSProtoKey key;
     JSProperty *prop;
+    jsval v;
     JSScopeProperty *sprop;
 
     if (start || (cx->fp && (start = cx->fp->scopeChain) != NULL)) {
         /* Find the topmost object in the scope chain. */
         do {
             obj = start;
             start = OBJ_GET_PARENT(cx, obj);
         } while (start);
@@ -2776,26 +2777,29 @@ js_FindClassObject(JSContext *cx, JSObje
         id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[key]);
     }
 
     JS_ASSERT(OBJ_IS_NATIVE(obj));
     if (!js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME,
                                     &pobj, &prop)) {
         return JS_FALSE;
     }
-    if (!prop)  {
-        *vp = JSVAL_VOID;
-        return JS_TRUE;
+    v = JSVAL_VOID;
+    if (prop)  {
+        if (OBJ_IS_NATIVE(pobj)) {
+            sprop = (JSScopeProperty *) prop;
+            if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))) {
+                v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
+                if (JSVAL_IS_PRIMITIVE(v))
+                    v = JSVAL_VOID; 
+            }
+        }
+        OBJ_DROP_PROPERTY(cx, pobj, prop);
     }
-
-    JS_ASSERT(OBJ_IS_NATIVE(pobj));
-    sprop = (JSScopeProperty *) prop;
-    JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj)));
-    *vp = OBJ_GET_SLOT(cx, pobj, sprop->slot);
-    OBJ_DROP_PROPERTY(cx, pobj, prop);
+    *vp = v;
     return JS_TRUE;
 }
 
 JSObject *
 js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
                    JSObject *parent, uintN argc, jsval *argv)
 {
     jsid id;
--- a/js/src/jsprf.c
+++ b/js/src/jsprf.c
@@ -701,20 +701,18 @@ static int dosprintf(SprintfState *ss, c
     static char *hex = "0123456789abcdef";
     static char *HEX = "0123456789ABCDEF";
     char *hexp;
     int rv, i;
     struct NumArgState *nas = NULL;
     struct NumArgState nasArray[ NAS_DEFAULT_NUM ];
     char pattern[20];
     const char *dolPt = NULL;  /* in "%4$.2f", dolPt will poiont to . */
-#ifdef JS_C_STRINGS_ARE_UTF8
     uint8 utf8buf[6];
     int utf8len;
-#endif
 
     /*
     ** build an argument array, IF the fmt is numbered argument
     ** list style, to contain the Numbered Argument list pointers
     */
 
     nas = BuildArgArray( fmt, ap, &rv, nasArray );
     if( rv < 0 ){
@@ -941,23 +939,23 @@ static int dosprintf(SprintfState *ss, c
                     rv = (*ss->stuff)(ss, " ", 1);
                     if (rv < 0) {
                         return rv;
                     }
                 }
             }
             switch (type) {
               case TYPE_INT16:
-                /* Treat %hc as %c if JS_C_STRINGS_ARE_UTF8 is undefined. */
-#ifdef JS_C_STRINGS_ARE_UTF8
-                u.wch = va_arg(ap, int);
-                utf8len = js_OneUcs4ToUtf8Char (utf8buf, u.wch);
-                rv = (*ss->stuff)(ss, (char *)utf8buf, utf8len);
-                break;
-#endif
+                /* Treat %hc as %c unless js_CStringsAreUTF8. */
+                if (js_CStringsAreUTF8) {
+                    u.wch = va_arg(ap, int);
+                    utf8len = js_OneUcs4ToUtf8Char (utf8buf, u.wch);
+                    rv = (*ss->stuff)(ss, (char *)utf8buf, utf8len);
+                    break;
+                }
               case TYPE_INTN:
                 u.ch = va_arg(ap, int);
                 rv = (*ss->stuff)(ss, &u.ch, 1);
                 break;
             }
             if (rv < 0) {
                 return rv;
             }
@@ -994,17 +992,17 @@ static int dosprintf(SprintfState *ss, c
             JS_ASSERT(0);
             break;
 #endif
 
           case 's':
             if(type == TYPE_INT16) {
                 /*
                  * This would do a simple string/byte conversion
-                 * if JS_C_STRINGS_ARE_UTF8 is not defined.
+                 * unless js_CStringsAreUTF8.
                  */
                 u.ws = va_arg(ap, const jschar*);
                 rv = cvt_ws(ss, u.ws, width, prec, flags);
             } else {
                 u.s = va_arg(ap, const char*);
                 rv = cvt_s(ss, u.s, width, prec, flags);
             }
             if (rv < 0) {
--- a/js/src/jsprf.h
+++ b/js/src/jsprf.h
@@ -45,19 +45,19 @@
 **      %u - unsigned decimal
 **      %x - unsigned hex
 **      %X - unsigned uppercase hex
 **      %o - unsigned octal
 **      %hd, %hu, %hx, %hX, %ho - 16-bit versions of above
 **      %ld, %lu, %lx, %lX, %lo - 32-bit versions of above
 **      %lld, %llu, %llx, %llX, %llo - 64 bit versions of above
 **      %s - string
-**      %hs - 16-bit version of above (only available if compiled with JS_C_STRINGS_ARE_UTF8)
+**      %hs - 16-bit version of above (only available if js_CStringsAreUTF8)
 **      %c - character
-**      %hc - 16-bit version of above (only available if compiled with JS_C_STRINGS_ARE_UTF8)
+**      %hc - 16-bit version of above (only available if js_CStringsAreUTF8)
 **      %p - pointer (deals with machine dependent pointer size)
 **      %f - float
 **      %g - float
 */
 #include "jstypes.h"
 #include <stdio.h>
 #include <stdarg.h>
 
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -244,11 +244,19 @@ typedef union JSTempValueUnion {
 } JSTempValueUnion;
 
 struct JSTempValueRooter {
     JSTempValueRooter   *down;
     ptrdiff_t           count;
     JSTempValueUnion    u;
 };
 
-
+/*
+ * The following determines whether JS_EncodeCharacters and JS_DecodeBytes
+ * treat char[] as utf-8 or simply as bytes that need to be inflated/deflated.
+ */
+#ifdef JS_C_STRINGS_ARE_UTF8
+# define js_CStringsAreUTF8 JS_TRUE
+#else
+extern JSBool js_CStringsAreUTF8;
+#endif
 
 #endif /* jsprvtd_h___ */
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -664,17 +664,17 @@ typedef enum JSExnType {
         JSEXN_REFERENCEERR,
         JSEXN_SYNTAXERR,
         JSEXN_TYPEERR,
         JSEXN_URIERR,
         JSEXN_LIMIT
 } JSExnType;
 
 typedef struct JSErrorFormatString {
-    /* The error format string (UTF-8 if JS_C_STRINGS_ARE_UTF8 is defined). */
+    /* The error format string (UTF-8 if js_CStringsAreUTF8). */
     const char *format;
 
     /* The number of arguments to expand in the formatted error message. */
     uint16 argCount;
 
     /* One of the JSExnType constants above. */
     int16 exnType;
 } JSErrorFormatString;
--- a/js/src/jsstr.c
+++ b/js/src/jsstr.c
@@ -2878,109 +2878,168 @@ const jschar *
 js_SkipWhiteSpace(const jschar *s, const jschar *end)
 {
     JS_ASSERT(s <= end);
     while (s != end && JS_ISSPACE(*s))
         s++;
     return s;
 }
 
-#ifdef JS_C_STRINGS_ARE_UTF8
-
 jschar *
-js_InflateString(JSContext *cx, const char *bytes, size_t *length)
+js_InflateString(JSContext *cx, const char *bytes, size_t *lengthp)
 {
-    jschar *chars = NULL;
-    size_t dstlen = 0;
-
-    if (!js_InflateStringToBuffer(cx, bytes, *length, NULL, &dstlen))
-        return NULL;
-    chars = (jschar *) JS_malloc(cx, (dstlen + 1) * sizeof (jschar));
-    if (!chars)
-        return NULL;
-    js_InflateStringToBuffer(cx, bytes, *length, chars, &dstlen);
-    chars[dstlen] = 0;
-    *length = dstlen;
+    size_t nbytes, nchars, i;
+    jschar *chars;
+#ifdef DEBUG
+    JSBool ok;
+#endif
+
+    nbytes = *lengthp;
+    if (js_CStringsAreUTF8) {
+        if (!js_InflateStringToBuffer(cx, bytes, nbytes, NULL, &nchars))
+            goto bad;
+        chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof (jschar));
+        if (!chars)
+            goto bad;
+#ifdef DEBUG
+        ok =
+#endif
+            js_InflateStringToBuffer(cx, bytes, nbytes, chars, &nchars);
+        JS_ASSERT(ok);
+    } else {
+        nchars = nbytes;
+        chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof(jschar));
+        if (!chars)
+            goto bad;
+        for (i = 0; i < nchars; i++)
+            chars[i] = (unsigned char) bytes[i];
+    }
+    *lengthp = nchars;
+    chars[nchars] = 0;
     return chars;
+
+  bad:
+    /*
+     * For compatibility with callers of JS_DecodeBytes we must zero lengthp
+     * on errors.
+     */
+    *lengthp = 0;
+    return NULL;
 }
 
 /*
  * May be called with null cx by js_GetStringBytes, see below.
  */
 char *
-js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
+js_DeflateString(JSContext *cx, const jschar *chars, size_t nchars)
 {
-    size_t size;
+    size_t nbytes, i;
     char *bytes;
-
-    size = js_GetDeflatedStringLength(cx, chars, length);
-    if (size == (size_t)-1)
-        return NULL;
-    bytes = (char *) (cx ? JS_malloc(cx, size+1) : malloc(size+1));
-    if (!bytes)
-        return NULL;
-    js_DeflateStringToBuffer(cx, chars, length, bytes, &size);
-    bytes[size] = 0;
+#ifdef DEBUG
+    JSBool ok;
+#endif
+
+    if (js_CStringsAreUTF8) {
+        nbytes = js_GetDeflatedStringLength(cx, chars, nchars);
+        if (nbytes == (size_t) -1)
+            return NULL;
+        bytes = (char *) (cx ? JS_malloc(cx, nbytes + 1) : malloc(nbytes + 1));
+        if (!bytes)
+            return NULL;
+#ifdef DEBUG
+        ok =
+#endif
+            js_DeflateStringToBuffer(cx, chars, nchars, bytes, &nbytes);
+        JS_ASSERT(ok);
+    } else {
+        nbytes = nchars;
+        bytes = (char *) (cx ? JS_malloc(cx, nbytes + 1) : malloc(nbytes + 1));
+        if (!bytes)
+            return NULL;
+        for (i = 0; i < nbytes; i++)
+            bytes[i] = (char) chars[i];
+    }
+    bytes[nbytes] = 0;
     return bytes;
 }
 
 /*
  * May be called with null cx through js_GetStringBytes, see below.
  */
 size_t
-js_GetDeflatedStringLength(JSContext *cx, const jschar *chars,
-                           size_t charsLength)
+js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars)
 {
+    size_t nbytes;
     const jschar *end;
-    size_t length;
     uintN c, c2;
     char buffer[10];
 
-    length = charsLength;
-    for (end = chars + length; chars != end; chars++) {
+    if (!js_CStringsAreUTF8)
+        return nchars;
+
+    nbytes = nchars;
+    for (end = chars + nchars; chars != end; chars++) {
         c = *chars;
         if (c < 0x80)
             continue;
         if (0xD800 <= c && c <= 0xDFFF) {
             /* Surrogate pair. */
             chars++;
             if (c >= 0xDC00 || chars == end)
                 goto bad_surrogate;
             c2 = *chars;
             if (c2 < 0xDC00 || c2 > 0xDFFF)
                 goto bad_surrogate;
             c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
         }
         c >>= 11;
-        length++;
+        nbytes++;
         while (c) {
             c >>= 5;
-            length++;
+            nbytes++;
         }
     }
-    return length;
+    return nbytes;
 
   bad_surrogate:
     if (cx) {
         JS_snprintf(buffer, 10, "0x%x", c);
         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
                                      NULL, JSMSG_BAD_SURROGATE_CHAR, buffer);
     }
-    return (size_t)-1;
+    return (size_t) -1;
 }
 
 JSBool
 js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen,
                          char *dst, size_t *dstlenp)
 {
-    size_t i, utf8Len, dstlen = *dstlenp, origDstlen = dstlen;
+    size_t dstlen, i, origDstlen, utf8Len;
     jschar c, c2;
     uint32 v;
     uint8 utf8buf[6];
 
+    dstlen = *dstlenp;
+    if (!js_CStringsAreUTF8) {
+        if (srclen > dstlen) {
+            for (i = 0; i < dstlen; i++)
+                dst[i] = (char) src[i];
+            if (cx) {
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                     JSMSG_BUFFER_TOO_SMALL);
+            }
+            return JS_FALSE;
+        }
+        for (i = 0; i < srclen; i++)
+            dst[i] = (char) src[i];
+        *dstlenp = srclen;
+        return JS_TRUE;
+    }
+
+    origDstlen = dstlen;
     while (srclen) {
         c = *src++;
         srclen--;
         if ((c >= 0xDC00) && (c <= 0xDFFF))
             goto badSurrogate;
         if (c < 0xD800 || c > 0xDBFF) {
             v = c;
         } else {
@@ -3026,21 +3085,41 @@ bufferTooSmall:
     }
     return JS_FALSE;
 }
 
 JSBool
 js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen,
                          jschar *dst, size_t *dstlenp)
 {
+    size_t dstlen, i, origDstlen, offset, j, n;
     uint32 v;
-    size_t offset = 0, j, n, dstlen = *dstlenp, origDstlen = dstlen;
-
-    if (!dst)
-        dstlen = origDstlen = (size_t) -1;
+
+    if (!js_CStringsAreUTF8) {
+        if (dst) {
+            dstlen = *dstlenp;
+            if (srclen > dstlen) {
+                for (i = 0; i < dstlen; i++)
+                    dst[i] = (unsigned char) src[i];
+                if (cx) {
+                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                         JSMSG_BUFFER_TOO_SMALL);
+                }
+                return JS_FALSE;
+            }
+            for (i = 0; i < srclen; i++)
+                dst[i] = (unsigned char) src[i];
+        }
+        *dstlenp = srclen;
+        return JS_TRUE;
+    }
+
+    dstlen = dst ? *dstlenp : (size_t) -1;
+    origDstlen = dstlen;
+    offset = 0;
 
     while (srclen) {
         v = (uint8) *src;
         n = 1;
         if (v & 0x80) {
             while (v & (0x80 >> n))
                 n++;
             if (n > srclen)
@@ -3104,108 +3183,16 @@ bufferTooSmall:
     *dstlenp = (origDstlen - dstlen);
     if (cx) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_BUFFER_TOO_SMALL);
     }
     return JS_FALSE;
 }
 
-#else /* !JS_C_STRINGS_ARE_UTF8 */
-
-JSBool
-js_InflateStringToBuffer(JSContext* cx, const char *bytes, size_t length,
-                         jschar *chars, size_t* charsLength)
-{
-    size_t i;
-
-    if (length > *charsLength) {
-        for (i = 0; i < *charsLength; i++)
-            chars[i] = (unsigned char) bytes[i];
-        if (cx) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_BUFFER_TOO_SMALL);
-        }
-        return JS_FALSE;
-    }
-    for (i = 0; i < length; i++)
-        chars[i] = (unsigned char) bytes[i];
-    *charsLength = length;
-    return JS_TRUE;
-}
-
-jschar *
-js_InflateString(JSContext *cx, const char *bytes, size_t *bytesLength)
-{
-    jschar *chars;
-    size_t i, length = *bytesLength;
-
-    chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
-    if (!chars) {
-        *bytesLength = 0;
-        return NULL;
-    }
-    for (i = 0; i < length; i++)
-        chars[i] = (unsigned char) bytes[i];
-    chars[length] = 0;
-    *bytesLength = length;
-    return chars;
-}
-
-size_t
-js_GetDeflatedStringLength(JSContext *cx, const jschar *chars,
-                           size_t charsLength)
-{
-    return charsLength;
-}
-
-JSBool
-js_DeflateStringToBuffer(JSContext* cx, const jschar *chars, size_t length,
-                         char *bytes, size_t* bytesLength)
-{
-    size_t i;
-
-    if (length > *bytesLength) {
-        for (i = 0; i < *bytesLength; i++)
-            bytes[i] = (char) chars[i];
-        if (cx) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_BUFFER_TOO_SMALL);
-        }
-        return JS_FALSE;
-    }
-    for (i = 0; i < length; i++)
-        bytes[i] = (char) chars[i];
-    *bytesLength = length;
-    return JS_TRUE;
-}
-
-/*
- * May be called with null cx by js_GetStringBytes, see below.
- */
-char *
-js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
-{
-    size_t i, size;
-    char *bytes;
-
-    size = (length + 1) * sizeof(char);
-    bytes = (char *) (cx ? JS_malloc(cx, size) : malloc(size));
-    if (!bytes)
-        return NULL;
-
-    for (i = 0; i < length; i++)
-        bytes[i] = (char) chars[i];
-
-    bytes[length] = 0;
-    return bytes;
-}
-
-#endif
-
 JSBool
 js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length)
 {
     JSRuntime *rt;
     JSHashTable *cache;
     JSBool ok;
     JSHashNumber hash;
     JSHashEntry **hep;
@@ -3258,21 +3245,21 @@ js_GetStringBytes(JSContext *cx, JSStrin
 
     cache = rt->deflatedStringCache;
     hash = js_hash_string_pointer(str);
     hep = JS_HashTableRawLookup(cache, hash, str);
     he = *hep;
     if (he) {
         bytes = (char *) he->value;
 
-#ifndef JS_C_STRINGS_ARE_UTF8
         /* Try to catch failure to JS_ShutDown between runtime epochs. */
-        JS_ASSERT_IF(*bytes != (char) JSSTRING_CHARS(str)[0],
-                     *bytes == '\0' && JSSTRING_LENGTH(str) == 0);
-#endif
+        if (!js_CStringsAreUTF8) {
+            JS_ASSERT_IF(*bytes != (char) JSSTRING_CHARS(str)[0],
+                         *bytes == '\0' && JSSTRING_LENGTH(str) == 0);
+        }
     } else {
         bytes = js_DeflateString(cx, JSSTRING_CHARS(str),
                                  JSSTRING_LENGTH(str));
         if (bytes) {
             if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
 #ifdef DEBUG
                 rt->deflatedStringCacheBytes += JSSTRING_LENGTH(str);
 #endif