Esempio n. 1
0
JSBool
js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
		jsval *rval)
{
    jschar *chars;
    size_t nchars;
    char *clazz, *prefix;
    JSString *str;

#if JS_HAS_OBJECT_LITERAL
    if (cx->version >= JSVERSION_1_2) {
	JSProperty *list, *prop;
	JSBool ok;
	char *comma, *idquote, *valquote;
	jsval id, val;
	JSString *idstr, *valstr;
#if JS_HAS_SHARP_VARS
	PRHashEntry *he;
#endif

	/* Early returns after this must unlock, or goto done with ok set. */
	JS_LOCK(cx);
	list = obj->map->props;

#if JS_HAS_SHARP_VARS
	he = js_EnterSharpObject(cx, obj, &chars);
	if (!he) {
	    JS_UNLOCK(cx);
	    return JS_FALSE;
	}
	if (IS_SHARP(he)) {	/* we didn't enter -- obj is already sharp */
	    JS_UNLOCK(cx);
	    nchars = js_strlen(chars);
	    goto make_string;
	}
	MAKE_SHARP(he);
#else
	/* Shut off recursion by temporarily clearing obj's property list. */
	obj->map->props = NULL;
	chars = NULL;
#endif
	ok = JS_TRUE;

	/* Allocate 2 + 1 for "{}" and the terminator. */
	if (!chars) {
	    chars = malloc((2 + 1) * sizeof(jschar));
	    nchars = 0;
	} else {
	    nchars = js_strlen(chars);
	    chars = realloc(chars, (nchars + 2 + 1) * sizeof(jschar));
	}
	if (!chars)
	    goto done;
	chars[nchars++] = '{';

	comma = NULL;

	for (prop = list; prop; prop = prop->next) {
	    if (!prop->symbols || !(prop->flags & JSPROP_ENUMERATE))
		continue;

	    /* Get strings for id and val and GC-root them via argv. */
	    id = js_IdToValue(sym_id(prop->symbols));
	    idstr = js_ValueToString(cx, id);
	    if (idstr)
		argv[0] = STRING_TO_JSVAL(idstr);
	    val = prop->object->slots[prop->slot];
	    valstr = js_ValueToString(cx, val);
	    if (!idstr || !valstr) {
		ok = JS_FALSE;
		goto done;
	    }
	    argv[1] = STRING_TO_JSVAL(valstr);

	    /* If id is a non-identifier string, it needs to be quoted. */
	    if (JSVAL_IS_STRING(id) && !js_IsIdentifier(idstr)) {
		idquote = "'";
		idstr = js_EscapeString(cx, idstr, *idquote);
		if (!idstr) {
		    ok = JS_FALSE;
		    goto done;
		}
		argv[0] = STRING_TO_JSVAL(idstr);
	    } else {
		idquote = NULL;
	    }

	    /* Same for val, except it can't be an identifier. */
	    if (JSVAL_IS_STRING(val)) {
		valquote = "\"";
		valstr = js_EscapeString(cx, valstr, *valquote);
		if (!valstr) {
		    ok = JS_FALSE;
		    goto done;
		}
		argv[1] = STRING_TO_JSVAL(valstr);
	    } else {
		valquote = NULL;
	    }

	    /* Allocate 1 + 1 at end for closing brace and terminating 0. */
	    chars = realloc(chars,
			    (nchars + (comma ? 2 : 0) +
			     (idquote ? 2 : 0) + idstr->length + 1 +
			     (valquote ? 2 : 0) + valstr->length +
			     1 + 1) * sizeof(jschar));
	    if (!chars)
		goto done;

	    if (comma) {
		chars[nchars++] = comma[0];
		chars[nchars++] = comma[1];
	    }
	    comma = ", ";

	    if (idquote)
		chars[nchars++] = *idquote;
	    js_strncpy(&chars[nchars], idstr->chars, idstr->length);
	    nchars += idstr->length;
	    if (idquote)
		chars[nchars++] = *idquote;

	    chars[nchars++] = ':';

	    if (valquote)
		chars[nchars++] = *valquote;
	    js_strncpy(&chars[nchars], valstr->chars, valstr->length);
	    nchars += valstr->length;
	    if (valquote)
		chars[nchars++] = *valquote;
	}

      done:
	if (chars) {
	    chars[nchars++] = '}';
	    chars[nchars] = 0;
	}
#if JS_HAS_SHARP_VARS
	js_LeaveSharpObject(cx);
#else
	/* Restore obj's property list before bailing on error. */
	obj->map->props = list;
#endif

	JS_UNLOCK(cx);
	if (!ok) {
	    if (chars)
		free(chars);
	    return ok;
	}
    } else
#endif /* JS_HAS_OBJECT_LITERAL */
    {
	clazz = obj->map->clasp->name;
	nchars = 9 + strlen(clazz);		/* 9 for "[object ]" */
	chars = malloc((nchars + 1) * sizeof(jschar));
	if (chars) {
	    prefix = "[object ";
	    nchars = 0;
	    while ((chars[nchars] = (jschar)*prefix) != 0)
		nchars++, prefix++;
	    while ((chars[nchars] = (jschar)*clazz) != 0)
		nchars++, clazz++;
	    chars[nchars++] = ']';
	    chars[nchars] = 0;
	}
    }

#if JS_HAS_SHARP_VARS
  make_string:
#endif
    if (!chars) {
	JS_ReportOutOfMemory(cx);
	return JS_FALSE;
    }
    str = js_NewString(cx, chars, nchars, 0);
    if (!str) {
	free(chars);
	return JS_FALSE;
    }
    *rval = STRING_TO_JSVAL(str);
    return JS_TRUE;
}
Esempio n. 2
0
static JSBool
array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
               jsval *rval, JSBool localeString)
{
    JSBool ok;
    jsval v;
    jsuint length, index;
    jschar *chars, *ochars;
    size_t nchars, growth, seplen, tmplen;
    const jschar *sepstr;
    JSString *str;
    JSHashEntry *he;
    JSObject *obj2;

    ok = js_GetLengthProperty(cx, obj, &length);
    if (!ok)
        return JS_FALSE;

    he = js_EnterSharpObject(cx, obj, NULL, &chars);
    if (!he)
        return JS_FALSE;
    if (literalize) {
        if (IS_SHARP(he)) {
#if JS_HAS_SHARP_VARS
            nchars = js_strlen(chars);
#else
            chars[0] = '[';
            chars[1] = ']';
            chars[2] = 0;
            nchars = 2;
#endif
            goto make_string;
        }

        /*
         * Allocate 1 + 3 + 1 for "[", the worst-case closing ", ]", and the
         * terminating 0.
         */
        growth = (1 + 3 + 1) * sizeof(jschar);
        if (!chars) {
            nchars = 0;
            chars = (jschar *) malloc(growth);
            if (!chars)
                goto done;
        } else {
            MAKE_SHARP(he);
            nchars = js_strlen(chars);
            chars = (jschar *)
                realloc((ochars = chars), nchars * sizeof(jschar) + growth);
            if (!chars) {
                free(ochars);
                goto done;
            }
        }
        chars[nchars++] = '[';
    } else {
        /*
         * Free any sharp variable definition in chars.  Normally, we would
         * MAKE_SHARP(he) so that only the first sharp variable annotation is
         * a definition, and all the rest are references, but in the current
         * case of (!literalize), we don't need chars at all.
         */
        if (chars)
            JS_free(cx, chars);
        chars = NULL;
        nchars = 0;

        /* Return the empty string on a cycle as well as on empty join. */
        if (IS_BUSY(he) || length == 0) {
            js_LeaveSharpObject(cx, NULL);
            *rval = JS_GetEmptyStringValue(cx);
            return ok;
        }

        /* Flag he as BUSY so we can distinguish a cycle from a join-point. */
        MAKE_BUSY(he);
    }
    sepstr = NULL;
    seplen = JSSTRING_LENGTH(sep);

    v = JSVAL_NULL;
    for (index = 0; index < length; index++) {
        ok = JS_GetElement(cx, obj, index, &v);
        if (!ok)
            goto done;

        if (!literalize && (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v))) {
            str = cx->runtime->emptyString;
        } else {
            if (localeString) {
                if (!js_ValueToObject(cx, v, &obj2) ||
                    !js_TryMethod(cx, obj2,
                                  cx->runtime->atomState.toLocaleStringAtom,
                                  0, NULL, &v)) {
                    str = NULL;
                } else {
                    str = js_ValueToString(cx, v);
                }
            } else {
                str = (literalize ? js_ValueToSource : js_ValueToString)(cx, v);
            }
            if (!str) {
                ok = JS_FALSE;
                goto done;
            }
        }

        /* Allocate 3 + 1 at end for ", ", closing bracket, and zero. */
        growth = (nchars + (sepstr ? seplen : 0) +
                  JSSTRING_LENGTH(str) +
                  3 + 1) * sizeof(jschar);
        if (!chars) {
            chars = (jschar *) malloc(growth);
            if (!chars)
                goto done;
        } else {
            chars = (jschar *) realloc((ochars = chars), growth);
            if (!chars) {
                free(ochars);
                goto done;
            }
        }

        if (sepstr) {
            js_strncpy(&chars[nchars], sepstr, seplen);
            nchars += seplen;
        }
        sepstr = JSSTRING_CHARS(sep);

        tmplen = JSSTRING_LENGTH(str);
        js_strncpy(&chars[nchars], JSSTRING_CHARS(str), tmplen);
        nchars += tmplen;
    }

  done:
    if (literalize) {
        if (chars) {
            if (JSVAL_IS_VOID(v)) {
                chars[nchars++] = ',';
                chars[nchars++] = ' ';
            }
            chars[nchars++] = ']';
        }
    } else {
        CLEAR_BUSY(he);
    }
    js_LeaveSharpObject(cx, NULL);
    if (!ok) {
        if (chars)
            free(chars);
        return ok;
    }

  make_string:
    if (!chars) {
        JS_ReportOutOfMemory(cx);
        return JS_FALSE;
    }
    chars[nchars] = 0;
    str = js_NewString(cx, chars, nchars, 0);
    if (!str) {
        free(chars);
        return JS_FALSE;
    }
    *rval = STRING_TO_JSVAL(str);
    return JS_TRUE;
}
Esempio n. 3
0
/*
 * Helper function for validating a DN.  This function will validate
 * a single RDN.  If the RDN is valid, 0 will be returned, otherwise
 * non-zero will be returned. A pointer to the last character processed
 * will be set in the "last parameter.  This will be the end of the RDN
 * in the valid case, and the illegal character in the invalid case.
 */
int rdn_validate( const char *begin, const char *end, const char **last )
{
	int rc = 0; /* Assume RDN is valid */
	int numericform = 0;
	char *separator = NULL;
	const char *p = begin;

	/* Find the '=', then use the helpers for descr and numericoid */
	if ((separator = PL_strnchr(p, '=', end - begin + 1)) == NULL) {
		rc = 1;
		goto exit;
	}

	/* Process an attribute type. The 'descr'
	 * form must start with a 'leadkeychar'. */
	if (IS_LEADKEYCHAR(*p)) {
		if ((rc = keystring_validate(p, separator - 1))) {
			goto exit;
		}
	/* See if the 'numericoid' form is being used */
	} else if (isdigit(*p)) {
		numericform = 1;
		if ((rc = numericoid_validate(p, separator - 1))) {
			goto exit;
		}
	} else {
		rc = 1;
		goto exit;
	}

	/* Advance the pointer past the '=' and make sure
	 * we're not past the end of the string. */
	p = separator + 1;
	if (p > end) {
		rc = 1;
		goto exit;
	}

	/* The value must be a 'hexstring' if the 'numericoid'
	 * form of 'attributeType' is used.  Per RFC 4514:
	 *
	 *   hexstring = SHARP 1*hexpair
	 *   hexpair = HEX HEX
	 */
	if (numericform) {
		if ((p == end) || !IS_SHARP(*p)) {
			rc = 1;
			goto exit;
		}
		p++;
	/* The value must be a 'string' when the 'descr' form
	 * of 'attributeType' is used.  Per RFC 4514:
	 *
	 *   string = [ ( leadchar / pair ) [ *( stringchar / pair )
	 *      ( trailchar / pair ) ] ]
	 *
	 *   leadchar   = LUTF1 / UTFMB
	 *   trailchar  = TUTF1 / UTFMB
	 *   stringchar = SUTF1 / UTFMB
	 *
	 *   pair = ESC (ESC / special / hexpair )
	 *   special = escaped / SPACE / SHARP / EQUALS
	 *   escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE
	 *   hexpair = HEX HEX
	 */
	} else {
		/* Check the leadchar to see if anything illegal
		 * is there.  We need to allow a 'pair' to get
		 * through, so we'll assume that a '\' is the
		 * start of a 'pair' for now. */
		if (IS_UTF1(*p) && !IS_ESC(*p) && !IS_LUTF1(*p)) {
			rc = 1;
			goto exit;
		}
	}

	/* Loop through string until we find the ',' separator, a '+'
	 * char indicating a multi-value RDN, or we reach the end.  */
	while ((p <= end) && (*p != ',') && (*p != '+')) {
		if (numericform) {
			/* Process a single 'hexpair' */
			if ((p == end) || !isxdigit(*p) || !isxdigit(*p + 1)) {
				rc = 1;
				goto exit;
			}
			p = p + 2;
		} else {
			/* Check for a valid 'stringchar'.  We handle
			 * multi-byte characters separately. */
			if (IS_UTF1(*p)) {
				/* If we're at the end, check if we have
				 * a valid 'trailchar'. */
				if ((p == end) && !IS_TUTF1(*p)) {
					rc = 1;
					goto exit;
				/* Check for a 'pair'. */
				} else if (IS_ESC(*p)) {
					/* We're guaranteed to still have at
					 * least one more character, so lets
					 * take a look at it. */
					p++;
					if (!IS_ESC(*p) && !IS_SPECIAL(*p)) {
						/* The only thing valid now
						 * is a 'hexpair'. */
						if ((p == end) || !isxdigit(*p) ||!isxdigit(*p + 1)) {
							rc = 1;
							goto exit;
						}
						p++;
					}
				/* Only allow 'SUTF1' chars now. */
				} else if (!IS_SUTF1(*p)) {
					rc = 1;
					goto exit;
				}

				p++;
			} else {
				/* Validate a single 'UTFMB' (multi-byte) character. */
				if (utf8char_validate(p, end, &p ) != 0) {
					rc = 1;
					goto exit;
				}

				/* Advance the pointer past the multi-byte char. */
				p++;
			}
		}
	}

	/* We'll end up either at the comma, a '+', or one past end.
	 * If we are processing a multi-valued RDN, we recurse to
	 * process the next 'attributeTypeAndValue'. */
	if ((p <= end) && (*p == '+')) {
		/* Make sure that there is something after the '+'. */
		if (p == end) {
			rc = 1;
			goto exit;
		}
		p++;

		/* Recurse to process the next value.  We need to reset p to
		 * ensure that last is set correctly for the original caller. */
		rc = rdn_validate( p, end, last );
		p = *last + 1;
	}

exit:
	*last = p - 1;
	return rc;
}