/* * Copyright 2007 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "hhctrl.h" #include "stream.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp); void strbuf_init(strbuf_t *buf) { buf->size = 8; buf->len = 0; buf->buf = heap_alloc(buf->size); } void strbuf_zero(strbuf_t *buf) { buf->len = 0; } void strbuf_free(strbuf_t *buf) { heap_free(buf->buf); } static void strbuf_append(strbuf_t *buf, const char *data, int len) { if(buf->len+len > buf->size) { buf->size = buf->len+len; buf->buf = heap_realloc(buf->buf, buf->size); } memcpy(buf->buf+buf->len, data, len); buf->len += len; } void stream_init(stream_t *stream, IStream *str) { memset(stream, 0, sizeof(stream_t)); stream->str = str; } static BOOL stream_chr(stream_t *stream, strbuf_t *buf, char c) { BOOL b = TRUE; ULONG i; while(b) { for(i=stream->p; isize; i++) { if(stream->buf[i] == c) { b = FALSE; break; } } if(buf && i > stream->p) strbuf_append(buf, stream->buf+stream->p, i-stream->p); stream->p = i; if(stream->p == stream->size) { stream->p = 0; IStream_Read(stream->str, stream->buf, sizeof(stream->buf), &stream->size); if(!stream->size) break; } } return stream->size != 0; } void get_node_name(strbuf_t *node, strbuf_t *name) { const char *ptr = node->buf+1; strbuf_zero(name); while(*ptr != '>' && !isspace(*ptr)) ptr++; strbuf_append(name, node->buf+1, ptr-node->buf-1); strbuf_append(name, "", 1); } /* Return the stream content up to the next HTML tag. * * Note: the first returned character is the end of the last tag (>). */ BOOL next_content(stream_t *stream, strbuf_t *buf) { if(!stream_chr(stream, buf, '<')) return FALSE; return TRUE; } static BOOL find_node_end(stream_t *stream, strbuf_t *buf) { int tag_count = 0, b = buf->len; char *p; while(1) { if(!stream_chr(stream, buf, '>')) return FALSE; if(buf->len == 0) break; p = &buf->buf[b]; while((p = memchr(p+1, '"', buf->len-(p+1-buf->buf))) != NULL) tag_count++; b = buf->len; if(tag_count % 2 != 0) { if(!stream_chr(stream, buf, '"')) return FALSE; tag_count++; } else break; } return TRUE; } BOOL next_node(stream_t *stream, strbuf_t *buf) { /* find the beginning of the next node */ if(!stream_chr(stream, NULL, '<')) return FALSE; /* read out the data of the next node */ if(!find_node_end(stream, buf)) return FALSE; strbuf_append(buf, ">", 2); return TRUE; } /* * Find the value of a named HTML attribute. * * Note: Attribute names are case insensitive, so it is necessary to * put both the node text and the attribute name in the same case * before attempting a string search. */ const char *get_attr(const char *node, const char *name, int *len) { const char *ptr, *ptr2; int name_len, node_len; char name_buf[32]; char *node_buf; int i; /* Create a lower case copy of the node */ node_len = strlen(node)+1; node_buf = heap_alloc(node_len*sizeof(char)); if(!node_buf) return NULL; memcpy(node_buf, node, node_len); for(i=0;i