/* Fall through . . */ case 107: if (tolower (ch) == 'h') { state = 1; start = n; } else state = ST_INITIAL; break; case ST_START_FOUND: if (isspace ((int) ((unsigned char) ch)) || (ch == '"') || (ch == '>')) { end = n; state = ST_END_FOUND; } break; } # undef CHK # undef CCHK } else { if (state == ST_START_FOUND) { end = n; state = ST_END_FOUND; } else state = ST_INITIAL; } n += clen; } else { if (state == ST_START_FOUND) { end = n; state = ST_END_FOUND; } ++n; } if (state == ST_END_FOUND) { int ulen, m, o; ulen = end - start; for (m = 0; m < blockmail -> url_count; ++m) if ((blockmail -> url[m] -> usage & mask) && (blockmail -> url[m] -> dlen == ulen) && (! xmlStrncmp (blockmail -> url[m] -> dptr, cont + start, ulen))) break; if (m < blockmail -> url_count) { if (lstore < start) xmlBufferAdd (block -> out, cont + lstore, start - lstore); for (o = 0; o < rec -> url_count; ++o) if (rec -> url[o] -> uid == blockmail -> url[m] -> uid) break; if (o < rec -> url_count) xmlBufferAdd (block -> out, rec -> url[o] -> dptr, rec -> url[o] -> dlen); lstore = end; changed = true; } state = ST_INITIAL; } } if (changed) { if (lstore < len) xmlBufferAdd (block -> out, cont + lstore, len - lstore); SWAP (block); } return true; }/*}}}*/ static bool_t collect_links (blockmail_t *blockmail, block_t *block, links_t *links) /*{{{*/ { bool_t rc; int n, clen; int len; const xmlChar *cont; int start; rc = true; len = xmlBufferLength (block -> in); cont = xmlBufferContent (block -> in); for (n = 0; rc && (n < len); ) { clen = xmlCharLength (cont[n]); if ((clen == 1) && (cont[n] == 'h')) { start = n; ++n; if ((n + 3 < len) && (cont[n] == 't') && (cont[n + 1] == 't') && (cont[n + 2] == 'p')) { n += 3; if ((n + 1 < len) && (cont[n] == 's')) ++n; if ((n + 3 < len) && (cont[n] == ':') && (cont[n + 1] == '/') && (cont[n + 2] == '/')) { n += 3; while ((n < len) && (xmlCharLength (cont[n]) == 1) && (cont[n] != '"') && (cont[n] != '<') && (cont[n] != '>') && (! isspace (cont[n]))) ++n; rc = links_nadd (links, (const char *) (cont + start), n - start); } } } else n += clen; } return rc; }/*}}}*/ static int find_top (const xmlChar *cont, int len) /*{{{*/ { int pos; int state; int n; int clen; unsigned char ch; for (pos = -1, state = 0, n = 0; (n < len) && (pos == -1); ) { clen = xmlCharLength (cont[n]); if (clen > 1) state = 0; else { ch = cont[n]; switch (state) { case 0: if (ch == '<') state = 1; break; case 1: if ((ch == 'b') || (ch == 'B')) state = 2; else if (ch == '>') state = 0; else if (! isspace (ch)) state = 100; break; case 2: if ((ch == 'o') || (ch == 'O')) state = 3; else if (ch == '>') state = 0; else state = 100; break; case 3: if ((ch == 'd') || (ch == 'D')) state = 4; else if (ch == '>') state = 0; else state = 100; break; case 4: if ((ch == 'y') || (ch == 'Y')) state = 5; else if (ch == '>') state = 0; else state = 100; break; case 5: if (ch == '>') { pos = n + clen; state = 0; } else if (isspace (ch)) state = 6; else state = 100; break; case 6: if (ch == '>') { pos = n + clen; state = 0; } # ifdef STRICT else if (ch == '"') state = 7; break; case 7: if (ch == '"') state = 6; # endif /* STRICT */ break; case 100: if (ch == '>') state = 0; break; } } n += clen; } return pos; }/*}}}*/ static int find_bottom (const xmlChar *cont, int len) /*{{{*/ { int pos; int last; int m; int bclen; for (pos = -1, last = len, m = len - 1; (m >= 0) && (pos == -1); ) { bclen = xmlCharLength (cont[m]); if ((bclen == 1) && (cont[m] == '<')) { int n; int state; int clen; unsigned char ch; for (n = m + bclen, state = 1; (n < last) && (state > 0) && (state != 99); ) { clen = xmlCharLength (cont[n]); if (clen != 1) state = 0; else { ch = cont[n]; switch (state) { case 1: if (ch == '/') state = 2; else if (! isspace (ch)) state = 0; break; case 2: if ((ch == 'b') || (ch == 'B')) state = 3; else if (! isspace (ch)) state = 0; break; case 3: if ((ch == 'o') || (ch == 'O')) state = 4; else state = 0; break; case 4: if ((ch == 'd') || (ch == 'D')) state = 5; else state = 0; break; case 5: if ((ch == 'y') || (ch == 'Y')) state = 6; else state = 0; break; case 6: if ((ch == '>') || isspace (ch)) state = 99; else state = 0; break; } } n += clen; } if (state == 99) pos = m; } else if ((bclen == 1) && (cont[m] == '>')) last = m + bclen; m -= bclen; } return pos; }/*}}}*/ static bool_t add_onepixellog_image (blockmail_t *blockmail, receiver_t *rec, block_t *block, opl_t opl) /*{{{*/ { bool_t rc; const xmlChar tname[] = "[agnONEPIXEL]"; int tlen = sizeof (tname) - 1; tag_t *opltag; rc = true; for (opltag = rec -> tag; opltag; opltag = opltag -> next) if (tag_match (opltag, tname, tlen)) break; if (opltag && opltag -> value) { int pos; int len; const xmlChar *cont; pos = -1; len = xmlBufferLength (block -> in); cont = xmlBufferContent (block -> in); switch (opl) { case OPL_None: break; case OPL_Top: pos = find_top (cont, len); if (pos == -1) pos = 0; break; case OPL_Bottom: pos = find_bottom (cont, len); if (pos == -1) pos = len; break; } if (pos != -1) { const xmlChar lprefix[] = "<img src=\""; const xmlChar lpostfix[] = "\" alt=\"\" border=\"0\" height=\"1\" width=\"1\">"; xmlBufferEmpty (block -> out); if (pos > 0) xmlBufferAdd (block -> out, cont, pos); xmlBufferAdd (block -> out, lprefix, sizeof (lprefix) - 1); xmlBufferAdd (block -> out, xmlBufferContent (opltag -> value), xmlBufferLength (opltag -> value)); xmlBufferAdd (block -> out, lpostfix, sizeof (lpostfix) - 1); if (pos < len) xmlBufferAdd (block -> out, cont + pos, len - pos); SWAP (block); } } return rc; }/*}}}*/
/* wrapper for stats_event, this takes a charset to convert from */ void stats_event_conv(const char *mount, const char *name, const char *value, const char *charset) { const char *metadata = value; xmlBufferPtr conv = xmlBufferCreate (); if (charset && value) { xmlCharEncodingHandlerPtr handle = xmlFindCharEncodingHandler (charset); if (handle) { xmlBufferPtr raw = xmlBufferCreate (); xmlBufferAdd (raw, (const xmlChar *)value, strlen (value)); if (xmlCharEncInFunc (handle, conv, raw) > 0) metadata = (char *)xmlBufferContent (conv); xmlBufferFree (raw); xmlCharEncCloseFunc (handle); } else WARN1 ("No charset found for \"%s\"", charset); } stats_event (mount, name, metadata); xmlBufferFree (conv); }
const std::string XMLNodeList::dump() const { xmlBufferPtr buffer = xmlBufferCreate(); for (xmlNode * cur = parent->children; cur; cur = cur->next) { xmlNodeDump(buffer, doc.getRealDocument(), cur, 0, 1); xmlBufferAdd(buffer, (xmlChar *) "\n", (int)strlen("\n")); } std::string str = std::string((const char *)buffer->content); xmlBufferFree(buffer); return str; }
int yaz_match_xsd_XML_n2(xmlNodePtr ptr, const char *elem, ODR o, char **val, int *len, int fixup_root) { xmlBufferPtr buf; int no_root_nodes = 0; if (!yaz_match_xsd_element(ptr, elem)) return 0; buf = xmlBufferCreate(); /* Copy each element nodes at top. In most cases there is only one root node.. At least one server http://www.theeuropeanlibrary.org/sru/sru.pl has multiple root nodes in recordData. */ for (ptr = ptr->children; ptr; ptr = ptr->next) { if (ptr->type == XML_ELEMENT_NODE) { /* copy node to get NS right (bug #740). */ xmlNode *tmp = xmlCopyNode(ptr, 1); xmlNodeDump(buf, tmp->doc, tmp, 0, 0); xmlFreeNode(tmp); no_root_nodes++; } } if (no_root_nodes != 1 && fixup_root) { /* does not appear to be an XML document. Make it so */ xmlBufferAddHead(buf, (const xmlChar *) "<yaz_record>", -1); xmlBufferAdd(buf, (const xmlChar *) "</yaz_record>", -1); } *val = odr_strdupn(o, (const char *) buf->content, buf->use); if (len) *len = buf->use; xmlBufferFree(buf); return 1; }
/** * exsltStrReplaceFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Takes a string, and two node sets and returns the string with all strings in * the first node set replaced by all strings in the second node set. */ static void exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) { int i, i_empty, n, slen0, rlen0, *slen, *rlen; void *mem = NULL; const xmlChar *src, *start; xmlChar *string, *search_str = NULL, *replace_str = NULL; xmlChar **search, **replace; xmlNodeSetPtr search_set = NULL, replace_set = NULL; xmlBufferPtr buf; if (nargs != 3) { xmlXPathSetArityError(ctxt); return; } /* get replace argument */ if (!xmlXPathStackIsNodeSet(ctxt)) replace_str = xmlXPathPopString(ctxt); else replace_set = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) goto fail_replace; /* get search argument */ if (!xmlXPathStackIsNodeSet(ctxt)) { search_str = xmlXPathPopString(ctxt); n = 1; } else { search_set = xmlXPathPopNodeSet(ctxt); n = search_set != NULL ? search_set->nodeNr : 0; } if (xmlXPathCheckError(ctxt)) goto fail_search; /* get string argument */ string = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) goto fail_string; /* check for empty search node list */ if (n <= 0) { exsltStrReturnString(ctxt, string, xmlStrlen(string)); goto done_empty_search; } /* allocate memory for string pointer and length arrays */ if (n == 1) { search = &search_str; replace = &replace_str; slen = &slen0; rlen = &rlen0; } else { mem = xmlMalloc(2 * n * (sizeof(const xmlChar *) + sizeof(int))); if (mem == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_malloc; } search = (xmlChar **) mem; replace = search + n; slen = (int *) (replace + n); rlen = slen + n; } /* process arguments */ i_empty = -1; for (i=0; i<n; ++i) { if (search_set != NULL) { search[i] = xmlXPathCastNodeToString(search_set->nodeTab[i]); if (search[i] == NULL) { n = i; goto fail_process_args; } } slen[i] = xmlStrlen(search[i]); if (i_empty < 0 && slen[i] == 0) i_empty = i; if (replace_set != NULL) { if (i < replace_set->nodeNr) { replace[i] = xmlXPathCastNodeToString(replace_set->nodeTab[i]); if (replace[i] == NULL) { n = i + 1; goto fail_process_args; } } else replace[i] = NULL; } else { if (i == 0) replace[i] = replace_str; else replace[i] = NULL; } if (replace[i] == NULL) rlen[i] = 0; else rlen[i] = xmlStrlen(replace[i]); } if (i_empty >= 0 && rlen[i_empty] == 0) i_empty = -1; /* replace operation */ buf = xmlBufferCreate(); if (buf == NULL) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_buffer; } src = string; start = string; while (*src != 0) { int max_len = 0, i_match = 0; for (i=0; i<n; ++i) { if (*src == search[i][0] && slen[i] > max_len && xmlStrncmp(src, search[i], slen[i]) == 0) { i_match = i; max_len = slen[i]; } } if (max_len == 0) { if (i_empty >= 0 && start < src) { if (xmlBufferAdd(buf, start, src - start) || xmlBufferAdd(buf, replace[i_empty], rlen[i_empty])) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_buffer_add; } start = src; } src += xmlUTF8Size(src); } else { if ((start < src && xmlBufferAdd(buf, start, src - start)) || (rlen[i_match] && xmlBufferAdd(buf, replace[i_match], rlen[i_match]))) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_buffer_add; } src += slen[i_match]; start = src; } } if (start < src && xmlBufferAdd(buf, start, src - start)) { xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); goto fail_buffer_add; } /* create result node set */ exsltStrReturnString(ctxt, xmlBufferContent(buf), xmlBufferLength(buf)); /* clean up */ fail_buffer_add: xmlBufferFree(buf); fail_buffer: fail_process_args: if (search_set != NULL) { for (i=0; i<n; ++i) xmlFree(search[i]); } if (replace_set != NULL) { for (i=0; i<n; ++i) { if (replace[i] != NULL) xmlFree(replace[i]); } } if (mem != NULL) xmlFree(mem); fail_malloc: done_empty_search: xmlFree(string); fail_string: if (search_set != NULL) xmlXPathFreeNodeSet(search_set); else xmlFree(search_str); fail_search: if (replace_set != NULL) xmlXPathFreeNodeSet(replace_set); else xmlFree(replace_str); fail_replace: return; }
/*}}}*/ }; static int psize = sizeof (parseable) / sizeof (parseable[0]); tag_t * tag_alloc (void) /*{{{*/ { tag_t *t; if (t = (tag_t *) malloc (sizeof (tag_t))) { t -> name = xmlBufferCreate (); t -> cname = NULL; t -> hash = 0; t -> type = NULL; t -> topt = NULL; t -> value = xmlBufferCreate (); t -> parm = NULL; t -> used = false; t -> next = NULL; if ((! t -> name) || (! t -> value)) t = tag_free (t); } return t; }/*}}}*/ tag_t * tag_free (tag_t *t) /*{{{*/ { if (t) { if (t -> name) xmlBufferFree (t -> name); if (t -> cname) free (t -> cname); if (t -> type) free (t -> type); if (t -> value) xmlBufferFree (t -> value); if (t -> parm) var_free_all (t -> parm); free (t); } return NULL; }/*}}}*/ tag_t * tag_free_all (tag_t *t) /*{{{*/ { tag_t *tmp; while (tmp = t) { t = t -> next; tag_free (tmp); } return NULL; }/*}}}*/ static void xmlSkip (xmlChar **ptr, int *len) /*{{{*/ { int n; while (*len > 0) { n = xmlCharLength (**ptr); if ((n == 1) && isspace (**ptr)) { *(*ptr)++ = '\0'; *len -= 1; while ((*len > 0) && (xmlCharLength (**ptr) == 1) && isspace (**ptr)) ++(*ptr); break; } else { *ptr += n; *len -= n; } } }/*}}}*/ static int mkRFCdate (char *dbuf, size_t dlen) /*{{{*/ { time_t now; struct tm *tt; time (& now); if (tt = gmtime (& now)) { const char *weekday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }, *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; return sprintf (dbuf, "%s, %2d %s %d %02d:%02d:%02d GMT", weekday[tt -> tm_wday], tt -> tm_mday, month[tt -> tm_mon], tt -> tm_year + 1900, tt -> tm_hour, tt -> tm_min, tt -> tm_sec) > 0; } return 0; }/*}}}*/ static const char * find_default (tag_t *t) /*{{{*/ { const char *dflt = NULL; var_t *run; for (run = t -> parm; run; run = run -> next) if (! strcmp (run -> var, "default")) { dflt = run -> val; break; } return dflt; }/*}}}*/ void tag_parse (tag_t *t, blockmail_t *blockmail) /*{{{*/ { xmlBufferPtr temp; if (t -> name && (xmlBufferLength (t -> name) > 0) && (temp = xmlBufferCreateSize (xmlBufferLength (t -> name) + 1))) { xmlChar *ptr; xmlChar *name; int len; int tid; xmlBufferAdd (temp, xmlBufferContent (t -> name), xmlBufferLength (t -> name)); ptr = (xmlChar *) xmlBufferContent (temp); len = xmlBufferLength (temp); if ((xmlCharLength (*ptr) == 1) && (*ptr == '[')) { ++ptr; --len; if ((len > 0) && (xmlStrictCharLength (*(ptr + len - 1)) == 1) && (*(ptr + len - 1) == ']')) { --len; if ((len > 0) && (xmlStrictCharLength (*(ptr + len - 1)) == 1) && (*(ptr + len - 1) == '/')) --len; ptr[len] = '\0'; } } name = ptr; xmlSkip (& ptr, & len); if (t -> type) { for (tid = 0; tid < psize; ++tid) if (! strcmp (t -> type, parseable[tid].tname)) break; } else tid = psize; if (tid == psize) for (tid = 0; tid < psize; ++tid) if (! xmlstrcmp (name, parseable[tid].tname)) break; if (tid < psize) { var_t *cur, *prev; xmlChar *var, *val; int n; for (prev = t -> parm; prev && prev -> next; prev = prev -> next) ; while (len > 0) { var = ptr; while (len > 0) { n = xmlCharLength (*ptr); if ((n == 1) && (*ptr == '=')) { *ptr++ = '\0'; len -= 1; break; } else { ptr += n; len -= n; } } if (len > 0) { if ((xmlCharLength (*ptr) == 1) && (*ptr == '"')) { ++ptr; --len; val = ptr; while (len > 0) { n = xmlCharLength (*ptr); if ((n == 1) && (*ptr == '"')) { *ptr++ = '\0'; len -= 1; xmlSkip (& ptr, & len); break; } else { ptr += n; len -= n; } } } else { val = ptr; xmlSkip (& ptr, & len); } if (cur = var_alloc (xml2char (var), xml2char (val))) { if (prev) prev -> next = cur; else t -> parm = cur; prev = cur; } } } switch ((enum PType) tid) { case P_Sysinfo: for (cur = t -> parm; cur; cur = cur -> next) if (! strcmp (cur -> var, "name")) { if (! strcmp (cur -> val, "FQDN")) { const char *dflt; if (blockmail -> fqdn) { xmlBufferEmpty (t -> value); xmlBufferCCat (t -> value, blockmail -> fqdn); } else if (dflt = find_default (t)) { xmlBufferEmpty (t -> value); xmlBufferCCat (t -> value, dflt); } } else if (! strcmp (cur -> val, "RFCDATE")) { char dbuf[128]; if (mkRFCdate (dbuf, sizeof (dbuf))) { xmlBufferEmpty (t -> value); xmlBufferCCat (t -> value, dbuf); } } else if (! strcmp (cur -> val, "EPOCH")) { time_t now; char dbuf[64]; time (& now); sprintf (dbuf, "%ld", (long) now); xmlBufferEmpty (t -> value); xmlBufferCCat (t -> value, dbuf); } } break; } } xmlBufferFree (temp); } }/*}}}*/
/** * xsltFormatNumberConversion: * @self: the decimal format * @format: the format requested * @number: the value to format * @result: the place to ouput the result * * format-number() uses the JDK 1.1 DecimalFormat class: * * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html * * Structure: * * pattern := subpattern{;subpattern} * subpattern := {prefix}integer{.fraction}{suffix} * prefix := '\\u0000'..'\\uFFFD' - specialCharacters * suffix := '\\u0000'..'\\uFFFD' - specialCharacters * integer := '#'* '0'* '0' * fraction := '0'* '#'* * * Notation: * X* 0 or more instances of X * (X | Y) either X or Y. * X..Y any character from X up to Y, inclusive. * S - T characters in S, except those in T * * Special Characters: * * Symbol Meaning * 0 a digit * # a digit, zero shows as absent * . placeholder for decimal separator * , placeholder for grouping separator. * ; separates formats. * - default negative prefix. * % multiply by 100 and show as percentage * ? multiply by 1000 and show as per mille * X any other characters can be used in the prefix or suffix * ' used to quote special characters in a prefix or suffix. */ xmlXPathError xsltFormatNumberConversion(xsltDecimalFormatPtr self, xmlChar *format, double number, xmlChar **result) { xmlXPathError status = XPATH_EXPRESSION_OK; xmlBufferPtr buffer; xmlChar *the_format, *prefix = NULL, *suffix = NULL; xmlChar *nprefix, *nsuffix = NULL; xmlChar pchar; int prefix_length, suffix_length = 0, nprefix_length, nsuffix_length; double scale; int j; xsltFormatNumberInfo format_info; /* delayed_multiplier allows a 'trailing' percent or permille to be treated as suffix */ int delayed_multiplier = 0; /* flag to show no -ve format present for -ve number */ char default_sign = 0; /* flag to show error found, should use default format */ char found_error = 0; *result = NULL; switch (xmlXPathIsInf(number)) { case -1: if (self->minusSign == NULL) *result = xmlStrdup(BAD_CAST "-"); else *result = xmlStrdup(self->minusSign); /* no-break on purpose */ case 1: if ((self == NULL) || (self->infinity == NULL)) *result = xmlStrcat(*result, BAD_CAST "Infinity"); else *result = xmlStrcat(*result, self->infinity); return(status); default: if (xmlXPathIsNaN(number)) { if ((self == NULL) || (self->noNumber == NULL)) *result = xmlStrdup(BAD_CAST "NaN"); else *result = xmlStrdup(self->noNumber); return(status); } } buffer = xmlBufferCreate(); if (buffer == NULL) { return XPATH_MEMORY_ERROR; } format_info.integer_digits = 0; format_info.frac_digits = 0; format_info.frac_hash = 0; format_info.group = -1; format_info.multiplier = 1; format_info.is_multiplier_set = FALSE; format_info.is_negative_pattern = FALSE; the_format = format; /* First we process the +ve pattern to get percent / permille, as well as main format */ prefix = the_format; prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (prefix_length < 0) { found_error = 1; goto OUTPUT_NUMBER; } /* Here we process the "number" part of the format. It gets a little messy because of */ /* the percent/per-mille - if that appears at the end, it may be part of the suffix */ /* instead of part of the number, so the variable delayed_multiplier is used to handle it */ while ((*the_format != 0) && (*the_format != self->decimalPoint[0]) && (*the_format != self->patternSeparator[0])) { if (delayed_multiplier != 0) { format_info.multiplier = delayed_multiplier; format_info.is_multiplier_set = TRUE; delayed_multiplier = 0; } if (*the_format == self->digit[0]) { if (format_info.integer_digits > 0) { found_error = 1; goto OUTPUT_NUMBER; } if (format_info.group >= 0) format_info.group++; } else if (*the_format == self->zeroDigit[0]) { format_info.integer_digits++; if (format_info.group >= 0) format_info.group++; } else if (*the_format == self->grouping[0]) { /* Reset group count */ format_info.group = 0; } else if (*the_format == self->percent[0]) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 100; } else if (*the_format == self->permille[0]) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 1000; } else break; /* while */ the_format++; } /* We have finished the integer part, now work on fraction */ if (*the_format == self->decimalPoint[0]) the_format++; /* Skip over the decimal */ while (*the_format != 0) { if (*the_format == self->zeroDigit[0]) { if (format_info.frac_hash != 0) { found_error = 1; goto OUTPUT_NUMBER; } format_info.frac_digits++; } else if (*the_format == self->digit[0]) { format_info.frac_hash++; } else if (*the_format == self->percent[0]) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 100; the_format++; continue; /* while */ } else if (*the_format == self->permille[0]) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 1000; the_format++; continue; /* while */ } else if (*the_format != self->grouping[0]) { break; /* while */ } the_format++; if (delayed_multiplier != 0) { format_info.multiplier = delayed_multiplier; delayed_multiplier = 0; format_info.is_multiplier_set = TRUE; } } /* If delayed_multiplier is set after processing the "number" part, should be in suffix */ if (delayed_multiplier != 0) { the_format--; delayed_multiplier = 0; } suffix = the_format; suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if ( (suffix_length < 0) || ((*the_format != 0) && (*the_format != self->patternSeparator[0])) ) { found_error = 1; goto OUTPUT_NUMBER; } /* We have processed the +ve prefix, number part and +ve suffix. */ /* If the number is -ve, we must substitute the -ve prefix / suffix */ if (number < 0) { the_format = (xmlChar *)xmlStrchr(format, self->patternSeparator[0]); if (the_format == NULL) { /* No -ve pattern present, so use default signing */ default_sign = 1; } else { /* Flag changes interpretation of percent/permille in -ve pattern */ the_format++; /* Skip over pattern separator */ format_info.is_negative_pattern = TRUE; format_info.is_multiplier_set = FALSE; /* First do the -ve prefix */ nprefix = the_format; nprefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (nprefix_length<0) { found_error = 1; goto OUTPUT_NUMBER; } /* Next skip over the -ve number info */ the_format += prefix_length; while (*the_format != 0) { if ( (*the_format == (self)->percent[0]) || (*the_format == (self)->permille[0]) ) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } format_info.is_multiplier_set = TRUE; delayed_multiplier = 1; } else if (IS_SPECIAL(self, *the_format)) delayed_multiplier = 0; else break; /* while */ the_format++; } if (delayed_multiplier != 0) { format_info.is_multiplier_set = FALSE; the_format--; } /* Finally do the -ve suffix */ if (*the_format != 0) { nsuffix = the_format; nsuffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (nsuffix_length < 0) { found_error = 1; goto OUTPUT_NUMBER; } } else nsuffix_length = 0; if (*the_format != 0) { found_error = 1; goto OUTPUT_NUMBER; } /* Here's another Java peculiarity: * if -ve prefix/suffix == +ve ones, discard & use default */ if ((nprefix_length != prefix_length) || (nsuffix_length != suffix_length) || ((nprefix_length > 0) && (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) || ((nsuffix_length > 0) && (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) { prefix = nprefix; prefix_length = nprefix_length; suffix = nsuffix; suffix_length = nsuffix_length; } else { default_sign = 1; } } } OUTPUT_NUMBER: if (found_error != 0) { xsltPrintErrorContext(NULL, NULL, NULL); xsltGenericError(xsltGenericErrorContext, "xsltFormatNumberConversion : error in format string, using default\n"); default_sign = (number < 0.0) ? 1 : 0; prefix_length = suffix_length = 0; format_info.integer_digits = 1; format_info.frac_digits = 1; format_info.frac_hash = 4; format_info.group = -1; format_info.multiplier = 1; } /* Ready to output our number. First see if "default sign" is required */ if (default_sign != 0) xmlBufferAdd(buffer, self->minusSign, 1); /* Put the prefix into the buffer */ for (j = 0; j < prefix_length; j++) { if ((pchar = *prefix++) == SYMBOL_QUOTE) { pchar = *prefix++; prefix++; } xmlBufferAdd(buffer, &pchar, 1); } /* Next do the integer part of the number */ number = fabs(number) * (double)format_info.multiplier; scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash)); number = floor((scale * number + 0.5)) / scale; if ((self->grouping != NULL) && (self->grouping[0] != 0)) xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.integer_digits, format_info.group, (xmlChar) self->grouping[0]); else xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.integer_digits, format_info.group, (xmlChar) ','); /* Next the fractional part, if required */ if (format_info.frac_digits + format_info.frac_hash > 0) { number -= floor(number); if ((number != 0) || (format_info.frac_digits != 0)) { xmlBufferAdd(buffer, self->decimalPoint, 1); number = floor(scale * number + 0.5); for (j = format_info.frac_hash; j > 0; j--) { if (fmod(number, 10.0) >= 1.0) break; /* for */ number /= 10.0; } xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.frac_digits + j, 0, (xmlChar)0); } } /* Put the suffix into the buffer */ for (j = 0; j < suffix_length; j++) { if ((pchar = *suffix++) == SYMBOL_QUOTE) { pchar = *suffix++; suffix++; } xmlBufferAdd(buffer, &pchar, 1); } *result = xmlStrdup(xmlBufferContent(buffer)); xmlBufferFree(buffer); return status; }
/********************************************************************************* * The contents of this file are subject to the Common Public Attribution * License Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.openemm.org/cpal1.html. The License is based on the Mozilla * Public License Version 1.1 but Sections 14 and 15 have been added to cover * use of software over a computer network and provide for limited attribution * for the Original Developer. In addition, Exhibit A has been modified to be * consistent with Exhibit B. * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is OpenEMM. * The Original Developer is the Initial Developer. * The Initial Developer of the Original Code is AGNITAS AG. All portions of * the code written by AGNITAS AG are Copyright (c) 2007 AGNITAS AG. All Rights * Reserved. * * Contributor(s): AGNITAS AG. ********************************************************************************/ # include "xmlback.h" static bool_t expand_tags (tag_t *base) /*{{{*/ { bool_t st; tag_t *cur, *tmp; const xmlChar *ptr; int len; int n, pos; int bstart; xmlBufferPtr out; st = true; for (cur = base; cur; cur = cur -> next) { for (tmp = base; tmp; tmp = tmp -> next) tmp -> used = (tmp == cur ? true : false); ptr = xmlBufferContent (cur -> value); len = xmlBufferLength (cur -> value); pos = 0; bstart = 0; out = NULL; while (pos < len) { n = xmlCharLength (ptr[pos]); if ((n == 1) && (ptr[pos] == '[')) { int start, end; start = pos++; end = -1; while (pos < len) { n = xmlCharLength (ptr[pos]); if ((n == 1) && (ptr[pos] == ']')) { ++pos; end = pos; break; } pos += n; } if (end != -1) { for (tmp = base; tmp; tmp = tmp -> next) if ((! tmp -> used) && tag_match (tmp, ptr + start, end - start)) break; if (tmp) { if (! out) if (! (out = xmlBufferCreate ())) { st = false; break; } if (bstart < start) xmlBufferAdd (out, ptr + bstart, start - bstart); xmlBufferAdd (out, xmlBufferContent (tmp -> value), xmlBufferLength (tmp -> value)); tmp -> used = true; bstart = pos; } } } else pos += n; } if (out) { if (bstart < len) xmlBufferAdd (out, ptr + bstart, len - bstart); xmlBufferFree (cur -> value); cur -> value = out; } } return st; }/*}}}*/ bool_t replace_tags (blockmail_t *blockmail, receiver_t *rec, block_t *block, bool_t ishtml) /*{{{*/ { bool_t st; long start, cur, next, end, len; const xmlChar *content; int tidx; tagpos_t *tp; int n; tag_t *tag; st = expand_tags (rec -> tag); start = 0; end = xmlBufferLength (block -> content); content = xmlBufferContent (block -> content); xmlBufferEmpty (block -> in); for (cur = start, tidx = 0; cur < end; ) { if (tidx < block -> tagpos_count) { tp = block -> tagpos[tidx++]; next = tp -> start; } else { tp = NULL; next = end; } len = next - cur; if (len > 0) xmlBufferAdd (block -> in, content + cur, len); if (tp) { cur = tp -> end; tag = NULL; if (tp -> type & (TP_DYNAMIC | TP_DYNAMICVALUE)) { if (tp -> tname) { dcache_t *dc; const dyn_t *dyn; for (dc = rec -> cache; dc; dc = dc -> next) if (! strcmp (dc -> name, tp -> tname)) break; if (! dc) for (dyn = blockmail -> dyn; dyn; dyn = dyn -> next) if (! strcmp (dyn -> name, tp -> tname)) { if (dc = dcache_alloc (tp -> tname, dyn)) { dc -> next = rec -> cache; rec -> cache = dc; } break; } if (dc) { for (dyn = dc -> dyn; dyn; dyn = dyn -> sibling) if (dyn_match (dyn, blockmail -> eval)) break; if (dyn) { block_t *use; use = NULL; if (tp -> type & TP_DYNAMICVALUE) { for (n = 0; (! use) && (n < dyn -> block_count); ++n) switch (dyn -> block[n] -> nr) { case 0: if (! ishtml) use = dyn -> block[n]; break; case 1: if (ishtml) use = dyn -> block[n]; break; } } else if (tp -> type & TP_DYNAMIC) use = tp -> content; if (use) if (replace_tags (blockmail, rec, use, ishtml)) xmlBufferAdd (block -> in, xmlBufferContent (use -> in), xmlBufferLength (use -> in)); else st = false; } } } } else { for (n = 0; (n < 2) && (! tag); ++n) { for (tag = n ? blockmail -> gtag : rec -> tag; tag; tag = tag -> next) if (((tag -> hash == 0) || (tp -> hash == 0) || (tag -> hash == tp -> hash)) && (xmlEqual (tag -> name, tp -> name))) break; } } if (tag && ((n = xmlBufferLength (tag -> value)) > 0)) xmlBufferAdd (block -> in, xmlBufferContent (tag -> value), n); } else cur = next; } return st; }/*}}}*/
static bool_t expand_tags (tag_t *base) /*{{{*/ { bool_t st; tag_t *cur, *tmp; const xmlChar *ptr; int len; int n, pos; int bstart; xmlBufferPtr out; st = true; for (cur = base; cur; cur = cur -> next) { for (tmp = base; tmp; tmp = tmp -> next) tmp -> used = (tmp == cur ? true : false); ptr = xmlBufferContent (cur -> value); len = xmlBufferLength (cur -> value); pos = 0; bstart = 0; out = NULL; while (pos < len) { n = xmlCharLength (ptr[pos]); if ((n == 1) && (ptr[pos] == '[')) { int start, end; start = pos++; end = -1; while (pos < len) { n = xmlCharLength (ptr[pos]); if ((n == 1) && (ptr[pos] == ']')) { ++pos; end = pos; break; } pos += n; } if (end != -1) { for (tmp = base; tmp; tmp = tmp -> next) if ((! tmp -> used) && tag_match (tmp, ptr + start, end - start)) break; if (tmp) { if (! out) if (! (out = xmlBufferCreate ())) { st = false; break; } if (bstart < start) xmlBufferAdd (out, ptr + bstart, start - bstart); xmlBufferAdd (out, xmlBufferContent (tmp -> value), xmlBufferLength (tmp -> value)); tmp -> used = true; bstart = pos; } } } else pos += n; } if (out) { if (bstart < len) xmlBufferAdd (out, ptr + bstart, len - bstart); xmlBufferFree (cur -> value); cur -> value = out; } } return st; }/*}}}*/
static void html_read_row (htmlNodePtr cur, htmlDocPtr doc, GnmHtmlTableCtxt *tc) { htmlNodePtr ptr; int col = -1; for (ptr = cur->children; ptr != NULL ; ptr = ptr->next) { if (xmlStrEqual (ptr->name, CC2XML ("td")) || xmlStrEqual (ptr->name, CC2XML ("th"))) { GString *buf; xmlBufferPtr a_buf; xmlAttrPtr props; int colspan = 1; int rowspan = 1; GnmCellPos pos; GnmStyle *mstyle; GSList *hrefs = NULL; GnmHLink *lnk = NULL; /* Check whether we need to skip merges from above */ pos.row = tc->row; pos.col = col + 1; while (gnm_sheet_merge_contains_pos (tc->sheet, &pos)) { col++; pos.col++; } /* Do we span across multiple rows or cols? */ props = ptr->properties; while (props) { if (xmlStrEqual (props->name, CC2XML ("colspan")) && props->children) colspan = atoi (CXML2C (props->children->content)); if (xmlStrEqual (props->name, CC2XML ("rowspan")) && props->children) rowspan = atoi (CXML2C (props->children->content)); props = props->next; } if (colspan < 1) colspan = 1; if (rowspan < 1) rowspan = 1; /* Let's figure out the content of the cell */ buf = g_string_new (NULL); a_buf = xmlBufferCreate (); mstyle = gnm_style_new_default (); if (xmlStrEqual (ptr->name, CC2XML ("th"))) gnm_style_set_font_bold (mstyle, TRUE); html_read_content (ptr, buf, mstyle, a_buf, &hrefs, TRUE, doc, tc); if (g_slist_length (hrefs) >= 1 && buf->len > 0) { /* One hyperlink, and text to make it * visible */ char *url; xmlBufferPtr h_buf = xmlBufferCreate (); hrefs = g_slist_reverse (hrefs); htmlNodeDump ( h_buf, doc, (htmlNodePtr)hrefs->data); url = g_strndup ( CXML2C (h_buf->content), h_buf->use); if (strncmp (url, "mailto:", strlen ("mailto:")) == 0) lnk = gnm_hlink_new ( gnm_hlink_email_get_type (), tc->sheet); else lnk = gnm_hlink_new ( gnm_hlink_url_get_type (), tc->sheet); gnm_hlink_set_target (lnk, url); gnm_style_set_hlink (mstyle, lnk); gnm_style_set_font_uline (mstyle, UNDERLINE_SINGLE); gnm_style_set_font_color (mstyle, gnm_color_new_go (GO_COLOR_BLUE)); g_free (url); xmlBufferFree (h_buf); } if (g_slist_length (hrefs) > 1 || buf->len <= 0) { /* Multiple links, * or no text to give hyperlink style, * so put them in a comment */ GSList *l; for (l = hrefs; l != NULL; l = l->next) { htmlNodeDump (a_buf, doc, (htmlNodePtr)l->data); xmlBufferAdd (a_buf, CC2XML ("\n"), -1); } } g_slist_free (hrefs); if (buf->len > 0) { GnmCell *cell = sheet_cell_fetch (tc->sheet, col + 1, tc->row); sheet_style_set_pos (tc->sheet, col + 1, tc->row, mstyle); gnm_cell_set_text (cell, buf->str); } else gnm_style_unref (mstyle); if (a_buf->use > 0) { char *name; name = g_strndup (CXML2C (a_buf->content), a_buf->use); cell_set_comment (tc->sheet, &pos, NULL, name, NULL); g_free (name); } g_string_free (buf, TRUE); xmlBufferFree (a_buf); /* If necessary create the merge */ if (colspan > 1 || rowspan > 1) { GnmRange range; GnmRange *r = ⦥ range_init (r, col + 1, tc->row, col + colspan, tc->row + rowspan - 1); gnm_sheet_merge_add (tc->sheet, r, FALSE, NULL); } col += colspan; } } }
static void html_read_content (htmlNodePtr cur, GString *buf, GnmStyle *mstyle, xmlBufferPtr a_buf, GSList **hrefs, gboolean first, htmlDocPtr doc, GnmHtmlTableCtxt *tc) { htmlNodePtr ptr; for (ptr = cur->children; ptr != NULL ; ptr = ptr->next) { if (ptr->type == XML_TEXT_NODE) { if (g_utf8_validate (ptr->content, -1, NULL)) html_append_text (buf, ptr->content); else g_string_append (buf, _("[Warning: Invalid text string has been removed.]")); } else if (ptr->type == XML_ELEMENT_NODE) { if (first) { if (xmlStrEqual (ptr->name, CC2XML ("i")) || xmlStrEqual (ptr->name, CC2XML ("em"))) gnm_style_set_font_italic (mstyle, TRUE); if (xmlStrEqual (ptr->name, CC2XML ("b"))) gnm_style_set_font_bold (mstyle, TRUE); } if (xmlStrEqual (ptr->name, CC2XML ("a"))) { xmlAttrPtr props; props = ptr->properties; while (props) { if (xmlStrEqual (props->name, CC2XML ("href")) && props->children) { *hrefs = g_slist_prepend ( *hrefs, props->children); } props = props->next; } } if (xmlStrEqual (ptr->name, CC2XML ("img"))) { xmlAttrPtr props; props = ptr->properties; while (props) { if (xmlStrEqual (props->name, CC2XML ("src")) && props->children) { htmlNodeDump (a_buf, doc, props->children); xmlBufferAdd (a_buf, CC2XML ("\n"), -1); } props = props->next; } } if (xmlStrEqual (ptr->name, CC2XML ("table"))) { Sheet *last_sheet = tc->sheet; int last_row = tc->row; tc->sheet = NULL; tc->row = -1; html_read_table (ptr, doc, tc->wb_view, tc); if (tc->sheet) { g_string_append_printf (buf, _("[see sheet %s]"), tc->sheet->name_quoted); xmlBufferAdd (a_buf, CC2XML (_("The original html file is\n" "using nested tables.")), -1); } tc->sheet = last_sheet; tc->row = last_row; } else html_read_content (ptr, buf, mstyle, a_buf, hrefs, first, doc, tc); } first = FALSE; } }
/* Fall through . . */ case 107: if (tolower (ch) == 'h') { state = 1; start = n; } else state = ST_INITIAL; break; case ST_START_FOUND: if (isspace ((int) ((unsigned char) ch)) || (ch == '"') || (ch == '>')) { end = n; state = ST_END_FOUND; } break; } # undef CHK # undef CCHK } else { if (state == ST_START_FOUND) { end = n; state = ST_END_FOUND; } else state = ST_INITIAL; } n += clen; } else { if (state == ST_START_FOUND) { end = n; state = ST_END_FOUND; } ++n; } if (state == ST_END_FOUND) { int ulen, m, o; ulen = end - start; for (m = 0; m < blockmail -> url_count; ++m) if ((blockmail -> url[m] -> usage & mask) && (blockmail -> url[m] -> dlen == ulen) && (! xmlStrncmp (blockmail -> url[m] -> dptr, cont + start, ulen))) break; if (m < blockmail -> url_count) { if (lstore < start) xmlBufferAdd (block -> out, cont + lstore, start - lstore); for (o = 0; o < rec -> url_count; ++o) if (rec -> url[o] -> uid == blockmail -> url[m] -> uid) break; if (o < rec -> url_count) xmlBufferAdd (block -> out, rec -> url[o] -> dptr, rec -> url[o] -> dlen); lstore = end; changed = true; } state = ST_INITIAL; } } if (changed) { if (lstore < len) xmlBufferAdd (block -> out, cont + lstore, len - lstore); SWAP (block); } return true; }/*}}}*/ static bool_t collect_links (blockmail_t *blockmail, block_t *block, links_t *links) /*{{{*/ { bool_t rc; int n, clen; int len; const xmlChar *cont; int start; rc = true; len = xmlBufferLength (block -> in); cont = xmlBufferContent (block -> in); for (n = 0; rc && (n < len); ) { clen = xmlCharLength (cont[n]); if ((clen == 1) && (cont[n] == 'h')) { start = n; ++n; if ((n + 3 < len) && (cont[n] == 't') && (cont[n + 1] == 't') && (cont[n + 2] == 'p')) { n += 3; if ((n + 1 < len) && (cont[n] == 's')) ++n; if ((n + 3 < len) && (cont[n] == ':') && (cont[n + 1] == '/') && (cont[n + 2] == '/')) { n += 3; while ((n < len) && (xmlCharLength (cont[n]) == 1) && (cont[n] != '"') && (cont[n] != '<') && (cont[n] != '>') && (! isspace (cont[n]))) ++n; rc = links_nadd (links, (const char *) (cont + start), n - start); } } } else n += clen; } return rc; }/*}}}*/ static int find_top (const xmlChar *cont, int len) /*{{{*/ { int pos; int state; int n; int clen; unsigned char ch; for (pos = -1, state = 0, n = 0; (n < len) && (pos == -1); ) { clen = xmlCharLength (cont[n]); if (clen > 1) state = 0; else { ch = cont[n]; switch (state) { case 0: if (ch == '<') state = 1; break; case 1: if ((ch == 'b') || (ch == 'B')) state = 2; else if (ch == '>') state = 0; else if (! isspace (ch)) state = 100; break; case 2: if ((ch == 'o') || (ch == 'O')) state = 3; else if (ch == '>') state = 0; else state = 100; break; case 3: if ((ch == 'd') || (ch == 'D')) state = 4; else if (ch == '>') state = 0; else state = 100; break; case 4: if ((ch == 'y') || (ch == 'Y')) state = 5; else if (ch == '>') state = 0; else state = 100; break; case 5: if (ch == '>') { pos = n + clen; state = 0; } else if (isspace (ch)) state = 6; else state = 100; break; case 6: if (ch == '>') { pos = n + clen; state = 0; } # ifdef STRICT else if (ch == '"') state = 7; break; case 7: if (ch == '"') state = 6; # endif /* STRICT */ break; case 100: if (ch == '>') state = 0; break; } } n += clen; } return pos; }/*}}}*/ static int find_bottom (const xmlChar *cont, int len) /*{{{*/ { int pos; int last; int m; int bclen; for (pos = -1, last = len, m = len - 1; (m >= 0) && (pos == -1); ) { bclen = xmlCharLength (cont[m]); if ((bclen == 1) && (cont[m] == '<')) { int n; int state; int clen; unsigned char ch; for (n = m + bclen, state = 1; (n < last) && (state > 0) && (state != 99); ) { clen = xmlCharLength (cont[n]); if (clen != 1) state = 0; else { ch = cont[n]; switch (state) { case 1: if (ch == '/') state = 2; else if (! isspace (ch)) state = 0; break; case 2: if ((ch == 'b') || (ch == 'B')) state = 3; else if (! isspace (ch)) state = 0; break; case 3: if ((ch == 'o') || (ch == 'O')) state = 4; else state = 0; break; case 4: if ((ch == 'd') || (ch == 'D')) state = 5; else state = 0; break; case 5: if ((ch == 'y') || (ch == 'Y')) state = 6; else state = 0; break; case 6: if ((ch == '>') || isspace (ch)) state = 99; else state = 0; break; } } n += clen; } if (state == 99) pos = m; } else if ((bclen == 1) && (cont[m] == '>')) last = m + bclen; m -= bclen; } return pos; }/*}}}*/ static bool_t add_onepixellog_image (blockmail_t *blockmail, receiver_t *rec, block_t *block, opl_t opl) /*{{{*/ { bool_t rc; const xmlChar tname[] = "[agnONEPIXEL]"; int tlen = sizeof (tname) - 1; tag_t *opltag; rc = true; for (opltag = rec -> tag; opltag; opltag = opltag -> next) if (tag_match (opltag, tname, tlen)) break; if (opltag && opltag -> value) { int pos; int len; const xmlChar *cont; pos = -1; len = xmlBufferLength (block -> in); cont = xmlBufferContent (block -> in); switch (opl) { case OPL_None: break; case OPL_Top: pos = find_top (cont, len); if (pos == -1) pos = 0; break; case OPL_Bottom: pos = find_bottom (cont, len); if (pos == -1) pos = len; break; } if (pos != -1) { const xmlChar lprefix[] = "<img src=\""; const xmlChar lpostfix[] = "\" alt=\"\" border=\"0\" height=\"1\" width=\"1\">"; xmlBufferEmpty (block -> out); if (pos > 0) xmlBufferAdd (block -> out, cont, pos); xmlBufferAdd (block -> out, lprefix, sizeof (lprefix) - 1); xmlBufferAdd (block -> out, xmlBufferContent (opltag -> value), xmlBufferLength (opltag -> value)); xmlBufferAdd (block -> out, lpostfix, sizeof (lpostfix) - 1); if (pos < len) xmlBufferAdd (block -> out, cont + pos, len - pos); SWAP (block); } } return rc; }/*}}}*/ static # ifdef __OPTIMIZE__ inline # endif /* __OPTIMIZE__ */ bool_t islink (const xmlChar *str, int len) /*{{{*/ { int n, state, clen; for (n = 0, state = 1; (n < len) && state; ) { clen = xmlCharLength (str[n]); if (clen != 1) return false; switch (state) { default: /* should NEVER happen */ return false; case 1: /* check for http:// https:// and mailto: */ if ((str[n] == 'h') || (str[n] == 'H')) ++state; else if ((str[n] == 'm') || (str[n] == 'M')) state = 100; else return false; break; case 2: if ((str[n] == 't') || (str[n] == 'T')) ++state; else return false; break; case 3: if ((str[n] == 't') || (str[n] == 'T')) ++state; else return false; break; case 4: if ((str[n] == 'p') || (str[n] == 'P')) ++state; else return false; break; case 5: if ((str[n] == 's') || (str[n] == 'S')) ++state; else if (str[n] == ':') state += 2; else return false; break; case 6: if (str[n] == ':') ++state; else return false; break; case 7: if (str[n] == '/') ++state; else return false; break; case 8: if (str[n] == '/') state = 0; else return false; break; case 100: if ((str[n] == 'a') || (str[n] == 'A')) ++state; else return false; break; case 101: if ((str[n] == 'i') || (str[n] == 'I')) ++state; else return false; break; case 102: if ((str[n] == 'l') || (str[n] == 'L')) ++state; else return false; break; case 103: if ((str[n] == 't') || (str[n] == 'T')) ++state; else return false; break; case 104: if ((str[n] == 'o') || (str[n] == 'O')) ++state; else return false; break; case 105: if (str[n] == ':') state = 0; else return false; break; } n += clen; } return (! state) ? true : false; }/*}}}*/ static bool_t modify_linelength (blockmail_t *blockmail, block_t *block, blockspec_t *bspec) /*{{{*/ { # define DOIT_NONE (0) # define DOIT_RESET (1 << 0) # define DOIT_NEWLINE (1 << 1) # define DOIT_IGNORE (1 << 2) # define DOIT_SKIP (1 << 3) int n; int len; const xmlChar *cont; int spos, slen; int space, dash; int spchr, dachr; int inspace, spacecount; int llen, wordstart; int doit; int skipcount; bool_t changed; xmlBufferEmpty (block -> out); len = xmlBufferLength (block -> in); cont = xmlBufferContent (block -> in); spos = 0; space = -1; dash = -1; spchr = -1; dachr = -1; inspace = 0; spacecount = 0; llen = 0; wordstart = 0; doit = DOIT_NONE; skipcount = 0; changed = false; for (n = 0; n < len; ) { if ((cont[n] == '\r') || (cont[n] == '\n')) { doit = DOIT_RESET; if (inspace && (spchr + inspace == llen)) { n = space; doit |= DOIT_NEWLINE | DOIT_IGNORE | DOIT_SKIP; skipcount = inspace + 1; } } else { if ((cont[n] == ' ') || (cont[n] == '\t')) { if (! inspace++) { space = n; spchr = llen; } spacecount = inspace; } else { if (inspace) { inspace = 0; wordstart = n; } if ((cont[n] == '-') && (llen > 2) && ((spchr == -1) || (llen - spchr > 2)) && (! islink (cont + wordstart, n - wordstart))) { dash = n; dachr = llen; } } if (++llen >= bspec -> linelength) if ((space != -1) || (dash != -1)) { if (space > dash) { if (! inspace) { n = space; doit = DOIT_RESET | DOIT_NEWLINE | DOIT_IGNORE | DOIT_SKIP; skipcount = spacecount; } } else { n = dash; doit = DOIT_RESET | DOIT_NEWLINE; } } } if (! (doit & DOIT_IGNORE)) n += xmlCharLength (cont[n]); if (doit) { slen = n - spos; if (slen > 0) xmlBufferAdd (block -> out, cont + spos, slen); if (doit & DOIT_NEWLINE) { xmlBufferAdd (block -> out, bspec -> linesep, bspec -> seplength); changed = true; } if (doit & DOIT_SKIP) { while ((skipcount-- > 0) && (n < len)) n += xmlCharLength (cont[n]); changed = true; } spos = n; space = -1; dash = -1; spchr = -1; dachr = -1; inspace = 0; spacecount = 0; llen = 0; wordstart = n; doit = DOIT_NONE; } } if (changed) { if (spos < len) xmlBufferAdd (block -> out, cont + spos, len - spos); SWAP (block); } return true; # undef DOIT_NONE # undef DOIT_RESET # undef DOIT_NEWLINE # undef DOIT_IGNORE # undef DOIT_SKIP }/*}}}*/
static bool_t modify_urls (blockmail_t *blockmail, receiver_t *rec, block_t *block) /*{{{*/ { int n; int len; const xmlChar *cont; int lstore; int state; char initial; char ch; int start, end; int mask; int clen; bool_t changed; xmlBufferEmpty (block -> out); len = xmlBufferLength (block -> in); cont = xmlBufferContent (block -> in); lstore = 0; state = ST_INITIAL; if (block -> nr == 1) initial = 'h'; else if (block -> nr == 2) initial = '<'; else initial = '\0'; start = -1; end = -1; mask = 1 << (block -> nr - 1); changed = false; for (n = 0; n <= len; ) { if (n < len) { clen = xmlCharLength (cont[n]); if ((clen == 1) && isascii ((char) cont[n])) { ch = (char) cont[n]; switch (state) { case ST_INITIAL: if (tolower (ch) == initial) { if (block -> nr == 1) { state = 1; start = n; } else if (block -> nr == 2) state = 100; } break; # define CHK(ccc) do { if ((ccc) == ch) ++state; else state = ST_INITIAL; } while (0) # define CCHK(ccc) do { if ((ccc) == tolower (ch)) ++state; else state = ST_INITIAL; } while (0) case 1: CCHK ('t'); break; case 2: CCHK ('t'); break; case 3: CCHK ('p'); break; case 4: ++state; if (tolower (ch) == 's') break; /* Fall through . . . */ case 5: CHK (':'); break; case 6: CHK ('/'); break; case 7: if (ch == '/') state = ST_START_FOUND; else state = ST_INITIAL; break; case 100: CCHK ('a'); break; # define HCHK(ccc) do { if ((ccc) == tolower (ch)) ++state; else if ('>' == ch) state = ST_INITIAL; else state = 101; } while (0) case 101: HCHK ('h'); break; case 102: HCHK ('r'); break; case 103: HCHK ('e'); break; case 104: HCHK ('f'); break; # undef HCHK case 105: CHK ('='); break; case 106: ++state; if (ch == '"') break; /* Fall through . . */ case 107: if (tolower (ch) == 'h') { state = 1; start = n; } else state = ST_INITIAL; break; case ST_START_FOUND: if (isspace ((int) ((unsigned char) ch)) || (ch == '"') || (ch == '>')) { end = n; state = ST_END_FOUND; } break; } # undef CHK # undef CCHK } else { if (state == ST_START_FOUND) { end = n; state = ST_END_FOUND; } else state = ST_INITIAL; } n += clen; } else { if (state == ST_START_FOUND) { end = n; state = ST_END_FOUND; } ++n; } if (state == ST_END_FOUND) { int ulen, m, o; ulen = end - start; for (m = 0; m < blockmail -> url_count; ++m) if ((blockmail -> url[m] -> usage & mask) && (blockmail -> url[m] -> dlen == ulen) && (! xmlStrncmp (blockmail -> url[m] -> dptr, cont + start, ulen))) break; if (m < blockmail -> url_count) { if (lstore < start) xmlBufferAdd (block -> out, cont + lstore, start - lstore); for (o = 0; o < rec -> url_count; ++o) if (rec -> url[o] -> uid == blockmail -> url[m] -> uid) break; if (o < rec -> url_count) xmlBufferAdd (block -> out, rec -> url[o] -> dptr, rec -> url[o] -> dlen); lstore = end; changed = true; } state = ST_INITIAL; } } if (changed) { if (lstore < len) xmlBufferAdd (block -> out, cont + lstore, len - lstore); SWAP (block); } return true; }/*}}}*/
/** * verify_request: * @mng: the keys manager * * Verifies XML signature in the request (stdin). * * Returns 0 on success or a negative value if an error occurs. */ int verify_request(xmlSecKeysMngrPtr mngr) { xmlBufferPtr buffer = NULL; char buf[256]; xmlDocPtr doc = NULL; xmlNodePtr node = NULL; xmlSecDSigCtxPtr dsigCtx = NULL; int ret; int res = -1; assert(mngr); /* load request in the buffer */ buffer = xmlBufferCreate(); if(buffer == NULL) { fprintf(stdout,"Error: failed to create buffer\n"); goto done; } while(!feof(stdin)) { ret = fread(buf, 1, sizeof(buf), stdin); if(ret < 0) { fprintf(stdout,"Error: read failed\n"); goto done; } xmlBufferAdd(buffer, buf, ret); } /* is the document subbmitted from the form? */ if(strncmp((char*)xmlBufferContent(buffer), "_xmldoc=", 8) == 0) { xmlBufferShrink(buffer, 8); buffer->use = url_decode((char*)xmlBufferContent(buffer), xmlBufferLength(buffer)); } /** * Load doc */ doc = xmlReadMemory(xmlBufferContent(buffer), xmlBufferLength(buffer), NULL, NULL, XML_PARSE_NOENT | XML_PARSE_NOCDATA | XML_PARSE_PEDANTIC | XML_PARSE_NOCDATA); if (doc == NULL) { fprintf(stdout, "Error: unable to parse xml document (syntax error)\n"); goto done; } /* * Check the document is of the right kind */ if(xmlDocGetRootElement(doc) == NULL) { fprintf(stdout,"Error: empty document\n"); goto done; } /* find start node */ node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs); if(node == NULL) { fprintf(stdout, "Error: start <dsig:Signature/> node not found\n"); goto done; } /* create signature context */ dsigCtx = xmlSecDSigCtxCreate(mngr); if(dsigCtx == NULL) { fprintf(stdout,"Error: failed to create signature context\n"); goto done; } /* we would like to store and print out everything */ /* actually we would not because it opens a security hole dsigCtx->flags = XMLSEC_DSIG_FLAGS_STORE_SIGNEDINFO_REFERENCES | XMLSEC_DSIG_FLAGS_STORE_MANIFEST_REFERENCES | XMLSEC_DSIG_FLAGS_STORE_SIGNATURE; */ /* Verify signature */ if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) { fprintf(stdout,"Error: signature verification failed\n"); goto done; } /* print verification result to stdout */ if(dsigCtx->status == xmlSecDSigStatusSucceeded) { fprintf(stdout, "RESULT: Signature is OK\n"); } else { fprintf(stdout, "RESULT: Signature is INVALID\n"); } fprintf(stdout, "---------------------------------------------------\n"); xmlSecDSigCtxDebugDump(dsigCtx, stdout); /* success */ res = 0; done: /* cleanup */ if(dsigCtx != NULL) { xmlSecDSigCtxDestroy(dsigCtx); } if(doc != NULL) { xmlFreeDoc(doc); } if(buffer != NULL) { xmlBufferFree(buffer); } return(res); }
int main(int argc, char * argv[]) { int optc; int mode = 'g'; char *url; char *token = NULL; char *timeout = NULL; char *infile = NULL; char *owner = NULL; char *orig_url = NULL; char *content_type = "application/x-www-form-urlencoded"; char *auth_realm = NULL; char *pauth_realm = NULL; char *ns = NULL; int scope = ND_LOCK_SCOPE_EXCLUSIVE; int infinite = 0; int force_overwrite = 0; ndAuthCtxtPtr auth; /* OMIT xml errors. */ xmlSetGenericErrorFunc(NULL, null_error_handler); while ( (optc = getopt_long(argc, argv, optstring, long_options, NULL)) != -1 ) { switch (optc) { case 'c': mode = 'c'; orig_url = optarg; break; case 'm': mode = 'm'; orig_url = optarg; break; case 'e': mode = 'e'; { char *value = optarg; ndPropPtr prp = ndPropNew(); /* Locate the equal sign. */ while (*value && (*value != '=')) value++; /* Capture assigned value, * and crop property name. */ if (*value) *value++ = '\0'; prp->name = strdup(optarg); prp->ns = ns ? strdup(ns) : NULL; prp->value = *value ? strdup(value) : NULL; prp->type = *value ? NDPROP_PATCH : NDPROP_REMOVE; prp->next = propreq; propreq = prp; } break; case 'F': mode = 'F'; break; case 'g': mode = 'F'; { ndPropPtr prp = ndPropNew(); prp->name = strdup(optarg); prp->ns = ns ? strdup(ns) : NULL; prp->value = NULL; prp->type = NDPROP_FIND; prp->next = propreq; propreq = prp; } break; case 'l': mode = 'l'; timeout = "Infinite"; scope = ND_LOCK_SCOPE_EXCLUSIVE; break; case 'i': timeout = optarg; break; case 'n': mode = 'n'; format |= ND_PRINT_NAMEONLY; break; case 'o': owner = optarg; break; case 'd': mode = 'd'; break; case 'D': debug = 1; break; case 'f': force_overwrite = 1; break; case 'S': format |= ND_PRINT_AS_SEXP; break; case 'q': format |= ND_PRINT_QUIETLY; break; case 'v': format |= ND_PRINT_VERBOSELY; break; case 'a': auth_realm = optarg; break; case 'A': pauth_realm = optarg; break; case 'P': mode = 'P'; infile = optarg; break; case 'T': content_type = optarg; break; case 'N': ns = optarg; break; case 'u': mode = 'u'; break; case 'k': mode = 'k'; break; case 'r': infinite = 1; break; case 's': if (! strcmp("shared", optarg)) scope = ND_LOCK_SCOPE_SHARED; break; case 't': token = optarg; break; case 'p': mode = 'p'; infile = optarg; break; case 'V': print_version(argv[0]); exit(EXIT_SUCCESS); break; case 'h': /* Long help. */ usage(argv[0]); exit(EXIT_SUCCESS); break; case '?': /* Short help and catch-all. */ default: short_usage(argv[0]); exit(EXIT_FAILURE); break; } } url = argv[optind]; if (url == NULL) { fprintf(stderr, "%s: No target URL was specified.\n", basename(argv[0])); exit(EXIT_FAILURE); } auth = ndCreateAuthCtxt(authenticate, auth_notify, auth_realm, pauth_realm); switch (mode) { case 'c': { int code; code = ndCopy(orig_url, auth, url, force_overwrite, token); ndFreeAuthCtxt(auth); if ( RETURNED_AN_ERROR(code) ) error_exit(format, "COPY failed, `%s'", ndReasonPhrase(code)); }; break; case 'e': { int code; ndNodeInfoPtr ret = NULL; if (propreq && propreq->next == NULL && propreq->ns == NULL) propreq->ns = ns; code = ndPropPatch(url, auth, propreq, token, &ret); if ( RETURNED_AN_ERROR(code) ) error_exit(format, "PROPPATCH failed, `%s'", ndReasonPhrase(code)); else if (code == 207) ndNodeInfoListPrint(stdout, ret, format); }; break; case 'm': { int code; code = ndMove(orig_url, auth, url, force_overwrite, token); ndFreeAuthCtxt(auth); if ( RETURNED_AN_ERROR(code) ) error_exit(format, "MOVE failed, `%s'", ndReasonPhrase(code)); }; break; case 'g': { #ifndef WAIT_FOR_END char *ct_return = NULL; int code; if (token != NULL) error_exit(format, "token is not required"); code = ndGetPrint(url, auth, &ct_return, stdout); ndFreeAuthCtxt(auth); if ( RETURNED_AN_ERROR(code) ) error_exit(format, "GET failed, `%s'", ndReasonPhrase(code)); #else /* WAIT_FOR_END */ xmlBufferPtr buf = NULL; int code; char *ct_return = NULL; if (token != NULL) error_exit(format, "token is not required"); code = ndGet(url, auth, &ct_return, &buf); ndFreeAuthCtxt(auth); if ( RETURNED_AN_ERROR(code) ) error_exit(format, "GET failed, `%s'", ndReasonPhrase(code)); if ( buf ) fprintf(stdout, "%s", xmlBufferContent(buf)); #endif /* WAIT_FOR_END */ }; break; case 'n': case 'F': { ndNodeInfoPtr ret = NULL; int code; int depth; if (token != NULL) error_exit(format, "token is not required"); depth = ( url[strlen(url) - 1] == '/' ) ? ( infinite ? ND_DEPTH_INFINITE : ND_DEPTH_1 ) : ND_DEPTH_0; if (propreq && propreq->next == NULL && propreq->ns == NULL) propreq->ns = ns; code = ndPropFind(url, auth, propreq, depth, (mode == 'n') ? 1 : 0, &ret); ndFreeAuthCtxt(auth); if (ret) ndNodeInfoListPrint(stdout, ret, format); else error_exit(format, "PROPFIND failed, `%s'", ndReasonPhrase(code)); }; break; case 'l': { ndLockInfoPtr lock = NULL; int code; int depth; depth = ( url[strlen(url) - 1] == '/' ) ? ( infinite ? ND_DEPTH_INFINITE : ND_DEPTH_1 ) : ND_DEPTH_0; code = ndLock(url, auth, depth, owner ? owner : getenv("USER"), scope, timeout, &lock); ndFreeAuthCtxt(auth); if (lock) { ndLockInfoPrint(stdout, lock, format); } else error_exit(format, "LOCK failed, `%s'", ndReasonPhrase(code)); }; break; case 'u': { int ret; int depth; if (token == NULL) error_exit(format, "token is required"); depth = ( url[strlen(url) - 1] == '/' ) ? ( infinite ? ND_DEPTH_INFINITE : ND_DEPTH_1 ) : ND_DEPTH_0; ret = ndUnlock(url, auth, depth, token); ndFreeAuthCtxt(auth); if ( RETURNED_AN_ERROR(ret) ) error_exit(format, "UNLOCK failed, `%s'", ndReasonPhrase(ret)); }; break; case 'P': { xmlBufferPtr buf = xmlBufferCreate(); int len; unsigned char s [1024]; int ret; FILE *fp; if ((fp = fopen(infile, "r")) == NULL) error_exit(format, "%s, %s", infile, strerror(errno)); while ( (len = fread(s, sizeof(unsigned char), sizeof(s), fp)) > 0) xmlBufferAdd(buf, s, len); fclose(fp); ret = ndPostPrint(url, auth, (char *) xmlBufferContent(buf), xmlBufferLength(buf), &content_type, stdout); ndFreeAuthCtxt(auth); if ( RETURNED_AN_ERROR(ret) ) error_exit(format, "POST failed, `%s'", ndReasonPhrase(ret)); }; break; case 'k': { int ret; ret = ndMkCol(url, auth, token); ndFreeAuthCtxt(auth); if ( RETURNED_AN_ERROR(ret) ) error_exit(format, "MKCOL failed, `%s'", ndReasonPhrase(ret)); }; break; case 'd': { int ret; ret = ndDelete(url, auth, token); ndFreeAuthCtxt(auth); if ( RETURNED_AN_ERROR(ret) ) error_exit(format, "DELETE failed, `%s'", ndReasonPhrase(ret)); }; break; case 'p': { int len; unsigned char s [1024]; int code; FILE *fp; ndNodeInfoPtr ret = NULL; xmlBufferPtr buf = xmlBufferCreate(); if ((fp = fopen(infile, "r")) == NULL) error_exit(format, "%s, %s", infile, strerror(errno)); while ( (len = fread(s, sizeof(unsigned char), sizeof(s), fp)) > 0) xmlBufferAdd(buf, s, len); fclose(fp); code = ndPut(url, auth, (char *) xmlBufferContent(buf), xmlBufferLength(buf), token, &ret); ndFreeAuthCtxt(auth); if ( RETURNED_AN_ERROR(code) ) error_exit(format, "PUT failed, `%s'", ndReasonPhrase(code)); else ndNodeInfoListPrint(stdout, ret, format); }; break; }; return 0; }; /* main(int, char * []) */
/** * xsltFormatNumberConversion: * @self: the decimal format * @format: the format requested * @number: the value to format * @result: the place to ouput the result * * format-number() uses the JDK 1.1 DecimalFormat class: * * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html * * Structure: * * pattern := subpattern{;subpattern} * subpattern := {prefix}integer{.fraction}{suffix} * prefix := '\\u0000'..'\\uFFFD' - specialCharacters * suffix := '\\u0000'..'\\uFFFD' - specialCharacters * integer := '#'* '0'* '0' * fraction := '0'* '#'* * * Notation: * X* 0 or more instances of X * (X | Y) either X or Y. * X..Y any character from X up to Y, inclusive. * S - T characters in S, except those in T * * Special Characters: * * Symbol Meaning * 0 a digit * # a digit, zero shows as absent * . placeholder for decimal separator * , placeholder for grouping separator. * ; separates formats. * - default negative prefix. * % multiply by 100 and show as percentage * ? multiply by 1000 and show as per mille * X any other characters can be used in the prefix or suffix * ' used to quote special characters in a prefix or suffix. * * Returns a possible XPath error */ xmlXPathError xsltFormatNumberConversion(xsltDecimalFormatPtr self, xmlChar *format, double number, xmlChar **result) { xmlXPathError status = XPATH_EXPRESSION_OK; xmlBufferPtr buffer; xmlChar *the_format, *prefix = NULL, *suffix = NULL; xmlChar *nprefix, *nsuffix = NULL; xmlChar pchar; int prefix_length, suffix_length = 0, nprefix_length, nsuffix_length; double scale; int j, len; int self_grouping_len; xsltFormatNumberInfo format_info; /* * delayed_multiplier allows a 'trailing' percent or * permille to be treated as suffix */ int delayed_multiplier = 0; /* flag to show no -ve format present for -ve number */ char default_sign = 0; /* flag to show error found, should use default format */ char found_error = 0; if (xmlStrlen(format) <= 0) { xsltTransformError(NULL, NULL, NULL, "xsltFormatNumberConversion : " "Invalid format (0-length)\n"); } *result = NULL; switch (xmlXPathIsInf(number)) { case -1: if (self->minusSign == NULL) *result = xmlStrdup(BAD_CAST "-"); else *result = xmlStrdup(self->minusSign); /* no-break on purpose */ case 1: if ((self == NULL) || (self->infinity == NULL)) *result = xmlStrcat(*result, BAD_CAST "Infinity"); else *result = xmlStrcat(*result, self->infinity); return(status); default: if (xmlXPathIsNaN(number)) { if ((self == NULL) || (self->noNumber == NULL)) *result = xmlStrdup(BAD_CAST "NaN"); else *result = xmlStrdup(self->noNumber); return(status); } } buffer = xmlBufferCreate(); if (buffer == NULL) { return XPATH_MEMORY_ERROR; } format_info.integer_hash = 0; format_info.integer_digits = 0; format_info.frac_digits = 0; format_info.frac_hash = 0; format_info.group = -1; format_info.multiplier = 1; format_info.add_decimal = FALSE; format_info.is_multiplier_set = FALSE; format_info.is_negative_pattern = FALSE; the_format = format; /* * First we process the +ve pattern to get percent / permille, * as well as main format */ prefix = the_format; prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (prefix_length < 0) { found_error = 1; goto OUTPUT_NUMBER; } /* * Here we process the "number" part of the format. It gets * a little messy because of the percent/per-mille - if that * appears at the end, it may be part of the suffix instead * of part of the number, so the variable delayed_multiplier * is used to handle it */ self_grouping_len = xmlStrlen(self->grouping); while ((*the_format != 0) && (xsltUTF8Charcmp(the_format, self->decimalPoint) != 0) && (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) { if (delayed_multiplier != 0) { format_info.multiplier = delayed_multiplier; format_info.is_multiplier_set = TRUE; delayed_multiplier = 0; } if (xsltUTF8Charcmp(the_format, self->digit) == 0) { if (format_info.integer_digits > 0) { found_error = 1; goto OUTPUT_NUMBER; } format_info.integer_hash++; if (format_info.group >= 0) format_info.group++; } else if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) { format_info.integer_digits++; if (format_info.group >= 0) format_info.group++; } else if ((self_grouping_len > 0) && (!xmlStrncmp(the_format, self->grouping, self_grouping_len))) { /* Reset group count */ format_info.group = 0; the_format += self_grouping_len; continue; } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 100; } else if (xsltUTF8Charcmp(the_format, self->permille) == 0) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 1000; } else break; /* while */ if ((len=xmlUTF8Strsize(the_format, 1)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; } /* We have finished the integer part, now work on fraction */ if ( (*the_format != 0) && (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) ) { format_info.add_decimal = TRUE; if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; /* Skip over the decimal */ } while (*the_format != 0) { if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) { if (format_info.frac_hash != 0) { found_error = 1; goto OUTPUT_NUMBER; } format_info.frac_digits++; } else if (xsltUTF8Charcmp(the_format, self->digit) == 0) { format_info.frac_hash++; } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 100; if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; continue; /* while */ } else if (xsltUTF8Charcmp(the_format, self->permille) == 0) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 1000; if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; continue; /* while */ } else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) { break; /* while */ } if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; if (delayed_multiplier != 0) { format_info.multiplier = delayed_multiplier; delayed_multiplier = 0; format_info.is_multiplier_set = TRUE; } } /* * If delayed_multiplier is set after processing the * "number" part, should be in suffix */ if (delayed_multiplier != 0) { the_format -= len; delayed_multiplier = 0; } suffix = the_format; suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if ( (suffix_length < 0) || ((*the_format != 0) && (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) ) { found_error = 1; goto OUTPUT_NUMBER; } /* * We have processed the +ve prefix, number part and +ve suffix. * If the number is -ve, we must substitute the -ve prefix / suffix */ if (number < 0) { /* * Note that j is the number of UTF8 chars before the separator, * not the number of bytes! (bug 151975) */ j = xmlUTF8Strloc(format, self->patternSeparator); if (j < 0) { /* No -ve pattern present, so use default signing */ default_sign = 1; } else { /* Skip over pattern separator (accounting for UTF8) */ the_format = (xmlChar *)xmlUTF8Strpos(format, j + 1); /* * Flag changes interpretation of percent/permille * in -ve pattern */ format_info.is_negative_pattern = TRUE; format_info.is_multiplier_set = FALSE; /* First do the -ve prefix */ nprefix = the_format; nprefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (nprefix_length<0) { found_error = 1; goto OUTPUT_NUMBER; } while (*the_format != 0) { if ( (xsltUTF8Charcmp(the_format, (self)->percent) == 0) || (xsltUTF8Charcmp(the_format, (self)->permille)== 0) ) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } format_info.is_multiplier_set = TRUE; delayed_multiplier = 1; } else if (IS_SPECIAL(self, the_format)) delayed_multiplier = 0; else break; /* while */ if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { found_error = 1; goto OUTPUT_NUMBER; } the_format += len; } if (delayed_multiplier != 0) { format_info.is_multiplier_set = FALSE; the_format -= len; } /* Finally do the -ve suffix */ if (*the_format != 0) { nsuffix = the_format; nsuffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (nsuffix_length < 0) { found_error = 1; goto OUTPUT_NUMBER; } } else nsuffix_length = 0; if (*the_format != 0) { found_error = 1; goto OUTPUT_NUMBER; } /* * Here's another Java peculiarity: * if -ve prefix/suffix == +ve ones, discard & use default */ if ((nprefix_length != prefix_length) || (nsuffix_length != suffix_length) || ((nprefix_length > 0) && (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) || ((nsuffix_length > 0) && (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) { prefix = nprefix; prefix_length = nprefix_length; suffix = nsuffix; suffix_length = nsuffix_length; } /* else { default_sign = 1; } */ } } OUTPUT_NUMBER: if (found_error != 0) { xsltTransformError(NULL, NULL, NULL, "xsltFormatNumberConversion : " "error in format string '%s', using default\n", format); default_sign = (number < 0.0) ? 1 : 0; prefix_length = suffix_length = 0; format_info.integer_hash = 0; format_info.integer_digits = 1; format_info.frac_digits = 1; format_info.frac_hash = 4; format_info.group = -1; format_info.multiplier = 1; format_info.add_decimal = TRUE; } /* Ready to output our number. First see if "default sign" is required */ if (default_sign != 0) xmlBufferAdd(buffer, self->minusSign, xmlUTF8Strsize(self->minusSign, 1)); /* Put the prefix into the buffer */ for (j = 0; j < prefix_length; j++) { if ((pchar = *prefix++) == SYMBOL_QUOTE) { len = xmlUTF8Strsize(prefix, 1); xmlBufferAdd(buffer, prefix, len); prefix += len; j += len - 1; /* length of symbol less length of quote */ } else xmlBufferAdd(buffer, &pchar, 1); } /* Next do the integer part of the number */ number = fabs(number) * (double)format_info.multiplier; scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash)); number = floor((scale * number + 0.5)) / scale; if ((self->grouping != NULL) && (self->grouping[0] != 0)) { len = xmlStrlen(self->grouping); pchar = xsltGetUTF8Char(self->grouping, &len); xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.integer_digits, format_info.group, pchar, len); } else xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.integer_digits, format_info.group, ',', 1); /* Special case: java treats '.#' like '.0', '.##' like '.0#', etc. */ if ((format_info.integer_digits + format_info.integer_hash + format_info.frac_digits == 0) && (format_info.frac_hash > 0)) { ++format_info.frac_digits; --format_info.frac_hash; } /* Add leading zero, if required */ if ((floor(number) == 0) && (format_info.integer_digits + format_info.frac_digits == 0)) { xmlBufferAdd(buffer, self->zeroDigit, xmlUTF8Strsize(self->zeroDigit, 1)); } /* Next the fractional part, if required */ if (format_info.frac_digits + format_info.frac_hash == 0) { if (format_info.add_decimal) xmlBufferAdd(buffer, self->decimalPoint, xmlUTF8Strsize(self->decimalPoint, 1)); } else { number -= floor(number); if ((number != 0) || (format_info.frac_digits != 0)) { xmlBufferAdd(buffer, self->decimalPoint, xmlUTF8Strsize(self->decimalPoint, 1)); number = floor(scale * number + 0.5); for (j = format_info.frac_hash; j > 0; j--) { if (fmod(number, 10.0) >= 1.0) break; /* for */ number /= 10.0; } xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.frac_digits + j, 0, 0, 0); } } /* Put the suffix into the buffer */ for (j = 0; j < suffix_length; j++) { if ((pchar = *suffix++) == SYMBOL_QUOTE) { len = xmlUTF8Strsize(suffix, 1); xmlBufferAdd(buffer, suffix, len); suffix += len; j += len - 1; /* length of symbol less length of escape */ } else xmlBufferAdd(buffer, &pchar, 1); } *result = xmlStrdup(xmlBufferContent(buffer)); xmlBufferFree(buffer); return status; }