diff options
Diffstat (limited to 'libdigidoc/DigiDocConvert.c')
-rw-r--r-- | libdigidoc/DigiDocConvert.c | 1373 |
1 files changed, 1373 insertions, 0 deletions
diff --git a/libdigidoc/DigiDocConvert.c b/libdigidoc/DigiDocConvert.c new file mode 100644 index 0000000..d81b070 --- /dev/null +++ b/libdigidoc/DigiDocConvert.c @@ -0,0 +1,1373 @@ +//================================================== +// FILE: DigiDocEnc.c +// PROJECT: Digi Doc Encryption +// DESCRIPTION: DigiDoc character conversion routines +// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia +//================================================== +// Copyright (C) AS Sertifitseerimiskeskus +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// GNU Lesser General Public Licence is available at +// http://www.gnu.org/copyleft/lesser.html +//==========< HISTORY >============================= +// 22.09.2004 Veiko Sinivee +// Creation +//================================================== + +#include <libdigidoc/DigiDocDebug.h> +#include <libdigidoc/DigiDocConvert.h> +#include <libdigidoc/DigiDocError.h> +#include <libdigidoc/DigiDocMem.h> +#include <libdigidoc/DigiDocGen.h> + +#ifdef WIN32 + #include <windows.h> +#endif +#include <libxml/globals.h> +#include <libxml/xmlerror.h> +#include <libxml/parser.h> +#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */ +#include <libxml/tree.h> +#include <libxml/debugXML.h> +#include <libxml/xmlmemory.h> +#include <libxml/c14n.h> +#include <ctype.h> +#include <memory.h> + + + +//==========< general fucntions >============ + +//-------------------------------------------------- +// Helper function that converts ISO Latin1 to UTF8 +// ascii - input data in ISO Latin1 +// utf8out - output buffer for UTF8 text +// outlen - output buffer length +// returns output buffer +//-------------------------------------------------- +EXP_OPTION char* ascii2utf8(const char* ascii, char* utf8out, int* outlen) +{ + int inlen = strlen(ascii); + memset(utf8out, 0, *outlen); + isolat1ToUTF8((unsigned char*)utf8out, outlen, (const unsigned char*)ascii, &inlen); + return utf8out; +} + +//-------------------------------------------------- +// Helper function that converts UTF8 to ISO Latin1 +// utf8in - input data in UTF8 +// asciiout - output buffer for ISO Latin1 text +// outlen - output buffer length +// returns output buffer +//-------------------------------------------------- +EXP_OPTION char* utf82ascii(const char* utf8in, char* asciiout, int* outlen) +{ + int inlen = strlen(utf8in); + memset(asciiout, 0, *outlen); + UTF8Toisolat1((unsigned char*)asciiout, outlen, (const unsigned char*)utf8in, &inlen); + return asciiout; +} + +int hex2char(char c) +{ + static char unidigits[] = "0123456789ABCDEF"; + unsigned int i, k = 0; + for(i = 0; i < sizeof(unidigits); i++) { + if(unidigits[i] == c) { + k = i; + break; + } + } + return k; +} + + +struct u2w { + long uni; + unsigned char cp1252; // cp 1252 charset + unsigned char cp1257; // baltic charset + unsigned char utf8_1; // UTF8 1. byte + unsigned char utf8_2; // UTF8 2. byte +}; + +struct u2w uni2cp1252 [] = { + { 8364, 128, 0, 0, 0 }, // euro sign + { 8218, 130, 0, 0, 0 }, // SINGLE LOW-9 QUOTATION MARK + { 402, 131, 0, 0, 0 }, // LATIN SMALL LETTER F WITH HOOK + { 8222, 132, 0, 0, 0 }, // DOUBLE LOW-9 QUOTATION MARK + { 8230, 133, 0, 0, 0 }, // HORIZONTAL ELLIPSIS + { 8224, 134, 0, 0, 0 }, // DAGGER + { 8225, 135, 0, 0, 0 }, // DOUBLE DAGGER + { 710, 136, 0, 0, 0 }, // MODIFIER LETTER CIRCUMFLEX ACCENT + { 8240, 137, 0, 0, 0 }, // PER MILLE SIGN + { 352, 138, 208, 197, 160 }, // LATIN CAPITAL LETTER S WITH CARON + { 8249, 139, 0, 0, 0 }, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + { 338, 140, 0, 0, 0 }, // LATIN CAPITAL LIGATURE OE + { 381, 142, 222, 197, 189 }, // LATIN CAPITAL LETTER Z WITH CARON + { 8216, 145, 0, 0, 0 }, // LEFT SINGLE QUOTATION MARK + { 8217, 146, 0, 0, 0 }, // RIGHT SINGLE QUOTATION MARK + { 8220, 147, 0, 0, 0 }, // LEFT DOUBLE QUOTATION MARK + { 8221, 148, 0, 0, 0 }, // RIGHT DOUBLE QUOTATION MARK + { 8226, 149, 0, 0, 0 }, // BULLET + { 8211, 150, 0, 0, 0 }, // EN DASH + { 8212, 151, 0, 0, 0 }, // EM DASH + { 732, 152, 0, 0, 0 }, // SMALL TILDE + { 8482, 153, 0, 0, 0 }, // TRADE MARK SIGN + { 353, 154, 240, 197, 161 }, // LATIN SMALL LETTER S WITH CARON + { 8250, 155, 0, 0, 0 }, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + { 339, 156, 0, 0, 0 }, // LATIN SMALL LIGATURE OE + { 382, 158, 254, 197, 190 }, // LATIN SMALL LETTER Z WITH CARON + { 376, 159, 0, 0, 0 }, // LATIN CAPITAL LETTER Y WITH DIAERESIS + { 196, 196, 196, 195, 132}, // Capital A with umlaut + { 214, 214, 214, 195, 150}, // Calital O with umlaut + { 220, 220, 220, 195, 156}, // Capital U with umlaut + { 213, 213, 213, 195, 149}, // Capital O with tilde + { 228, 228, 228, 195, 164}, // small a with umlaut + { 246, 246, 246, 195, 132}, // small o with umlaut + { 245, 245, 245, 195, 181}, // small o with tilde + { 252, 252, 252, 195, 188}, // small u with umlaut + + { 0, 0, 0, 0, 0 } // table end marker +}; + +int isUmlaut(unsigned char c) +{ + int i; + for(i = 0; uni2cp1252[i].uni; i++) { + if(uni2cp1252[i].cp1252 == c) { + return 1; + } + } + return 0; +} + +int hasUmlauts(const char* str) +{ + int i; + for(i = 0; str[i]; i++) { + if(isUmlaut((unsigned char)str[i])) + return 1; + } + return 0; +} + +int uni2char(long c) +{ + int i, k = 0x20; // use space for all undisplayable unicode chars + for(i = 0; uni2cp1252[i].uni; i++) { + if(uni2cp1252[i].uni == c) { + if(uni2cp1252[i].cp1257) + k = uni2cp1252[i].cp1257; + else + k = uni2cp1252[i].cp1252; + break; + } + } + return k; +} + +int uni2utf8(long c, int utfidx) +{ + int i, k = 0x20; // use space for all undisplayable unicode chars + for(i = 0; uni2cp1252[i].uni; i++) { + if(uni2cp1252[i].uni == c) { + if(uni2cp1252[i].utf8_1) { + if(utfidx) + k = uni2cp1252[i].utf8_2; + else + k = uni2cp1252[i].utf8_1; + } + else + k = uni2cp1252[i].cp1252; + break; + } + } + return k; +} + + +EXP_OPTION void unicode2ascii(const char* uni, char* dest) +{ + int len, i, j, k; + long c; + + RETURN_VOID_IF_NULL(uni); + RETURN_VOID_IF_NULL(dest); + + len = strlen(uni); + memset(dest, 0, len+1); + for(i = j = 0; i < len; i++) { + if(uni[i] == '\\' && uni[i+1] == 'x') { + if(uni[i+2] == '0' && uni[i+3] == '0') { + if(uni[i+4] >= 'A' && uni[i+4] <= 'Z') { // simple char in form \x00A + dest[j] = (unsigned char)uni[i+4]; + i += 4; + j++; + continue; + } else { + i += 3; + continue; + } + } + if(uni[i+2] == '0' && uni[i+3] != '0') { // more complex char like \x0}1 + c = 0; + // first pos + k = uni[i+2]; + k = (((k >= '0') && (k <= '9')) ? k - '0' : k); + k *= 4096; + c += k; + // second pos + k = uni[i+3]; + k = (((k >= '0') && (k <= '9')) ? k - '0' : k); + k *= 256; + c += k; + // third pos + k = uni[i+4]; + k = (((k >= '0') && (k <= '9')) ? k - '0' : k); + c += k; + if(c >= 0 && c <= 9) c+= '0'; + // get corresponding cp1252 char + if(c > 256) { +#ifdef WIN32 + dest[j] = (unsigned char)uni2char(c); + j++; +#else + dest[j] = uni2utf8(c, 0); + j++; + dest[j] = uni2utf8(c, 1); + j++; +#endif + } else { + dest[j] = (unsigned char)c; + j++; + } + i += 4; + continue; + } + if(uni[i+2] != '0' && uni[i+3] != '0') { // hex char code like \xC4 + c = hex2char(uni[i+2]) * 16 + hex2char(uni[i+3]); + if(c > 256) { +#ifdef WIN32 + dest[j] = (unsigned char)uni2char(c); + j++; +#else + dest[j] = uni2utf8(c, 0); + j++; + dest[j] = uni2utf8(c, 1); + j++; +#endif + } else { + dest[j] = (unsigned char)c; + j++; + } + i += 3; + continue; + } + } else { + dest[j] = uni[i]; + j++; + } + } +} + +typedef struct xmlsym_st { + char sym; + char* escape; +} xmlsym; + +int g_xmlsyms = 6, g_xmlsyms2 = 7; +xmlsym g_xmlsym[] = { + { '\n', "
" }, + { '\r', "
" }, + { '<', "<" }, + { '>', ">" }, + { '"', """ }, + { '&', "&" }, // VS: test if really necessary! + { '&', "&" } +}; + +int findEscape(const char* src, char* sym) +{ + int i; + + *sym = 0; + for(i = 0; i < g_xmlsyms; i++) { + if(!strncmp(g_xmlsym[i].escape, src, strlen(g_xmlsym[i].escape))) { + *sym = g_xmlsym[i].sym; + return strlen(g_xmlsym[i].escape); + } + } + return 0; +} + +char findSym(const char* sym, int len) +{ + int i; + + for(i = 0; i < g_xmlsyms2; i++) { + if(!strncmp(g_xmlsym[i].escape, sym, len)) { + return g_xmlsym[i].sym; + } + } + return 0; +} + +//-------------------------------------------------- +// Converts xml symbols to corresponding escapes +// src - string with xml special sybols +// returns string with esacpes +//-------------------------------------------------- +char* escape2xmlsym(const char* src) +{ + char* dest = 0, c; + int i, j, l, k; + + l = strlen(src); + dest = (char*)malloc(l+1); + SET_LAST_ERROR_RETURN_IF_NOT(dest, ERR_BAD_ALLOC, NULL); + memset(dest, 0, l+1); + for(i = j = 0; i < l; i++, j++) { + if(src[i] == '&') { + k = findEscape(src + i, &c); + if(k && c) { + dest[j] = c; + i += k - 1; + } + else + dest[j] = src[i]; + } + else + dest[j] = src[i]; + } + ddocDebug(4, "escape2xmlsym", "%s --> %s", src, dest); + return dest; +} + + +//-------------------------------------------------- +// Converts xml symbols to corresponding escapes +// src - string with xml special sybols +// returns string with esacpes +//-------------------------------------------------- +char* unescapeXmlsym(const char* src) +{ + char* dest = 0, c; + int i, j, l, k; + + l = strlen(src); + dest = (char*)malloc(l+1); + SET_LAST_ERROR_RETURN_IF_NOT(dest, ERR_BAD_ALLOC, NULL); + memset(dest, 0, l+1); + for(i = j = 0; i < l; i++, j++) { + if(src[i] == '&') { + if(src[i+1] == ';') k = 1; + if(src[i+2] == ';') k = 2; + if(src[i+3] == ';') k = 3; + if(src[i+4] == ';') k = 4; + c = findSym(src + i, k); + if(k && c) { + dest[j] = c; + i += k; + } + else + dest[j] = src[i]; + } + else + dest[j] = src[i]; + } + ddocDebug(4, "unescapeXmlsym", "%s --> %s", src, dest); + return dest; +} + +char g_hexChars[] = "0123456789ABCDEF"; + +//-------------------------------------------------- +// Decodes a single hex digit +// h - hex digit +// return binary value +//-------------------------------------------------- +byte h2b(char h) +{ + int i; + for(i = 0; i < 16; i++) { + if(g_hexChars[i] == h || g_hexChars[i] == toupper(h)) + return (byte)i; + } + // if not found then return an error + ddocDebug(1, "h2b", "Invalid hex byte: %c", h); + SET_LAST_ERROR(ERR_BAD_PARAM); + return 0; // MSTERN: incorrect, VS - yes return -1 if not found. This is an error code +} + +//-------------------------------------------------- +// Converts a hex number (string) to binary value +// hex - hex number +// bin - buffer for binary value +// len - buffer length +//-------------------------------------------------- +EXP_OPTION void hex2bin(const char* hex, byte* bin, int* len) +{ + int i, l; + byte b; + + RETURN_VOID_IF_NULL(hex); + RETURN_VOID_IF_NULL(bin); + RETURN_VOID_IF_NULL(len); + memset(bin, 0, *len); + l = strlen(hex); + for(i = 0; i < l; i += 2) { + b = (byte) ((h2b(hex[i]) << 4) | h2b(hex[i+1])); + bin[i/2] = b; + } + *len = i / 2; +} + +//-------------------------------------------------- +// Converts a single byte to two hex characters +// b - binary value +// dest - destination buffer +//-------------------------------------------------- +void b2h(byte b, char* dest) +{ + dest[0] = g_hexChars[(b & 0xF0) >> 4]; + dest[1] = g_hexChars[b & 0x0F]; +} + +//-------------------------------------------------- +// Converts a binary value to hex string +// bin - binary value +// blen - binary value length +// hex - buffer for hex string +// len - buffer length +//-------------------------------------------------- +EXP_OPTION void bin2hex(const byte* bin, int blen, char* hex, int* len) +{ + int i; + byte b; + + RETURN_VOID_IF_NULL(hex); + RETURN_VOID_IF_NULL(bin); + RETURN_VOID_IF_NULL(len); + memset(hex, 0, *len); + for(i = 0; i < blen; i++) { + b = bin[i]; + hex[i*2] = g_hexChars[(b & 0xF0) >> 4]; + hex[i*2+1] = g_hexChars[b & 0x0F]; + } + *len = i / 2; +} + +//============================================================ +// Encodes input data in hex format. +// pMBufSrc - input data +// pMBufDest - destination buffer +//============================================================ +EXP_OPTION int ddocBin2Hex(const DigiDocMemBuf* pMBufSrc, DigiDocMemBuf* pMBufDest) +{ + int err = ERR_OK, n; + + RETURN_IF_NULL(pMBufSrc); + RETURN_IF_NULL(pMBufDest); + pMBufDest->pMem = 0; + pMBufDest->nLen = 0; + // alloc mem for result + if(pMBufSrc->pMem && pMBufSrc->nLen) { + err = ddocMemSetLength(pMBufDest, pMBufSrc->nLen * 2 + 10); + n = pMBufSrc->nLen * 2 + 10; + if(err) return err; + bin2hex((const byte*)pMBufSrc->pMem, pMBufSrc->nLen, (char*)pMBufDest->pMem, &n); + pMBufDest->nLen = n; + } + return err; +} + +//-------------------------------------------------- +// Converts correct filename to incorrect encoding +// used in formats 1.0, 1.1 and 1.2 +// src - input data +// dest - buffer for converted data +// len - length of destination buffer +//-------------------------------------------------- +EXP_OPTION void convFNameToWin(const char* src, char* dest, int len) +{ + int i, j; + for(i = j = 0; src[i] && (j < len - 1); i++, j++) { + if(((unsigned char)src[i]) == 197 && ((unsigned char)src[i+1]) == 161) { + dest[j] = (unsigned char)195; dest[j+1] = (unsigned char)176; j++, i++; continue; + } else if(((unsigned char)src[i]) == 197 && ((unsigned char)src[i+1]) == 160) { + dest[j] = (unsigned char)195; dest[j+1] = (unsigned char)144; j++, i++; continue; + } else if(((unsigned char)src[i]) == 197 && ((unsigned char)src[i+1]) == 190) { + dest[j] = (unsigned char)195; dest[j+1] = (unsigned char)190; j++, i++; continue; + } else if(((unsigned char)src[i]) == 197 && ((unsigned char)src[i+1]) == 189) { + dest[j] = (unsigned char)195; dest[j+1] = (unsigned char)158; j++, i++; continue; + } else { + dest[j] = src[i]; + } + } + dest[j] = 0; +} + +//-------------------------------------------------- +// Converts bad UTF-8 filename used in formats 1.0, +// 1.1 and 1.2 to correct encoding +// src - input data +// dest - buffer for converted data +// len - length of destination buffer +//-------------------------------------------------- +EXP_OPTION void convWinToFName(const char* src, char* dest, int len) +{ + int i, j; + for(i = j = 0; src[i] && (j < len - 1); i++, j++) { + if(((unsigned char)src[i]) == 195 && ((unsigned char)src[i+1]) == 176) { + dest[j] = (unsigned char)197; dest[j+1] = (unsigned char)161; j++, i++; continue; + } else if(((unsigned char)src[i]) == 195 && ((unsigned char)src[i+1]) == 144) { + dest[j] = (unsigned char)197; dest[j+1] = (unsigned char)160; j++, i++; continue; + } else if(((unsigned char)src[i]) == 195 && ((unsigned char)src[i+1]) == 190) { + dest[j] = (unsigned char)197; dest[j+1] = (unsigned char)190; j++, i++; continue; + } else if(((unsigned char)src[i]) == 195 && ((unsigned char)src[i+1]) == 158) { + dest[j] = (unsigned char)197; dest[j+1] = (unsigned char)189; j++, i++; continue; + } else { + dest[j] = src[i]; + } + } + dest[j] = 0; +} + + +//==========< only win32 fucntions >============ + +#ifdef WIN32 + +//-------------------------------------------------- +// Converts input OEM charset data to 16 bit unicode. +// oem - 8 bit oem charset input data +// unicode - address of pointer for allocated unicode string. Caller must free() ! +// outlen - address of length variable for unicode string +// returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int oem2unicode(const char* oem, char** unicode, int* outlen) +{ + int len; + + *unicode = 0; + // convert oem to unicode + if(!oem || !strlen(oem)) + return ERR_OK; + ddocDebug(4, "oem2unicode", "Convert: \'%s\' len: %d", oem, strlen(oem)); + len = MultiByteToWideChar(CP_ACP, 0, oem, -1, NULL, 0) * 2 + 10; + ddocDebug(5, "oem2unicode", "Alloc: %d", len); + *unicode = (char*)malloc(len); + RETURN_IF_BAD_ALLOC(*unicode); + memset(*unicode, 0, len); + *outlen = MultiByteToWideChar(CP_ACP, 0, oem, -1, (LPWSTR)(*unicode), len); + if(!(*outlen)) { + SET_LAST_ERROR(ERR_CHARSET_CONVERT); + return ERR_CHARSET_CONVERT; + } + else + return ERR_OK; +} + +//-------------------------------------------------- +// Converts input 16 bit unicode data to UTF8. +// unicode - 16 bit unicode input data +// utf8 - address of pointer for allocated utf8 string. Caller must free() ! +// outlen - address of length variable for utf8 string +// returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int unicode2utf8(const char* unicode, char** utf8, int* outlen) +{ + int len; + + *utf8 = 0; + // now convert unicode to UTF8 + if(!unicode || !strlen(unicode)) + return ERR_OK; + len = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)unicode, -1, NULL, 0, NULL, NULL) + 10; + ddocDebug(5, "unicode2utf8", "Alloc: %d", len); + *utf8 = (char*)malloc(len); + RETURN_IF_BAD_ALLOC(*utf8); + memset(*utf8, 0, len); + *outlen = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)unicode, -1, *utf8, len, NULL, NULL); + ddocDebug(5, "unicode2utf8", "Convert: \'%s\' len: %d", *utf8, strlen(*utf8)); + if(!(*outlen)) { + SET_LAST_ERROR(ERR_CHARSET_CONVERT); + return ERR_CHARSET_CONVERT; + } + else + return ERR_OK; +} + +//-------------------------------------------------- +// Converts input OEM charset data to UTF-8 +// oem - 8 bit oem charset input data +// utf8 - address of buffer allocated utf8 string. +// len - size of buffer +// returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int oem2utf8(const char* oem, char* utf8, int len) +{ + int err = ERR_OK, len1, len2; + char *pTmp1 = 0, *pTmp2 = 0; + + ddocDebug(5, "oem2utf8", "oem2utf8"); + // Kaido: 2.1.13 - initialize return value + *utf8 = 0; + // convert oem to unicode + if(!oem || !strlen(oem)) + return ERR_OK; + err = oem2unicode(oem, &pTmp1, &len1); + if(err) return err; + // now convert unicode to UTF8 + err = unicode2utf8(pTmp1, &pTmp2, &len2); + if(len2 < len) + memcpy(utf8, pTmp2, len2); + else + err = ERR_CHARSET_CONVERT; + if(pTmp1) + free(pTmp1); + if(pTmp2) + free(pTmp2); + return err; +} + +//-------------------------------------------------- +// Converts input UTF-8 data to 16 bit unicode data. +// utf8 - UTF-8 input data +// unicode - address of pointer for allocated unicode string. Caller must free() ! +// outlen - address of length variable for unicode string +// returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int utf82unicode(const char* utf8, char** unicode, int* outlen) +{ + int len; + + *unicode = 0; + // convert unicode to UTF-8 + if(!utf8 || !strlen(utf8)) + return ERR_OK; + ddocDebug(5, "utf82unicode", "Convert: \'%s\' len: %d", utf8, strlen(utf8)); + len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0) * 2 + 10; + ddocDebug(5, "utf82unicode", "Alloc: %d", len); + *unicode = (char*)malloc(len); + RETURN_IF_BAD_ALLOC(*unicode); + memset(*unicode, 0, len); + *outlen = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, (LPWSTR)(*unicode), len); + ddocDebug(5, "utf82unicode", "Converted: \'%s\' to \'%s\' len: %d", utf8, *unicode, *outlen); + if(!(*outlen)) { + SET_LAST_ERROR(ERR_CHARSET_CONVERT); + return ERR_CHARSET_CONVERT; + } + else + return ERR_OK; +} + +//-------------------------------------------------- +// Converts input 16 bit unicode data to oem charset data. +// unicode - 16 bit unicode input data +// oem - address of pointer for allocated oem string. Caller must free() ! +// outlen - address of length variable for oem string +// returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int unicode2oem(const char* unicode, char** oem, int* outlen) +{ + int len; + + *oem = 0; + if(!unicode || !strlen(unicode)) + return ERR_OK; + // now convert unicode to OEM + len = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)unicode, -1, NULL, 0, NULL, NULL) + 10; + ddocDebug(5, "unicode2oem", "Alloc: %d", len); + *oem = (char*)malloc(len); + RETURN_IF_BAD_ALLOC(*oem); + memset(*oem, 0, len); + *outlen = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)unicode, -1, *oem, len, NULL, NULL); + ddocDebug(5, "unicode2oem", "Convert: \'%s\' len: %d", *oem, strlen(*oem)); + if(!(*outlen)) { + SET_LAST_ERROR(ERR_CHARSET_CONVERT); + return ERR_CHARSET_CONVERT; + } + else + return ERR_OK; +} + + +//-------------------------------------------------- +// Converts input UTF-8 data to OEM charset data +// utf8 - UTF-8 input data +// oem - address of buffer for oem string. +// len - size of buffer +// returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int utf82oem(const char* utf8, char* oem, int len) +{ + int err = ERR_OK, len1, len2; + char *pTmp1 = 0, *pTmp2 = 0; + + // Kaido: 2.1.13 - initialize return value + *oem = 0; + // convert utf8 to unicode + if(!utf8 || !strlen(utf8)) + return ERR_OK; + memset(oem, 0, len); + err = utf82unicode(utf8, &pTmp1, &len1); + if(err) return err; + // now convert unicode to OEM + err = unicode2oem(pTmp1, &pTmp2, &len2); + if(len2 < len) + memcpy(oem, pTmp2, len2); + else + err = ERR_CHARSET_CONVERT; + if(pTmp1) + free(pTmp1); + if(pTmp2) + free(pTmp2); + return err; +} + +//-------------------------------------------------- +// Converts input UTF-8 data to OEM charset data +// pSigDoc - signed doc object +// pDf - data file obejct +// outFileName - output buffer +// len - length of output buffer +// returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int getDataFileFileName(SignedDoc* pSigDoc, DataFile* pDf, char* outFileName, int len) +{ + int err = ERR_OK; + RETURN_IF_NULL_PARAM(pSigDoc); + RETURN_IF_NULL_PARAM(pDf); + RETURN_IF_NULL_PARAM(outFileName); + + // Kaido: 2.1.13 - initialize return value + *outFileName = 0; + if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) { + //utf82oem(pDf->szFileName, buf1, 300); + //convFNameToWin(buf1, outFileName, len); + strncpy(outFileName, pDf->szFileName, len); + } else { + convWinToFName(pDf->szFileName, outFileName, len); + } + return err; +} + + +#endif + + +//-------------------------------------------------- +// Converts input data to UTF-8 +// src - input data +// returns converted string or NULL. Caller must free it. +//-------------------------------------------------- +EXP_OPTION int ddocConvertInput(const char* src, char** dest) +{ + int l1, err = ERR_OK; + + *dest = 0; + l1 = strlen(src) * 2 + 3; + *dest = (char*)malloc(l1); + if(*dest) { + memset(*dest, 0, l1); +#ifdef WIN32 + RETURN_IF_NULL(*dest); + err = oem2utf8(src, *dest, l1); +#else + strncpy(*dest, src, l1); +#endif + } + return err; +} + +//-------------------------------------------------- +// Releases mem-block allocated by lib. In win32 +// this must be done since the mem was allocated by dll +// and must also be released by dll that allocated it. +// p - mem to be freed +//-------------------------------------------------- +EXP_OPTION void freeLibMem(void* p) +{ + if(p) + free(p); +} + + +//-------------------------------------------------- +// Converts a filename according to platform rules +// dest - destination buffer +// destlen - destination buffer length +// src - source filename +// returns error code or ERR_OK +//-------------------------------------------------- +int ddocConvertFileName(char* dest, int destlen, const char* src) +{ + int err = ERR_OK; + + RETURN_IF_NULL_PARAM(dest); + RETURN_IF_NULL_PARAM(src); + + *dest = 0; // initialize +#ifdef WIN32 + err = utf82oem(src, dest, destlen); +#else + SET_LAST_ERROR_IF_NOT((int)strlen(src) < destlen, ERR_BUF_LEN); + strncpy(dest, src, destlen); +#endif + return err; +} + +//==========< Base64 functions >================ + + +//============================================================ +// Encode a byte array in Base64 format. +// raw - input data +// rawlen - length of input data +// buf - destination buffer +// buflen - destination buffer length (will be modified by catual number of bytes) +//============================================================ +EXP_OPTION void encode(const byte* raw, int rawlen, byte* buf, int* buflen) +{ + EVP_ENCODE_CTX ectx; + + RETURN_VOID_IF_NULL(raw); + RETURN_VOID_IF_NULL(buf); + RETURN_VOID_IF_NULL(buflen); + + memset(buf, 0, *buflen); + EVP_EncodeInit(&ectx); + EVP_EncodeUpdate(&ectx, buf, buflen, (byte*)raw, rawlen); + EVP_EncodeFinal(&ectx, (unsigned char*)strchr((const char*)buf, 0), buflen); + *buflen = strlen((const char*)buf); + while(buf[*buflen-1] == '\n' || buf[*buflen-1] == '\r' || buf[*buflen-1] == '-') { + if(buf[*buflen-1] == '-') + ddocDebug(1, "encode", "Found - at the end of base64 code: %s", buf); + + buf[*buflen-1] = 0; + *buflen = *buflen - 1; + } + *buflen = strlen((const char*)buf); +} + + +byte* breakToLinesOf64(byte* raw, int rawlen) +{ + int i, l1, j; + byte* p = raw; + + // if it's not divide in lines + l1 = rawlen; + j = l1 + (l1/64) * 3; + p = (byte*)malloc(j); + if (!p) return NULL; + memset(p, 0, j); + for(i = j = 0; i < l1; i += 64) { + strncpy(strchr((const char*)p,0), (const char*)raw+i, ((i+64<l1) ? 64 : l1-i)); + if(i + 64 < l1) + strncat((char*)p, "\n", j - strlen((char*)p)); + } + l1 = strlen((const char*)p); + return p; +} + +//============================================================ +// Decodes input data in Base64 format. +// raw - input data +// rawlen - length of input data +// buf - destination buffer +// buflen - destination buffer length (will be modified by catual number of bytes) +//============================================================ +EXP_OPTION void decode(const byte* raw, int rawlen, byte* buf, int* buflen) +{ + EVP_ENCODE_CTX ectx; + int l1 = 0; + byte* p; + + RETURN_VOID_IF_NULL(raw); + RETURN_VOID_IF_NULL(buf); + RETURN_VOID_IF_NULL(buflen); + + memset(buf, 0, *buflen); + *buflen = 0; + EVP_DecodeInit(&ectx); + if((!strstr((const char*)raw, "\n") || + !strstr((const char*)raw, "\r")) && + strlen((const char*)raw) > 64) { + p = breakToLinesOf64((byte*)raw, rawlen); + l1 = strlen((const char*)p); + EVP_DecodeUpdate(&ectx, (unsigned char*)buf, &l1, + (unsigned char*)p, + strlen((const char*)p)); + *buflen += l1; + free(p); + } + else + EVP_DecodeUpdate(&ectx, buf, buflen, (byte*)raw, rawlen); + EVP_DecodeFinal(&ectx, buf, &l1); + *buflen += l1; +} + + +//============================================================ +// Helper function to determine if this is a base64 char +//============================================================ +int isb64char(int c) +{ + return ( (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + (c == '+') || + (c == '/') || + (c == '=') + ); +} + +//============================================================ +// Decodes input data in Base64 format. +// pMBufSrc - input data +// pMBufDest - destination buffer +//============================================================ +EXP_OPTION int ddocDecodeBase64(DigiDocMemBuf* pMBufSrc, DigiDocMemBuf* pMBufDest) +{ + int err = ERR_OK, n; + long lPos1 = 0, lPos2 = 0; + EVP_ENCODE_CTX ectx; + char buf1[70]; + RETURN_IF_NULL(pMBufSrc); + RETURN_IF_NULL(pMBufDest); + + pMBufDest->pMem = 0; + pMBufDest->nLen = 0; + // alloc mem for result - it will get smaller so original length must be enough + err = ddocMemSetLength(pMBufDest, pMBufSrc->nLen); + if(err) return err; + EVP_DecodeInit(&ectx); + // decode base64 + while(lPos1 < pMBufSrc->nLen) { + // copy next input row + memset(buf1, 0, sizeof(buf1)); + n = 0; + while(n < 64 && lPos1 < pMBufSrc->nLen) { + if(isb64char(((char*)pMBufSrc->pMem)[lPos1])) { + buf1[n] = ((char*)pMBufSrc->pMem)[lPos1]; + n++; + } + lPos1++; + } + strncat(buf1, "\n", sizeof(buf1) - strlen(buf1)); + // decode this chunk + n = pMBufDest->nLen - lPos2; + EVP_DecodeUpdate(&ectx, (unsigned char*)((char*)pMBufDest->pMem + lPos2), &n, + (unsigned char*)buf1, strlen((const char*)buf1)); + lPos2 += n; + } + memset(buf1, 0, sizeof(buf1)); + n = sizeof(buf1); + EVP_DecodeFinal(&ectx, (unsigned char*)buf1, &n); + lPos2 += n; + pMBufDest->nLen = lPos2; + return err; +} + + +//============================================================ +// Decodes input data in Base64 format. +// data - input data +// len - length of input data. Use -1 for zero terminated strings +// pMBufDest - destination buffer +//============================================================ +EXP_OPTION int ddocDecodeBase64Data(void* data, long len, DigiDocMemBuf* pMBufDest) +{ + DigiDocMemBuf mbuf1; + + mbuf1.pMem = data; + if(len == -1) + mbuf1.nLen = strlen((const char*)data); + else + mbuf1.nLen = len; + return ddocDecodeBase64(&mbuf1, pMBufDest); +} + + +//============================================================ +// Encodes input data in Base64 format. +// pMBufSrc - input data +// pMBufDest - destination buffer +//============================================================ +EXP_OPTION int ddocEncodeBase64(const DigiDocMemBuf* pMBufSrc, DigiDocMemBuf* pMBufDest) +{ + int err = ERR_OK, nLen; + EVP_ENCODE_CTX ectx; + + RETURN_IF_NULL(pMBufSrc); + RETURN_IF_NULL(pMBufDest); + + pMBufDest->pMem = 0; + pMBufDest->nLen = 0; + // alloc mem for result + err = ddocMemSetLength(pMBufDest, pMBufSrc->nLen * 2 + 10); + if(err) return err; + EVP_EncodeInit(&ectx); + // encode base64 + nLen = pMBufDest->nLen; + EVP_EncodeUpdate(&ectx, (unsigned char*)pMBufDest->pMem, &nLen, + (byte*)pMBufSrc->pMem, pMBufSrc->nLen); + pMBufDest->nLen = nLen; + nLen = (pMBufSrc->nLen * 2 + 10) - pMBufDest->nLen; + EVP_EncodeFinal(&ectx, (unsigned char*)pMBufDest->pMem + pMBufDest->nLen, &nLen); + pMBufDest->nLen += nLen; //strlen((const char*)pMBufDest->pMem); + return err; +} + +//==========< conversion fucntions >================ + +//-------------------------------------------------- +// Decodes an ASN1 generalized time +// tm - ASN1 generalized time +// y - year +// M - month +// d - day of month +// h - hour +// m - minute +// s - second +// returns error code or ERR_OK +//-------------------------------------------------- +int decodeGeneralizedTime(ASN1_GENERALIZEDTIME *tm, + int* y, int* M, int* d, + int* h, int* m, int* s) +{ + char *v = NULL; + int gmt=0; + int i, err = ERR_OK; + + RETURN_IF_NULL_PARAM(tm); + RETURN_IF_NULL_PARAM(y); + RETURN_IF_NULL_PARAM(M); + RETURN_IF_NULL_PARAM(d); + RETURN_IF_NULL_PARAM(h); + RETURN_IF_NULL_PARAM(m); + RETURN_IF_NULL_PARAM(s); + + i=tm->length; + v=(char *)tm->data; + if (i < 12) + err = ERR_TIMESTAMP_DECODE; + if (v[i-1] == 'Z') gmt=1; + for (i=0; i<12; i++) + if ((v[i] > '9') || (v[i] < '0')) + err = ERR_TIMESTAMP_DECODE; + *y= (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0'); + *M= (v[4]-'0')*10+(v[5]-'0'); + if ((*M > 12) || (*M < 1)) + err = ERR_TIMESTAMP_DECODE; + *d= (v[6]-'0')*10+(v[7]-'0'); + *h= (v[8]-'0')*10+(v[9]-'0'); + *m= (v[10]-'0')*10+(v[11]-'0'); + if ( (v[12] >= '0') && (v[12] <= '9') && + (v[13] >= '0') && (v[13] <= '9')) + *s= (v[12]-'0')*10+(v[13]-'0'); + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + +//-------------------------------------------------- +// Decodes an ASN1 UTC time +// tm - ASN1 generalized time +// y - year +// M - month +// d - day of month +// h - hour +// m - minute +// s - second +// returns error code or ERR_OK +//-------------------------------------------------- +int decodeUTCTime(ASN1_UTCTIME *tm, + int* y, int* M, int* d, + int* h, int* m, int* s) +{ + char *v; + int gmt=0; + int i, err = 0; + + RETURN_IF_NULL_PARAM(tm); + RETURN_IF_NULL_PARAM(y); + RETURN_IF_NULL_PARAM(M); + RETURN_IF_NULL_PARAM(d); + RETURN_IF_NULL_PARAM(h); + RETURN_IF_NULL_PARAM(m); + RETURN_IF_NULL_PARAM(s); + + i=tm->length; + v=(char *)tm->data; + + if (i < 10) + err = ERR_TIMESTAMP_DECODE; + if (v[i-1] == 'Z') gmt=1; + for (i=0; i<10; i++) + if ((v[i] > '9') || (v[i] < '0')) + err = ERR_TIMESTAMP_DECODE; + *y= (v[0]-'0')*10+(v[1]-'0'); + if (*y < 50) *y+=100; + *M= (v[2]-'0')*10+(v[3]-'0'); + if ((*M > 12) || (*M < 1)) + err = ERR_TIMESTAMP_DECODE; + *d= (v[4]-'0')*10+(v[5]-'0'); + *h= (v[6]-'0')*10+(v[7]-'0'); + *m= (v[8]-'0')*10+(v[9]-'0'); + if ( (v[10] >= '0') && (v[10] <= '9') && + (v[11] >= '0') && (v[11] <= '9')) + *s= (v[10]-'0')*10+(v[11]-'0'); + + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + +//========================================================== +// converts ASN1 time to time_t +//========================================================== +int asn1time2time_t(ASN1_TIME* tm, time_t* pT) +{ + int err = ERR_OK; + struct tm tm1; + //int dmz=0; + + RETURN_IF_NULL_PARAM(tm); + RETURN_IF_NULL_PARAM(pT); + _tzset(); + memset(&tm1, 0, sizeof(tm1)); + if(tm->type == V_ASN1_UTCTIME) + err = decodeUTCTime(tm, &tm1.tm_year, &tm1.tm_mon, + &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec); + if(tm->type == V_ASN1_GENERALIZEDTIME) + err = decodeGeneralizedTime(tm, &tm1.tm_year, &tm1.tm_mon, + &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec); + tm1.tm_year -= 1900; + tm1.tm_mon -= 1; + tm1.tm_isdst = _daylight; + (*pT) = mktime(&tm1); + /* + if(_daylight!=0) { + if(_timezone<0){ + dmz = (_timezone / 3600) - _daylight; + }else{ + dmz = (_timezone / 3600) + _daylight; + } + }else{ + dmz=_timezone / 3600; + } + (*pT) = (*pT) - (dmz * 3600); + */ + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + + +//========================================================== +// converts ASN1 time to time_t +//========================================================== +int asn1time2time_t_local(ASN1_TIME* tm, time_t* pT) +{ + int err = ERR_OK; + struct tm tm1; + int dmz=0; + + RETURN_IF_NULL_PARAM(tm); + RETURN_IF_NULL_PARAM(pT); + _tzset(); + memset(&tm1, 0, sizeof(tm1)); + if(tm->type == V_ASN1_UTCTIME) + err = decodeUTCTime(tm, &tm1.tm_year, &tm1.tm_mon, + &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec); + if(tm->type == V_ASN1_GENERALIZEDTIME) + err = decodeGeneralizedTime(tm, &tm1.tm_year, &tm1.tm_mon, + &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec); + if(tm1.tm_year > 1900) + tm1.tm_year -= 1900; + tm1.tm_mon -= 1; + tm1.tm_isdst = _daylight; + (*pT) = mktime(&tm1); + if(_daylight != 0) { + if(_timezone<0){ + dmz = (_timezone / 3600) - _daylight; + }else{ + dmz = (_timezone / 3600) + _daylight; + } + }else{ + dmz=_timezone / 3600; + } + (*pT) = (*pT) - (dmz * 3600); + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + +//========================================================== +// converts ASN1 time to string +//========================================================== +int asn1time2strYear(const SignedDoc* pSigDoc, ASN1_TIME* tm, char* buf, int year, int len) +{ + int err = ERR_OK; + struct tm tm1, tm2; + time_t t2; + int dmz=0; + + RETURN_IF_NULL_PARAM(tm); + RETURN_IF_NULL_PARAM(buf); + //RETURN_IF_NULL_PARAM(pSigDoc); + _tzset(); + memset(&tm1, 0, sizeof(tm1)); + if(tm->type == V_ASN1_UTCTIME) + err = decodeUTCTime(tm, &tm1.tm_year, &tm1.tm_mon, + &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec); + if(tm->type == V_ASN1_GENERALIZEDTIME) + err = decodeGeneralizedTime(tm, &tm1.tm_year, &tm1.tm_mon, + &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec); + + // V 1.76 - in format 1.3 we use CCYY-MM-DDTHH:MM:SSZ + if(!pSigDoc || (pSigDoc && + !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) )) { + snprintf(buf, len, "%04d-%02d-%02dT%02d:%02d:%02dZ", + year + tm1.tm_year, tm1.tm_mon, tm1.tm_mday, + tm1.tm_hour, tm1.tm_min, tm1.tm_sec); + } else + // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ + if(pSigDoc && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) { + tm1.tm_year -= 1900 - year; + tm1.tm_mon -= 1; + tm1.tm_isdst = _daylight; + t2 = mktime(&tm1); + if (err == ERR_OK) { + if (_daylight!=0) { + if (_timezone<0) { + dmz = (_timezone / 3600) - _daylight; + } else { + dmz = (_timezone / 3600) + _daylight; + } + } else { + dmz=_timezone / 3600; + } + t2 -= (dmz * 3600); + ddocLocalTime(&t2, &tm2, 1); + snprintf(buf, len, "%04d.%02d.%02dT%02d:%02d:%02d%+03d:00", + tm2.tm_year + 1900, tm2.tm_mon + 1, + tm2.tm_mday, tm2.tm_hour, tm2.tm_min, + tm2.tm_sec, dmz * -1); + ddocDebug(5, "asn1time2strYear", + "ASN1 time: %s, tz: %d, string: %s\n", tm->data, dmz * -1, buf); + } + } else { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time + snprintf(buf, len, "%04d.%02d.%02dT%02d:%02d:%02dZ", + year + tm1.tm_year, tm1.tm_mon, tm1.tm_mday, + tm1.tm_hour, tm1.tm_min, tm1.tm_sec); + } + + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + +//========================================================== +// converts ASN1 time to string +//========================================================== +int asn1time2str(const SignedDoc* pSigDoc, ASN1_TIME* tm, char* buf, int len) +{ + return asn1time2strYear(pSigDoc, tm, buf, 0, len); +} + + + +//============================================================================== +// converts ASN1_GENERALIZEDTOME object to string +//============================================================================== +int str2asn1time(const SignedDoc* pSigDoc, const char* str, ASN1_GENERALIZEDTIME* asn1tm) +{ + char buf[50]; + int rc, dmz = 0; + struct tm tm1, tm2; + time_t t2; + + + RETURN_IF_NULL_PARAM(str); + RETURN_IF_NULL_PARAM(asn1tm); + _tzset(); + memset(&tm1, 0, sizeof(tm1)); + // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ + if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) { + sscanf(str, "%04d.%02d.%04dT%02d:%02d:%02d%3d:00", + &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday), + &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec), &dmz); + tm1.tm_year -= 1900; + tm1.tm_mon -= 1; + tm1.tm_isdst = _daylight; + t2 = mktime(&tm1); + t2 -= (dmz * 3600); + ddocLocalTime(&t2, &tm2, 1); + snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ", + tm2.tm_year + 1900, tm2.tm_mon + 1, tm2.tm_mday, + tm2.tm_hour, tm2.tm_min, tm2.tm_sec); + } else { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time + sscanf(str, "%04d.%02d.%04dT%02d:%02d:%02dZ", + &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday), + &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec)); + snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ", + tm1.tm_year, tm1.tm_mon, tm1.tm_mday, + tm1.tm_hour, tm1.tm_min, tm1.tm_sec); + } + rc = ASN1_GENERALIZEDTIME_set_string(asn1tm, buf); + //printf("String: %s, tz: %d, ASN1 time: %s\n", str, dmz, asn1tm->data); + return ERR_OK; +} + +//=================================================================== +// converts time_t to timestamp string +// t - time_t input value +// szTimestamp - output buffer +// len - length of buffer +// returns error code or ERR_OK +//=================================================================== +EXP_OPTION int time_t2str(time_t t, char* szTimestamp, int len) +{ + struct tm tm1; + + RETURN_IF_NULL_PARAM(szTimestamp); + ddocLocalTime(&t, &tm1, 0); + snprintf(szTimestamp, len, "%04d-%02d-%02dT%02d:%02d:%02dZ", + tm1.tm_year + 1900, tm1.tm_mon + 1, + tm1.tm_mday, tm1.tm_hour, tm1.tm_min, tm1.tm_sec); + return ERR_OK; +} + +//=================================================================== +// converts string to time_t +// szTimestamp - input buffer +// pT - address time_t output value +// returns error code or ERR_OK +//=================================================================== +EXP_OPTION int str2time_t(char* szTimestamp, time_t* pT) +{ + struct tm tm1; + time_t t1 = 0; + //int dmz = 0; + + RETURN_IF_NULL_PARAM(szTimestamp); + RETURN_IF_NULL_PARAM(pT); + _tzset(); + memset(&tm1, 0, sizeof(tm1)); + sscanf(szTimestamp, "%04d.%02d.%04dT%02d:%02d:%02dZ", + &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday), + &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec) /*, &dmz*/); + tm1.tm_year -= 1900; + tm1.tm_mon -= 1; + tm1.tm_isdst = _daylight; + t1 = mktime(&tm1); + //t1 -= (dmz * 3600); + (*pT) = t1; + return ERR_OK; +} + |