From dd445b59f0c0ad02be389e579eabef07dc97be3a Mon Sep 17 00:00:00 2001 From: bit4bit Date: Mon, 6 Dec 2021 17:39:37 +0000 Subject: [PATCH] experimental: facho-signer: xml layout FossilOrigin-Name: 6fda6ceb8a3fd6d45cd68601b4608b9ce3a8f8af0eb79b99f9ec73a20a8023b3 --- experimental/facho-signer/xades/Makefile | 7 + experimental/facho-signer/xades/minunit.h | 391 ++++ experimental/facho-signer/xades/minunit_ext.h | 13 + experimental/facho-signer/xades/xades.c | 115 + experimental/facho-signer/xades/xades.h | 22 + experimental/facho-signer/xades/xades_test.c | 69 + .../facho-signer/xades/xmlsec1/errors.c | 259 +++ .../xades/xmlsec1/errors_helpers.h | 869 ++++++++ .../facho-signer/xades/xmlsec1/xmltree.c | 1950 +++++++++++++++++ .../facho-wasm/xmlsec-wasm/build_libxml2.sh | 12 +- 10 files changed, 3702 insertions(+), 5 deletions(-) create mode 100644 experimental/facho-signer/xades/Makefile create mode 100644 experimental/facho-signer/xades/minunit.h create mode 100644 experimental/facho-signer/xades/minunit_ext.h create mode 100644 experimental/facho-signer/xades/xades.c create mode 100644 experimental/facho-signer/xades/xades.h create mode 100644 experimental/facho-signer/xades/xades_test.c create mode 100644 experimental/facho-signer/xades/xmlsec1/errors.c create mode 100644 experimental/facho-signer/xades/xmlsec1/errors_helpers.h create mode 100644 experimental/facho-signer/xades/xmlsec1/xmltree.c diff --git a/experimental/facho-signer/xades/Makefile b/experimental/facho-signer/xades/Makefile new file mode 100644 index 0000000..c73ae4f --- /dev/null +++ b/experimental/facho-signer/xades/Makefile @@ -0,0 +1,7 @@ +.PHONY: test + +CC=gcc + +test: xmlsec1/errors.c xmlsec1/xmltree.c xades.c xades_test.c + $(CC) -o $@ -Wall $(shell pkg-config libxml-2.0 --cflags --libs) $(shell pkg-config xmlsec1 --cflags --libs) $^ + ./test diff --git a/experimental/facho-signer/xades/minunit.h b/experimental/facho-signer/xades/minunit.h new file mode 100644 index 0000000..b716888 --- /dev/null +++ b/experimental/facho-signer/xades/minunit.h @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2012 David SiƱuela Pastor, siu.4coders@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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. + */ +#ifndef MINUNIT_MINUNIT_H +#define MINUNIT_MINUNIT_H + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined(_WIN32) +#include +#if defined(_MSC_VER) && _MSC_VER < 1900 + #define snprintf _snprintf + #define __func__ __FUNCTION__ +#endif + +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) + +/* Change POSIX C SOURCE version for pure c99 compilers */ +#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif + +#include /* POSIX flags */ +#include /* clock_gettime(), time() */ +#include /* gethrtime(), gettimeofday() */ +#include +#include +#include + +#if defined(__MACH__) && defined(__APPLE__) +#include +#include +#endif + +#if __GNUC__ >= 5 && !defined(__STDC_VERSION__) +#define __func__ __extension__ __FUNCTION__ +#endif + +#else +#error "Unable to define timers for an unknown OS." +#endif + +#include +#include + +/* Maximum length of last message */ +#define MINUNIT_MESSAGE_LEN 1024 +/* Accuracy with which floats are compared */ +#define MINUNIT_EPSILON 1E-12 + +/* Misc. counters */ +static int minunit_run = 0; +static int minunit_assert = 0; +static int minunit_fail = 0; +static int minunit_status = 0; + +/* Timers */ +static double minunit_real_timer = 0; +static double minunit_proc_timer = 0; + +/* Last message */ +static char minunit_last_message[MINUNIT_MESSAGE_LEN]; + +/* Test setup and teardown function pointers */ +static void (*minunit_setup)(void) = NULL; +static void (*minunit_teardown)(void) = NULL; + +/* Definitions */ +#define MU_TEST(method_name) static void method_name(void) +#define MU_TEST_SUITE(suite_name) static void suite_name(void) + +#define MU__SAFE_BLOCK(block) do {\ + block\ +} while(0) + +/* Run test suite and unset setup and teardown functions */ +#define MU_RUN_SUITE(suite_name) MU__SAFE_BLOCK(\ + suite_name();\ + minunit_setup = NULL;\ + minunit_teardown = NULL;\ +) + +/* Configure setup and teardown functions */ +#define MU_SUITE_CONFIGURE(setup_fun, teardown_fun) MU__SAFE_BLOCK(\ + minunit_setup = setup_fun;\ + minunit_teardown = teardown_fun;\ +) + +/* Test runner */ +#define MU_RUN_TEST(test) MU__SAFE_BLOCK(\ + if (minunit_real_timer==0 && minunit_proc_timer==0) {\ + minunit_real_timer = mu_timer_real();\ + minunit_proc_timer = mu_timer_cpu();\ + }\ + if (minunit_setup) (*minunit_setup)();\ + minunit_status = 0;\ + test();\ + minunit_run++;\ + if (minunit_status) {\ + minunit_fail++;\ + printf("F");\ + printf("\n%s\n", minunit_last_message);\ + }\ + fflush(stdout);\ + if (minunit_teardown) (*minunit_teardown)();\ +) + +/* Report */ +#define MU_REPORT() MU__SAFE_BLOCK(\ + double minunit_end_real_timer;\ + double minunit_end_proc_timer;\ + printf("\n\n%d tests, %d assertions, %d failures\n", minunit_run, minunit_assert, minunit_fail);\ + minunit_end_real_timer = mu_timer_real();\ + minunit_end_proc_timer = mu_timer_cpu();\ + printf("\nFinished in %.8f seconds (real) %.8f seconds (proc)\n\n",\ + minunit_end_real_timer - minunit_real_timer,\ + minunit_end_proc_timer - minunit_proc_timer);\ +) +#define MU_EXIT_CODE minunit_fail + +/* Assertions */ +#define mu_check(test) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (!(test)) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, #test);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_fail(message) MU__SAFE_BLOCK(\ + minunit_assert++;\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, message);\ + minunit_status = 1;\ + return;\ +) + +#define mu_assert(test, message) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (!(test)) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, message);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_int_eq(expected, result) MU__SAFE_BLOCK(\ + int minunit_tmp_e;\ + int minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (expected);\ + minunit_tmp_r = (result);\ + if (minunit_tmp_e != minunit_tmp_r) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %d expected but was %d", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_double_eq(expected, result) MU__SAFE_BLOCK(\ + double minunit_tmp_e;\ + double minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (expected);\ + minunit_tmp_r = (result);\ + if (fabs(minunit_tmp_e-minunit_tmp_r) > MINUNIT_EPSILON) {\ + int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON);\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %.*g expected but was %.*g", __func__, __FILE__, __LINE__, minunit_significant_figures, minunit_tmp_e, minunit_significant_figures, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_string_eq(expected, result) MU__SAFE_BLOCK(\ + const char* minunit_tmp_e = expected;\ + const char* minunit_tmp_r = result;\ + minunit_assert++;\ + if (!minunit_tmp_e) {\ + minunit_tmp_e = "";\ + }\ + if (!minunit_tmp_r) {\ + minunit_tmp_r = "";\ + }\ + if(strcmp(minunit_tmp_e, minunit_tmp_r)) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: '%s' expected but was '%s'", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +/* + * The following two functions were written by David Robert Nadeau + * from http://NadeauSoftware.com/ and distributed under the + * Creative Commons Attribution 3.0 Unported License + */ + +/** + * Returns the real time, in seconds, or -1.0 if an error occurred. + * + * Time is measured since an arbitrary and OS-dependent start time. + * The returned real time is only useful for computing an elapsed time + * between two calls to this function. + */ +static double mu_timer_real(void) +{ +#if defined(_WIN32) + /* Windows 2000 and later. ---------------------------------- */ + LARGE_INTEGER Time; + LARGE_INTEGER Frequency; + + QueryPerformanceFrequency(&Frequency); + QueryPerformanceCounter(&Time); + + Time.QuadPart *= 1000000; + Time.QuadPart /= Frequency.QuadPart; + + return (double)Time.QuadPart / 1000000.0; + +#elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) + /* HP-UX, Solaris. ------------------------------------------ */ + return (double)gethrtime( ) / 1000000000.0; + +#elif defined(__MACH__) && defined(__APPLE__) + /* OSX. ----------------------------------------------------- */ + static double timeConvert = 0.0; + if ( timeConvert == 0.0 ) + { + mach_timebase_info_data_t timeBase; + (void)mach_timebase_info( &timeBase ); + timeConvert = (double)timeBase.numer / + (double)timeBase.denom / + 1000000000.0; + } + return (double)mach_absolute_time( ) * timeConvert; + +#elif defined(_POSIX_VERSION) + /* POSIX. --------------------------------------------------- */ + struct timeval tm; +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + { + struct timespec ts; +#if defined(CLOCK_MONOTONIC_PRECISE) + /* BSD. --------------------------------------------- */ + const clockid_t id = CLOCK_MONOTONIC_PRECISE; +#elif defined(CLOCK_MONOTONIC_RAW) + /* Linux. ------------------------------------------- */ + const clockid_t id = CLOCK_MONOTONIC_RAW; +#elif defined(CLOCK_HIGHRES) + /* Solaris. ----------------------------------------- */ + const clockid_t id = CLOCK_HIGHRES; +#elif defined(CLOCK_MONOTONIC) + /* AIX, BSD, Linux, POSIX, Solaris. ----------------- */ + const clockid_t id = CLOCK_MONOTONIC; +#elif defined(CLOCK_REALTIME) + /* AIX, BSD, HP-UX, Linux, POSIX. ------------------- */ + const clockid_t id = CLOCK_REALTIME; +#else + const clockid_t id = (clockid_t)-1; /* Unknown. */ +#endif /* CLOCK_* */ + if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) + return (double)ts.tv_sec + + (double)ts.tv_nsec / 1000000000.0; + /* Fall thru. */ + } +#endif /* _POSIX_TIMERS */ + + /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, POSIX, Solaris. ----- */ + gettimeofday( &tm, NULL ); + return (double)tm.tv_sec + (double)tm.tv_usec / 1000000.0; +#else + return -1.0; /* Failed. */ +#endif +} + +/** + * Returns the amount of CPU time used by the current process, + * in seconds, or -1.0 if an error occurred. + */ +static double mu_timer_cpu(void) +{ +#if defined(_WIN32) + /* Windows -------------------------------------------------- */ + FILETIME createTime; + FILETIME exitTime; + FILETIME kernelTime; + FILETIME userTime; + + /* This approach has a resolution of 1/64 second. Unfortunately, Windows' API does not offer better */ + if ( GetProcessTimes( GetCurrentProcess( ), + &createTime, &exitTime, &kernelTime, &userTime ) != 0 ) + { + ULARGE_INTEGER userSystemTime; + memcpy(&userSystemTime, &userTime, sizeof(ULARGE_INTEGER)); + return (double)userSystemTime.QuadPart / 10000000.0; + } + +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) + /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris --------- */ + +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + /* Prefer high-res POSIX timers, when available. */ + { + clockid_t id; + struct timespec ts; +#if _POSIX_CPUTIME > 0 + /* Clock ids vary by OS. Query the id, if possible. */ + if ( clock_getcpuclockid( 0, &id ) == -1 ) +#endif +#if defined(CLOCK_PROCESS_CPUTIME_ID) + /* Use known clock id for AIX, Linux, or Solaris. */ + id = CLOCK_PROCESS_CPUTIME_ID; +#elif defined(CLOCK_VIRTUAL) + /* Use known clock id for BSD or HP-UX. */ + id = CLOCK_VIRTUAL; +#else + id = (clockid_t)-1; +#endif + if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) + return (double)ts.tv_sec + + (double)ts.tv_nsec / 1000000000.0; + } +#endif + +#if defined(RUSAGE_SELF) + { + struct rusage rusage; + if ( getrusage( RUSAGE_SELF, &rusage ) != -1 ) + return (double)rusage.ru_utime.tv_sec + + (double)rusage.ru_utime.tv_usec / 1000000.0; + } +#endif + +#if defined(_SC_CLK_TCK) + { + const double ticks = (double)sysconf( _SC_CLK_TCK ); + struct tms tms; + if ( times( &tms ) != (clock_t)-1 ) + return (double)tms.tms_utime / ticks; + } +#endif + +#if defined(CLOCKS_PER_SEC) + { + clock_t cl = clock( ); + if ( cl != (clock_t)-1 ) + return (double)cl / (double)CLOCKS_PER_SEC; + } +#endif + +#endif + + return -1; /* Failed. */ +} + +#ifdef __cplusplus +} +#endif + +#endif /* MINUNIT_MINUNIT_H */ diff --git a/experimental/facho-signer/xades/minunit_ext.h b/experimental/facho-signer/xades/minunit_ext.h new file mode 100644 index 0000000..b70b77f --- /dev/null +++ b/experimental/facho-signer/xades/minunit_ext.h @@ -0,0 +1,13 @@ +#ifndef MINUNIT_EXT_H + +#include + +#include "minunit.h" + +// cuando escribe esto el compilar me arrojo que si no era +// mejor usar mu_assert_string_eq increble a +//int mu_assert_string_equals(const char *a, const char *b) { +// return mu_assert(strcmp(a, b) == 0, "string not equals"); +//} + +#endif //MINUNIT_EXT_H diff --git a/experimental/facho-signer/xades/xades.c b/experimental/facho-signer/xades/xades.c new file mode 100644 index 0000000..cfd275b --- /dev/null +++ b/experimental/facho-signer/xades/xades.c @@ -0,0 +1,115 @@ +#include + +#include "xades.h" + +#define xmlXadesAssert2(p, ret) \ + xmlSecAssert2(p, ret) + +#define xmlXadesNodeNotFoundError(errorFunction, startNode, targetNodeName, errorObject) \ + xmlSecNodeNotFoundError(errorFunction, startNode, targetNodeName, errorObject) + +#define xmlXadesError2(errorFunction, errorObject, msg, param) \ + xmlSecXmlError2(errorFunction, errorObject, msg, param) + +#define xmlXadesErrorsSafeString(msg) \ + xmlSecErrorsSafeString(msg) + +#define xmlXadesInternalError(errorFunction, errorObject) \ + xmlSecInternalError(errorFunction, errorObject) + + +xmlNodePtr +xmlXadesTmplQualifyingPropertiesCreateNsPref(xmlDocPtr doc, const xmlChar* id, const xmlChar* nsPrefix) { + xmlNodePtr qualifyingPropertiesNode; + xmlNodePtr cur; + xmlNsPtr ns; + + // crear nodo + qualifyingPropertiesNode = xmlNewDocNode(doc, NULL, xmlXadesNodeQualifyingProperties, NULL); + if (qualifyingPropertiesNode == NULL) { + xmlXadesError2("xmlNewDocNode", NULL, "node=%s", xmlXadesErrorsSafeString(xmlXadesNodeQualifyingProperties)); + return(NULL); + } + + // crear namespace y asignar + ns = xmlNewNs(qualifyingPropertiesNode, xmlXadesDSigNs, nsPrefix); + if (ns == NULL) { + xmlXadesError2("xmlNewNs", NULL, + "ns=%s", xmlXadesErrorsSafeString(xmlXadesDSigNs)); + xmlFreeNode(qualifyingPropertiesNode); + return(NULL); + } + xmlSetNs(qualifyingPropertiesNode, ns); + + if (id != NULL) { + xmlSetProp(qualifyingPropertiesNode, BAD_CAST "id", id); + } + + // add SignedProperties + cur = xmlSecAddChild(qualifyingPropertiesNode, xmlXadesNodeSignedProperties, xmlXadesDSigNs); + if (cur == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSignedProperties)", NULL); + xmlFreeNode(qualifyingPropertiesNode); + return(NULL); + } + + + return (qualifyingPropertiesNode); +} + +xmlNodePtr +xmlXadesTmplAddSignedSignatureProperties(xmlNodePtr parentNode, const xmlChar* id, struct tm* signingTime) { + xmlNodePtr cur; + xmlNodePtr node; + xmlNodePtr signedPropertiesNode; + + xmlXadesAssert2(parentNode != NULL, NULL); + + signedPropertiesNode = xmlSecFindChild(parentNode, xmlXadesNodeSignedProperties, xmlXadesDSigNs); + if (signedPropertiesNode == NULL) { + xmlXadesNodeNotFoundError("xmlSecFindChild", parentNode, + xmlXadesNodeSignedProperties, NULL); + return(NULL); + } + + // add SignedSignatureProperties + node = xmlSecAddChild(signedPropertiesNode, xmlXadesNodeSignedSignatureProperties, xmlXadesDSigNs); + if (node == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSignedSignatureProperties)", NULL); + return(NULL); + } + + if (id != NULL) { + xmlSetProp(node, BAD_CAST "id", id); + } + + // add SignigTime + cur = xmlSecAddChild(node, xmlXadesNodeSigningTime, xmlXadesDSigNs); + if (cur == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSigningTime)", NULL); + xmlFreeNode(node); + return(NULL); + } + + { + int ret; + char strtime[200]; + + if (strftime(strtime, sizeof(strtime), "%Y-%m-%dT%T", signingTime) == 0) { + xmlXadesInternalError("strftime", NULL); + xmlFreeNode(cur); + xmlFreeNode(node); + return(NULL); + } + + ret = xmlSecNodeEncodeAndSetContent(cur, BAD_CAST strtime); + if (ret < 0) { + xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); + xmlFreeNode(cur); + xmlFreeNode(node); + return(NULL); + } + } + + return(node); +} diff --git a/experimental/facho-signer/xades/xades.h b/experimental/facho-signer/xades/xades.h new file mode 100644 index 0000000..3d556b6 --- /dev/null +++ b/experimental/facho-signer/xades/xades.h @@ -0,0 +1,22 @@ +#ifndef XADES_H +#define XADES_H + +#include + +#include + +#include "xmlsec1/errors_helpers.h" + +static const xmlChar xmlXadesNodeQualifyingProperties[] = "QualifyingProperties"; +static const xmlChar xmlXadesNodeSignedProperties[] = "SignedProperties"; + +static const xmlChar xmlXadesNodeSignedSignatureProperties[] = "SignedSignatureProperties"; +static const xmlChar xmlXadesNodeSigningTime[] = "SigningTime"; + +static const xmlChar xmlXadesDSigNs[] = "http://uri.etsi.org/01903/v1.3.2#"; + +xmlNodePtr +xmlXadesTmplQualifyingPropertiesCreateNsPref(xmlDocPtr doc, const xmlChar* id, const xmlChar* nsPrefix); +xmlNodePtr +xmlXadesTmplAddSignedSignatureProperties(xmlNodePtr parentNode, const xmlChar* id, struct tm* signingTime); +#endif //XADES_H diff --git a/experimental/facho-signer/xades/xades_test.c b/experimental/facho-signer/xades/xades_test.c new file mode 100644 index 0000000..6457748 --- /dev/null +++ b/experimental/facho-signer/xades/xades_test.c @@ -0,0 +1,69 @@ +#include + +#include +#include "minunit.h" + +#include "xades.h" + + + + +MU_TEST(test_qualifying_properties_layout) { + xmlDocPtr doc; + xmlNodePtr root; + xmlNodePtr node; + xmlChar* xmlbuff; + int buffersize; + struct tm tm; + + memset(&tm, 0, sizeof(tm)); + tm.tm_year = 2021 - 1900; + tm.tm_mon = 11; + tm.tm_mday = 6; + tm.tm_hour = 12; + tm.tm_min = 0; + tm.tm_sec = 50; + + + doc = xmlNewDoc(BAD_CAST "1.0"); + root = xmlNewNode(NULL, BAD_CAST "root"); + xmlDocSetRootElement(doc, root); + + node = xmlXadesTmplQualifyingPropertiesCreateNsPref(doc, BAD_CAST "123", NULL); + xmlXadesTmplAddSignedSignatureProperties(node, NULL, &tm); + mu_check(node != NULL); + + xmlSecAddChildNode(root, node); + xmlDocDumpMemory(doc, &xmlbuff, &buffersize); + + // bit4bit: no se como pasar el namespace al root + mu_assert_string_eq("\n" + "\n" + "\n" + "\n" + "\n" + "2021-12-06T12:00:50\n" + "\n" + "\n" + "\n" + "\n" + , (char *)xmlbuff); + + xmlFree(xmlbuff); + xmlFreeDoc(doc); +} + +MU_TEST(test_check) { + mu_check(5 == 7); +} + +MU_TEST_SUITE(test_suite) { + MU_RUN_TEST(test_check); + MU_RUN_TEST(test_qualifying_properties_layout); +} + +int main() { + MU_RUN_SUITE(test_suite); + MU_REPORT(); + return MU_EXIT_CODE; +} diff --git a/experimental/facho-signer/xades/xmlsec1/errors.c b/experimental/facho-signer/xades/xmlsec1/errors.c new file mode 100644 index 0000000..46d487e --- /dev/null +++ b/experimental/facho-signer/xades/xmlsec1/errors.c @@ -0,0 +1,259 @@ +/* + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2016 Aleksey Sanin . All Rights Reserved. + */ +/** + * SECTION:errors + * @Short_description: Error reporting and logging functions. + * @Stability: Stable + * + */ + +#define XMLSEC_PRIVATE 1 + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* Must be bigger than fatal_error */ +#define XMLSEC_ERRORS_BUFFER_SIZE 1024 + +/* Must fit into xmlChar[XMLSEC_ERRORS_BUFFER_SIZE] */ +static const xmlChar fatal_error[] = "Can not format error message"; + +typedef struct _xmlSecErrorDescription xmlSecErrorDescription, *xmlSecErrorDescriptionPtr; +struct _xmlSecErrorDescription { + int errorCode; + const char* errorMsg; +}; + +static xmlSecErrorDescription xmlSecErrorsTable[XMLSEC_ERRORS_MAX_NUMBER + 1] = { + { XMLSEC_ERRORS_R_XMLSEC_FAILED, "xmlsec library function failed" }, + { XMLSEC_ERRORS_R_MALLOC_FAILED, "malloc function failed" }, + { XMLSEC_ERRORS_R_STRDUP_FAILED, "strdup function failed" }, + { XMLSEC_ERRORS_R_CRYPTO_FAILED, "crypto library function failed" }, + { XMLSEC_ERRORS_R_XML_FAILED, "libxml2 library function failed" }, + { XMLSEC_ERRORS_R_XSLT_FAILED, "libxslt library function failed" }, + { XMLSEC_ERRORS_R_IO_FAILED, "io function failed" }, + { XMLSEC_ERRORS_R_DISABLED, "feature is disabled" }, + { XMLSEC_ERRORS_R_NOT_IMPLEMENTED, "feature is not implemented" }, + { XMLSEC_ERRORS_R_INVALID_CONFIG, "invalid configuration" }, + { XMLSEC_ERRORS_R_INVALID_SIZE, "invalid size" }, + { XMLSEC_ERRORS_R_INVALID_DATA, "invalid data" }, + { XMLSEC_ERRORS_R_INVALID_RESULT, "invalid result" }, + { XMLSEC_ERRORS_R_INVALID_TYPE, "invalid type" }, + { XMLSEC_ERRORS_R_INVALID_OPERATION, "invalid operation" }, + { XMLSEC_ERRORS_R_INVALID_STATUS, "invalid status" }, + { XMLSEC_ERRORS_R_INVALID_FORMAT, "invalid format" }, + { XMLSEC_ERRORS_R_DATA_NOT_MATCH, "data do not match" }, + { XMLSEC_ERRORS_R_INVALID_VERSION, "invalid version" }, + { XMLSEC_ERRORS_R_INVALID_NODE, "invalid node" }, + { XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, "invalid node content" }, + { XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, "invalid node attribute" }, + { XMLSEC_ERRORS_R_MISSING_NODE_ATTRIBUTE, "missing node attribute" }, + { XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, "node already present" }, + { XMLSEC_ERRORS_R_UNEXPECTED_NODE, "unexpected node" }, + { XMLSEC_ERRORS_R_NODE_NOT_FOUND, "node node found" }, + { XMLSEC_ERRORS_R_INVALID_TRANSFORM, "invalid transform" }, + { XMLSEC_ERRORS_R_INVALID_TRANSFORM_KEY, "invalid transform key" }, + { XMLSEC_ERRORS_R_INVALID_URI_TYPE, "invalid URI type" }, + { XMLSEC_ERRORS_R_TRANSFORM_SAME_DOCUMENT_REQUIRED, "same document is required for transform" }, + { XMLSEC_ERRORS_R_TRANSFORM_DISABLED, "transform is disabled" }, + { XMLSEC_ERRORS_R_INVALID_KEY_DATA, "invalid key data" }, + { XMLSEC_ERRORS_R_KEY_DATA_NOT_FOUND, "key data is not found" }, + { XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, "key data already exist" }, + { XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, "invalid key data size" }, + { XMLSEC_ERRORS_R_KEY_NOT_FOUND, "key is not found" }, + { XMLSEC_ERRORS_R_KEYDATA_DISABLED, "key data is disabled" }, + { XMLSEC_ERRORS_R_MAX_RETRIEVALS_LEVEL, "maximum key retrieval level" }, + { XMLSEC_ERRORS_R_MAX_RETRIEVAL_TYPE_MISMATCH,"key retrieval type mismatch" }, + { XMLSEC_ERRORS_R_MAX_ENCKEY_LEVEL, "maximum encrypted key level" }, + { XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, "certificate verification failed" }, + { XMLSEC_ERRORS_R_CERT_NOT_FOUND, "certificate is not found" }, + { XMLSEC_ERRORS_R_CERT_REVOKED, "certificate is revoked" }, + { XMLSEC_ERRORS_R_CERT_ISSUER_FAILED, "certificate issuer check failed" }, + { XMLSEC_ERRORS_R_CERT_NOT_YET_VALID, "certificate is not yet valid" }, + { XMLSEC_ERRORS_R_CERT_HAS_EXPIRED, "certificate has expired" }, + { XMLSEC_ERRORS_R_DSIG_NO_REFERENCES, "Reference nodes are not found" }, + { XMLSEC_ERRORS_R_DSIG_INVALID_REFERENCE, "Reference verification failed" }, + { XMLSEC_ERRORS_R_ASSERTION, "assertion" }, + { 0, NULL} +}; + +static xmlSecErrorsCallback xmlSecErrorsClbk = xmlSecErrorsDefaultCallback; +static int xmlSecPrintErrorMessages = 1; /* whether the error messages will be printed immediately */ + +/** + * xmlSecErrorsInit: + * + * Initializes the errors reporting. It is called from #xmlSecInit function. + * and applications must not call this function directly. + */ +void +xmlSecErrorsInit(void) { +} + +/** + * xmlSecErrorsShutdown: + * + * Cleanups the errors reporting. It is called from #xmlSecShutdown function. + * and applications must not call this function directly. + */ +void +xmlSecErrorsShutdown(void) { +} + +/** + * xmlSecErrorsSetCallback: + * @callback: the new errors callback function. + * + * Sets the errors callback function to @callback that will be called + * every time an error occurs. + */ +void +xmlSecErrorsSetCallback(xmlSecErrorsCallback callback) { + xmlSecErrorsClbk = callback; +} + +/** + * xmlSecErrorsDefaultCallback: + * @file: the error location file name (__FILE__ macro). + * @line: the error location line number (__LINE__ macro). + * @func: the error location function name (__FUNCTION__ macro). + * @errorObject: the error specific error object + * @errorSubject: the error specific error subject. + * @reason: the error code. + * @msg: the additional error message. + * + * The default error reporting callback that utilizes LibXML + * error reporting #xmlGenericError function. + */ +void +xmlSecErrorsDefaultCallback(const char* file, int line, const char* func, + const char* errorObject, const char* errorSubject, + int reason, const char* msg) { + if(xmlSecPrintErrorMessages) { + const char* error_msg = NULL; + xmlSecSize i; + + for(i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) { + if(xmlSecErrorsGetCode(i) == reason) { + error_msg = xmlSecErrorsGetMsg(i); + break; + } + } + xmlGenericError(xmlGenericErrorContext, + "func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n", + (func != NULL) ? func : "unknown", + (file != NULL) ? file : "unknown", + line, + (errorObject != NULL) ? errorObject : "unknown", + (errorSubject != NULL) ? errorSubject : "unknown", + reason, + (error_msg != NULL) ? error_msg : "", + (msg != NULL) ? msg : ""); + } +} + +/** + * xmlSecErrorsDefaultCallbackEnableOutput: + * @enabled: the flag. + * + * Enables or disables calling LibXML2 callback from the default + * errors callback. + */ +void +xmlSecErrorsDefaultCallbackEnableOutput(int enabled) { + xmlSecPrintErrorMessages = enabled; +} + +/** + * xmlSecErrorsGetCode: + * @pos: the error position. + * + * Gets the known error code at position @pos. + * + * Returns: the known error code or 0 if @pos is greater than + * total number of known error codes. + */ +int +xmlSecErrorsGetCode(xmlSecSize pos) { + /* could not use asserts here! */ + if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) { + return(xmlSecErrorsTable[pos].errorCode); + } + return(0); +} + +/** + * xmlSecErrorsGetMsg: + * @pos: the error position. + * + * Gets the known error message at position @pos. + * + * Returns: the known error message or NULL if @pos is greater than + * total number of known error codes. + */ +const char* +xmlSecErrorsGetMsg(xmlSecSize pos) { + /* could not use asserts here! */ + if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) { + return(xmlSecErrorsTable[pos].errorMsg); + } + return(NULL); +} + +/** + * xmlSecError: + * @file: the error location filename (__FILE__). + * @line: the error location line number (__LINE__). + * @func: the error location function (__FUNCTION__). + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @errorSubject: the error specific error subject (e.g. failed function name). + * @reason: the error code. + * @msg: the error message in printf format. + * @...: the parameters for the @msg. + * + * Reports an error to the default (#xmlSecErrorsDefaultCallback) or + * application specific callback installed using #xmlSecErrorsSetCallback + * function. + */ +void +xmlSecError(const char* file, int line, const char* func, + const char* errorObject, const char* errorSubject, + int reason, const char* msg, ...) { + if(xmlSecErrorsClbk != NULL) { + xmlChar error_msg[XMLSEC_ERRORS_BUFFER_SIZE]; + int ret; + + if(msg != NULL) { + va_list va; + + va_start(va, msg); + ret = xmlStrVPrintf(error_msg, sizeof(error_msg), msg, va); + if(ret < 0) { + /* Can't really report an error from an error callback */ + memcpy(error_msg, fatal_error, sizeof(fatal_error)); + } + error_msg[sizeof(error_msg) - 1] = '\0'; /* just in case */ + va_end(va); + } else { + error_msg[0] = '\0'; + } + xmlSecErrorsClbk(file, line, func, errorObject, errorSubject, reason, (char*)error_msg); + } +} diff --git a/experimental/facho-signer/xades/xmlsec1/errors_helpers.h b/experimental/facho-signer/xades/xmlsec1/errors_helpers.h new file mode 100644 index 0000000..1781e27 --- /dev/null +++ b/experimental/facho-signer/xades/xmlsec1/errors_helpers.h @@ -0,0 +1,869 @@ +/* + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Internal header only used during the compilation, + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2016 Aleksey Sanin . All Rights Reserved. + */ + +#ifndef __XMLSEC_ERROR_HELPERS_H__ +#define __XMLSEC_ERROR_HELPERS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/********************************************************************** + * + * Error handling macros. + * + **********************************************************************/ + +/** + * xmlSecInternalError: + * @errorFunction: the failed function name. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting internal XMLSec errors. + */ +#define xmlSecInternalError(errorFunction, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_XMLSEC_FAILED, \ + XMLSEC_ERRORS_NO_MESSAGE \ + ) + +/** + * xmlSecInternalError2: + * @errorFunction: the failed function name. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @msg: the extra message. + * @param: the extra message param. + * + * Macro. The XMLSec library macro for reporting internal XMLSec errors. + */ +#define xmlSecInternalError2(errorFunction, errorObject, msg, param) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_XMLSEC_FAILED, \ + (msg), (param) \ + ) + +/** + * xmlSecInternalError3: + * @errorFunction: the failed function name. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @msg: the extra message. + * @param1: the extra message param1. + * @param2: the extra message param2. + * + * Macro. The XMLSec library macro for reporting internal XMLSec errors. + */ +#define xmlSecInternalError3(errorFunction, errorObject, msg, param1, param2) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_XMLSEC_FAILED, \ + (msg), (param1), (param2) \ + ) + +/** + * xmlSecInternalError4: + * @errorFunction: the failed function name. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @msg: the extra message. + * @param1: the extra message param1. + * @param2: the extra message param2. + * @param3: the extra message param3. + * + * Macro. The XMLSec library macro for reporting internal XMLSec errors. + */ +#define xmlSecInternalError4(errorFunction, errorObject, msg, param1, param2, param3) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_XMLSEC_FAILED, \ + (msg), (param1), (param2), (param3) \ + ) + +/** + * xmlSecMallocError: + * @allocSize: the failed allocation size. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting xmlMalloc() errors. + */ +#define xmlSecMallocError(allocSize, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + "xmlMalloc", \ + XMLSEC_ERRORS_R_MALLOC_FAILED, \ + "size=%lu", (unsigned long)(allocSize) \ + ) + +/** + * xmlSecStrdupError: + * @str: the failed string. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting xmlStrdup() errors. + */ +#define xmlSecStrdupError(str, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + "xmlStrdup", \ + XMLSEC_ERRORS_R_STRDUP_FAILED, \ + "size=%lu", (unsigned long)xmlStrlen(str) \ + ) + +/** + * xmlSecXmlError: + * @errorFunction: the failed function. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting generic XML errors. + */ +#define xmlSecXmlError(errorFunction, errorObject) \ + { \ + xmlErrorPtr error = xmlGetLastError(); \ + int code = (error != NULL) ? error->code : 0; \ + const char* message = (error != NULL) ? error->message : NULL; \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_XML_FAILED, \ + "xml error: %lu: %s", \ + (unsigned long)code, \ + xmlSecErrorsSafeString(message) \ + ); \ + } + +/** + * xmlSecXmlError2: + * @errorFunction: the failed function. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @msg: the extra message. + * @param: the extra message param. + * + * Macro. The XMLSec library macro for reporting generic XML errors. + */ +#define xmlSecXmlError2(errorFunction, errorObject, msg, param) \ + { \ + xmlErrorPtr error = xmlGetLastError(); \ + int code = (error != NULL) ? error->code : 0; \ + const char* message = (error != NULL) ? error->message : NULL; \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_XML_FAILED, \ + msg "; xml error: %lu: %s", \ + (param), \ + (unsigned long)code, \ + xmlSecErrorsSafeString(message) \ + ); \ + } + +/** + * xmlSecXmlParserError: + * @errorFunction: the failed function. + * @ctxt: the parser context. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting XML parser errors. + */ +#define xmlSecXmlParserError(errorFunction, ctxt, errorObject) \ + { \ + xmlErrorPtr error = xmlCtxtGetLastError(ctxt);\ + int code = (error != NULL) ? error->code : 0; \ + const char* message = (error != NULL) ? error->message : NULL; \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_XML_FAILED, \ + "xml error: %lu: %s", \ + (unsigned long)code, \ + xmlSecErrorsSafeString(message) \ + ); \ + } + +/** + * xmlSecXmlParserError2: + * @errorFunction: the failed function. + * @ctxt: the parser context. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @msg: the extra message. + * @param: the extra message param. + * + * Macro. The XMLSec library macro for reporting XML parser errors. + */ +#define xmlSecXmlParserError2(errorFunction, ctxt, errorObject, msg, param) \ + { \ + xmlErrorPtr error = xmlCtxtGetLastError(ctxt);\ + int code = (error != NULL) ? error->code : 0; \ + const char* message = (error != NULL) ? error->message : NULL; \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_XML_FAILED, \ + msg "; xml error: %lu: %s", \ + (param), \ + (unsigned long)code, \ + xmlSecErrorsSafeString(message) \ + ); \ + } + +/** + * xmlSecXsltError: + * @errorFunction: the failed function. + * @ctxt: the parser context. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting XSLT errors. + */ +#define xmlSecXsltError(errorFunction, ctxt, errorObject) \ + { \ + xmlErrorPtr error = xmlGetLastError(); \ + int code = (error != NULL) ? error->code : 0; \ + const char* message = (error != NULL) ? error->message : NULL; \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_XSLT_FAILED, \ + "xslt error: %lu: %s", \ + (unsigned long)code, \ + xmlSecErrorsSafeString(message) \ + ); \ + } + +/** + * xmlSecIOError: + * @errorFunction: the failed function. + * @name: the filename, function name, uri, etc. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting IO errors. + */ +#define xmlSecIOError(errorFunction, name, errorObject) \ + { \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_IO_FAILED, \ + "name=\"%s\"; errno=%d", \ + xmlSecErrorsSafeString(name), \ + errno \ + ); \ + } + +/** + * xmlSecNotImplementedError: + * @details: the additional details. + * + * Macro. The XMLSec library macro for reporting "not implemented" errors. + */ +#define xmlSecNotImplementedError(details) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + NULL, \ + NULL, \ + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, \ + "details=%s", \ + xmlSecErrorsSafeString(details) \ + ) +/** + * xmlSecInvalidSizeError: + * @name: the name of the variable, parameter, etc. + * @actual: the actual value. + * @expected: the expected value. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid size" errors when + * we expect exact match. + */ +#define xmlSecInvalidSizeError(name, actual, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_SIZE, \ + "invalid size for '%s': actual=%lu is not equal to expected=%lu", \ + xmlSecErrorsSafeString(name), \ + (unsigned long)(actual), \ + (unsigned long)(expected) \ + ) + +/** + * xmlSecInvalidSizeLessThanError: + * @name: the name of the variable, parameter, etc. + * @actual: the actual value. + * @expected: the expected value. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid size" errors when + * we expect at least the expected size. + */ +#define xmlSecInvalidSizeLessThanError(name, actual, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_SIZE, \ + "invalid size for '%s': actual=%lu is less than expected=%lu", \ + xmlSecErrorsSafeString(name), \ + (unsigned long)(actual), \ + (unsigned long)(expected) \ + ) + +/** + * xmlSecInvalidSizeMoreThanError: + * @name: the name of the variable, parameter, etc. + * @actual: the actual value. + * @expected: the expected value. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid size" errors when + * we expect at most the expected size. + */ +#define xmlSecInvalidSizeMoreThanError(name, actual, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, \ + "invalid size for '%s': actual=%lu is more than expected=%lu", \ + xmlSecErrorsSafeString(name), \ + (unsigned long)(actual), \ + (unsigned long)(expected) \ + ) + +/** + * xmlSecInvalidSizeNotMultipleOfError: + * @name: the name of the variable, parameter, etc. + * @actual: the actual value. + * @divider: the expected divider. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid size" errors when + * we expect the size to be a multiple of the divider. + */ +#define xmlSecInvalidSizeNotMultipleOfError(name, actual, divider, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, \ + "invalid size for '%s': actual=%lu is not a multiple of %lu", \ + xmlSecErrorsSafeString(name), \ + (unsigned long)(actual), \ + (unsigned long)(divider) \ + ) + +/** + * xmlSecInvalidSizeOtherError: + * @msg: the message about the error. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid size" errors when + * we expect exact match. + */ +#define xmlSecInvalidSizeOtherError(msg, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_SIZE, \ + "invalid size: %s", \ + xmlSecErrorsSafeString(msg) \ + ) + +/** + * xmlSecInvalidDataError: + * @msg: the msg with explanation. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid data" errors. + */ +#define xmlSecInvalidDataError(msg, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_DATA, \ + "%s", \ + xmlSecErrorsSafeString(msg) \ + ) + +/** + * xmlSecInvalidStringDataError: + * @name: the name of the variable, parameter, etc. + * @actual: the actual value as a string. + * @expected: the expected value(s) as a string. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid data" errors for string. + */ +#define xmlSecInvalidStringDataError(name, actual, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_DATA, \ + "invalid data for '%s': actual='%s' and expected %s", \ + xmlSecErrorsSafeString(name), \ + xmlSecErrorsSafeString(actual), \ + (expected) \ + ) + +/** + * xmlSecInvalidIntegerDataError: + * @name: the name of the variable, parameter, etc. + * @actual: the actual value as an integer. + * @expected: the expected value(s) as a string. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid data" errors for integers. + */ +#define xmlSecInvalidIntegerDataError(name, actual, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_DATA, \ + "invalid data for '%s': actual=%ld and expected %s", \ + xmlSecErrorsSafeString(name), \ + (unsigned long)(actual), \ + (expected) \ + ) + +/** + * xmlSecInvalidIntegerDataError2: + * @name1: the name of the first variable, parameter, etc. + * @actual1: the actual first value as an integer. + * @name2: the name of the second variable, parameter, etc. + * @actual2: the actual second value as an integer. + * @expected: the expected value(s) as a string. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid data" errors for integers. + */ +#define xmlSecInvalidIntegerDataError2(name1, actual1, name2, actual2, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_DATA, \ + "invalid data: actual value '%s'=%ld, actual value '%s'=%ld and expected %s", \ + xmlSecErrorsSafeString(name1), \ + (unsigned long)(actual1), \ + xmlSecErrorsSafeString(name2), \ + (unsigned long)(actual2), \ + (expected) \ + ) + +/** + * xmlSecInvalidTypeError: + * @msg: the msg with explanation. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid type" errors. + */ +#define xmlSecInvalidTypeError(msg, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_TYPE, \ + "%s", \ + xmlSecErrorsSafeString(msg) \ + ) + +/** + * xmlSecInvalidStringTypeError: + * @name: the name of the variable, parameter, etc. + * @actual: the actual value as a string. + * @expected: the expected value(s) as a string. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid type" errors for string. + */ +#define xmlSecInvalidStringTypeError(name, actual, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_TYPE, \ + "invalid type for '%s': actual='%s' and expected %s", \ + xmlSecErrorsSafeString(name), \ + xmlSecErrorsSafeString(actual), \ + (expected) \ + ) + +/** + * xmlSecInvalidIntegerTypeError: + * @name: the name of the variable, parameter, etc. + * @actual: the actual value as an integer. + * @expected: the expected value(s) as a string. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid type" errors for integers. + */ +#define xmlSecInvalidIntegerTypeError(name, actual, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_TYPE, \ + "invalid type for '%s': actual=%ld and expected %s", \ + xmlSecErrorsSafeString(name), \ + (unsigned long)(actual), \ + (expected) \ + ) + +/** + * xmlSecInvalidIntegerTypeError2: + * @name1: the name of the first variable, parameter, etc. + * @actual1: the actual first value as an integer. + * @name2: the name of the second variable, parameter, etc. + * @actual2: the actual second value as an integer. + * @expected: the expected value(s) as a string. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid type" errors for integers. + */ +#define xmlSecInvalidIntegerTypeError2(name1, actual1, name2, actual2, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_TYPE, \ + "invalid type: actual value '%s'=%ld, actual value '%s'=%ld and expected %s", \ + xmlSecErrorsSafeString(name1), \ + (unsigned long)(actual1), \ + xmlSecErrorsSafeString(name2), \ + (unsigned long)(actual2), \ + (expected) \ + ) + +/** + * xmlSecInvalidNodeError: + * @actualNode: the actual node. + * @expectedNodeName: the expected node name. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting an invalid node errors. + */ +#define xmlSecInvalidNodeError(actualNode, expectedNodeName, errorObject) \ + { \ + const char* actualNodeName = xmlSecNodeGetName(actualNode); \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_NODE, \ + "actual=%s; expected=%s", \ + xmlSecErrorsSafeString(actualNodeName), \ + xmlSecErrorsSafeString(expectedNodeName) \ + ); \ + } + +/** + * xmlSecInvalidNodeContentError: + * @node: the node. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @reason: the reason why node content is invalid. + * + * Macro. The XMLSec library macro for reporting an invalid node content errors. + */ +#define xmlSecInvalidNodeContentError(node, errorObject, reason) \ + { \ + const char* nName = xmlSecNodeGetName(node); \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, \ + "node=%s; reason=%s", \ + xmlSecErrorsSafeString(nName), \ + xmlSecErrorsSafeString(reason) \ + ); \ + } + +/** + * xmlSecInvalidNodeAttributeError: + * @node: the node. + * @attrName: the attribute name. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @reason: the reason why node content is invalid. + * + * Macro. The XMLSec library macro for reporting an invalid node attribute errors. + */ +#define xmlSecInvalidNodeAttributeError(node, attrName, errorObject, reason) \ + { \ + const char* nName = xmlSecNodeGetName(node); \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, \ + "node=%s; attribute=%s; reason=%s",\ + xmlSecErrorsSafeString(nName), \ + xmlSecErrorsSafeString(attrName), \ + xmlSecErrorsSafeString(reason) \ + ); \ + } + +/** + * xmlSecNodeAlreadyPresentError: + * @parent: the parent node. + * @nodeName: the node name. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting node already present errors. + */ +#define xmlSecNodeAlreadyPresentError(parent, nodeName, errorObject) \ + { \ + const char* pName = xmlSecNodeGetName(parent);\ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, \ + "parent=%s; node=%s", \ + xmlSecErrorsSafeString(pName), \ + xmlSecErrorsSafeString(nodeName) \ + ); \ + } + +/** + * xmlSecUnexpectedNodeError: + * @node: the node. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting an invalid node errors. + */ +#define xmlSecUnexpectedNodeError(node, errorObject) \ + { \ + const char* nName = xmlSecNodeGetName(node); \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_UNEXPECTED_NODE, \ + "node=%s", \ + xmlSecErrorsSafeString(nName) \ + ); \ + } + +/** + * xmlSecNodeNotFoundError: + * @errorFunction: the failed function. + * @startNode: the search start node. + * @targetNodeName: the expected child node name. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting node not found errors. + */ +#define xmlSecNodeNotFoundError(errorFunction, startNode, targetNodeName, errorObject) \ + { \ + const char* startNodeName = xmlSecNodeGetName(startNode); \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + (errorFunction), \ + XMLSEC_ERRORS_R_NODE_NOT_FOUND, \ + "startNode=%s; target=%s", \ + xmlSecErrorsSafeString(startNodeName), \ + xmlSecErrorsSafeString(targetNodeName) \ + ); \ + } + +/** + * xmlSecInvalidTransfromError: + * @transform: the transform. + * + * Macro. The XMLSec library macro for reporting an invalid transform errors. + */ +#define xmlSecInvalidTransfromError(transform) \ + { \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)xmlSecTransformGetName(transform), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_TRANSFORM, \ + XMLSEC_ERRORS_NO_MESSAGE \ + ); \ + } + +/** + * xmlSecInvalidTransfromError2: + * @transform: the transform. + * @msg: the extra message. + * @param: the extra message param. + * + * + * Macro. The XMLSec library macro for reporting an invalid transform errors. + */ +#define xmlSecInvalidTransfromError2(transform, msg, param) \ + { \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)xmlSecTransformGetName(transform), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_TRANSFORM, \ + (msg), (param) \ + ); \ + } + +/** + * xmlSecInvalidTransfromStatusError: + * @transform: the transform. + * + * Macro. The XMLSec library macro for reporting an invalid transform status errors. + */ +#define xmlSecInvalidTransfromStatusError(transform) \ + { \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)xmlSecTransformGetName(transform), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_STATUS, \ + "transformStatus=%d", \ + (int)((transform)->status) \ + ); \ + } + +/** + * xmlSecInvalidTransfromStatusError2: + * @transform: the transform. + * @msg: the extra message. + * + * Macro. The XMLSec library macro for reporting an invalid transform status errors. + */ +#define xmlSecInvalidTransfromStatusError2(transform, msg) \ + { \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)xmlSecTransformGetName(transform), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_STATUS, \ + "transformStatus=%ld, msg=%s", \ + (long int)((transform)->status), \ + msg \ + ); \ + } + +/** + * xmlSecInvalidKeyDataSizeError: + * @name: the name of the variable, parameter, etc. + * @actual: the actual value. + * @expected: the expected value(s). + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid keydata size" errors. + */ +#define xmlSecInvalidKeyDataSizeError(actual, expected, errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, \ + "invalid key data size: actual=%ld and expected=%ld", \ + (unsigned long)(actual), \ + (unsigned long)(expected) \ + ) + +/** + * xmlSecInvalidZeroKeyDataSizeError: + * @name: the name of the variable, parameter, etc. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * + * Macro. The XMLSec library macro for reporting "invalid keydata size" errors. + */ +#define xmlSecInvalidZeroKeyDataSizeError(errorObject) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, \ + "invalid zero key data size" \ + ) + + +/** + * xmlSecOtherError: + * @code: the error code. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @details: the error message. + * + * Macro. The XMLSec library macro for reporting other XMLSec errors. + */ +#define xmlSecOtherError(code, errorObject, details) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + (code), \ + "details=%s", \ + xmlSecErrorsSafeString(details) \ + ) + +/** + * xmlSecOtherError2: + * @code: the error code. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @msg: the extra message. + * @param: the extra message param. + * + * Macro. The XMLSec library macro for reporting other XMLSec errors. + */ +#define xmlSecOtherError2(code, errorObject, msg, param) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + (code), \ + (msg), (param) \ + ) + +/** + * xmlSecOtherError3: + * @code: the error code. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @msg: the extra message. + * @param1: the extra message param. + * @param2: the extra message param. + * + * Macro. The XMLSec library macro for reporting other XMLSec errors. + */ +#define xmlSecOtherError3(code, errorObject, msg, param1, param2) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + (code), \ + (msg), (param1), (param2) \ + ) + +/** + * xmlSecOtherError4: + * @code: the error code. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @msg: the extra message. + * @param1: the extra message param. + * @param2: the extra message param. + * @param3: the extra message param. + * + * Macro. The XMLSec library macro for reporting other XMLSec errors. + */ +#define xmlSecOtherError4(code, errorObject, msg, param1, param2, param3) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + (code), \ + (msg), (param1), (param2), (param3) \ + ) + +/** + * xmlSecOtherError5: + * @code: the error code. + * @errorObject: the error specific error object (e.g. transform, key data, etc). + * @msg: the extra message. + * @param1: the extra message param. + * @param2: the extra message param. + * @param3: the extra message param. + * @param4: the extra message param. + * + * Macro. The XMLSec library macro for reporting other XMLSec errors. + */ +#define xmlSecOtherError5(code, errorObject, msg, param1, param2, param3, param4) \ + xmlSecError(XMLSEC_ERRORS_HERE, \ + (const char*)(errorObject), \ + NULL, \ + (code), \ + (msg), (param1), (param2), (param3), (param4) \ + ) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __XMLSEC_ERROR_HELPERS_H__ */ diff --git a/experimental/facho-signer/xades/xmlsec1/xmltree.c b/experimental/facho-signer/xades/xmlsec1/xmltree.c new file mode 100644 index 0000000..3056bb5 --- /dev/null +++ b/experimental/facho-signer/xades/xmlsec1/xmltree.c @@ -0,0 +1,1950 @@ +/* + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2016 Aleksey Sanin . All Rights Reserved. + */ +/** + * SECTION:xmltree + * @Short_description: XML tree functions. + * @Stability: Stable + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "errors_helpers.h" + +static const xmlChar* g_xmlsec_xmltree_default_linefeed = xmlSecStringCR; + +/** + * xmlSecGetDefaultLineFeed: + * + * Gets the current default linefeed. + * + * Returns: the current default linefeed. + */ +const xmlChar* +xmlSecGetDefaultLineFeed(void) +{ + return g_xmlsec_xmltree_default_linefeed; +} + +/** + * xmlSecSetDefaultLineFeed: + * @linefeed: default linefeed. + * + * Sets the current default linefeed. The caller must ensure that the linefeed + * string exists for the lifetime of the program or until the new linefeed is set. + */ +void +xmlSecSetDefaultLineFeed(const xmlChar *linefeed) +{ + g_xmlsec_xmltree_default_linefeed = linefeed; +} + +/** + * xmlSecFindSibling: + * @cur: the pointer to XML node. + * @name: the name. + * @ns: the namespace href (may be NULL). + * + * Searches @cur and the next siblings of the @cur node having given name and + * namespace href. + * + * Returns: the pointer to the found node or NULL if an error occurs or + * node is not found. + */ +xmlNodePtr +xmlSecFindSibling(const xmlNodePtr cur, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr tmp; + xmlSecAssert2(name != NULL, NULL); + + for(tmp = cur; tmp != NULL; tmp = tmp->next) { + if(tmp->type == XML_ELEMENT_NODE) { + if(xmlSecCheckNodeName(tmp, name, ns)) { + return(tmp); + } + } + } + return(NULL); +} + +/** + * xmlSecFindChild: + * @parent: the pointer to XML node. + * @name: the name. + * @ns: the namespace href (may be NULL). + * + * Searches a direct child of the @parent node having given name and + * namespace href. + * + * Returns: the pointer to the found node or NULL if an error occurs or + * node is not found. + */ +xmlNodePtr +xmlSecFindChild(const xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) { + xmlSecAssert2(parent != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + return(xmlSecFindSibling(parent->children, name, ns)); +} + +/** + * xmlSecFindParent: + * @cur: the pointer to an XML node. + * @name: the name. + * @ns: the namespace href (may be NULL). + * + * Searches the ancestors axis of the @cur node for a node having given name + * and namespace href. + * + * Returns: the pointer to the found node or NULL if an error occurs or + * node is not found. + */ +xmlNodePtr +xmlSecFindParent(const xmlNodePtr cur, const xmlChar *name, const xmlChar *ns) { + xmlSecAssert2(cur != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + if(xmlSecCheckNodeName(cur, name, ns)) { + return(cur); + } else if(cur->parent != NULL) { + return(xmlSecFindParent(cur->parent, name, ns)); + } + return(NULL); +} + +/** + * xmlSecFindNode: + * @parent: the pointer to XML node. + * @name: the name. + * @ns: the namespace href (may be NULL). + * + * Searches all children of the @parent node having given name and + * namespace href. + * + * Returns: the pointer to the found node or NULL if an error occurs or + * node is not found. + */ +xmlNodePtr +xmlSecFindNode(const xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur; + xmlNodePtr ret; + + xmlSecAssert2(name != NULL, NULL); + + cur = parent; + while(cur != NULL) { + if((cur->type == XML_ELEMENT_NODE) && xmlSecCheckNodeName(cur, name, ns)) { + return(cur); + } + if(cur->children != NULL) { + ret = xmlSecFindNode(cur->children, name, ns); + if(ret != NULL) { + return(ret); + } + } + cur = cur->next; + } + return(NULL); +} + +/** + * xmlSecGetNodeNsHref: + * @cur: the pointer to node. + * + * Get's node's namespace href. + * + * Returns: node's namespace href. + */ +const xmlChar* +xmlSecGetNodeNsHref(const xmlNodePtr cur) { + xmlNsPtr ns; + + xmlSecAssert2(cur != NULL, NULL); + + /* do we have a namespace in the node? */ + if(cur->ns != NULL) { + return(cur->ns->href); + } + + /* search for default namespace */ + ns = xmlSearchNs(cur->doc, cur, NULL); + if(ns != NULL) { + return(ns->href); + } + + return(NULL); +} + +/** + * xmlSecCheckNodeName: + * @cur: the pointer to an XML node. + * @name: the name, + * @ns: the namespace href. + * + * Checks that the node has a given name and a given namespace href. + * + * Returns: 1 if the node matches or 0 otherwise. + */ +int +xmlSecCheckNodeName(const xmlNodePtr cur, const xmlChar *name, const xmlChar *ns) { + xmlSecAssert2(cur != NULL, 0); + + return(xmlStrEqual(cur->name, name) && + xmlStrEqual(xmlSecGetNodeNsHref(cur), ns)); +} + +/** + * xmlSecAddChild: + * @parent: the pointer to an XML node. + * @name: the new node name. + * @ns: the new node namespace. + * + * Adds a child to the node @parent with given @name and namespace @ns. + * + * Returns: pointer to the new node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecAddChild(xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur; + xmlNodePtr text; + + xmlSecAssert2(parent != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + if(parent->children == NULL) { + /* TODO: add indents */ + text = xmlNewText(xmlSecGetDefaultLineFeed()); + if(text == NULL) { + xmlSecXmlError("xmlNewText", NULL); + return(NULL); + } + xmlAddChild(parent, text); + } + + cur = xmlNewChild(parent, NULL, name, NULL); + if(cur == NULL) { + xmlSecXmlError("xmlNewChild", NULL); + return(NULL); + } + + /* namespaces support */ + if(ns != NULL) { + xmlNsPtr nsPtr; + + /* find namespace by href and check that its prefix is not overwritten */ + nsPtr = xmlSearchNsByHref(cur->doc, cur, ns); + if((nsPtr == NULL) || (xmlSearchNs(cur->doc, cur, nsPtr->prefix) != nsPtr)) { + nsPtr = xmlNewNs(cur, ns, NULL); + if(nsPtr == NULL) { + xmlSecXmlError("xmlNewNs", NULL); + return(NULL); + } + } + xmlSetNs(cur, nsPtr); + } + + /* TODO: add indents */ + text = xmlNewText(xmlSecGetDefaultLineFeed()); + if(text == NULL) { + xmlSecXmlError("xmlNewText", NULL); + return(NULL); + } + xmlAddChild(parent, text); + + return(cur); +} + +/** + * xmlSecAddChildNode: + * @parent: the pointer to an XML node. + * @child: the new node. + * + * Adds @child node to the @parent node. + * + * Returns: pointer to the new node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecAddChildNode(xmlNodePtr parent, xmlNodePtr child) { + xmlNodePtr text; + + xmlSecAssert2(parent != NULL, NULL); + xmlSecAssert2(child != NULL, NULL); + + if(parent->children == NULL) { + /* TODO: add indents */ + text = xmlNewText(xmlSecGetDefaultLineFeed()); + if(text == NULL) { + xmlSecXmlError("xmlNewText", NULL); + return(NULL); + } + xmlAddChild(parent, text); + } + + xmlAddChild(parent, child); + + /* TODO: add indents */ + text = xmlNewText(xmlSecGetDefaultLineFeed()); + if(text == NULL) { + xmlSecXmlError("xmlNewText", NULL); + return(NULL); + } + xmlAddChild(parent, text); + + return(child); +} + +/** + * xmlSecEnsureEmptyChild: + * @parent: the pointer to XML node. + * @name: the name. + * @ns: the namespace href (may be NULL). + * + * Searches a direct child of the @parent node having given name and + * namespace href. If not found then element node with given name / namespace + * is added. + * + * Returns: the pointer to the found or created node; or NULL if an error occurs. + */ +xmlNodePtr +xmlSecEnsureEmptyChild(xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur = NULL; + xmlNodePtr tmp; + + xmlSecAssert2(parent != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + /* try to find an empty node first */ + tmp = xmlSecFindNode(parent, name, ns); + while(tmp != NULL) { + cur = tmp; + if(xmlSecIsEmptyNode(cur) == 1) { + return(cur); + } + tmp = xmlSecFindSibling(cur->next, name, ns); + } + + /* if not found then either add next or add at the end */ + if(cur == NULL) { + cur = xmlSecAddChild(parent, name, ns); + } else if((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE)) { + cur = xmlSecAddNextSibling(cur->next, name, ns); + } else { + cur = xmlSecAddNextSibling(cur, name, ns); + } + if(cur == NULL) { + xmlSecInternalError2("xmlSecAddChild or xmlSecAddNextSibling", NULL, + "node=%s", xmlSecErrorsSafeString(name)); + return(NULL); + } + return(cur); +} + +/** + * xmlSecAddNextSibling + * @node: the pointer to an XML node. + * @name: the new node name. + * @ns: the new node namespace. + * + * Adds next sibling to the node @node with given @name and namespace @ns. + * + * Returns: pointer to the new node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecAddNextSibling(xmlNodePtr node, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur; + xmlNodePtr text; + + xmlSecAssert2(node != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + cur = xmlNewNode(NULL, name); + if(cur == NULL) { + xmlSecXmlError("xmlNewNode", NULL); + return(NULL); + } + xmlAddNextSibling(node, cur); + + /* namespaces support */ + if(ns != NULL) { + xmlNsPtr nsPtr; + + /* find namespace by href and check that its prefix is not overwritten */ + nsPtr = xmlSearchNsByHref(cur->doc, cur, ns); + if((nsPtr == NULL) || (xmlSearchNs(cur->doc, cur, nsPtr->prefix) != nsPtr)) { + nsPtr = xmlNewNs(cur, ns, NULL); + } + xmlSetNs(cur, nsPtr); + } + + /* TODO: add indents */ + text = xmlNewText(xmlSecGetDefaultLineFeed()); + if(text == NULL) { + xmlSecXmlError("xmlNewText", NULL); + return(NULL); + } + xmlAddNextSibling(node, text); + + return(cur); +} + +/** + * xmlSecAddPrevSibling + * @node: the pointer to an XML node. + * @name: the new node name. + * @ns: the new node namespace. + * + * Adds prev sibling to the node @node with given @name and namespace @ns. + * + * Returns: pointer to the new node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecAddPrevSibling(xmlNodePtr node, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur; + xmlNodePtr text; + + xmlSecAssert2(node != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + cur = xmlNewNode(NULL, name); + if(cur == NULL) { + xmlSecXmlError("xmlNewNode", NULL); + return(NULL); + } + xmlAddPrevSibling(node, cur); + + /* namespaces support */ + if(ns != NULL) { + xmlNsPtr nsPtr; + + /* find namespace by href and check that its prefix is not overwritten */ + nsPtr = xmlSearchNsByHref(cur->doc, cur, ns); + if((nsPtr == NULL) || (xmlSearchNs(cur->doc, cur, nsPtr->prefix) != nsPtr)) { + nsPtr = xmlNewNs(cur, ns, NULL); + } + xmlSetNs(cur, nsPtr); + } + + /* TODO: add indents */ + text = xmlNewText(xmlSecGetDefaultLineFeed()); + if(text == NULL) { + xmlSecXmlError("xmlNewText", NULL); + return(NULL); + } + xmlAddPrevSibling(node, text); + + return(cur); +} + +/** + * xmlSecGetNextElementNode: + * @cur: the pointer to an XML node. + * + * Seraches for the next element node. + * + * Returns: the pointer to next element node or NULL if it is not found. + */ +xmlNodePtr +xmlSecGetNextElementNode(xmlNodePtr cur) { + + while((cur != NULL) && (cur->type != XML_ELEMENT_NODE)) { + cur = cur->next; + } + return(cur); +} + +/** + * xmlSecReplaceNode: + * @node: the current node. + * @newNode: the new node. + * + * Swaps the @node and @newNode in the XML tree. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceNode(xmlNodePtr node, xmlNodePtr newNode) { + return xmlSecReplaceNodeAndReturn(node, newNode, NULL); +} + +/** + * xmlSecReplaceNodeAndReturn: + * @node: the current node. + * @newNode: the new node. + * @replaced: the replaced node, or release it if NULL is given + * + * Swaps the @node and @newNode in the XML tree. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceNodeAndReturn(xmlNodePtr node, xmlNodePtr newNode, xmlNodePtr* replaced) { + xmlNodePtr oldNode; + int restoreRoot = 0; + + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(newNode != NULL, -1); + + /* fix documents children if necessary first */ + if((node->doc != NULL) && (node->doc->children == node)) { + node->doc->children = node->next; + restoreRoot = 1; + } + if((newNode->doc != NULL) && (newNode->doc->children == newNode)) { + newNode->doc->children = newNode->next; + } + + oldNode = xmlReplaceNode(node, newNode); + if(oldNode == NULL) { + xmlSecXmlError("xmlReplaceNode", NULL); + return(-1); + } + + if(restoreRoot != 0) { + xmlDocSetRootElement(oldNode->doc, newNode); + } + + /* return the old node if requested */ + if(replaced != NULL) { + (*replaced) = oldNode; + } else { + xmlFreeNode(oldNode); + } + + return(0); +} + +/** + * xmlSecReplaceContent + * @node: the current node. + * @newNode: the new node. + * + * Swaps the content of @node and @newNode. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceContent(xmlNodePtr node, xmlNodePtr newNode) { + return xmlSecReplaceContentAndReturn(node, newNode, NULL); +} + +/** + * xmlSecReplaceContentAndReturn + * @node: the current node. + * @newNode: the new node. + * @replaced: the replaced nodes, or release them if NULL is given + * + * Swaps the content of @node and @newNode. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceContentAndReturn(xmlNodePtr node, xmlNodePtr newNode, xmlNodePtr *replaced) { + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(newNode != NULL, -1); + + /* return the old nodes if requested */ + if(replaced != NULL) { + xmlNodePtr cur, next, tail; + + (*replaced) = tail = NULL; + for(cur = node->children; (cur != NULL); cur = next) { + next = cur->next; + if((*replaced) != NULL) { + /* cur is unlinked in this function */ + xmlAddNextSibling(tail, cur); + tail = cur; + } else { + /* this is the first node, (*replaced) is the head */ + xmlUnlinkNode(cur); + (*replaced) = tail = cur; + } + } + } else { + /* just delete the content */ + xmlNodeSetContent(node, NULL); + } + + /* swap nodes */ + xmlUnlinkNode(newNode); + xmlAddChildList(node, newNode); + + return(0); +} + +/** + * xmlSecReplaceNodeBuffer: + * @node: the current node. + * @buffer: the XML data. + * @size: the XML data size. + * + * Swaps the @node and the parsed XML data from the @buffer in the XML tree. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceNodeBuffer(xmlNodePtr node, const xmlSecByte *buffer, xmlSecSize size) { + return xmlSecReplaceNodeBufferAndReturn(node, buffer, size, NULL); +} + +/** + * xmlSecReplaceNodeBufferAndReturn: + * @node: the current node. + * @buffer: the XML data. + * @size: the XML data size. + * @replaced: the replaced nodes, or release them if NULL is given + * + * Swaps the @node and the parsed XML data from the @buffer in the XML tree. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceNodeBufferAndReturn(xmlNodePtr node, const xmlSecByte *buffer, xmlSecSize size, xmlNodePtr *replaced) { + xmlNodePtr results = NULL; + xmlNodePtr next = NULL; + int ret; + + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(node->parent != NULL, -1); + + /* parse buffer in the context of node's parent (also see xmlSecParsePrepareCtxt): + * XML_PARSE_NONET to support c14n + * XML_PARSE_NODICT to avoid problems with moving nodes around + * XML_PARSE_HUGE to enable parsing of XML documents with large text nodes + */ + ret = xmlParseInNodeContext(node->parent, (const char*)buffer, size, + XML_PARSE_NONET | XML_PARSE_NODICT | XML_PARSE_HUGE, &results); + if(ret != XML_ERR_OK) { + xmlSecXmlError("xmlParseInNodeContext", NULL); + return(-1); + } + + /* add new nodes */ + while (results != NULL) { + next = results->next; + xmlAddPrevSibling(node, results); + results = next; + } + + /* remove old node */ + xmlUnlinkNode(node); + + /* return the old node if requested */ + if(replaced != NULL) { + (*replaced) = node; + } else { + xmlFreeNode(node); + } + + return(0); +} + +/** + * xmlSecNodeEncodeAndSetContent: + * @node: the pointer to an XML node. + * @buffer: the pointer to the node content. + * + * Encodes "special" characters in the @buffer and sets the result + * as the node content. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecNodeEncodeAndSetContent(xmlNodePtr node, const xmlChar * buffer) { + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(node->doc != NULL, -1); + + if(buffer != NULL) { + xmlChar * tmp; + tmp = xmlEncodeSpecialChars(node->doc, buffer); + if (tmp == NULL) { + xmlSecXmlError("xmlEncodeSpecialChars", NULL); + return(-1); + } + xmlNodeSetContent(node, tmp); + xmlFree(tmp); + } else { + xmlNodeSetContent(node, NULL); + } + return(0); +} + +/** + * xmlSecAddIDs: + * @doc: the pointer to an XML document. + * @cur: the pointer to an XML node. + * @ids: the pointer to a NULL terminated list of ID attributes. + * + * Walks thru all children of the @cur node and adds all attributes + * from the @ids list to the @doc document IDs attributes hash. + */ +void +xmlSecAddIDs(xmlDocPtr doc, xmlNodePtr cur, const xmlChar** ids) { + xmlNodePtr children = NULL; + + xmlSecAssert(doc != NULL); + xmlSecAssert(ids != NULL); + + if((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) { + xmlAttrPtr attr; + xmlAttrPtr tmp; + int i; + xmlChar* name; + + for(attr = cur->properties; attr != NULL; attr = attr->next) { + for(i = 0; ids[i] != NULL; ++i) { + if(xmlStrEqual(attr->name, ids[i])) { + name = xmlNodeListGetString(doc, attr->children, 1); + if(name != NULL) { + tmp = xmlGetID(doc, name); + if(tmp == NULL) { + xmlAddID(NULL, doc, name, attr); + } else if(tmp != attr) { + xmlSecInvalidStringDataError("id", name, "unique id (id already defined)", NULL); + } + xmlFree(name); + } + } + } + } + + children = cur->children; + } else if(cur == NULL) { + children = doc->children; + } + + while(children != NULL) { + if(children->type == XML_ELEMENT_NODE) { + xmlSecAddIDs(doc, children, ids); + } + children = children->next; + } +} + +/** + * xmlSecCreateTree: + * @rootNodeName: the root node name. + * @rootNodeNs: the root node namespace (optional). + * + * Creates a new XML tree with one root node @rootNodeName. + * + * Returns: pointer to the newly created tree or NULL if an error occurs. + */ +xmlDocPtr +xmlSecCreateTree(const xmlChar* rootNodeName, const xmlChar* rootNodeNs) { + xmlDocPtr doc; + xmlNodePtr root; + xmlNsPtr ns; + + xmlSecAssert2(rootNodeName != NULL, NULL); + + /* create doc */ + doc = xmlNewDoc(BAD_CAST "1.0"); + if(doc == NULL) { + xmlSecXmlError("xmlNewDoc", NULL); + return(NULL); + } + + /* create root node */ + root = xmlNewDocNode(doc, NULL, rootNodeName, NULL); + if(root == NULL) { + xmlSecXmlError2("xmlNewDocNode", NULL, + "node=%s", rootNodeName); + xmlFreeDoc(doc); + return(NULL); + } + xmlDocSetRootElement(doc, root); + + /* and set root node namespace */ + ns = xmlNewNs(root, rootNodeNs, NULL); + if(ns == NULL) { + xmlSecXmlError2("xmlNewNs", NULL, + "ns=%s", xmlSecErrorsSafeString(rootNodeNs)); + xmlFreeDoc(doc); + return(NULL); + } + xmlSetNs(root, ns); + + return(doc); +} + +/** + * xmlSecIsEmptyNode: + * @node: the node to check + * + * Checks whether the @node is empty (i.e. has only whitespaces children). + * + * Returns: 1 if @node is empty, 0 otherwise or a negative value if an error occurs. + */ +int +xmlSecIsEmptyNode(xmlNodePtr node) { + xmlChar* content; + int res; + + xmlSecAssert2(node != NULL, -1); + + if(xmlSecGetNextElementNode(node->children) != NULL) { + return(0); + } + + content = xmlNodeGetContent(node); + if(content == NULL) { + return(1); + } + + res = xmlSecIsEmptyString(content); + xmlFree(content); + return(res); +} + +/** + * xmlSecIsEmptyString: + * @str: the string to check + * + * Checks whether the @str is empty (i.e. has only whitespaces children). + * + * Returns: 1 if @str is empty, 0 otherwise or a negative value if an error occurs. + */ +int +xmlSecIsEmptyString(const xmlChar* str) { + xmlSecAssert2(str != NULL, -1); + + for( ;*str != '\0'; ++str) { + if(!isspace((int)(*str))) { + return(0); + } + } + return(1); +} + +/** + * xmlSecPrintXmlString: + * @fd: the file descriptor to write the XML string to + * @str: the string + * + * Encodes the @str (e.g. replaces '&' with '&') and writes it to @fd. + * + * Returns: he number of bytes transmitted or a negative value if an error occurs. + */ +int +xmlSecPrintXmlString(FILE * fd, const xmlChar * str) { + int res; + + if(str != NULL) { + xmlChar * encoded_str = NULL; + encoded_str = xmlEncodeSpecialChars(NULL, str); + if(encoded_str == NULL) { + xmlSecXmlError2("xmlEncodeSpecialChars", NULL, + "string=%s", xmlSecErrorsSafeString(str)); + return(-1); + } + + res = fprintf(fd, "%s", (const char*)encoded_str); + xmlFree(encoded_str); + } else { + res = fprintf(fd, "NULL"); + } + + if(res < 0) { + xmlSecIOError("fprintf", NULL, NULL); + return(-1); + } + return(res); +} + +/** + * xmlSecGetQName: + * @node: the context node. + * @href: the QName href (can be NULL). + * @local: the QName local part. + * + * Creates QName (prefix:local) from @href and @local in the context of the @node. + * Caller is responsible for freeing returned string with xmlFree. + * + * Returns: qname or NULL if an error occurs. + */ +xmlChar* +xmlSecGetQName(xmlNodePtr node, const xmlChar* href, const xmlChar* local) { + xmlChar* qname; + xmlNsPtr ns; + int ret; + + xmlSecAssert2(node != NULL, NULL); + xmlSecAssert2(local != NULL, NULL); + + /* we don't want to create namespace node ourselves because + * it might cause collisions */ + ns = xmlSearchNsByHref(node->doc, node, href); + if((ns == NULL) && (href != NULL)) { + xmlSecXmlError2("xmlSearchNsByHref", NULL, + "node=%s", xmlSecErrorsSafeString(node->name)); + return(NULL); + } + + if((ns != NULL) && (ns->prefix != NULL)) { + xmlSecSize len; + + len = xmlStrlen(local) + xmlStrlen(ns->prefix) + 4; + qname = (xmlChar *)xmlMalloc(len); + if(qname == NULL) { + xmlSecMallocError(len, NULL); + return(NULL); + } + + ret = xmlStrPrintf(qname, len, "%s:%s", ns->prefix, local); + if(ret < 0) { + xmlSecXmlError("xmlStrPrintf", NULL); + xmlFree(qname); + return(NULL); + } + } else { + qname = xmlStrdup(local); + if(qname == NULL) { + xmlSecStrdupError(local, NULL); + return(NULL); + } + } + + + return(qname); +} + + +/************************************************************************* + * + * QName <-> Integer mapping + * + ************************************************************************/ +/** + * xmlSecQName2IntegerGetInfo: + * @info: the qname<->integer mapping information. + * @intValue: the integer value. + * + * Maps integer @intValue to a QName prefix. + * + * Returns: the QName info that is mapped to @intValue or NULL if such value + * is not found. + */ +xmlSecQName2IntegerInfoConstPtr +xmlSecQName2IntegerGetInfo(xmlSecQName2IntegerInfoConstPtr info, int intValue) { + unsigned int ii; + + xmlSecAssert2(info != NULL, NULL); + + for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) { + if(info[ii].intValue == intValue) { + return(&info[ii]); + } + } + + return(NULL); +} + +/** + * xmlSecQName2IntegerGetInteger: + * @info: the qname<->integer mapping information. + * @qnameHref: the qname href value. + * @qnameLocalPart: the qname local part value. + * @intValue: the pointer to result integer value. + * + * Maps qname qname to an integer and returns it in @intValue. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerGetInteger(xmlSecQName2IntegerInfoConstPtr info, + const xmlChar* qnameHref, const xmlChar* qnameLocalPart, + int* intValue) { + unsigned int ii; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(qnameLocalPart != NULL, -1); + xmlSecAssert2(intValue != NULL, -1); + + for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) { + if(xmlStrEqual(info[ii].qnameLocalPart, qnameLocalPart) && + xmlStrEqual(info[ii].qnameHref, qnameHref)) { + (*intValue) = info[ii].intValue; + return(0); + } + } + + return(-1); +} + +/** + * xmlSecQName2IntegerGetIntegerFromString: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @qname: the qname string. + * @intValue: the pointer to result integer value. + * + * Converts @qname into integer in context of @node. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerGetIntegerFromString(xmlSecQName2IntegerInfoConstPtr info, + xmlNodePtr node, const xmlChar* qname, + int* intValue) { + const xmlChar* qnameLocalPart = NULL; + xmlChar* qnamePrefix = NULL; + const xmlChar* qnameHref; + xmlNsPtr ns; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(qname != NULL, -1); + xmlSecAssert2(intValue != NULL, -1); + + qnameLocalPart = xmlStrchr(qname, ':'); + if(qnameLocalPart != NULL) { + qnamePrefix = xmlStrndup(qname, (int)(qnameLocalPart - qname)); + if(qnamePrefix == NULL) { + xmlSecStrdupError(qname, NULL); + return(-1); + } + qnameLocalPart++; + } else { + qnamePrefix = NULL; + qnameLocalPart = qname; + } + + /* search namespace href */ + ns = xmlSearchNs(node->doc, node, qnamePrefix); + if((ns == NULL) && (qnamePrefix != NULL)) { + xmlSecXmlError2("xmlSearchNs", NULL, + "node=%s", xmlSecErrorsSafeString(node->name)); + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(-1); + } + qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL; + + /* and finally search for integer */ + ret = xmlSecQName2IntegerGetInteger(info, qnameHref, qnameLocalPart, intValue); + if(ret < 0) { + xmlSecInternalError4("xmlSecQName2IntegerGetInteger", NULL, + "node=%s,qnameLocalPart=%s,qnameHref=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(qnameLocalPart), + xmlSecErrorsSafeString(qnameHref)); + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(-1); + } + + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(0); +} + + +/** + * xmlSecQName2IntegerGetStringFromInteger: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @intValue: the integer value. + * + * Creates qname string for @intValue in context of given @node. Caller + * is responsible for freeing returned string with @xmlFree. + * + * Returns: pointer to newly allocated string on success or NULL if an error occurs, + */ +xmlChar* +xmlSecQName2IntegerGetStringFromInteger(xmlSecQName2IntegerInfoConstPtr info, + xmlNodePtr node, int intValue) { + xmlSecQName2IntegerInfoConstPtr qnameInfo; + + xmlSecAssert2(info != NULL, NULL); + xmlSecAssert2(node != NULL, NULL); + + qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue); + if(qnameInfo == NULL) { + xmlSecInternalError3("xmlSecQName2IntegerGetInfo", NULL, + "node=%s,intValue=%d", + xmlSecErrorsSafeString(node->name), + intValue); + return(NULL); + } + + return (xmlSecGetQName(node, qnameInfo->qnameHref, qnameInfo->qnameLocalPart)); +} + +/** + * xmlSecQName2IntegerNodeRead: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @intValue: the pointer to result integer value. + * + * Reads the content of @node and converts it to an integer using mapping + * from @info. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerNodeRead(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, int* intValue) { + xmlChar* content = NULL; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(intValue != NULL, -1); + + content = xmlNodeGetContent(node); + if(content == NULL) { + xmlSecXmlError2("xmlNodeGetContent", NULL, + "node=%s", xmlSecErrorsSafeString(node->name)); + return(-1); + } + /* todo: trim content? */ + + ret = xmlSecQName2IntegerGetIntegerFromString(info, node, content, intValue); + if(ret < 0) { + xmlSecInternalError3("xmlSecQName2IntegerGetIntegerFromString", NULL, + "node=%s,value=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(content)); + xmlFree(content); + return(-1); + } + + xmlFree(content); + return(0); +} + +/** + * xmlSecQName2IntegerNodeWrite: + * @info: the qname<->integer mapping information. + * @node: the parent node. + * @nodeName: the child node name. + * @nodeNs: the child node namespace. + * @intValue: the integer value. + * + * Creates new child node in @node and sets its value to @intValue. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerNodeWrite(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, + const xmlChar* nodeName, const xmlChar* nodeNs, int intValue) { + xmlNodePtr cur; + xmlChar* qname = NULL; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(nodeName != NULL, -1); + + /* find and build qname */ + qname = xmlSecQName2IntegerGetStringFromInteger(info, node, intValue); + if(qname == NULL) { + xmlSecInternalError3("xmlSecQName2IntegerGetStringFromInteger", NULL, + "node=%s,intValue=%d", + xmlSecErrorsSafeString(node->name), + intValue); + return(-1); + } + + cur = xmlSecAddChild(node, nodeName, nodeNs); + if(cur == NULL) { + xmlSecInternalError3("xmlSecAddChild", NULL, + "node=%s,intValue=%d", + xmlSecErrorsSafeString(nodeName), + intValue); + xmlFree(qname); + return(-1); + } + + xmlNodeSetContent(cur, qname); + xmlFree(qname); + return(0); +} + +/** + * xmlSecQName2IntegerAttributeRead: + * @info: the qname<->integer mapping information. + * @node: the element node. + * @attrName: the attribute name. + * @intValue: the pointer to result integer value. + * + * Gets the value of @attrName atrtibute from @node and converts it to integer + * according to @info. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerAttributeRead(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, + const xmlChar* attrName, int* intValue) { + xmlChar* attrValue; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(attrName != NULL, -1); + xmlSecAssert2(intValue != NULL, -1); + + attrValue = xmlGetProp(node, attrName); + if(attrValue == NULL) { + xmlSecXmlError2("xmlGetProp", NULL, + "node=%s", xmlSecErrorsSafeString(node->name)); + return(-1); + } + /* todo: trim value? */ + + ret = xmlSecQName2IntegerGetIntegerFromString(info, node, attrValue, intValue); + if(ret < 0) { + xmlSecInternalError4("xmlSecQName2IntegerGetIntegerFromString", NULL, + "node=%s,attrName=%s,attrValue=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(attrName), + xmlSecErrorsSafeString(attrValue)); + xmlFree(attrValue); + return(-1); + } + + xmlFree(attrValue); + return(0); +} + +/** + * xmlSecQName2IntegerAttributeWrite: + * @info: the qname<->integer mapping information. + * @node: the parent node. + * @attrName: the name of attribute. + * @intValue: the integer value. + * + * Converts @intValue to a qname and sets it to the value of + * attribute @attrName in @node. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerAttributeWrite(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, + const xmlChar* attrName, int intValue) { + xmlChar* qname; + xmlAttrPtr attr; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(attrName != NULL, -1); + + /* find and build qname */ + qname = xmlSecQName2IntegerGetStringFromInteger(info, node, intValue); + if(qname == NULL) { + xmlSecInternalError4("xmlSecQName2IntegerGetStringFromInteger", NULL, + "node=%s,attrName=%s,intValue=%d", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(attrName), + intValue); + return(-1); + } + + attr = xmlSetProp(node, attrName, qname); + if(attr == NULL) { + xmlSecInternalError4("xmlSetProp", NULL, + "node=%s,attrName=%s,intValue=%d", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(attrName), + intValue); + xmlFree(qname); + return(-1); + } + + xmlFree(qname); + return(0); +} + +/** + * xmlSecQName2IntegerDebugDump: + * @info: the qname<->integer mapping information. + * @intValue: the integer value. + * @name: the value name to print. + * @output: the pointer to output FILE. + * + * Prints @intValue into @output. + */ +void +xmlSecQName2IntegerDebugDump(xmlSecQName2IntegerInfoConstPtr info, int intValue, + const xmlChar* name, FILE* output) { + xmlSecQName2IntegerInfoConstPtr qnameInfo; + + xmlSecAssert(info != NULL); + xmlSecAssert(name != NULL); + xmlSecAssert(output != NULL); + + qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue); + if(qnameInfo != NULL) { + fprintf(output, "== %s: %d (name=\"%s\", href=\"%s\")\n", name, intValue, + (qnameInfo->qnameLocalPart) ? qnameInfo->qnameLocalPart : BAD_CAST NULL, + (qnameInfo->qnameHref) ? qnameInfo->qnameHref : BAD_CAST NULL); + } +} + +/** + * xmlSecQName2IntegerDebugXmlDump: + * @info: the qname<->integer mapping information. + * @intValue: the integer value. + * @name: the value name to print. + * @output: the pointer to output FILE. + * + * Prints @intValue into @output in XML format. + */ +void +xmlSecQName2IntegerDebugXmlDump(xmlSecQName2IntegerInfoConstPtr info, int intValue, + const xmlChar* name, FILE* output) { + xmlSecQName2IntegerInfoConstPtr qnameInfo; + + xmlSecAssert(info != NULL); + xmlSecAssert(name != NULL); + xmlSecAssert(output != NULL); + + qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue); + if(qnameInfo != NULL) { + fprintf(output, "<%s value=\"%d\" href=\"%s\">%s<%s>\n", name, intValue, + (qnameInfo->qnameHref) ? qnameInfo->qnameHref : BAD_CAST NULL, + (qnameInfo->qnameLocalPart) ? qnameInfo->qnameLocalPart : BAD_CAST NULL, + name); + } +} + + +/************************************************************************* + * + * QName <-> Bits mask mapping + * + ************************************************************************/ +/** + * xmlSecQName2BitMaskGetInfo: + * @info: the qname<->bit mask mapping information. + * @mask: the bit mask. + * + * Converts @mask to qname. + * + * Returns: pointer to the qname info for @mask or NULL if mask is unknown. + */ +xmlSecQName2BitMaskInfoConstPtr +xmlSecQName2BitMaskGetInfo(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask) { + unsigned int ii; + + xmlSecAssert2(info != NULL, NULL); + + for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) { + xmlSecAssert2(info[ii].mask != 0, NULL); + if(info[ii].mask == mask) { + return(&info[ii]); + } + } + + return(NULL); +} + +/** + * xmlSecQName2BitMaskGetBitMask: + * @info: the qname<->bit mask mapping information. + * @qnameHref: the qname Href value. + * @qnameLocalPart: the qname LocalPart value. + * @mask: the pointer to result mask. + * + * Converts @qnameLocalPart to @mask. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2BitMaskGetBitMask(xmlSecQName2BitMaskInfoConstPtr info, + const xmlChar* qnameHref, const xmlChar* qnameLocalPart, + xmlSecBitMask* mask) { + unsigned int ii; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(qnameLocalPart != NULL, -1); + xmlSecAssert2(mask != NULL, -1); + + for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) { + xmlSecAssert2(info[ii].mask != 0, -1); + if(xmlStrEqual(info[ii].qnameLocalPart, qnameLocalPart) && + xmlStrEqual(info[ii].qnameHref, qnameHref)) { + + (*mask) = info[ii].mask; + return(0); + } + } + + return(-1); +} + +/** + * xmlSecQName2BitMaskGetBitMaskFromString: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @qname: the qname string. + * @mask: the pointer to result msk value. + * + * Converts @qname into integer in context of @node. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2BitMaskGetBitMaskFromString(xmlSecQName2BitMaskInfoConstPtr info, + xmlNodePtr node, const xmlChar* qname, + xmlSecBitMask* mask) { + const xmlChar* qnameLocalPart = NULL; + xmlChar* qnamePrefix = NULL; + const xmlChar* qnameHref; + xmlNsPtr ns; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(qname != NULL, -1); + xmlSecAssert2(mask != NULL, -1); + + qnameLocalPart = xmlStrchr(qname, ':'); + if(qnameLocalPart != NULL) { + qnamePrefix = xmlStrndup(qname, (int)(qnameLocalPart - qname)); + if(qnamePrefix == NULL) { + xmlSecStrdupError(qname, NULL); + return(-1); + } + qnameLocalPart++; + } else { + qnamePrefix = NULL; + qnameLocalPart = qname; + } + + /* search namespace href */ + ns = xmlSearchNs(node->doc, node, qnamePrefix); + if((ns == NULL) && (qnamePrefix != NULL)) { + xmlSecXmlError2("xmlSearchNs", NULL, + "node=%s", xmlSecErrorsSafeString(node->name)); + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(-1); + } + qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL; + + /* and finally search for integer */ + ret = xmlSecQName2BitMaskGetBitMask(info, qnameHref, qnameLocalPart, mask); + if(ret < 0) { + xmlSecInternalError4("xmlSecQName2BitMaskGetBitMask", NULL, + "node=%s,qnameLocalPart=%s,qnameHref=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(qnameLocalPart), + xmlSecErrorsSafeString(qnameHref)); + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(-1); + } + + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(0); +} + + +/** + * xmlSecQName2BitMaskGetStringFromBitMask: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @mask: the mask. + * + * Creates qname string for @mask in context of given @node. Caller + * is responsible for freeing returned string with @xmlFree. + * + * Returns: pointer to newly allocated string on success or NULL if an error occurs, + */ +xmlChar* +xmlSecQName2BitMaskGetStringFromBitMask(xmlSecQName2BitMaskInfoConstPtr info, + xmlNodePtr node, xmlSecBitMask mask) { + xmlSecQName2BitMaskInfoConstPtr qnameInfo; + + xmlSecAssert2(info != NULL, NULL); + xmlSecAssert2(node != NULL, NULL); + + qnameInfo = xmlSecQName2BitMaskGetInfo(info, mask); + if(qnameInfo == NULL) { + xmlSecInternalError3("xmlSecQName2BitMaskGetInfo", NULL, + "node=%s,mask=%d", + xmlSecErrorsSafeString(node->name), + mask); + return(NULL); + } + + return(xmlSecGetQName(node, qnameInfo->qnameHref, qnameInfo->qnameLocalPart)); +} + +/** + * xmlSecQName2BitMaskNodesRead: + * @info: the qname<->bit mask mapping information. + * @node: the start. + * @nodeName: the mask nodes name. + * @nodeNs: the mask nodes namespace. + * @stopOnUnknown: if this flag is set then function exits if unknown + * value was found. + * @mask: the pointer to result mask. + * + * Reads <@nodeNs:@nodeName> elements and puts the result bit mask + * into @mask. When function exits, @node points to the first element node + * after all the <@nodeNs:@nodeName> elements. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2BitMaskNodesRead(xmlSecQName2BitMaskInfoConstPtr info, xmlNodePtr* node, + const xmlChar* nodeName, const xmlChar* nodeNs, + int stopOnUnknown, xmlSecBitMask* mask) { + xmlNodePtr cur; + xmlChar* content; + xmlSecBitMask tmp; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(mask != NULL, -1); + + (*mask) = 0; + cur = (*node); + while((cur != NULL) && (xmlSecCheckNodeName(cur, nodeName, nodeNs))) { + content = xmlNodeGetContent(cur); + if(content == NULL) { + xmlSecXmlError2("xmlNodeGetContent", NULL, + "node=%s", xmlSecErrorsSafeString(cur->name)); + return(-1); + } + + ret = xmlSecQName2BitMaskGetBitMaskFromString(info, cur, content, &tmp); + if(ret < 0) { + xmlSecInternalError2("xmlSecQName2BitMaskGetBitMaskFromString", NULL, + "value=%s", xmlSecErrorsSafeString(content)); + xmlFree(content); + return(-1); + } + xmlFree(content); + + if((stopOnUnknown != 0) && (tmp == 0)) { + /* todo: better error */ + xmlSecInternalError2("xmlSecQName2BitMaskGetBitMaskFromString", NULL, + "value=%s", xmlSecErrorsSafeString(content)); + return(-1); + } + + (*mask) |= tmp; + cur = xmlSecGetNextElementNode(cur->next); + } + + (*node) = cur; + return(0); +} + +/** + * xmlSecQName2BitMaskNodesWrite: + * @info: the qname<->bit mask mapping information. + * @node: the parent element for mask nodes. + * @nodeName: the mask nodes name. + * @nodeNs: the mask nodes namespace. + * @mask: the bit mask. + * + * Writes <@nodeNs:@nodeName> elemnts with values from @mask to @node. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2BitMaskNodesWrite(xmlSecQName2BitMaskInfoConstPtr info, xmlNodePtr node, + const xmlChar* nodeName, const xmlChar* nodeNs, + xmlSecBitMask mask) { + unsigned int ii; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(nodeName != NULL, -1); + + for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) { + xmlSecAssert2(info[ii].mask != 0, -1); + + if((mask & info[ii].mask) != 0) { + xmlNodePtr cur; + xmlChar* qname; + + qname = xmlSecGetQName(node, info[ii].qnameHref, info[ii].qnameLocalPart); + if(qname == NULL) { + xmlSecXmlError2("xmlSecGetQName", NULL, + "node=%s", xmlSecErrorsSafeString(nodeName)); + return(-1); + } + + cur = xmlSecAddChild(node, nodeName, nodeNs); + if(cur == NULL) { + xmlSecXmlError2("xmlSecAddChild", NULL, + "node=%s", xmlSecErrorsSafeString(nodeName)); + xmlFree(qname); + return(-1); + } + + xmlNodeSetContent(cur, qname); + xmlFree(qname); + } + } + return(0); +} + +/** + * xmlSecQName2BitMaskDebugDump: + * @info: the qname<->bit mask mapping information. + * @mask: the bit mask. + * @name: the value name to print. + * @output: the pointer to output FILE. + * + * Prints debug information about @mask to @output. + */ +void +xmlSecQName2BitMaskDebugDump(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask, + const xmlChar* name, FILE* output) { + unsigned int ii; + + xmlSecAssert(info != NULL); + xmlSecAssert(name != NULL); + xmlSecAssert(output != NULL); + + if(mask == 0) { + return; + } + + fprintf(output, "== %s (0x%08x): ", name, mask); + for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) { + xmlSecAssert(info[ii].mask != 0); + + if((mask & info[ii].mask) != 0) { + fprintf(output, "name=\"%s\" (href=\"%s\"),", info[ii].qnameLocalPart, info[ii].qnameHref); + } + } + fprintf(output, "\n"); +} + +/** + * xmlSecQName2BitMaskDebugXmlDump: + * @info: the qname<->bit mask mapping information. + * @mask: the bit mask. + * @name: the value name to print. + * @output: the pointer to output FILE. + * + * Prints debug information about @mask to @output in XML format. + */ +void +xmlSecQName2BitMaskDebugXmlDump(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask, + const xmlChar* name, FILE* output) { + unsigned int ii; + + xmlSecAssert(info != NULL); + xmlSecAssert(name != NULL); + xmlSecAssert(output != NULL); + + if(mask == 0) { + return; + } + + fprintf(output, "<%sList>\n", name); + for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) { + xmlSecAssert(info[ii].mask != 0); + + if((mask & info[ii].mask) != 0) { + fprintf(output, "<%s href=\"%s\">%s\n", name, + info[ii].qnameHref, info[ii].qnameLocalPart, name); + } + } + fprintf(output, "\n", name); +} + +/************************************************************************* + * + * Windows string conversions + * + ************************************************************************/ +#ifdef WIN32 + +/** + * xmlSecWin32ConvertUtf8ToUnicode: + * @str: the string to convert. + * + * Converts input string from UTF8 to Unicode. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +LPWSTR +xmlSecWin32ConvertUtf8ToUnicode(const xmlChar* str) { + LPWSTR res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + /* call MultiByteToWideChar first to get the buffer size */ + ret = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)str, -1, NULL, 0); + if(ret <= 0) { + return(NULL); + } + len = ret + 1; + + /* allocate buffer */ + res = (LPWSTR)xmlMalloc(sizeof(WCHAR) * len); + if(res == NULL) { + xmlSecMallocError(sizeof(WCHAR) * len, NULL); + return(NULL); + } + + /* convert */ + ret = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)str, -1, res, len); + if(ret <= 0) { + xmlFree(res); + return(NULL); + } + + /* done */ + return(res); +} + +/** + * xmlSecWin32ConvertUnicodeToUtf8: + * @str: the string to convert. + * + * Converts input string from Unicode to UTF8. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +xmlChar* +xmlSecWin32ConvertUnicodeToUtf8(LPCWSTR str) { + xmlChar * res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + /* call WideCharToMultiByte first to get the buffer size */ + ret = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + if(ret <= 0) { + return(NULL); + } + len = ret + 1; + + /* allocate buffer */ + res = (xmlChar*)xmlMalloc(sizeof(xmlChar) * len); + if(res == NULL) { + xmlSecMallocError(sizeof(xmlChar) * len, NULL); + return(NULL); + } + + /* convert */ + ret = WideCharToMultiByte(CP_UTF8, 0, str, -1, (LPSTR)res, len, NULL, NULL); + if(ret <= 0) { + xmlFree(res); + return(NULL); + } + + /* done */ + return(res); +} + +/** + * xmlSecWin32ConvertLocaleToUnicode: + * @str: the string to convert. + * + * Converts input string from current system locale to Unicode. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +LPWSTR +xmlSecWin32ConvertLocaleToUnicode(const char* str) { + LPWSTR res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + /* call MultiByteToWideChar first to get the buffer size */ + ret = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + if(ret <= 0) { + return(NULL); + } + len = ret; + + /* allocate buffer */ + res = (LPWSTR)xmlMalloc(sizeof(WCHAR) * len); + if(res == NULL) { + xmlSecMallocError(sizeof(WCHAR) * len, NULL); + return(NULL); + } + + /* convert */ + ret = MultiByteToWideChar(CP_ACP, 0, str, -1, res, len); + if(ret <= 0) { + xmlFree(res); + return(NULL); + } + + /* done */ + return(res); +} + +/** + * xmlSecWin32ConvertLocaleToUtf8: + * @str: the string to convert. + * + * Converts input string from locale to UTF8. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +xmlChar* +xmlSecWin32ConvertLocaleToUtf8(const char * str) { + LPWSTR strW = NULL; + xmlChar * res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + strW = xmlSecWin32ConvertLocaleToUnicode(str); + if(strW == NULL) { + return(NULL); + } + + /* call WideCharToMultiByte first to get the buffer size */ + ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL); + if(ret <= 0) { + xmlFree(strW); + return(NULL); + } + len = ret + 1; + + /* allocate buffer */ + res = (xmlChar*)xmlMalloc(sizeof(xmlChar) * len); + if(res == NULL) { + xmlSecMallocError(sizeof(xmlChar) * len, NULL); + xmlFree(strW); + return(NULL); + } + + /* convert */ + ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, (LPSTR)res, len, NULL, NULL); + if(ret <= 0) { + xmlFree(strW); + xmlFree(res); + return(NULL); + } + + /* done */ + xmlFree(strW); + return(res); +} + +/** + * xmlSecWin32ConvertUtf8ToLocale: + * @str: the string to convert. + * + * Converts input string from UTF8 to locale. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +char * +xmlSecWin32ConvertUtf8ToLocale(const xmlChar* str) { + LPWSTR strW = NULL; + char * res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + strW = xmlSecWin32ConvertUtf8ToUnicode(str); + if(strW == NULL) { + return(NULL); + } + + /* call WideCharToMultiByte first to get the buffer size */ + ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL); + if(ret <= 0) { + xmlFree(strW); + return(NULL); + } + len = ret + 1; + + /* allocate buffer */ + res = (char*)xmlMalloc(sizeof(char) * len); + if(res == NULL) { + xmlSecMallocError(sizeof(char) * len, NULL); + xmlFree(strW); + return(NULL); + } + + /* convert */ + ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, res, len, NULL, NULL); + if(ret <= 0) { + xmlFree(strW); + xmlFree(res); + return(NULL); + } + + /* done */ + xmlFree(strW); + return(res); +} + +/** + * xmlSecWin32ConvertTstrToUtf8: + * @str: the string to convert. + * + * Converts input string from TSTR (locale or Unicode) to UTF8. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +xmlChar* +xmlSecWin32ConvertTstrToUtf8(LPCTSTR str) { +#ifdef UNICODE + return xmlSecWin32ConvertUnicodeToUtf8(str); +#else /* UNICODE */ + return xmlSecWin32ConvertLocaleToUtf8(str); +#endif /* UNICODE */ +} + +/** + * xmlSecWin32ConvertUtf8ToTstr: + * @str: the string to convert. + * + * Converts input string from UTF8 to TSTR (locale or Unicode). + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +LPTSTR +xmlSecWin32ConvertUtf8ToTstr(const xmlChar* str) { +#ifdef UNICODE + return xmlSecWin32ConvertUtf8ToUnicode(str); +#else /* UNICODE */ + return xmlSecWin32ConvertUtf8ToLocale(str); +#endif /* UNICODE */ +} + +#endif /* WIN32 */ + + + diff --git a/experimental/facho-wasm/xmlsec-wasm/build_libxml2.sh b/experimental/facho-wasm/xmlsec-wasm/build_libxml2.sh index d5743b7..fa6fb36 100644 --- a/experimental/facho-wasm/xmlsec-wasm/build_libxml2.sh +++ b/experimental/facho-wasm/xmlsec-wasm/build_libxml2.sh @@ -6,14 +6,16 @@ tar xf libxml2-${LIBXML2_VERSION}.tar.gz mv libxml2-${LIBXML2_VERSION} libxml2 -cd libxml2 +pushd libxml2 wasiconfigure ./configure --enable-static --without-http --without-ftp --without-modules --without-python --without-zlib --without-lzma --without-threads --host=x86_64 wasimake make clean wasimake make -j4 -mkdir -p ../vendor/libxml2/lib -mkdir -p ../vendor/libxml2/include -cp -r include/libxml2 ../vendor/libxml2/include -cp -r .libs/libxml2.a ../vendor/libxml2/lib +popd + +mkdir -p vendor/libxml2/lib +mkdir -p vendor/libxml2/include +cp -r libxml2/include/libxml2 vendor/libxml2/include +cp -r libxml2/.libs/libxml2.a vendor/libxml2/lib