/* 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; }
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); } }