Ejemplo n.º 1
0
/**
 * Handle a plain string (e.g., 'text').
 * 
 * @param[in, out] state
 */
static void sqltfn_normalize_pg_handle_string(tfn_state_t *state, int delimiter) {
    // Process input until the end of string is encountered
    while (state->slen > 0) {
        if (MATCH_TWO_BYTES('\\', '\\')) {
            // Backslash-escaped backslash
            COPY_BYTE;
            COPY_BYTE;            
        } else if (MATCH_TWO_BYTES('\\', delimiter)) {
            // Backslash-escaped delimiter
            COPY_BYTE;
            COPY_BYTE;
        } else if (MATCH_BYTE(delimiter)) {
            // Delimiter
            COPY_BYTE;

            // End of string
            return;
        } else {
            // Copy the current byte
            COPY_BYTE;
        }
    }

    return;
}
Ejemplo n.º 2
0
/**
 * Handle a Unicode-escaped string (e.g., U&'unicode-text').
 * 
 * @param[in, out] state
 */
static void sqltfn_normalize_pg_handle_string_unicode(tfn_state_t *state, int delimiter) {
    // Process input until the end of string is encountered
    while (state->slen > 0) {
        if (MATCH_BYTE(delimiter)) {
            // Copy the terminating single quote
            COPY_BYTE;

            return;
        } else {
            // Copy the current byte
            COPY_BYTE;
        }
    }

    return;
}
Ejemplo n.º 3
0
/*
* Loads all resources from the stream, except images, binaries and sprites.
*/
bool Syscall::loadResources(Stream& file, const char* aFilename)  {
    bool hasResources = true;
    if(!file.isOpen())
        hasResources = false;
    else {
        int len, pos;
        TEST(file.length(len));
        TEST(file.tell(pos));
        if(len == pos)
            hasResources = false;
    }
    if(!hasResources/* && aFilename != NULL*/) {
        resources.init(0);
        return true;
    }

#define MATCH_BYTE(c) { DAR_UBYTE(b); if(b != c) { FAIL; } }
    MATCH_BYTE('M');
    MATCH_BYTE('A');
    MATCH_BYTE('R');
    MATCH_BYTE('S');

    DAR_UVINT(nResources);
    DAR_UVINT(rSize);
    resources.init(nResources);

    resourcesCount = nResources;
    resourceOffset = new int[nResources];
    resourceSize = new int[nResources];
    resourceType = new int[nResources];
    resourcesFilename = new char[strlen(aFilename) + 1];
    strcpy(resourcesFilename, aFilename);

    // rI is the resource index.
    int rI = 1;

    while(true) {
        DAR_UBYTE(type);
        if(type == 0)
            break;

        //dispose flag

        DAR_UVINT(size);
        LOG_RES("Type %i, size %i\n", type, size);

        int index = rI - 1;

        TEST(file.tell(resourceOffset[index]));
        resourceSize[index] = size;
        resourceType[index] = type;

        switch(type) {
        case RT_UBIN:
        {
            int pos;
            MYASSERT(aFilename, ERR_RES_LOAD_UBIN);
            TEST(file.tell(pos));
#ifndef _android
            ROOM(resources.dadd_RT_BINARY(rI,
                                          new LimitedFileStream(aFilename, pos, size)));
#else
            // Android loads ubins by using JNI.
            loadUBinary(rI, pos, size);
            ROOM(resources.dadd_RT_BINARY(rI,
                                          new LimitedFileStream(
                                              aFilename,
                                              pos,
                                              size,
                                              getJNIEnvironment(),
                                              getJNIThis())));
#endif
            TEST(file.seek(Seek::Current, size));
        }
        break;
        case RT_PLACEHOLDER:
            ROOM(resources.dadd_RT_PLACEHOLDER(rI, NULL));
            break;
        case RT_LABEL:
        {
            MemStream b(size);
            TEST(file.readFully(b));
            ROOM(resources.dadd_RT_LABEL(rI, new Label((const char*)b.ptr(), rI)));
        }
        break;

#ifdef LOGGING_ENABLED
        case 99:  //testtype
#define DUMP_UVI { DAR_UVINT(u); LOG_RES("u %i\n", u); }
#define DUMP_SVI { DAR_SVINT(s); LOG_RES("s %i\n", s); }
            DUMP_UVI;
            DUMP_UVI;
            DUMP_UVI;
            DUMP_SVI;
            DUMP_SVI;
            DUMP_SVI;
            DUMP_SVI;
            DUMP_SVI;
            DUMP_SVI;
            break;
#endif
        default:
            TEST(file.seek(Seek::Current, size));
        }

        rI++;
    }
    if(rI != nResources + 1) {
        LOG("rI %i, nR %i\n", rI, nResources);
        BIG_PHAT_ERROR(ERR_RES_FILE_INCONSISTENT);
    }
    LOG_RES("ResLoad complete\n");
    return true;
}
Ejemplo n.º 4
0
/*
* Loads all resources from the given buffer.
*/
bool Syscall::loadResourcesFromBuffer(Stream& file, const char* aFilename)  {
    bool hasResources = true;
    if(!file.isOpen())
        hasResources = false;
    else {
        int len, pos;
        TEST(file.length(len));
        TEST(file.tell(pos));
        if(len == pos)
            hasResources = false;
    }
    if(!hasResources/* && aFilename != NULL*/) {
        resources.init(0);
        return true;
    }

#define MATCH_BYTE(c) { DAR_UBYTE(b); if(b != c) { FAIL; } }
    MATCH_BYTE('M');
    MATCH_BYTE('A');
    MATCH_BYTE('R');
    MATCH_BYTE('S');

    DAR_UVINT(nResources);
    DAR_UVINT(rSize);
    resources.init(nResources);

    // rI is the resource index.
    int rI = 1;

    while(true) {
        DAR_UBYTE(type);
        if(type == 0)
            break;

        //dispose flag

        DAR_UVINT(size);
        LOG_RES("Type %i, size %i\n", type, size);

        switch(type) {
        case RT_BINARY:
        {
#ifndef _android
            MemStream* ms = new MemStream(size);
#else
            char* b = loadBinary(rI, size);
            MemStream* ms = new MemStream(b, size);
#endif
            TEST(file.readFully(*ms));
            ROOM(resources.dadd_RT_BINARY(rI, ms));
#ifdef _android
            checkAndStoreAudioResource(rI);
#endif
        }
        break;
        case RT_UBIN:
        {
            int pos;
            MYASSERT(aFilename, ERR_RES_LOAD_UBIN);
            TEST(file.tell(pos));
#ifndef _android
            ROOM(resources.dadd_RT_BINARY(rI,
                                          new LimitedFileStream(aFilename, pos, size)));
#else
            // Android loads ubins by using JNI.
            loadUBinary(rI, pos, size);
            ROOM(resources.dadd_RT_BINARY(rI,
                                          new LimitedFileStream(
                                              aFilename,
                                              pos,
                                              size,
                                              getJNIEnvironment(),
                                              getJNIThis())));
#endif
            TEST(file.seek(Seek::Current, size));
        }
        break;
        case RT_PLACEHOLDER:
            ROOM(resources.dadd_RT_PLACEHOLDER(rI, NULL));
            break;
        case RT_IMAGE:
        {
            MemStream b(size);
            TEST(file.readFully(b));
#ifndef _android
            // On all platforms except Android, we load and add
            // the image data. "dadd" means "delete and add",
            // and is defined in runtimes\cpp\base\ResourceArray.h
            RT_IMAGE_Type* image = loadImage(b);
            if(!image)
                BIG_PHAT_ERROR(ERR_IMAGE_LOAD_FAILED);
            ROOM(resources.dadd_RT_IMAGE(rI, image));
#else
            // On Android images are stored on the Java side.
            // Here we allocate a dummy array (real image is
            // in a table in Java) so that the resource handling,
            // like deleting resources, will work also on Android.
            // The actual image will be garbage collected on
            // Android when a resource is replaced in the Java table.
            ROOM(resources.dadd_RT_IMAGE(rI, new int[1]));
            int pos;
            file.tell(pos);
            loadImage(
                rI,
                pos - size,
                size,
                Base::gSyscall->getReloadHandle());
#endif
        }
        break;
        case RT_SPRITE:
        {
            DAR_USHORT(indexSource);
            DAR_USHORT(left);
            DAR_USHORT(top);
            DAR_USHORT(width);
            DAR_USHORT(height);
            DAR_SHORT(cx);
            DAR_SHORT(cy);
#ifndef _android
            ROOM(resources.dadd_RT_IMAGE(rI, loadSprite(resources.get_RT_IMAGE(indexSource),
                                         left, top, width, height, cx, cy)));
#endif
        }
        break;
        case RT_LABEL:
        {
            MemStream b(size);
            TEST(file.readFully(b));
            ROOM(resources.dadd_RT_LABEL(rI, new Label((const char*)b.ptr(), rI)));
        }
        break;

#ifdef LOGGING_ENABLED
        case 99:  //testtype
#define DUMP_UVI { DAR_UVINT(u); LOG_RES("u %i\n", u); }
#define DUMP_SVI { DAR_SVINT(s); LOG_RES("s %i\n", s); }
            DUMP_UVI;
            DUMP_UVI;
            DUMP_UVI;
            DUMP_SVI;
            DUMP_SVI;
            DUMP_SVI;
            DUMP_SVI;
            DUMP_SVI;
            DUMP_SVI;
            break;
#endif
        default:
            TEST(file.seek(Seek::Current, size));
        }
        rI++;
    }
    if(rI != nResources + 1) {
        LOG("rI %i, nR %i\n", rI, nResources);
        BIG_PHAT_ERROR(ERR_RES_FILE_INCONSISTENT);
    }
    LOG_RES("ResLoad complete\n");
    return true;
}
Ejemplo n.º 5
0
/**
 * Handle a dollar-escaped string (e.g., $$text$$ or $tag$text$tag$).
 * 
 * @param[in, out] state
 * @return -1 in case of memory allocation errorr 
 */
static int sqltfn_normalize_pg_handle_dollar_string(tfn_state_t *state) {
    char *tag = NULL;
    size_t tag_len = 0;

    // copy $
    COPY_BYTE;

    // Have we reached the end of input?
    if (state->slen == 0) {
        return 1;
    }

    // The first character cannot be a digit
    if (isdigit(*state->s)) {
        return 1;
    }

    // Is there a tag?
    if (!MATCH_BYTE('$')) {
        // Extract tag

        char *tag_start = state->s;
        size_t tag_len = 0;
        while (((state->slen - tag_len) > 0) && (*(state->s + tag_len) != '$')) {
            // Check that the byte is a valid tag character
            if (!TAG_CHAR(*(state->s + tag_len))) {
                return 1;
            }

            tag_len++;
        }

        // Have we reached the end of input without
        // finding the second $ character?
        if (state->slen - tag_len == 0) {
            return 1;
        }

        // Now that we know that we have a valid tag, make
        // a copy of it, and also copy it into output       

        // Determine the tag length, and copy it
        // TODO Why copy when the tag is always available in input?        
        tag = malloc(tag_len);
        if (tag == NULL) return -1;
        memcpy(tag, tag_start, tag_len);

        while(tag_len--) {            
            COPY_BYTE;
        }
    }

    // Copy the second $    
    COPY_BYTE;       

    // Loop until the end of the string
    while (state->slen > 0) {
        if (MATCH_BYTE('$')) {
            // Possible end of string

            // Match the tag, if any
            size_t i = 0;
            while (((state->slen - i) > 0) && (i < tag_len) && (state->s[i + 1] == tag[i])) {
                i++;
            }

            // If we've matched the entire tag, and the next character
            // is a $, then we've reached the end of the string

            if ((i == tag_len) && (state->slen - i - 1 > 0) && (*(state->s + i + 1) == '$')) {
                // Copy the first $
                COPY_BYTE;

                // Copy tag characters
                while (i--) {
                    COPY_BYTE;
                }

                // Copy the second $
                COPY_BYTE;

                if (tag != NULL) {
                    free(tag);
                }

                return 1;
            }
        }

        // Copy the current byte
        COPY_BYTE;
    }

    if (tag != NULL) {
        free(tag);
    }

    return 1;
}
Ejemplo n.º 6
0
static int _sqltfn_normalize_pg(const char *input, size_t input_len, char **output, size_t *output_len) {
    tfn_state_t _state;
    tfn_state_t *state = &_state;

    // Parameter sanity check
    if (input == NULL) return -1;
    if (output == NULL) return -1;
    if (*output == NULL) return -1;
    if (output_len == NULL) return -1;

    // Setup transformation state
    state->s = (char *) input;
    state->d = *output;
    state->slen = input_len;
    state->dlen = 0;
    state->last_byte = -1;

    int comment_depth = 0;

    // Loop until there is input data to process
    while (state->slen > 0) {
        // Are we in a multi-line comment?
        if (comment_depth > 0) {
            // In a multi-line comment; ignoring bytes
            // until the comments unwrap.

            // Is it a beginning of a sub-comment?
            if (MATCH_TWO_BYTES('/', '*')) {
                // Sub-comment

                comment_depth++;

                // Go over /*
                SKIP_BYTE;
                SKIP_BYTE;
            }
            if (MATCH_TWO_BYTES('*', '/')) {
                // End of an existing comment

                comment_depth--;

                // Go over */
                SKIP_BYTE;
                SKIP_BYTE;

                // If we have unwrapped the entire comment, determine
                // if we need to replace it with a space.
                if (comment_depth == 0) {
                    // If the last byte we sent to output was
                    // not a whitespace, send one whitespace
                    // instead of the entire comment.
                    if (state->last_byte != SP) {
                        WRITE_BYTE(SP);
                    }
                }
            } else {
                // Go over one byte of input data
                SKIP_BYTE;
            }
        } else {
            // Not in a multi-line comment           

            // Determine the next token
            if (MATCH_BYTE('\'')) { // 'text'
                // String
                COPY_BYTE;
                sqltfn_normalize_pg_handle_string(state, '\'');
            } else if (MATCH_BYTE('"')) { // "text"
                // String
                COPY_BYTE;
                sqltfn_normalize_pg_handle_string(state, '"');
            } else
                /* "A dollar sign (cash) followed by digits is used to represent a
                 *  positional parameter in the body of a function definition or a
                 *  prepared statement. In other contexts the dollar sign can be
                 *  part of an identifier or a dollar-quoted string constant."
                 */
                if ((MATCH_BYTE('$')) && (!isalpha(state->last_byte))) { // $$text$$ or $tag$text$tag$, but not a$b$
                // $ string
                if (sqltfn_normalize_pg_handle_dollar_string(state) < 0) {
                    free(*output);
                    return -1;
                }
            } else if (MATCH_E_STRING) { // E'text'
                // E string
                COPY_BYTE;
                COPY_BYTE;
                sqltfn_normalize_pg_handle_string(state, '\'');
            } else if (MATCH_U_STRING) { // U&'text'
                // U string
                COPY_BYTE;
                COPY_BYTE;
                COPY_BYTE;
                sqltfn_normalize_pg_handle_string_unicode(state, state->last_byte);
            } else if (IS_WHITESPACE(*state->s)) {
                // Handle a whitespace character

                // Was the previous character also a whitespace?                
                if (state->last_byte != SP) {
                    // The previous character was not a whitespace

                    // Go over the whitespace character
                    SKIP_BYTE;

                    // Convert whitespace to SP
                    WRITE_BYTE(SP);
                } else {
                    // The previous character was also a whitespace,
                    // so we're going to ignore this one.
                    SKIP_BYTE;
                }
            } else if (MATCH_TWO_BYTES('/', '*')) {
                // Handle the beginning of a multi-line comment
                comment_depth++;

                // Go over /*
                SKIP_BYTE;
                SKIP_BYTE;
            } else if (MATCH_TWO_BYTES('-', '-')) {
                // Handle a dash comment

                // Go over --
                SKIP_BYTE;
                SKIP_BYTE;

                // Find end of line or end of input
                while ((state->slen > 0) && (*state->s != CR) && (*state->s != LF)) {
                    SKIP_BYTE;
                }

                // If we stopped because we encountered a newline, go over it
                if (state->slen > 0) {
                    SKIP_BYTE;

                    // Replace comment with a SP, but only if
                    // the previous character was not a SP
                    if (state->last_byte != SP) {
                        WRITE_BYTE(SP);
                    }
                }
            } else {
                // Handle a non-significant byte               

                // Copy byte
                COPY_BYTE;
            }
        }
    }

    *output_len = state->dlen;

    return 1;
}