/* libmib/filesys/html.c
- - - - - - - - - - - - Copyright Notice - - - - - - - - - - - -
Copyright 1999 Forrest J. Cavalier III
WARNING: This software may have been modified.
See http://www.mibsoftware.com/libmib/ for documentation and
up-to-date original copies. Arrangements for custom versions,
support, and other licensing terms are made in writing.
We would appreciate that you notify us of defect discoveries
and enhancements so that others can benefit from improvements
to this software.
- - - - - - - - - - - - - License - - - - - - - - - - - - - - - - -
Permission is hereby granted, to any person obtaining a copy of
this software (the "Software"), to deal in the Software without
restriction, including the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
subject to all the following conditions.
1. The text beginning with the copyright notice above, and including
the four clauses of this license shall be included in full and
unmodified in all copies of the source files or portions thereof.
2. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Software or its derivative works. These actions are
prohibited by law if you do not accept this License.
3. The author(s) grant you a non-exclusive right to use the author-
given names and trademarks of the Software to publish and distribute
only unmodified source files. Your rights to deal in the Software
under this license are subject to the condition that you do not
use nor associate trademarks, names, or reputation of the author(s)
with derivative works except within the source files.
4. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define USE_librock
#ifdef USE_librock
/* 2001-07-23 use librock */
#define librock_ISOLATED
#define librock_WRAP
#define librock_PTR
#define librock_CONST const
#include
#include
#include
#include
#include
#include
#define librock_astrensure astrensure
#define librock_astrcat astrcat
#define librock_astrn0cat astrn0cat
#define librock_astrfree astrfree
#define librock_counttoch counttoch
#define librock_astrn0cpy astrn0cpy
#define librock_body_HTML_astrcatValueEncode librock_HTML_astrcatValueEncode
#define librock_body_HTTP_astrcatUrlEncode HTTP_AppendUrlEnc
#define librock_HTTP_astrcatUrlEncode HTTP_AppendUrlEnc
#define librock_body_HTML_astrcatEntityEncode librock_HTML_astrcatEntityEncode
#define librock_body_HTTP_astrcpyFieldFromUrlEncode HTTP_FieldFromUrlEnc
#include "../librock/text/html.c"
#include
void HTML_VSBAppendAsHTML(struct VSB_s *pv,const char *text,int len)
{
char *asz = 0;
librock_HTML_astrcatEntityEncode(&asz,text,len);
VSBAppend(pv,asz,strlen(asz));
astrfree(&asz);
}
char *HTTP_FieldIter(const char *pQueryString,char **ppszName,char **ppasz)
{ /* DEBUG: reuse */
int ind;
int ensure;
int cbLen;
int cbName;
const char *endptr;
if (!pQueryString || !*pQueryString) {
return 0;
}
if (*pQueryString == '?') {
pQueryString++;
} else if (*pQueryString == '&') {
pQueryString++;
}
cbLen = counttoch(pQueryString,'&');
endptr = pQueryString + cbLen;
cbName = counttoch(pQueryString,'=');
if (cbName > cbLen) {
cbName = cbLen;
}
astrn0cpy(ppszName,pQueryString,cbName);
pQueryString += cbName;
if (*pQueryString == '=') {
pQueryString++;
}
/* Process until end of string, or get another '&' */
ind = 0;
ensure = 64;
astrensure(ppasz,ensure);
while(pQueryString < endptr) {
if (ind+1 > ensure) {
ensure += 64;
if (!astrensure(ppasz,ensure)) {
return 0;
}
}
if (*pQueryString == '+') {
(*ppasz)[ind++] = ' ';
pQueryString++;
} else if (*pQueryString == '%') {
(*ppasz)[ind++] = (aschex2nib(pQueryString[1])<<4) | aschex2nib(pQueryString[2]);
pQueryString += 3;
} else {
(*ppasz)[ind++] = *pQueryString++;
}
}
(*ppasz)[ind] = 0;
return (char *) pQueryString;
} /* HTTP_FieldIter */
#else // not using USE_librock
#include
#include
#include
#include
#include
#include
void HTML_VSBAppendAsHTML(struct VSB_s *pv,const char *text,int len)
{ /* DEBUG: reuse */
char buf[20];
const char *ptr = text;
while((len > 0)||((len == -1)&&*ptr)) {
if (*ptr == '<') {
VSBAppend(pv,"<",4);
ptr++;
} else if (*ptr == '>') {
VSBAppend(pv,">",4);
ptr++;
} else if (*ptr == '&') {
VSBAppend(pv,"&",5);
ptr++;
} else if (*ptr == '\"') {
VSBAppend(pv,""",6);
ptr++;
} else if ((*ptr&0xff) == 241) { /* 9-12-96 */
VSBAppend(pv,"ñ",8);
ptr++;
} else if ((*ptr&0xff) == 225) { /* 9-12-96 */
VSBAppend(pv,"á",8);
ptr++;
} else if ((*ptr&0xff) == 233) { /* 9-12-96 */
VSBAppend(pv,"é",8);
ptr++;
} else if ((*ptr&0xff) == 237) { /* 9-12-96 */
VSBAppend(pv,"í",8);
ptr++;
} else if ((*ptr&0xff) == 243) { /* 9-12-96 */
VSBAppend(pv,"ó",8);
ptr++;
} else if ((*ptr&0xff) == 250) { /* 9-12-96 */
VSBAppend(pv,"ú",8);
ptr++;
} else if (*ptr & 0x80) { /* 9-12-96 Take a shot at it */
strcpy(buf,"");
if ((*ptr & 0xff) >= 100) {
buf[2] = '0' + (*ptr & 0xff) / 100;
buf[3] = '0' + (((*ptr & 0xff) / 10)%10);
buf[4] = '0' + (((*ptr & 0xff) / 1)%10);
buf[5] = 0;
} else if((*ptr & 0xff) >= 10) {
buf[2] = '0' + (((*ptr & 0xff) / 10)%10);
buf[3] = '0' + (((*ptr & 0xff) / 1)%10);
buf[4] = 0;
} else {
buf[2] = '0' + (((*ptr & 0xff) / 1)%10);
buf[3] = 0;
}
VSBAppend(pv,buf,strlen(buf));
ptr++;
} else {
VSBAppend(pv,ptr,1);
ptr++;
}
if (len > 0) {
len--;
}
}
}
void HTML_VSBAppendFromHTML(struct VSB_s *pv,const char *textHTML,int len)
{ /* DEBUG: reuse */
char buf[20];
const char *ptr = textHTML;
while(*ptr && (ptr < textHTML + len)) {
if (!strncmp(ptr,"<",4)) {
VSBAppend(pv,"<",1);
ptr += counttoch(ptr,';') + 1;
} else if (!strncmp(ptr,">",4)) {
ptr += counttoch(ptr,';') + 1;
VSBAppend(pv,">",1);
} else if (!strncmp(ptr,"&",5)) {
VSBAppend(pv,"&",1);
ptr += counttoch(ptr,';') + 1;
} else if (!strncmp(ptr,""",6)) {
ptr += counttoch(ptr,';') + 1;
VSBAppend(pv,"\"",1);
} else if (!strncmp(ptr,"ñ",8)) {
VSBAppend(pv,"\xf1",1);
ptr += counttoch(ptr,';') + 1;
} else if (!strncmp(ptr,"á",8)) {
VSBAppend(pv,"\xe1",1);
ptr += counttoch(ptr,';') + 1;
} else if (!strncmp(ptr,"é",8)) {
VSBAppend(pv,"\xe9",1);
ptr += counttoch(ptr,';') + 1;
} else if (!strncmp(ptr,"í",8)) {
VSBAppend(pv,"\xed",1);
ptr += counttoch(ptr,';') + 1;
} else if (!strncmp(ptr,"ó",8)) {
VSBAppend(pv,"\xf3",1);
ptr += counttoch(ptr,';') + 1;
} else if (!strncmp(ptr,"ú",8)) {
VSBAppend(pv,"\xfa",1);
ptr += counttoch(ptr,';') + 1;
} else if ((ptr[0]=='&')&&(ptr[1]=='#')) { /* 9-12-96 Take a shot at it */
buf[0] = atoi(ptr+2);
VSBAppend(pv,buf,1);
ptr += counttoch(ptr,';') + 1;
} else {
VSBAppend(pv,ptr,1);
ptr++;
}
}
}
int HTML_ParseTag(struct VSB_s *pv,const char *buf,int cbBuf)
{ /* Text at buf should be a valid HTML element. Each attribute in
the element is split into a null terminated string
and stored into VSB. quotes, if any are removed.
The first string is the HTML element name itself.
Returns number of characters processed, or 0.
Elements attributes are not checked for validity.
The content of an element (if any) is not checked.
A \0\0 terminates the VSB list which is appended.
DEBUG: untested!
*/
const char *ptr = buf;
const char *nptr;
if (*ptr != '<') {
return 0;
}
ptr++;
nptr = ptr;
while(*ptr && (*ptr != '>')) {
if (*ptr <= ' ') {
if (nptr) {
VSBAppend(pv,nptr,ptr-nptr);
VSBAppend(pv,"\0",1);
nptr = 0;
}
ptr++;
} else if (*ptr == '=') {
const char *eptr;
if (!nptr) {
nptr = ptr;
}
ptr++;
VSBAppend(pv,nptr,ptr-nptr);
if (*ptr == '\"') {
ptr++;
nptr = ptr;
eptr = memchr(ptr,'"',cbBuf - (ptr - buf));
ptr = eptr;
} else {
nptr = ptr;
eptr = memchr(ptr,' ',cbBuf - (ptr - buf));
ptr = eptr;
}
if (!eptr) {
eptr = cbBuf + buf - 1;
ptr = eptr;
}
VSBAppend(pv,nptr,ptr-nptr);
VSBAppend(pv,"\0",1);
nptr = 0;
if (*ptr != '>') {
ptr++;
}
} else {
if (!nptr) {
nptr = ptr;
}
ptr++;
}
}
if (nptr) {
VSBAppend(pv,nptr,ptr-nptr);
VSBAppend(pv,"\0",1);
}
return ptr - buf;
} /* ParseTag */
/**************************************************************/
static int aschex2nib(char ch)
{
if (ch > '9') {
return (ch & 0x0f)+9;
}
return ch & 0x0f;
}
static int nib2aschex(int n)
{
if ((n&0x0f) > 9) {
return ((n&0x0f) - 10)+'A';
}
return (n&0x0f)+'0';
}
#include
char *HTTP_AppendUrlEnc(char **ppasz,const char *pszString,int cbString)
{ /* 3/23/99 */
char buf[64];
int ind = 0;
while((cbString > 0)&&*pszString) {
if (isalnum(*pszString)||strchr("-_.!~*'()",*pszString)) {
buf[ind++] = *pszString;
} else {
buf[ind++] = '%';
buf[ind++] = nib2aschex((*pszString>>4)&0x0f);
buf[ind++] = nib2aschex(*pszString&0x0f);
}
if (ind >= sizeof(buf)-4) {
astrn0cat(ppasz,buf,ind);
ind = 0;
}
pszString++;
cbString--;
}
if (ind) {
astrn0cat(ppasz,buf,ind);
}
return *ppasz;
} /* HTTP_AppendUrlEnc */
char *HTML_AppendValueEscape(char **ppasz,const char *pszString,int cbString)
{ /* 2/22/2000 */
char buf[64];
int ind = 0;
while((cbString > 0)&&*pszString) {
if (strchr("\r\n%\x22",*pszString)) {
buf[ind++] = '%';
buf[ind++] = nib2aschex((*pszString>>4)&0x0f);
buf[ind++] = nib2aschex(*pszString&0x0f);
} else {
buf[ind++] = *pszString;
}
if (ind >= sizeof(buf)-4) {
astrn0cat(ppasz,buf,ind);
ind = 0;
}
pszString++;
cbString--;
}
if (ind) {
astrn0cat(ppasz,buf,ind);
}
return *ppasz;
} /* HTML_AppendValueEscape */
char *HTML_AppendAmpEscape(char **ppasz,const char *pszString,int cbString)
{ /* 2/22/2000 */
char buf[64];
int ind = 0;
while((cbString > 0)&&*pszString) {
if (*pszString == '&') {
memcpy(buf+ind,"&",5);
ind += 5;
} else if (*pszString == '<') {
memcpy(buf+ind,"<",4);
ind += 4;
} else if (*pszString == '>') {
memcpy(buf+ind,">",4);
ind += 4;
} else {
buf[ind++] = *pszString;
}
if (ind >= sizeof(buf)-5) {
astrn0cat(ppasz,buf,ind);
ind = 0;
}
pszString++;
cbString--;
}
if (ind) {
astrn0cat(ppasz,buf,ind);
}
return *ppasz;
} /* HTML_AppendAmpEscape */
char *HTTP_FieldFromUrlEnc(char **ppasz,const char *pszName,const char *pszQuerystring)
{ /* DEBUG: reuse */
/* # Un-Webify plus signs and %-encoding
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
*/
/* As of 7/7/99, returns pointer to pszQueryString to allow for
additional parsing of duplicated field values
*/
const char *ptr = pszQuerystring;
const char *pRet = 0;
int ind;
int ensure;
int cbName = strlen(pszName);
const char *endptr;
while(ptr) {
if (!strncmp(ptr,pszName,cbName) &&
(ptr[cbName] == '=')) {
/* Match */
break;
}
ptr = strchr(ptr,'&');
if (ptr) {
ptr++;
}
}
if (!ptr) {
astrfree(ppasz);
return 0;
}
pRet = ptr;
ptr += cbName;
ptr++;
/* Process until end of string, or get another '&' */
ind = 0;
ensure = 64;
astrensure(ppasz,ensure);
endptr = ptr + counttoch(ptr,'&');
while(ptr < endptr) {
if (ind+1 > ensure) {
ensure += 64;
if (!astrensure(ppasz,ensure)) {
return 0;
}
}
if (*ptr == '+') {
(*ppasz)[ind++] = ' ';
ptr++;
} else if (*ptr == '%') {
(*ppasz)[ind++] = (aschex2nib(ptr[1])<<4) | aschex2nib(ptr[2]);
ptr += 3;
} else {
(*ppasz)[ind++] = *ptr++;
}
}
(*ppasz)[ind] = 0;
return (char *) pRet;
} /* HTTP_FieldFromUrlEnc */
char *HTTP_SetFieldUrlEnc(char **ppaszQueryString,const char *pszName,const char *pszValue)
{ /* DEBUG: reuse */
/* # Un-Webify plus signs and %-encoding
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
*/
/* As of 7/7/99, returns pointer to pszQueryString to allow for
additional parsing of duplicated field values
*/
const char *ptr = *ppaszQueryString;
char *asz = 0;
int cbName = strlen(pszName);
const char *endptr;
while(ptr) {
if (!strncmp(ptr,pszName,cbName) &&
(ptr[cbName] == '=')) {
/* Match */
break;
}
ptr = strchr(ptr,'&');
if (ptr) {
ptr++;
}
}
if (!ptr) {
/* No match. Append */
astrcat(ppaszQueryString,"&");
HTTP_AppendUrlEnc(ppaszQueryString,pszName,strlen(pszName));
astrcat(ppaszQueryString,"=");
HTTP_AppendUrlEnc(ppaszQueryString,pszValue,strlen(pszValue));
return *ppaszQueryString;
}
ptr += cbName;
ptr++;
endptr = ptr + counttoch(ptr,'&');
astrn0cpy(&asz,*ppaszQueryString,ptr-*ppaszQueryString);
HTTP_AppendUrlEnc(&asz,pszValue,strlen(pszValue));
astrcat(&asz,endptr);
astrfree(ppaszQueryString);
*ppaszQueryString = asz;
return asz;
} /* HTTP_SetFieldUrlEnc */
#endif