Exemplo n.º 1
0
/* Converts an attribute string into an attr struct. 
 *
 * Note that the attribute string is trashed.
 *
 * Returns:
 *  SLP_PARAMETER_BAD -- If there is a parse error in the attribute string. 
 *  SLP_OK -- If everything went okay.
 */
SLPError attr_destringify(
		struct xx_SLPAttributes *slp_attr, 
		char *str, 
		SLPInsertionPolicy policy
) {
	char *cur; /* Current index into str. */
	enum {
		/* Note: everything contained in []s in this enum is a production from
		 * RFC 2608's grammar defining attribute lists. 
		 */
		START_ATTR /* The start of an individual [attribute]. */,
		START_TAG /* The start of a [attr-tag]. */,
		VALUE /* The start of an [attr-val]. */,
		STOP_VALUE /* The end of an [attr-val]. */
	} state = START_ATTR; /* The current state of the parse. */
	char *tag; /* A tag that has been parsed. (carries data across state changes)*/
	assert(str != NULL);
	if (strlen(str) == 0) {
		return SLP_OK;
	}
	
	tag = NULL;
	cur = str;
	/***** Pull apart str. *****/
	while (*cur) {
		char *end; /* The end of a parse entity. */
		switch (state) {
			case(START_ATTR): /* At the beginning of an attribute. */
				if (strncmp(cur, VAR_PREFIX, VAR_PREFIX_LEN) == 0) {
					/* At the start of a non-keyword. */
					state = START_TAG;
					cur += VAR_PREFIX_LEN;
				} else {
					/* At the start of a keyword:
					 * Gobble up the keyword and set it. 
					 */
					end = find_tag_end(cur);
					
					if (end == NULL) {
						/* FIXME Ummm, I dunno. */
						assert(0);
					}
					/*** Check that the tag ends on a legal ending char. ***/
					if (*end == ',') {
						/** Add the keyword. **/
						*end = '\0';
						SLPAttrSet_keyw((SLPAttributes)slp_attr, cur);
						cur = end + 1;
						break;
					}
					else if (*end == '\0') {
						SLPAttrSet_keyw((SLPAttributes)slp_attr, cur);
						return SLP_OK; /* FIXME Return success. */
						break;
					} 
					else {
						return SLP_PARAMETER_BAD; /* FIXME Return error code. -- Illegal tag char */
					}
				}
				break;
			case(START_TAG): /* At the beginning of a tag, in brackets. */
				end = find_tag_end(cur);
				
				if (end == NULL) {
					return SLP_PARAMETER_BAD; /* FIXME Err. code -- Illegal char. */
				}
				
				if (*end == '\0') {
					return SLP_PARAMETER_BAD; /* FIXME err: Premature end. */
				}
				
				/*** Check the the end character is valid. ***/
				if (strncmp(end, VAR_INFIX, VAR_INFIX_LEN) == 0) {
					size_t len = end - cur; /* Note that end is on the character _after_ the last character of the tag (the =). */
					assert(tag == NULL);
					tag = (char *)malloc(len + 1); /* TODO This is incorporated into the corresponding attribute. It is therefore free()'d in the var_free(). */
					strncpy(tag, cur, len);
					tag[len] = '\0';
					cur = end + VAR_INFIX_LEN;
					state = VALUE;
				} 
				else {
					/** ERROR! **/
					return SLP_PARAMETER_BAD; /* FIXME Err. code.-- Logic error. */
				}
				
				break;
				
			case(VALUE): /* At the beginning of the value portion. */
				assert(tag != NULL); /* We should not be able to get into this state is the string is malformed. */
				
				/*** Find the end of the value. ***/
				end = find_value_end(cur);
				
				/*** Check the validity of the end chararcter. */
				if ((strncmp(end, VAR_SUFFIX, VAR_SUFFIX_LEN) == 0) 
					|| strncmp(end, VAR_SEPARATOR, VAR_SEPARATOR_LEN) == 0 ) {
			
					SLPAttrStore(slp_attr, tag, cur, end - cur, policy);
					
					cur = end;
					state = STOP_VALUE;
				} else {
					/*** ERROR! ***/
					return SLP_PARAMETER_BAD; /* FIXME err -- invalid value terminator. */
				}
				break;
			case(STOP_VALUE): /* At the end of a value. */
				/***** Check to see which state we should move into next.*****/
				/*** Done? ***/
				if (*cur == '\0') {
					return SLP_OK;
				}
				/*** Another value? (ie, we're in a value list) ***/
				else if (strncmp(cur, VAR_SEPARATOR, VAR_SEPARATOR_LEN)==0) {
					cur += VAR_SEPARATOR_LEN;
					state = VALUE;
				}
				/*** End of the attribute? ***/
				else if (strncmp(cur, VAR_SUFFIX, VAR_SUFFIX_LEN) == 0) {
					assert(tag != NULL);
					free(tag);
					tag = NULL;
					cur += VAR_SUFFIX_LEN;
					
					/*** Are we at string end? ***/
					if (*cur == '\0') {
						return SLP_OK;
					}
					
					/*** Ensure that there is a seperator ***/
					if (strncmp(cur, VAR_SEPARATOR, VAR_SEPARATOR_LEN) != 0) {
						return  SLP_PARAMETER_BAD; /* FIXME err -- unexpected character. */
					}
					
					cur += VAR_SEPARATOR_LEN;
					state = START_ATTR;
				}
				/*** Error. ***/
				else {
					return SLP_PARAMETER_BAD; /* FIXME err -- Illegal char at value end. */
				}
				break;
			default:
				printf("Unknown state %d\n", state);
		}
	}

	return SLP_OK;
}
Exemplo n.º 2
0
void CharacterImageObject::update_text()
{
    lines.clear();
    blocks.clear();
    total_height[0] = total_height[1] = total_height[2] = 0;

    if (text.empty())
        return;

    char * data = &text[0];
    char * end = data + text.size();

    char * start_text = NULL;
    char * tag_start = NULL;

    AttributeStack alias_stack(ALIAS_ATTRIB);
    AttributeStack tracking_stack(TRACKING_ATTRIB);
    AttributeStack transparent_stack(TRANSPARENT_ATTRIB);

    lines.resize(1);

    CharacterImageAttributes attribs;

    int line = 0;
    int line_height = 0;
    int line_width = 0;
    int leading = 0;

    while (true) {
        // read text
        char * text_start = data;
        char * wrap_point = data;
        int test_width = line_width;
        bool wrap_newline = false;
        bool has_newline = false;

        // scan for newline, tag start or wrap point
        while (true) {
            if (data >= end)
                break;
            unsigned char c = (unsigned char)*data;
            if (c == '\n') {
                data++;
                has_newline = true;
                break;
            } else if (c == '\r') {
                data++;
                continue;
            } else if (c == '[')
                break;
            if (c == ' ')
                wrap_point = data+1;

            int alias_index = attribs.values[ALIAS_ATTRIB];
            CharacterImageAlias & alias = aliases[alias_index];
            CharacterImage & img = alias.charmap[c];
            test_width += img.width + attribs.values[TRACKING_ATTRIB];
            if (c != ' ' && (test_width+1) >= width) {
                data = wrap_point;
                has_newline = true;
                wrap_newline = true;
                break;
            }
            data++;
        }

        char * text_end = data;

        bool at_end = data >= end;

        if (text_start != text_end) {
            int alias_index = attribs.values[ALIAS_ATTRIB];
            CharacterImageAlias & alias = aliases[alias_index];
            std::string new_text(text_start, text_end - text_start);

            for (int i = 0; i < int(new_text.size()); i++) {
                unsigned char c = (unsigned char)new_text[i];
                CharacterImage & img = alias.charmap[c];
                line_height = std::max(img.height, line_height);
                if (c == '\n' || c == '\r')
                    continue;
                line_width += img.width + attribs.values[TRACKING_ATTRIB];
            }

            if (line_height == 0)
                line_height = alias.charmap[' '].height;

            unformatted += new_text;
            blocks.push_back(CharacterImageBlock(line, attribs, new_text));
        }

        if (has_newline || at_end) {
            CharacterImageLine & l = lines[line];
            l.width = line_width;
            line_height += (line_height * leading) / 100;
            total_height[get_vertical_index(l)] += line_height;
            l.height = line_height;
            line_width = line_height = 0;
            if (!wrap_newline)
                leading = 0;
            line++;
        }

        if (at_end)
            return;

        if (has_newline) {
            lines.resize(line+1);
            if (wrap_newline) {
                // inherit line config
                lines[line].x_align = lines[line-1].x_align;
                lines[line].y_align = lines[line-1].y_align;
            }
        }

        if (has_newline)
            continue;

        // read tag
        data++; // skip '[''
        data = lskip(data, end);
        bool is_end_tag = *data == '/';
        if (is_end_tag) {
            data++;
            data = lskip(data, end);
        }
        char * tag_start = data;
        data = find_tag_end(data, end);
        char * tag_end = data;

        // read tag value
        data = lskip(data, end);
        bool has_value = *data == '=';
        char * value_start;
        char * value_end;

        if (*data == '=') {
            data++;
            data = lskip(data, end);
            value_start = data;
            data = find_tag_end(data, end);
            value_end = data;
        }
        data = find_char(data, end, ']');
        data++;

        // convert value to integer
        int value;
        if (has_value) {
            bool is_alignment = true;
            switch (value_start[0]) {
                case 'l': // left
                    value = ALIGN_LEFT;
                    break;
                case 'r': // right
                    value = ALIGN_RIGHT;
                    break;
                case 'c': // centre
                    value = ALIGN_HCENTER | ALIGN_VCENTER;
                    break;
                case 'j': // justify
                    value = ALIGN_JUSTIFY;
                    break;
                case 't': // top
                    value = ALIGN_TOP;
                    break;
                case 'b': // bottom
                    value = ALIGN_BOTTOM;
                    break;
                default:
                    is_alignment = false;
                    break;
            }

            if (!is_alignment) {
                std::string value_str(value_start, value_end-value_start);
                value = string_to_int(value_str);
            }
        }

        // test attributes
        AttributeStack * stack_ref;

        if (test_str(tag_start, tag_end, "alias")) {
            stack_ref = &alias_stack;
        } else if (test_str(tag_start, tag_end, "tracking")) {
            stack_ref = &tracking_stack;
        } else if (test_str(tag_start, tag_end, "transparent")) {
            stack_ref = &transparent_stack;
        } else if (test_str(tag_start, tag_end, "veralign")) {
            lines[line].y_align = value;
            continue;
        } else if (test_str(tag_start, tag_end, "horalign")) {
            lines[line].x_align = value;
            continue;
        } else if (test_str(tag_start, tag_end, "leading")) {
            leading = value;
            continue;
        } else {
            std::string tag(tag_start, tag_end - tag_start);
            std::cout << "Unknown tag: " << tag << std::endl;
            continue;
        }

        if (is_end_tag) {
            stack_ref->pop(attribs);
            continue;
        }

        stack_ref->push(value, attribs);
    }
}