1 /* 2 * Copyright 2007 Jacek Caban for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "hhctrl.h" 20 #include "stream.h" 21 22 #include "wine/debug.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp); 25 26 void strbuf_init(strbuf_t *buf) 27 { 28 buf->size = 8; 29 buf->len = 0; 30 buf->buf = heap_alloc(buf->size); 31 } 32 33 void strbuf_zero(strbuf_t *buf) 34 { 35 buf->len = 0; 36 } 37 38 void strbuf_free(strbuf_t *buf) 39 { 40 heap_free(buf->buf); 41 } 42 43 static void strbuf_append(strbuf_t *buf, const char *data, int len) 44 { 45 if(buf->len+len > buf->size) { 46 buf->size = buf->len+len; 47 buf->buf = heap_realloc(buf->buf, buf->size); 48 } 49 50 memcpy(buf->buf+buf->len, data, len); 51 buf->len += len; 52 } 53 54 void stream_init(stream_t *stream, IStream *str) 55 { 56 memset(stream, 0, sizeof(stream_t)); 57 stream->str = str; 58 } 59 60 static BOOL stream_chr(stream_t *stream, strbuf_t *buf, char c) 61 { 62 BOOL b = TRUE; 63 ULONG i; 64 65 while(b) { 66 for(i=stream->p; i<stream->size; i++) { 67 if(stream->buf[i] == c) { 68 b = FALSE; 69 break; 70 } 71 } 72 73 if(buf && i > stream->p) 74 strbuf_append(buf, stream->buf+stream->p, i-stream->p); 75 stream->p = i; 76 77 if(stream->p == stream->size) { 78 stream->p = 0; 79 IStream_Read(stream->str, stream->buf, sizeof(stream->buf), &stream->size); 80 if(!stream->size) 81 break; 82 } 83 } 84 85 return stream->size != 0; 86 } 87 88 void get_node_name(strbuf_t *node, strbuf_t *name) 89 { 90 const char *ptr = node->buf+1; 91 92 strbuf_zero(name); 93 94 while(*ptr != '>' && !isspace(*ptr)) 95 ptr++; 96 97 strbuf_append(name, node->buf+1, ptr-node->buf-1); 98 strbuf_append(name, "", 1); 99 } 100 101 /* Return the stream content up to the next HTML tag. 102 * 103 * Note: the first returned character is the end of the last tag (>). 104 */ 105 BOOL next_content(stream_t *stream, strbuf_t *buf) 106 { 107 if(!stream_chr(stream, buf, '<')) 108 return FALSE; 109 110 return TRUE; 111 } 112 113 static BOOL find_node_end(stream_t *stream, strbuf_t *buf) 114 { 115 int tag_count = 0, b = buf->len; 116 char *p; 117 118 while(1) 119 { 120 if(!stream_chr(stream, buf, '>')) 121 return FALSE; 122 if(buf->len == 0) 123 break; 124 p = &buf->buf[b]; 125 while((p = memchr(p+1, '"', buf->len-(p+1-buf->buf))) != NULL) 126 tag_count++; 127 b = buf->len; 128 if(tag_count % 2 != 0) 129 { 130 if(!stream_chr(stream, buf, '"')) 131 return FALSE; 132 tag_count++; 133 } 134 else 135 break; 136 } 137 return TRUE; 138 } 139 140 BOOL next_node(stream_t *stream, strbuf_t *buf) 141 { 142 /* find the beginning of the next node */ 143 if(!stream_chr(stream, NULL, '<')) 144 return FALSE; 145 146 /* read out the data of the next node */ 147 if(!find_node_end(stream, buf)) 148 return FALSE; 149 150 strbuf_append(buf, ">", 2); 151 152 return TRUE; 153 } 154 155 /* 156 * Find the value of a named HTML attribute. 157 * 158 * Note: Attribute names are case insensitive, so it is necessary to 159 * put both the node text and the attribute name in the same case 160 * before attempting a string search. 161 */ 162 const char *get_attr(const char *node, const char *name, int *len) 163 { 164 const char *ptr, *ptr2; 165 int name_len, node_len; 166 char name_buf[32]; 167 char *node_buf; 168 int i; 169 170 /* Create a lower case copy of the node */ 171 node_len = strlen(node)+1; 172 node_buf = heap_alloc(node_len*sizeof(char)); 173 if(!node_buf) 174 return NULL; 175 memcpy(node_buf, node, node_len); 176 for(i=0;i<node_len;i++) 177 node_buf[i] = tolower(node_buf[i]); 178 /* Create a lower case copy of the attribute name (search string) */ 179 name_len = strlen(name); 180 memcpy(name_buf, name, name_len); 181 for(i=0;i<name_len;i++) 182 name_buf[i] = tolower(name_buf[i]); 183 name_buf[name_len++] = '='; 184 name_buf[name_len++] = '\"'; 185 name_buf[name_len] = 0; 186 187 ptr = strstr(node_buf, name_buf); 188 if(!ptr) { 189 WARN("name not found\n"); 190 heap_free(node_buf); 191 return NULL; 192 } 193 194 ptr += name_len; 195 ptr2 = strchr(ptr, '\"'); 196 if(!ptr2) 197 { 198 heap_free(node_buf); 199 return NULL; 200 } 201 202 *len = ptr2-ptr; 203 /* Return the pointer offset within the original string */ 204 ptr = node+(ptr-node_buf); 205 206 heap_free(node_buf); 207 return ptr; 208 } 209