コード例 #1
0
ファイル: df.c プロジェクト: lianshun/XDF4C
static int cdata_hook(void *udata, char *data, size_t len)
{
    int               ret;
    int               nw_off, nw_len;
    char             *nw_data, *cur, *dlr;
    sax_usrdata_t    *ptSaxUsrData;
    xdf4c_df_t       *pDf;

    xdf4c_field_t    *a_field;
    xdf4c_record_t   *a_record;

    char   tmp[64 + 1];
    int    i;
    char   x;

    ptSaxUsrData = (sax_usrdata_t *)udata;
    pDf = ptSaxUsrData->pDf;

    for (i = 0; i < len; i ++) {
        x = data[i];
        if (NOT_WHITESPACE(x)) {
            break;
        }
    }
    if (i == len) {
        return SAX_OK;
    }
    nw_off = i;
    nw_len = len - nw_off;
    nw_data = data + nw_off;

    if (ptSaxUsrData->depth < 3)
        return SAX_OK;

    switch (ptSaxUsrData->tNode[ptSaxUsrData->depth - 2].type) {
    case TAG_TYPE_DH:
        if (nw_len >= sizeof(tmp)) {
            xdf4c_error("length [%d] of data is too larger than max [%d]", len, sizeof(tmp) - 1);
            return SAX_HOOK;
        }
        memcpy(tmp, nw_data, nw_len);
        tmp[nw_len] = 0;

        if (!strcmp(ptSaxUsrData->tNode[ptSaxUsrData->depth - 1].name, XML_TAG_DATA_NAME)) {
            snprintf(pDf->mass.data_name, sizeof(pDf->mass.data_name), "%s", tmp);
            pDf->pInstance = xdf4c_instance_get(pDf->mass.data_name);
            if (!pDf->pInstance) {
                xdf4c_error("xdf4c_instance_get fail: name = %s", ptSaxUsrData->tNode[ptSaxUsrData->depth - 1].name);
                return SAX_HOOK;
            }

            break;
        }

        if (!strcmp(ptSaxUsrData->tNode[ptSaxUsrData->depth - 1].name, XML_TAG_DATA_TYPE)) {
            snprintf(pDf->mass.data_type, sizeof(pDf->mass.data_type), "%s", tmp);
            break;
        }

        if (!strcmp(ptSaxUsrData->tNode[ptSaxUsrData->depth - 1].name, XML_TAG_ROW_NUM)) {
            pDf->mass.row_num = atoi(tmp);
            break;
        }

        if (!strncmp(ptSaxUsrData->tNode[ptSaxUsrData->depth - 1].name, XML_TAG_FIELD_NAME, strlen(XML_TAG_FIELD_NAME))) {
            if (!pDf->mass.record->rec_name[0]) {
                strcpy(pDf->mass.record->rec_name,       pDf->pInstance->ins_record->rec_name);
                strcpy(pDf->mass.record->rec_delimiter,  pDf->pInstance->ins_record->rec_delimiter);
                strcpy(pDf->mass.record->rec_terminator, pDf->pInstance->ins_record->rec_terminator);
                pDf->pSax->user_tag = pDf->mass.record->rec_terminator;
            }
            
            a_field = xdf4c_record_get_field(pDf->pInstance->ins_record, tmp);
            if (!a_field) {
                xdf4c_error("xdf4c_record_get_field fail: name = %s", tmp);
                return SAX_HOOK;
            }

            if (xdf4c_record_add_field(pDf->mass.record, a_field)) {
                xdf4c_error("xdf4c_record_add_field fail: name = %s", a_field->fld_name);
                return SAX_HOOK;
            }

            break;
        }

        break;

    case TAG_TYPE_DB:
        if (!strcmp(ptSaxUsrData->tNode[ptSaxUsrData->depth - 1].name, XML_TAG_PAGE)) {
            char         field_data[FIELD_DATA_SIZE + 1];
            int          field_data_len = 0;
            json_object *obj = pDf->objs.record_list[pDf->objs.record_count ++];

            if (gpXdf4cCfg->config.needcheck) {
                pDf->mass.row_num --;
                pDf->page.record_num --;
            }

            a_record = pDf->mass.record;
            for (cur = nw_data, i = 0; cur < nw_data + nw_len && i < a_record->fields_count; 
                                       cur += strlen(a_record->rec_delimiter), i ++) {
                dlr = strstr(cur, a_record->rec_delimiter);
                if (dlr && dlr < nw_data + nw_len) {
                    field_data_len = xdf4c_format_txt_content(field_data, sizeof(field_data), cur, dlr - cur);
                } else {
                    field_data_len = xdf4c_format_txt_content(field_data, sizeof(field_data), cur, nw_len - (cur - nw_data));
                }
                if (0 > field_data_len) {
                    xdf4c_error("xdf4c_format_txt_content fail: %d", field_data_len);
                    return SAX_HOOK;
                } else {
                    field_data[field_data_len] = 0;
                }

                json_object_object_add(obj, a_record->fields_list[i].fld_name, json_object_new_string(field_data));

                if (!(cur = dlr)) break;
            }

            json_object_array_set_length(pDf->objs.user_record, pDf->objs.record_count);

            if (pDf->objs.record_count >= gpXdf4cCfg->config.cachesize) {
                xdf4c_debug("%s", json_object_to_json_string(pDf->objs.user_data));
                if (pDf->user.deal_func && (ret = pDf->user.deal_func(pDf->user.user_data, 
                                            json_object_to_json_string(pDf->objs.user_data), 0))) {
                    if (pDf->user.done_func) pDf->user.done_func(pDf->user.user_data, ret);
                    xdf4c_error("call user.before_func fail");
                    return SAX_HOOK;
                }
                pDf->objs.record_count = 0;
            }
            break;
        }
        break;

    default:
        break;
    }

    return SAX_OK;
}
コード例 #2
0
ファイル: sax.c プロジェクト: contextlogger/contextlogger2
static enum ikserror
sax_core (iksparser *prs, char *buf, int len)
{
	enum ikserror err;
	int pos = 0, old = 0, re, stack_old = -1;
	unsigned char c;

	while (pos < len) {
		re = 0;
		c = buf[pos];
		if (0 == c || 0xFE == c || 0xFF == c) return IKS_BADXML;
		if (prs->uni_max) {
			if ((c & 0xC0) != 0x80) return IKS_BADXML;
			prs->uni_char <<= 6;
			prs->uni_char += (c & 0x3f);
			prs->uni_len++;
			if (prs->uni_len == prs->uni_max) {
				/* Security check: avoid overlong sequences */
				if (prs->uni_max == 2 && prs->uni_char < 0x80)
					return IKS_BADXML;
				if (prs->uni_max == 3 && prs->uni_char < 0x7FF)
					return IKS_BADXML;
				if (prs->uni_max == 4 && prs->uni_char < 0xffff)
					return IKS_BADXML;
				if (prs->uni_max == 5 && prs->uni_char < 0x1fffff)
					return IKS_BADXML;
				if (prs->uni_max == 6 && prs->uni_char < 0x3ffffff)
					return IKS_BADXML;
				prs->uni_max = 0;
				prs->uni_char = 0;
			}
			goto cont;
		} else {
			if (c & 0x80) {
				unsigned char mask;
				if ((c & 0x60) == 0x40) {
					prs->uni_max = 2;
					mask = 0x1F;
				} else if ((c & 0x70) == 0x60) {
					prs->uni_max = 3;
					mask = 0x0F;
				} else if ((c & 0x78) == 0x70) {
					prs->uni_max = 4;
					mask = 0x07;
				} else if ((c & 0x7C) == 0x78) {
					prs->uni_max = 5;
					mask = 0x03;
				} else if ((c & 0x7E) == 0x7C) {
					prs->uni_max = 6;
					mask = 0x01;
				} else {
					return IKS_BADXML;
				}
				prs->uni_char = c & mask;
				prs->uni_len = 1;
				if (stack_old == -1
					&& (prs->context == C_TAG
						|| prs->context == C_ATTRIBUTE_1
						|| prs->context == C_VALUE_APOS
						|| prs->context == C_VALUE_QUOT)) stack_old = pos;
				goto cont;
			}
		}

		switch (prs->context) {
			case C_CDATA:
				if ('&' == c) {
					if (old < pos && prs->cdataHook) {
						err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
						if (IKS_OK != err) return err;
					}
					prs->context = C_ENTITY;
					prs->entpos = 0;
					break;
				}
				if ('<' == c) {
					if (old < pos && prs->cdataHook) {
						err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
						if (IKS_OK != err) return err;
					}
					STACK_INIT;
					prs->tag_name = STACK_PUSH_START;
					if (!prs->tag_name) return IKS_NOMEM;
					prs->context = C_TAG_START;
				}
				break;

			case C_TAG_START:
				prs->context = C_TAG;
				if ('/' == c) {
					prs->tagtype = IKS_CLOSE;
					break;
				}
				if ('?' == c) {
					prs->context = C_PI;
					break;
				}
				if ('!' == c) {
					prs->context = C_MARKUP;
					break;
				}
				prs->tagtype = IKS_OPEN;
				stack_old = pos;
				break;

			case C_TAG:
				if (IS_WHITESPACE(c)) {
					if (IKS_CLOSE == prs->tagtype)
						prs->oldcontext = C_TAG_END;
					else
						prs->oldcontext = C_ATTRIBUTE;
					prs->context = C_WHITESPACE;
					if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
					stack_old = -1;
					STACK_PUSH_END;
					break;
				}
				if ('/' == c) {
					if (IKS_CLOSE == prs->tagtype) return IKS_BADXML;
					prs->tagtype = IKS_SINGLE;
					prs->context = C_TAG_END;
					if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
					stack_old = -1;
					STACK_PUSH_END;
					break;
				}
				if ('>' == c) {
					prs->context = C_TAG_END;
					if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
					stack_old = -1;
					STACK_PUSH_END;
					re = 1;
					break;
				}
				if (stack_old == -1) stack_old = pos;
				break;

			case C_TAG_END:
				if (c != '>') return IKS_BADXML;
				if (prs->tagHook) {
					char **tmp;
					if (prs->attcur == 0) tmp = NULL; else tmp = prs->atts;
					err = prs->tagHook (prs->user_data, prs->tag_name, tmp, prs->tagtype);
					if (IKS_OK != err) return err;
				}
				prs->stack_pos = 0;
				stack_old = -1;
				prs->attcur = 0;
				prs->attflag = 0;
				prs->context = C_CDATA;
				old = pos + 1;
				break;

			case C_ATTRIBUTE:
				if ('/' == c) {
					prs->tagtype = IKS_SINGLE;
					prs->context = C_TAG_END;
					break;
				}
				if ('>' == c) {
					prs->context = C_TAG_END;
					re = 1;
					break;
				}
				if (!prs->atts) {
					prs->attmax = 12;
					prs->atts = iks_malloc (sizeof(char *) * 2 * 12);
					if (!prs->atts) return IKS_NOMEM;
					memset (prs->atts, 0, sizeof(char *) * 2 * 12);
					prs->attcur = 0;
				} else {
					if (prs->attcur >= ((prs->attmax - 1) * 2)) {
						void *tmp;
						prs->attmax += 12;
						tmp = iks_malloc (sizeof(char *) * 2 * prs->attmax);
						if (!tmp) return IKS_NOMEM;
						memset (tmp, 0, sizeof(char *) * 2 * prs->attmax);
						memcpy (tmp, prs->atts, sizeof(char *) * prs->attcur);
						free (prs->atts);
						prs->atts = tmp;
					}
				}
				prs->attflag = 1;
				prs->atts[prs->attcur] = STACK_PUSH_START;
				stack_old = pos;
				prs->context = C_ATTRIBUTE_1;
				break;

			case C_ATTRIBUTE_1:
				if ('=' == c) {
					if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
					stack_old = -1;
					STACK_PUSH_END;
					prs->context = C_VALUE;
					break;
				}
				if (IS_WHITESPACE(c)) {
					if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
					stack_old = -1;
					STACK_PUSH_END;
					prs->oldcontext = C_ATTRIBUTE_1;
					prs->context = C_WHITESPACE;
					break;
				}
				if (stack_old == -1) stack_old = pos;
				break;

			case C_ATTRIBUTE_2:
				if ('/' == c) {
					prs->tagtype = IKS_SINGLE;
					prs->atts[prs->attcur] = NULL;
					prs->context = C_TAG_END;
					break;
				}
				if ('>' == c) {
					prs->atts[prs->attcur] = NULL;
					prs->context = C_TAG_END;
					re = 1;
					break;
				}
				prs->context = C_ATTRIBUTE;
				re = 1;
				break;

			case C_VALUE:
				if (IS_WHITESPACE(c)) break;
				prs->atts[prs->attcur + 1] = STACK_PUSH_START;
				if ('\'' == c) {
					prs->context = C_VALUE_APOS;
					break;
				}
				if ('"' == c) {
					prs->context = C_VALUE_QUOT;
					break;
				}
				return IKS_BADXML;

			case C_VALUE_APOS:
				if ('\'' == c) {
					if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
					stack_old = -1;
					STACK_PUSH_END;
					prs->oldcontext = C_ATTRIBUTE_2;
					prs->context = C_WHITESPACE;
					prs->attcur += 2;
				}
				if (stack_old == -1) stack_old = pos;
				break;

			case C_VALUE_QUOT:
				if ('"' == c) {
					if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
					stack_old = -1;
					STACK_PUSH_END;
					prs->oldcontext = C_ATTRIBUTE_2;
					prs->context = C_WHITESPACE;
					prs->attcur += 2;
				}
				if (stack_old == -1) stack_old = pos;
				break;

			case C_WHITESPACE:
				if (NOT_WHITESPACE(c)) {
					prs->context = prs->oldcontext;
					re = 1;
				}
				break;

			case C_ENTITY:
				if (';' == c) {
					char hede[2];
					char t = '?';
					prs->entity[prs->entpos] = '\0';
					if (strcmp(prs->entity, "amp") == 0)
						t = '&';
					else if (strcmp(prs->entity, "quot") == 0)
						t = '"';
					else if (strcmp(prs->entity, "apos") == 0)
						t = '\'';
					else if (strcmp(prs->entity, "lt") == 0)
						t = '<';
					else if (strcmp(prs->entity, "gt") == 0)
						t = '>';
					old = pos + 1;
					hede[0] = t;
					if (prs->cdataHook) {
						err = prs->cdataHook (prs->user_data, &hede[0], 1);
						if (IKS_OK != err) return err;
					}
					prs->context = C_CDATA;
				} else {
					prs->entity[prs->entpos++] = buf[pos];
					if (prs->entpos > 7) return IKS_BADXML;
				}
				break;

			case C_COMMENT:
				if ('-' != c) return IKS_BADXML;
				prs->context = C_COMMENT_1;
				break;

			case C_COMMENT_1:
				if ('-' == c) prs->context = C_COMMENT_2;
				break;

			case C_COMMENT_2:
				if ('-' == c)
					prs->context = C_COMMENT_3;
				else
					prs->context = C_COMMENT_1;
				break;

			case C_COMMENT_3:
				if ('>' != c) return IKS_BADXML;
				prs->context = C_CDATA;
				old = pos + 1;
				break;

			case C_MARKUP:
				if ('[' == c) {
					prs->context = C_SECT;
					break;
				}
				if ('-' == c) {
					prs->context = C_COMMENT;
					break;
				}
				prs->context = C_MARKUP_1;

			case C_MARKUP_1:
				if ('>' == c) {
					old = pos + 1;
					prs->context = C_CDATA;
				}
				break;

			case C_SECT:
				if ('C' == c) {
					prs->context = C_SECT_CDATA;
					break;
				}
				return IKS_BADXML;

			case C_SECT_CDATA:
				if ('D' != c) return IKS_BADXML;
				prs->context = C_SECT_CDATA_1;
				break;

			case C_SECT_CDATA_1:
				if ('A' != c) return IKS_BADXML;
				prs->context = C_SECT_CDATA_2;
				break;

			case C_SECT_CDATA_2:
				if ('T' != c) return IKS_BADXML;
				prs->context = C_SECT_CDATA_3;
				break;

			case C_SECT_CDATA_3:
				if ('A' != c) return IKS_BADXML;
				prs->context = C_SECT_CDATA_4;
				break;

			case C_SECT_CDATA_4:
				if ('[' != c) return IKS_BADXML;
				old = pos + 1;
				prs->context = C_SECT_CDATA_C;
				break;

			case C_SECT_CDATA_C:
				if (']' == c) {
					prs->context = C_SECT_CDATA_E;
					if (prs->cdataHook && old < pos) {
						err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
						if (IKS_OK != err) return err;
					}
				}
				break;

			case C_SECT_CDATA_E:
				if (']' == c) {
					prs->context = C_SECT_CDATA_E2;
				} else {
					if (prs->cdataHook) {
						err = prs->cdataHook (prs->user_data, "]", 1);
						if (IKS_OK != err) return err;
					}
					old = pos;
					prs->context = C_SECT_CDATA_C;
				}
				break;

			case C_SECT_CDATA_E2:
				if ('>' == c) {
					old = pos + 1;
					prs->context = C_CDATA;
				} else {
					if (prs->cdataHook) {
						err = prs->cdataHook (prs->user_data, "]]", 2);
						if (IKS_OK != err) return err;
					}
					old = pos;
					prs->context = C_SECT_CDATA_C;
				}
				break;

			case C_PI:
				old = pos + 1;
				if ('>' == c) prs->context = C_CDATA;
				break;
		}
cont:
		if (0 == re) {
			pos++;
			prs->nr_bytes++;
			if ('\n' == c) prs->nr_lines++;
		}
	}

	if (stack_old != -1)
		STACK_PUSH (buf + stack_old, pos - stack_old);

	err = IKS_OK;
	if (prs->cdataHook && (prs->context == C_CDATA || prs->context == C_SECT_CDATA_C) && old < pos)
		err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
	return err;
}
コード例 #3
0
ファイル: sax.c プロジェクト: lianshun/XDF4C
static enum saxerror sax_core (sax_parser_t *prs, char *buf, int len)
{
    enum saxerror err;
    int pos = 0, old = 0, re, stack_old = -1;
    unsigned char c;

    while (pos < len) {
        re = 0;
        c = buf[pos];
        if (0 == c) return SAX_BADXML;
        if (prs->encode_max) {
            prs->encode_len++;
            if (prs->encode_len == prs->encode_max) prs->encode_max = 0;
            goto cont;
        }
        else {
            if (c & 0x80) {
                /* only support ANSI */
                prs->encode_max = 2;
                prs->encode_len = 1;
                if (stack_old == -1
                    && (prs->context == C_TAG
                      || prs->context == C_ATTRIBUTE_1
                      || prs->context == C_VALUE_APOS
                      || prs->context == C_VALUE_QUOT)) stack_old = pos;
                goto cont;
            }
        }

        switch (prs->context) {
        case C_CDATA:
#if 0
            if ('&' == c) {
                if (old < pos && prs->cdataHook) {
                    err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
                    if (SAX_OK != err) return err;
                }
                prs->context = C_ENTITY;
                prs->entpos = 0;
                break;
            }
#endif
            if ('<' == c) {
                if (old < pos && prs->cdataHook) {
                    err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
                    if (SAX_OK != err) return err;
                }
                STACK_INIT;
                prs->tag_name = STACK_PUSH_START;
                if (!prs->tag_name) return SAX_NOMEM;
                prs->context = C_TAG_START;
            }
            if (is_tail_user_tag(buf, old, pos, prs->user_tag)) {
                if (old < pos && prs->cdataHook) {
                    err = prs->cdataHook (prs->user_data, &buf[old], pos - old - strlen(prs->user_tag) + 1);
                    if (SAX_OK != err) return err;
                }
                old = pos + 1;
            }
            break;

        case C_TAG_START:
            prs->context = C_TAG;
            if ('/' == c) {
                prs->tagtype = TAG_CLOSE;
                break;
            }
            if ('?' == c) {
                prs->context = C_PI;
                break;
            }
            if ('!' == c) {
                prs->context = C_MARKUP;
                break;
            }
            prs->tagtype = TAG_OPEN;
            stack_old = pos;
            break;

        case C_TAG:
            if (IS_WHITESPACE(c)) {
                if (TAG_CLOSE == prs->tagtype)
                    prs->oldcontext = C_TAG_END;
                else
                    prs->oldcontext = C_ATTRIBUTE;
                prs->context = C_WHITESPACE;
                if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
                stack_old = -1;
                STACK_PUSH_END;
                break;
            }
            if ('/' == c) {
                if (TAG_CLOSE == prs->tagtype) return SAX_BADXML;
                prs->tagtype = TAG_SINGLE;
                prs->context = C_TAG_END;
                if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
                stack_old = -1;
                STACK_PUSH_END;
                break;
            }
            if ('>' == c) {
                prs->context = C_TAG_END;
                if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
                stack_old = -1;
                STACK_PUSH_END;
                re = 1;
                break;
            }
            if (stack_old == -1) stack_old = pos;
            break;

        case C_TAG_END:
            if (c != '>') return SAX_BADXML;
            if (prs->tagHook) {
                char **tmp;
                if (prs->attcur == 0) tmp = NULL; else tmp = prs->atts;
                err = prs->tagHook (prs->user_data, prs->tag_name, tmp, prs->tagtype);
                if (SAX_OK != err) return err;
            }
            prs->stack_pos = 0;
            stack_old = -1;
            prs->attcur = 0;
            prs->attflag = 0;
            prs->context = C_CDATA;
            old = pos + 1;
            break;

        case C_ATTRIBUTE:
            if ('/' == c) {
                prs->tagtype = TAG_SINGLE;
                prs->context = C_TAG_END;
                break;
            }
            if ('>' == c) {
                prs->context = C_TAG_END;
                re = 1;
                break;
            }
            if (!prs->atts) {
                prs->attmax = 12;
                prs->atts = malloc(sizeof(char *) * 2 * 12);
                if (!prs->atts) return SAX_NOMEM;
                memset(prs->atts, 0, sizeof(char *) * 2 * 12);
                prs->attcur = 0;
            }
            else {
                if (prs->attcur >= (prs->attmax * 2)) {
                    void *tmp;
                    prs->attmax += 12;
                    tmp = malloc(sizeof(char *) * 2 * prs->attmax);
                    if (!tmp) return SAX_NOMEM;
                    memset(tmp, 0, sizeof(char *) * 2 * prs->attmax);
                    memcpy(tmp, prs->atts, sizeof(char *) * prs->attcur);
                    free(prs->atts);
                    prs->atts = tmp;
                }
            }
            prs->attflag = 1;
            prs->atts[prs->attcur] = STACK_PUSH_START;
            stack_old = pos;
            prs->context = C_ATTRIBUTE_1;
            break;

        case C_ATTRIBUTE_1:
            if ('=' == c) {
                if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
                stack_old = -1;
                STACK_PUSH_END;
                prs->context = C_VALUE;
                break;
            }
            if (stack_old == -1) stack_old = pos;
            break;

        case C_ATTRIBUTE_2:
            if ('/' == c) {
                prs->tagtype = TAG_SINGLE;
                prs->atts[prs->attcur] = NULL;
                prs->context = C_TAG_END;
                break;
            }
            if ('>' == c) {
                prs->atts[prs->attcur] = NULL;
                prs->context = C_TAG_END;
                re = 1;
                break;
            }
            prs->context = C_ATTRIBUTE;
            re = 1;
            break;

        case C_VALUE:
            prs->atts[prs->attcur + 1] = STACK_PUSH_START;
            if ('\'' == c) {
                prs->context = C_VALUE_APOS;
                break;
            }
            if ('"' == c) {
                prs->context = C_VALUE_QUOT;
                break;
            }
            return SAX_BADXML;

        case C_VALUE_APOS:
            if ('\'' == c) {
                if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
                stack_old = -1;
                STACK_PUSH_END;
                prs->oldcontext = C_ATTRIBUTE_2;
                prs->context = C_WHITESPACE;
                prs->attcur += 2;
            }
            if (stack_old == -1) stack_old = pos;
            break;

        case C_VALUE_QUOT:
            if ('"' == c) {
                if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
                stack_old = -1;
                STACK_PUSH_END;
                prs->oldcontext = C_ATTRIBUTE_2;
                prs->context = C_WHITESPACE;
                prs->attcur += 2;
            }
            if (stack_old == -1) stack_old = pos;
            break;

        case C_WHITESPACE:
            if (NOT_WHITESPACE(c)) {
                prs->context = prs->oldcontext;
                re = 1;
            }
            break;

        case C_ENTITY:
            if (';' == c) {
                char hede[2];
                char t = '?';
                prs->entity[prs->entpos] = 0;
                if (strcmp(prs->entity, "amp") == 0)
                    t = '&';
                else if (strcmp(prs->entity, "quot") == 0)
                    t = '"';
                else if (strcmp(prs->entity, "apos") == 0)
                    t = '\'';
                else if (strcmp(prs->entity, "lt") == 0)
                    t = '<';
                else if (strcmp(prs->entity, "gt") == 0)
                    t = '>';
                old = pos + 1;
                hede[0] = t;
                if (prs->cdataHook) {
                    err = prs->cdataHook (prs->user_data, &hede[0], 1);
                    if (SAX_OK != err) return err;
                }
                prs->context = C_CDATA;
            }
            else {
                prs->entity[prs->entpos++] = buf[pos];
                if (prs->entpos > 7) return SAX_BADXML;
            }
            break;

        case C_COMMENT:
            if ('-' != c) return SAX_BADXML;
            prs->context = C_COMMENT_1;
            break;

        case C_COMMENT_1:
            if ('-' == c) prs->context = C_COMMENT_2;
            break;

        case C_COMMENT_2:
            if ('-' == c)
                prs->context = C_COMMENT_3;
            else
                prs->context = C_COMMENT_1;
            break;

        case C_COMMENT_3:
            if ('>' != c) return SAX_BADXML;
            prs->context = C_CDATA;
            old = pos + 1;
            break;

        case C_MARKUP:
            if ('[' == c) {
                prs->context = C_SECT;
                break;
            }
            if ('-' == c) {
                prs->context = C_COMMENT;
                break;
            }
            prs->context = C_MARKUP_1;

        case C_MARKUP_1:
            if ('>' == c) {
                old = pos + 1;
                prs->context = C_CDATA;
            }
            break;

        case C_SECT:
            if ('C' == c) {
                prs->context = C_SECT_CDATA;
                break;
            }
            return SAX_BADXML;

        case C_SECT_CDATA:
            if ('D' != c) return SAX_BADXML;
            prs->context = C_SECT_CDATA_1;
            break;

        case C_SECT_CDATA_1:
            if ('A' != c) return SAX_BADXML;
            prs->context = C_SECT_CDATA_2;
            break;

        case C_SECT_CDATA_2:
            if ('T' != c) return SAX_BADXML;
            prs->context = C_SECT_CDATA_3;
            break;

        case C_SECT_CDATA_3:
            if ('A' != c) return SAX_BADXML;
            prs->context = C_SECT_CDATA_4;
            break;

        case C_SECT_CDATA_4:
            if ('[' != c) return SAX_BADXML;
            old = pos + 1;
            prs->context = C_SECT_CDATA_C;
            break;

        case C_SECT_CDATA_C:
            if (']' == c) {
                prs->context = C_SECT_CDATA_E;
                if (prs->ctxtHook && old < pos) {
                    err = prs->ctxtHook (prs->user_data, &buf[old], pos - old);
                    if (SAX_OK != err) return err;
                }
            }
            break;

        case C_SECT_CDATA_E:
            if (']' == c) {
                prs->context = C_SECT_CDATA_E2;
            }
            else {
                if (prs->ctxtHook) {
                    err = prs->ctxtHook (prs->user_data, "]", 1);
                    if (SAX_OK != err) return err;
                }
                old = pos;
                prs->context = C_SECT_CDATA_C;
            }
            break;

        case C_SECT_CDATA_E2:
            if ('>' == c) {
                old = pos + 1;
                prs->context = C_CDATA;
            }
            else {
                if (prs->ctxtHook) {
                    err = prs->ctxtHook (prs->user_data, "]]", 2);
                    if (SAX_OK != err) return err;
                }
                old = pos;
                prs->context = C_SECT_CDATA_C;
            }
            break;

        case C_PI:
            old = pos + 1;
            if ('>' == c) prs->context = C_CDATA;
            break;
        }
cont:
        if (0 == re) {
            pos++;
            prs->nr_bytes++;
            if ('\n' == c) prs->nr_lines++;
        }
    }

    if (stack_old != -1)
        STACK_PUSH (buf + stack_old, pos - stack_old);

    err = SAX_OK;
    if (prs->context == C_CDATA || prs->context == C_SECT_CDATA_C) {
        prs->rewind_bytes = old - pos;
    }
    return err;
}