Exemplo n.º 1
0
def InternalElement2Json(elem, ParseNumbers=True):
    telem = type(elem)
    if telem == unicode:
        elem = llStringTrim(elem, 3)  # STRING_TRIM
        if elem == u'':
            return u'""'
        # Yes, these are checked after trimming. Don't facepalm too hard.
        if elem == JSON_NULL:
            return u'null'
        if elem == JSON_TRUE:
            return u'true'
        if elem == JSON_FALSE:
            return u'false'
        if elem[0] == elem[-1] == u'"' and elem[1:2] or elem in ('null','false','true') \
                or elem[0] == u'[' and elem[-1] == u']' \
                or elem[0] == u'{' and elem[-1] == u'}':
            return elem

        if ParseNumbers:
            match = (jsonnumbug_re if 6466 in Bugs else jsonnum_re).match(elem)
            if match and match.end() == len(elem):
                return elem

        if elem == JSON_INVALID:
            return u''

        return InternalJsonQuote(elem)

    if telem == Key:
        return u'"' + unicode(elem) + u'"'
    if telem in (Vector, Quaternion):
        return u'"<' + u', '.join([InternalJsonF2S(x) for x in elem]) + u'>"'
    if telem == float:
        return InternalJsonF2S(elem)
    # Integer
    return unicode(elem)
Exemplo n.º 2
0
def llJson2List(json):
    json = fs(json)
    json = llStringTrim(json, 3)  # STRING_TRIM

    if json == u'':
        return []

    if json[0] == u'[' and json[-1] == u']':
        # Array can of worms. Not all LSL quirks are implemented.
        ret = []
        token = InternalJsonGetTokenFull(json, 1)
        if token[2] == u']' and token[1] == len(json):
            return ret
        if token[2] == u':':
            return [JSON_INVALID]
        if token[2] == u',':
            ret.append(u'')
        else:
            ret.append(InternalJson2Elem(json[token[0]:token[1]]))
            token = InternalJsonGetTokenFull(json, token[1])
        while True:
            if token[2] == u']' and token[1] == len(json):
                break
            elif token[2] != u',':
                return [JSON_INVALID]
            token = InternalJsonGetTokenFull(json, token[1])
            if token[2] == u',' or token[2] == u']' and token[1] == len(json):
                ret.append(u'')
            else:
                if token[2] == u':':
                    return JSON_INVALID
                ret.append(InternalJson2Elem(json[token[0]:token[1]]))
                token = InternalJsonGetTokenFull(json, token[1])
        return ret

    if json[0] == u'{' and json[-1] == u'}':
        # Object can of worms. Worse than array. Not all LSL quirks are implemented.

        # Parse this grammar:
        # object: '{' complete_list incomplete_element '}' $
        # complete_list: <empty> | complete_list complete_element ','
        # complete_element: nonempty_string ':' value
        # incomplete_element: <empty> | value | string ':' value
        # string: '"' '"' | nonempty_string
        #
        # That allows:
        # {"a":1,"b":2,} # incomplete_element is empty
        # {"a":1,"b":2} # "b" is an incomplete_element
        # {2} # complete_list empty
        # {} # both empty
        # etc.

        ret = []
        token = InternalJsonGetTokenFull(json, 1)
        if token[2] == u'}' and token[1] == len(json):
            return ret
        if token[2] in (u':', u','):
            return [JSON_INVALID]

        while True:
            k = u''
            if token[2] == u'}' and token[1] == len(json):
                ret.append(k)
                ret.append(k)
                return ret
            if token[2] == JSON_STRING:
                colon = InternalJsonGetTokenFull(json, token[1])
                if colon[2] == u':':
                    k = InternalJsonUnquote(json[token[0]:token[1]])
                    token = InternalJsonGetTokenFull(json, colon[1])
            if token[2] in (u',', u':'):
                return [JSON_INVALID]
            ret.append(k)
            ret.append(InternalJson2Elem(json[token[0]:token[1]]))
            token = InternalJsonGetTokenFull(json, token[1])
            if token[2] == u'}' and token[1] == len(json):
                return ret
            if token[2] != u',' or k == u'':
                return [JSON_INVALID]
            token = InternalJsonGetTokenFull(json, token[1])

    return [InternalJson2Elem(json)]
Exemplo n.º 3
0
def InternalJsonFindValue(json, tgtpath, ReturnsToken, SetRules=False):

    # Building a function that meets the strange requisites of LL's json is not easy.
    # These requisites include syntax-checking of all items at the current level,
    # but not of items at a deeper nesting level.

    # Making it one-pass iterative O(len) instead of recursive O(depth*len) is even
    # more of a challenge, especially with these constraints.

    token = InternalJsonGetToken(json, 0)

    if tgtpath == []:
        # No nesting receives special treatment.
        if token[2] in (JSON_NUMBER, JSON_STRING, JSON_NULL, JSON_TRUE,
                        JSON_FALSE, JSON_INVALID):
            if InternalJsonGetToken(json, token[1])[2] is None:
                if ReturnsToken:
                    return token
                if token[2] == JSON_NUMBER:
                    return json[token[0]:token[1]]
                if token[2] == JSON_STRING:
                    return InternalJsonUnquote(json[token[0]:token[1]])
                if token[2] == JSON_INVALID:
                    # Accept malformed strings if they start and end in quotes
                    s = json[token[0]:token[1]]
                    if s[1:2] and s[0] == s[-1] == u'"':
                        return InternalJsonUnquote(s)
                return token[2]
            return JSON_INVALID
        if token[2] not in (u'{', u'['):
            return JSON_INVALID

        json = llStringTrim(json, 2)  # STRING_TRIM_RIGHT
        if json[-1] == u'}' and token[2] == u'{':
            if ReturnsToken:
                return (token[0], len(json), JSON_OBJECT)
            return json[token[0]:]
        if json[-1] == u']' and token[2] == u'[':
            if ReturnsToken:
                return (token[0], len(json), JSON_ARRAY)
            return json[token[0]:]
        return JSON_INVALID

        # This would be the code if there was proper scanning.
        #match = InternalJsonScanMatching(json, token[0])
        #if match is None or InternalJsonGetToken(json, match)[2] is not None:
        #    return JSON_INVALID
        #if ReturnsType: # this has been changed tho' - review if ever used
        #    return JSON_OBJECT if token[2] == u'{' else JSON_ARRAY
        #return json[token[0]:match]

    if token[2] not in (u'{', u'['):
        return JSON_INVALID

    # Follow the path
    L = len(tgtpath)
    # For the current position, matchlvl keeps track of how many levels are
    # matched. When matchlvl == L, we are at the item of interest.
    # For example: if we're at the ! in [1.0, "y", true, [1, ![6], {"a":5}]]
    # and the path is [3, 2, "a"], matchlvl will be 1 (meaning the first level
    # of the path, i.e. position 3, is matched, but we're not in sub-position
    # 2 yet).
    matchlvl = 0
    ret = None  # the target token, if found, or None if not

    # Keeps track of what we have opened so far.
    stk = [token[2]]

    # This tracks the current key within an array or object. Here we assume
    # it's an array; if it's an object, the item key will replace it anyway.
    curkey = 0

    just_open = True
    just_closed = False

    # Load next token
    token = InternalJsonGetToken(json, token[1])

    try:
        while True:
            # Process value if it can be present
            kind = token[2]
            if not (just_closed or just_open and kind in (u'}', u']')):
                # Item processing.
                # Not entering here immediately after a } or ] (just_closed)
                # or after a { or [ followed by } or ] (just_open...)
                just_open = False
                if kind in u':,]}' or kind == JSON_INVALID:
                    return JSON_INVALID
                if stk[-1] == u'{':
                    # Read the current key
                    if kind != JSON_STRING:
                        return JSON_INVALID
                    colon = InternalJsonGetToken(json, token[1])
                    if colon[2] != u':':
                        return JSON_INVALID
                    curkey = InternalJsonUnquote(json[token[0]:token[1]])
                    token = InternalJsonGetToken(json, colon[1])
                    kind = token[2]
                    del colon
                if matchlvl < L and InternalJsonPathMatches(
                        curkey, tgtpath[matchlvl]):
                    # Descend to this level
                    matchlvl += 1
                    ret = None  # because e.g. llJsonGetValue("{\"a\":[1],\"a\":2}",["a",0])==JSON_INVALID
                    if matchlvl == L:
                        if kind in u'{[':
                            match = InternalJsonScanMatching(json, token[0])
                            if match is None:
                                return JSON_INVALID
                            token = (token[0], match, JSON_OBJECT
                                     if token[2] == u'{' else JSON_ARRAY)
                        ret = token
                        matchlvl -= 1
                    elif kind in u'{[':
                        stk.append(token[2])
                        curkey = 0
                        just_open = True
                        token = InternalJsonGetToken(json, token[1])
                        continue
                else:
                    # We're skipping the element
                    if kind in u'[{':
                        match = InternalJsonScanMatching(json, token[0])
                        if match is None:
                            return JSON_INVALID
                        token = (
                            None, match
                        )  # HACK: shortcut to: (token[0], match, JSON_OBJECT if kind == u'{' else JSON_ARRAY)
                        just_closed = True

                token = InternalJsonGetToken(json,
                                             token[1])  # prepare next token
                kind = token[2]

            just_closed = False
            # Process coma if it can be present
            if not just_open:
                if kind == u',':
                    token = InternalJsonGetToken(json,
                                                 token[1])  # load next token
                    if stk[-1] == u'[':
                        curkey += 1
                    continue

            if kind == u'}' and stk[-1] == u'{' or kind == u']' and stk[
                    -1] == u'[':
                stk = stk[:-1]
                matchlvl -= 1
                if stk == []:
                    if InternalJsonGetToken(json, token[1])[2] is None:
                        break  # Yay! end of job!
                    return JSON_INVALID  # No yay - something at end of string
                just_closed = True
                token = InternalJsonGetToken(json, token[1])
                continue

            return JSON_INVALID

    except EInternalJsonInvalid:
        return JSON_INVALID

    if ret is None:
        return JSON_INVALID
    if ReturnsToken:
        return ret
    if ret[2] == JSON_STRING:
        return InternalJsonUnquote(json[ret[0]:ret[1]])
    if ret[2] in (JSON_NUMBER, JSON_OBJECT, JSON_ARRAY):
        return json[ret[0]:ret[1]]
    return ret[2]  # JSON_TRUE, JSON_FALSE, JSON_NULL