From 24c0dd3e35ae97183a994cc6f25fc78d08da1311 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Sun, 2 Nov 2014 12:12:42 +0000 Subject: reverted MSN removal (too early) git-svn-id: http://svn.miranda-ng.org/main/trunk@10901 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/MSN/src/des.c | 639 +++++++++ protocols/MSN/src/des.h | 170 +++ protocols/MSN/src/ezxml.c | 967 +++++++++++++ protocols/MSN/src/ezxml.h | 165 +++ protocols/MSN/src/msn.cpp | 151 ++ protocols/MSN/src/msn_auth.cpp | 485 +++++++ protocols/MSN/src/msn_avatar.cpp | 122 ++ protocols/MSN/src/msn_chat.cpp | 469 ++++++ protocols/MSN/src/msn_commands.cpp | 1753 +++++++++++++++++++++++ protocols/MSN/src/msn_contact.cpp | 272 ++++ protocols/MSN/src/msn_errors.cpp | 93 ++ protocols/MSN/src/msn_ftold.cpp | 395 ++++++ protocols/MSN/src/msn_global.h | 884 ++++++++++++ protocols/MSN/src/msn_http.cpp | 130 ++ protocols/MSN/src/msn_libstr.cpp | 319 +++++ protocols/MSN/src/msn_links.cpp | 171 +++ protocols/MSN/src/msn_lists.cpp | 623 ++++++++ protocols/MSN/src/msn_mail.cpp | 424 ++++++ protocols/MSN/src/msn_menu.cpp | 460 ++++++ protocols/MSN/src/msn_mime.cpp | 536 +++++++ protocols/MSN/src/msn_misc.cpp | 1293 +++++++++++++++++ protocols/MSN/src/msn_msgqueue.cpp | 190 +++ protocols/MSN/src/msn_msgsplit.cpp | 124 ++ protocols/MSN/src/msn_natdetect.cpp | 496 +++++++ protocols/MSN/src/msn_opts.cpp | 684 +++++++++ protocols/MSN/src/msn_p2p.cpp | 2525 +++++++++++++++++++++++++++++++++ protocols/MSN/src/msn_p2ps.cpp | 292 ++++ protocols/MSN/src/msn_proto.cpp | 1107 +++++++++++++++ protocols/MSN/src/msn_proto.h | 567 ++++++++ protocols/MSN/src/msn_soapab.cpp | 1713 ++++++++++++++++++++++ protocols/MSN/src/msn_soapstore.cpp | 781 ++++++++++ protocols/MSN/src/msn_srv.cpp | 378 +++++ protocols/MSN/src/msn_ssl.cpp | 140 ++ protocols/MSN/src/msn_std.cpp | 65 + protocols/MSN/src/msn_svcs.cpp | 624 ++++++++ protocols/MSN/src/msn_switchboard.cpp | 53 + protocols/MSN/src/msn_threads.cpp | 769 ++++++++++ protocols/MSN/src/msn_ws.cpp | 180 +++ protocols/MSN/src/resource.h | 100 ++ protocols/MSN/src/stdafx.cpp | 18 + protocols/MSN/src/version.h | 33 + 41 files changed, 21360 insertions(+) create mode 100644 protocols/MSN/src/des.c create mode 100644 protocols/MSN/src/des.h create mode 100644 protocols/MSN/src/ezxml.c create mode 100644 protocols/MSN/src/ezxml.h create mode 100644 protocols/MSN/src/msn.cpp create mode 100644 protocols/MSN/src/msn_auth.cpp create mode 100644 protocols/MSN/src/msn_avatar.cpp create mode 100644 protocols/MSN/src/msn_chat.cpp create mode 100644 protocols/MSN/src/msn_commands.cpp create mode 100644 protocols/MSN/src/msn_contact.cpp create mode 100644 protocols/MSN/src/msn_errors.cpp create mode 100644 protocols/MSN/src/msn_ftold.cpp create mode 100644 protocols/MSN/src/msn_global.h create mode 100644 protocols/MSN/src/msn_http.cpp create mode 100644 protocols/MSN/src/msn_libstr.cpp create mode 100644 protocols/MSN/src/msn_links.cpp create mode 100644 protocols/MSN/src/msn_lists.cpp create mode 100644 protocols/MSN/src/msn_mail.cpp create mode 100644 protocols/MSN/src/msn_menu.cpp create mode 100644 protocols/MSN/src/msn_mime.cpp create mode 100644 protocols/MSN/src/msn_misc.cpp create mode 100644 protocols/MSN/src/msn_msgqueue.cpp create mode 100644 protocols/MSN/src/msn_msgsplit.cpp create mode 100644 protocols/MSN/src/msn_natdetect.cpp create mode 100644 protocols/MSN/src/msn_opts.cpp create mode 100644 protocols/MSN/src/msn_p2p.cpp create mode 100644 protocols/MSN/src/msn_p2ps.cpp create mode 100644 protocols/MSN/src/msn_proto.cpp create mode 100644 protocols/MSN/src/msn_proto.h create mode 100644 protocols/MSN/src/msn_soapab.cpp create mode 100644 protocols/MSN/src/msn_soapstore.cpp create mode 100644 protocols/MSN/src/msn_srv.cpp create mode 100644 protocols/MSN/src/msn_ssl.cpp create mode 100644 protocols/MSN/src/msn_std.cpp create mode 100644 protocols/MSN/src/msn_svcs.cpp create mode 100644 protocols/MSN/src/msn_switchboard.cpp create mode 100644 protocols/MSN/src/msn_threads.cpp create mode 100644 protocols/MSN/src/msn_ws.cpp create mode 100644 protocols/MSN/src/resource.h create mode 100644 protocols/MSN/src/stdafx.cpp create mode 100644 protocols/MSN/src/version.h (limited to 'protocols/MSN/src') diff --git a/protocols/MSN/src/des.c b/protocols/MSN/src/des.c new file mode 100644 index 0000000000..030fb983cd --- /dev/null +++ b/protocols/MSN/src/des.c @@ -0,0 +1,639 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License, version 2.1 as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +/* + * DES, on which TDES is based, was originally designed by IBM in + * 1974 and adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + + +#ifndef __GNUC__ +#pragma hdrstop +#endif + +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include + +#include "des.h" + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ + | ( (unsigned long) (b)[(i) + 1] << 16 ) \ + | ( (unsigned long) (b)[(i) + 2] << 8 ) \ + | ( (unsigned long) (b)[(i) + 3] ); \ +} +#endif +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const unsigned long SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const unsigned long SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const unsigned long SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const unsigned long SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const unsigned long SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const unsigned long SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const unsigned long SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const unsigned long SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const unsigned long LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const unsigned long RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +static void des_main_ks( unsigned long SK[32], unsigned char key[8] ) +{ + int i; + unsigned long X, Y, T; + + GET_UINT32_BE( X, key, 0 ); + GET_UINT32_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for ( i = 0; i < 16; i++ ) + { + if ( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} + +/* + * DES key schedule (56-bit) + */ +void des_set_key( des_context *ctx, unsigned char key[8] ) +{ + int i; + + des_main_ks( ctx->esk, key ); + + for ( i = 0; i < 32; i += 2 ) + { + ctx->dsk[i ] = ctx->esk[30 - i]; + ctx->dsk[i + 1] = ctx->esk[31 - i]; + } +} + +static void des_crypt( unsigned long SK[32], + unsigned char input[8], + unsigned char output[8] ) +{ + unsigned long X, Y, T; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); +} + +/* + * DES block encryption (ECB mode) + */ +void des_encrypt( des_context *ctx, + unsigned char input[8], + unsigned char output[8] ) +{ + des_crypt( ctx->esk, input, output ); +} + +/* + * DES block decryption (ECB mode) + */ +void des_decrypt( des_context *ctx, + unsigned char input[8], + unsigned char output[8] ) +{ + des_crypt( ctx->dsk, input, output ); +} + +/* + * DES-CBC buffer encryption + */ +void des_cbc_encrypt( des_context *ctx, + unsigned char iv[8], + unsigned char *input, + unsigned char *output, + int len ) +{ + int i; + + while( len > 0 ) + { + for ( i = 0; i < 8; i++ ) + output[i] = input[i] ^ iv[i]; + + des_crypt( ctx->esk, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + len -= 8; + } +} + +/* + * DES-CBC buffer decryption + */ +void des_cbc_decrypt( des_context *ctx, + unsigned char iv[8], + unsigned char *input, + unsigned char *output, + int len ) +{ + int i; + unsigned char temp[8]; + + while( len > 0 ) + { + memcpy( temp, input, 8 ); + des_crypt( ctx->dsk, input, output ); + + for ( i = 0; i < 8; i++ ) + output[i] = output[i] ^ iv[i]; + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + len -= 8; + } +} + +/* + * Triple-DES key schedule (112-bit) + */ +void des3_set_2keys( des3_context *ctx, unsigned char key[16] ) +{ + int i; + + des_main_ks( ctx->esk , key ); + des_main_ks( ctx->dsk + 32, key + 8 ); + + for ( i = 0; i < 32; i += 2 ) + { + ctx->dsk[i ] = ctx->esk[30 - i]; + ctx->dsk[i + 1] = ctx->esk[31 - i]; + + ctx->esk[i + 32] = ctx->dsk[62 - i]; + ctx->esk[i + 33] = ctx->dsk[63 - i]; + + ctx->esk[i + 64] = ctx->esk[ i]; + ctx->esk[i + 65] = ctx->esk[ 1 + i]; + + ctx->dsk[i + 64] = ctx->dsk[ i]; + ctx->dsk[i + 65] = ctx->dsk[ 1 + i]; + } +} + +/* + * Triple-DES key schedule (168-bit) + */ +void des3_set_3keys( des3_context *ctx, unsigned char key[24] ) +{ + int i; + + des_main_ks( ctx->esk , key ); + des_main_ks( ctx->dsk + 32, key + 8 ); + des_main_ks( ctx->esk + 64, key + 16 ); + + for ( i = 0; i < 32; i += 2 ) + { + ctx->dsk[i ] = ctx->esk[94 - i]; + ctx->dsk[i + 1] = ctx->esk[95 - i]; + + ctx->esk[i + 32] = ctx->dsk[62 - i]; + ctx->esk[i + 33] = ctx->dsk[63 - i]; + + ctx->dsk[i + 64] = ctx->esk[30 - i]; + ctx->dsk[i + 65] = ctx->esk[31 - i]; + } +} + +static void des3_crypt( unsigned long SK[96], + unsigned char input[8], + unsigned char output[8] ) +{ + unsigned long X, Y, T; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + DES_ROUND( X, Y ); DES_ROUND( Y, X ); + + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + DES_ROUND( Y, X ); DES_ROUND( X, Y ); + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); +} + +/* + * Triple-DES block encryption (ECB mode) + */ +void des3_encrypt( des3_context *ctx, + unsigned char input[8], + unsigned char output[8] ) +{ + des3_crypt( ctx->esk, input, output ); +} + +/* + * Triple-DES block decryption (ECB mode) + */ +void des3_decrypt( des3_context *ctx, + unsigned char input[8], + unsigned char output[8] ) +{ + des3_crypt( ctx->dsk, input, output ); +} + +/* + * 3DES-CBC buffer encryption + */ +void des3_cbc_encrypt( des3_context *ctx, + unsigned char iv[8], + unsigned char *input, + unsigned char *output, + int len ) +{ + int i; + + while( len > 0 ) + { + for ( i = 0; i < 8; i++ ) + output[i] = input[i] ^ iv[i]; + + des3_crypt( ctx->esk, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + len -= 8; + } +} + +/* + * 3DES-CBC buffer decryption + */ +void des3_cbc_decrypt( des3_context *ctx, + unsigned char iv[8], + unsigned char *input, + unsigned char *output, + int len ) +{ + int i; + unsigned char temp[8]; + + while( len > 0 ) + { + memcpy( temp, input, 8 ); + des3_crypt( ctx->dsk, input, output ); + + for ( i = 0; i < 8; i++ ) + output[i] = output[i] ^ iv[i]; + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + len -= 8; + } +} diff --git a/protocols/MSN/src/des.h b/protocols/MSN/src/des.h new file mode 100644 index 0000000000..e1fc923fad --- /dev/null +++ b/protocols/MSN/src/des.h @@ -0,0 +1,170 @@ +/** + * \file des.h + */ +#ifndef _DES_H +#define _DES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES context structure + */ +typedef struct +{ + unsigned long esk[32]; /*!< DES encryption subkeys */ + unsigned long dsk[32]; /*!< DES decryption subkeys */ +} +des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct +{ + unsigned long esk[96]; /*!< Triple-DES encryption subkeys */ + unsigned long dsk[96]; /*!< Triple-DES decryption subkeys */ +} +des3_context; + +/** + * \brief DES key schedule (56-bit) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + */ +void des_set_key( des_context *ctx, unsigned char key[8] ); + +/** + * \brief DES block encryption (ECB mode) + * + * \param ctx DES context + * \param input plaintext block + * \param output ciphertext block + */ +void des_encrypt( des_context *ctx, + unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief DES block decryption (ECB mode) + * + * \param ctx DES context + * \param input ciphertext block + * \param output plaintext block + */ +void des_decrypt( des_context *ctx, + unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief DES-CBC buffer encryption + * + * \param ctx DES context + * \param iv initialization vector (modified after use) + * \param input buffer holding the plaintext + * \param output buffer holding the ciphertext + * \param len length of the data to be encrypted + */ +void des_cbc_encrypt( des_context *ctx, + unsigned char iv[8], + unsigned char *input, + unsigned char *output, + int len ); + +/** + * \brief DES-CBC buffer decryption + * + * \param ctx DES context + * \param iv initialization vector (modified after use) + * \param input buffer holding the ciphertext + * \param output buffer holding the plaintext + * \param len length of the data to be decrypted + */ +void des_cbc_decrypt( des_context *ctx, + unsigned char iv[8], + unsigned char *input, + unsigned char *output, + int len ); + +/** + * \brief Triple-DES key schedule (112-bit) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + */ +void des3_set_2keys( des3_context *ctx, unsigned char key[16] ); + +/** + * \brief Triple-DES key schedule (168-bit) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + */ +void des3_set_3keys( des3_context *ctx, unsigned char key[24] ); + +/** + * \brief Triple-DES block encryption (ECB mode) + * + * \param ctx 3DES context + * \param input plaintext block + * \param output ciphertext block + */ +void des3_encrypt( des3_context *ctx, + unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief Triple-DES block decryption (ECB mode) + * + * \param ctx 3DES context + * \param input ciphertext block + * \param output plaintext block + */ +void des3_decrypt( des3_context *ctx, + unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief 3DES-CBC buffer encryption + * + * \param ctx 3DES context + * \param iv initialization vector (modified after use) + * \param input buffer holding the plaintext + * \param output buffer holding the ciphertext + * \param len length of the data to be encrypted + */ +void des3_cbc_encrypt( des3_context *ctx, + unsigned char iv[8], + unsigned char *input, + unsigned char *output, + int len ); + +/** + * \brief 3DES-CBC buffer decryption + * + * \param ctx 3DES context + * \param iv initialization vector (modified after use) + * \param input buffer holding the ciphertext + * \param output buffer holding the plaintext + * \param len length of the data to be decrypted + */ +void des3_cbc_decrypt( des3_context *ctx, + unsigned char iv[8], + unsigned char *input, + unsigned char *output, + int len ); + +/* + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/protocols/MSN/src/ezxml.c b/protocols/MSN/src/ezxml.c new file mode 100644 index 0000000000..41ef70598e --- /dev/null +++ b/protocols/MSN/src/ezxml.c @@ -0,0 +1,967 @@ +/* ezxml.c + * + * Copyright 2004-2006 Aaron Voisine + * + * 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. + */ + +#if defined(_DEBUG) && !defined(__GNUC__) + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif + +#include +#include +#include +#include +#include + +#include "ezxml.h" + +#ifndef SIZE_MAX +#define SIZE_MAX UINT_MAX +#endif + +#define EZXML_WS "\t\r\n " // whitespace +#define EZXML_ERRL 128 // maximum error string length + +typedef struct ezxml_root *ezxml_root_t; +struct ezxml_root { // additional data for the root tag + struct ezxml xml; // is a super-struct built on top of ezxml struct + ezxml_t cur; // current xml tree insertion point + char *m; // original xml string + size_t len; // length of allocated memory for mmap, -1 for malloc + char *u; // UTF-8 conversion of string if original was UTF-16 + char *s; // start of work area + char *e; // end of work area + char **ent; // general entities (ampersand sequences) + char ***attr; // default attributes + char ***pi; // processing instructions + short standalone; // non-zero if + char err[EZXML_ERRL]; // error string +}; + +char *EZXML_NIL[] = { NULL }; // empty, null terminated array of strings + +// returns the first child tag with the given name or NULL if not found +ezxml_t ezxml_child(ezxml_t xml, const char *name) +{ + xml = (xml) ? xml->child : NULL; + while (xml && strcmp(name, xml->name)) xml = xml->sibling; + return xml; +} + +// returns the Nth tag with the same name in the same subsection or NULL if not +// found +ezxml_t ezxml_idx(ezxml_t xml, int idx) +{ + for (; xml && idx; idx--) xml = xml->next; + return xml; +} + +// returns the value of the requested tag attribute or NULL if not found +const char *ezxml_attr(ezxml_t xml, const char *attr) +{ + int i = 0, j = 1; + ezxml_root_t root = (ezxml_root_t)xml; + + if (! xml || ! xml->attr) return NULL; + while (xml->attr[i] && strcmp(attr, xml->attr[i])) i += 2; + if (xml->attr[i]) return xml->attr[i + 1]; // found attribute + + while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag + for (i = 0; root->attr[i] && strcmp(xml->name, root->attr[i][0]); i++); + if (! root->attr[i]) return NULL; // no matching default attributes + while (root->attr[i][j] && strcmp(attr, root->attr[i][j])) j += 3; + return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; // found default +} + +// same as ezxml_get but takes an already initialized va_list +ezxml_t ezxml_vget(ezxml_t xml, va_list ap) +{ + char *name = va_arg(ap, char *); + int idx = -1; + + if (name && *name) { + idx = va_arg(ap, int); + xml = ezxml_child(xml, name); + } + return (idx < 0) ? xml : ezxml_vget(ezxml_idx(xml, idx), ap); +} + +// Traverses the xml tree to retrieve a specific subtag. Takes a variable +// length list of tag names and indexes. The argument list must be terminated +// by either an index of -1 or an empty string tag name. Example: +// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1); +// This retrieves the title of the 3rd book on the 1st shelf of library. +// Returns NULL if not found. +ezxml_t ezxml_get(ezxml_t xml, ...) +{ + va_list ap; + ezxml_t r; + + va_start(ap, xml); + r = ezxml_vget(xml, ap); + va_end(ap); + return r; +} + +// returns a null terminated array of processing instructions for the given +// target +const char **ezxml_pi(ezxml_t xml, const char *target) +{ + ezxml_root_t root = (ezxml_root_t)xml; + int i = 0; + + if (! root) return (const char **)EZXML_NIL; + while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag + while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target + return (const char **)((root->pi[i]) ? root->pi[i] + 1 : EZXML_NIL); +} + +// set an error string and return root +ezxml_t ezxml_err(ezxml_root_t root, char *s, const char *err, ...) +{ + va_list ap; + int line = 1; + char *t, fmt[EZXML_ERRL]; + + for (t = root->s; t < s; t++) if (*t == '\n') line++; + _snprintf(fmt, EZXML_ERRL, "[error near line %d]: %s", line, err); + + va_start(ap, err); + _vsnprintf(root->err, EZXML_ERRL, fmt, ap); + va_end(ap); + + return &root->xml; +} + +// Recursively decodes entity and character references and normalizes new lines +// ent is a null terminated array of alternating entity names and values. set t +// to '&' for general entity decoding, '%' for parameter entity decoding, 'c' +// for cdata sections, ' ' for attribute normalization, or '*' for non-cdata +// attribute normalization. Returns s, or if the decoded string is longer than +// s, returns a malloced string that must be freed. +char *ezxml_decode(char *s, char **ent, char t) +{ + char *e, *r = s, *m = s; + long b, c, d, l; +/* + for (; *s; s++) { // normalize line endings + while (*s == '\r') { + *(s++) = '\n'; + if (*s == '\n') memmove(s, (s + 1), strlen(s)); + } + } +*/ + for (s = r; ; ) { + while (*s && *s != '&' && (*s != '%' || t != '%') && (*s & 0x80 || !isspace(*s))) s++; + + if (! *s) break; + else if (t != 'c' && ! strncmp(s, "&#", 2)) { // character reference + if (s[2] == 'x') c = strtol(s + 3, &e, 16); // base 16 + else c = strtol(s + 2, &e, 10); // base 10 + if (! c || *e != ';') { s++; continue; } // not a character ref + + if (c < 0x80) *(s++) = (char)c; // US-ASCII subset + else { // multi-byte UTF-8 sequence + for (b = 0, d = c; d; d /= 2) b++; // number of bits in c + b = (b - 2) / 5; // number of bytes in payload + *(s++) = (char)((0xFF << (7 - b)) | (c >> (6 * b))); // head + while (b) *(s++) = (char)(0x80 | ((c >> (6 * --b)) & 0x3F)); // payload + } + + memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';'))); + } + else if ((*s == '&' && (t == '&' || t == ' ' || t == '*')) || + (*s == '%' && t == '%')) { // entity reference + for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b])); + b += 2); // find entity in entity list + + if (ent[b++]) { // found a match + if ((c = (long)strlen(ent[b])) - 1 > (e = strchr(s, ';')) - s) { + l = (d = (long)(s - r)) + c + (long)strlen(e); // new length + r = (r == m) ? strcpy(malloc(l), r) : realloc(r, l); + e = strchr((s = r + d), ';'); // fix up pointers + } + + memmove(s + c, e + 1, strlen(e)); // shift rest of string + strncpy(s, ent[b], c); // copy in replacement text + } + else s++; // not a known entity + } + else if ((t == ' ' || t == '*') && isspace(*s)) *(s++) = ' '; + else s++; // no decoding needed + } + + if (t == '*') { // normalize spaces for non-cdata attributes + for (s = r; *s; s++) { + if ((l = (long)strspn(s, " "))) memmove(s, s + l, strlen(s + l) + 1); + while (*s && *s != ' ') s++; + } + if (--s >= r && *s == ' ') *s = '\0'; // trim any trailing space + } + return r; +} + +// called when parser finds start of new tag +void ezxml_open_tag(ezxml_root_t root, char *name, char **attr) +{ + ezxml_t xml = root->cur; + + if (xml->name) xml = ezxml_add_child(xml, name, strlen(xml->txt)); + else xml->name = name; // first open tag + + xml->attr = attr; + root->cur = xml; // update tag insertion point +} + +// called when parser finds character content between open and closing tag +void ezxml_char_content(ezxml_root_t root, char *s, size_t len, char t) +{ + ezxml_t xml = root->cur; + char *m = s; + size_t l; + + if (! xml || ! xml->name || ! len) return; // sanity check + + s[len] = '\0'; // null terminate text (calling functions anticipate this) + len = strlen(s = ezxml_decode(s, root->ent, t)) + 1; + + if (! *(xml->txt)) xml->txt = s; // initial character content + else { // allocate our own memory and make a copy + xml->txt = (xml->flags & EZXML_TXTM) // allocate some space + ? realloc(xml->txt, (l = strlen(xml->txt)) + len) + : strcpy(malloc((l = strlen(xml->txt)) + len), xml->txt); + strcpy(xml->txt + l, s); // add new char content + if (s != m) free(s); // free s if it was malloced by ezxml_decode() + } + + if (xml->txt != m) ezxml_set_flag(xml, EZXML_TXTM); +} + +// called when parser finds closing tag +ezxml_t ezxml_close_tag(ezxml_root_t root, char *name, char *s) +{ + if (! root->cur || ! root->cur->name || strcmp(name, root->cur->name)) + return ezxml_err(root, s, "unexpected closing tag ", name); + + root->cur = root->cur->parent; + return NULL; +} + +// checks for circular entity references, returns non-zero if no circular +// references are found, zero otherwise +int ezxml_ent_ok(char *name, char *s, char **ent) +{ + int i; + + for (; ; s++) { + while (*s && *s != '&') s++; // find next entity reference + if (! *s) return 1; + if (! strncmp(s + 1, name, strlen(name))) return 0; // circular ref. + for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2); + if (ent[i] && ! ezxml_ent_ok(name, ent[i + 1], ent)) return 0; + } +} + +// called when the parser finds a processing instruction +void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len) +{ + int i = 0, j = 1; + char *target = s; + + s[len] = '\0'; // null terminate instruction + if (*(s += strcspn(s, EZXML_WS))) { + *s = '\0'; // null terminate target + s += strspn(s + 1, EZXML_WS) + 1; // skip whitespace after target + } + + if (! strcmp(target, "xml")) { // + if ((s = strstr(s, "standalone")) && ! strncmp(s + strspn(s + 10, + EZXML_WS "='\"") + 10, "yes", 3)) root->standalone = 1; + return; + } + + if (! root->pi[0]) *(root->pi = malloc(sizeof(char **))) = NULL; //first pi + + while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target + if (! root->pi[i]) { // new target + root->pi = realloc(root->pi, sizeof(char **) * (i + 2)); + root->pi[i] = malloc(sizeof(char *) * 3); + root->pi[i][0] = target; + root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); // terminate pi list + root->pi[i][2] = _strdup(""); // empty document position list + } + + while (root->pi[i][j]) j++; // find end of instruction list for this target + root->pi[i] = realloc(root->pi[i], sizeof(char *) * (j + 3)); + root->pi[i][j + 2] = realloc(root->pi[i][j + 1], j + 1); + strcpy(root->pi[i][j + 2] + j - 1, (root->xml.name) ? ">" : "<"); + root->pi[i][j + 1] = NULL; // null terminate pi list for this target + root->pi[i][j] = s; // set instruction +} + +// called when the parser finds an internal doctype subset +short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len) +{ + char q, *c, *t, *n = NULL, *v, **ent, **pe; + int i, j; + + pe = memcpy(malloc(sizeof(EZXML_NIL)), EZXML_NIL, sizeof(EZXML_NIL)); + + for (s[len] = '\0'; s; ) { + while (*s && *s != '<' && *s != '%') s++; // find next declaration + + if (! *s) break; + else if (! strncmp(s, "'); + continue; + } + + for (i = 0, ent = (*c == '%') ? pe : root->ent; ent[i]; i++); + ent = realloc(ent, (i + 3) * sizeof(char *)); // space for next ent + if (*c == '%') pe = ent; + else root->ent = ent; + + *(++s) = '\0'; // null terminate name + if ((s = strchr(v, q))) *(s++) = '\0'; // null terminate value + ent[i + 1] = ezxml_decode(v, pe, '%'); // set value + ent[i + 2] = NULL; // null terminate entity list + if (! ezxml_ent_ok(n, ent[i + 1], ent)) { // circular reference + if (ent[i + 1] != v) free(ent[i + 1]); + ezxml_err(root, v, "circular entity declaration &%s", n); + break; + } + else ent[i] = n; // set entity name + } + else if (! strncmp(s, "")) == '>') continue; + else *s = '\0'; // null terminate tag name + for (i = 0; root->attr[i] && strcmp(n, root->attr[i][0]); i++); + + while (*(n = s + 1 + strspn(s + 1, EZXML_WS)) && *n != '>') { + if (*(s = n + strcspn(n, EZXML_WS))) *s = '\0'; // attr name + else { ezxml_err(root, t, "malformed ") - 1; + if (*c == ' ') continue; // cdata is default, nothing to do + v = NULL; + } + else if ((*s == '"' || *s == '\'') && // default value + (s = strchr(v = s + 1, *s))) *s = '\0'; + else { ezxml_err(root, t, "malformed attr[i]) { // new tag name + root->attr = (! i) ? malloc(2 * sizeof(char **)) + : realloc(root->attr, + (i + 2) * sizeof(char **)); + root->attr[i] = malloc(2 * sizeof(char *)); + root->attr[i][0] = t; // set tag name + root->attr[i][1] = (char *)(root->attr[i + 1] = NULL); + } + + for (j = 1; root->attr[i][j]; j += 3); // find end of list + root->attr[i] = realloc(root->attr[i], + (j + 4) * sizeof(char *)); + + root->attr[i][j + 3] = NULL; // null terminate list + root->attr[i][j + 2] = c; // is it cdata? + root->attr[i][j + 1] = (v) ? ezxml_decode(v, root->ent, *c) + : NULL; + root->attr[i][j] = n; // attribute name + } + } + else if (! strncmp(s, ""); // comments + else if (! strncmp(s, ""))) + ezxml_proc_inst(root, c, s++ - c); + } + else if (*s == '<') s = strchr(s, '>'); // skip other declarations + else if (*(s++) == '%' && ! root->standalone) break; + } + + free(pe); + return ! *root->err; +} + +// Converts a UTF-16 string to UTF-8. Returns a new string that must be freed +// or NULL if no conversion was needed. +char *ezxml_str2utf8(char **s, size_t *len) +{ + char *u; + size_t l = 0, sl, max = *len; + long c, d; + int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1; + + if (be == -1) return NULL; // not UTF-16 + + u = malloc(max); + for (sl = 2; sl < *len - 1; sl += 2) { + c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF) //UTF-16BE + : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); //UTF-16LE + if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { // high-half + d = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF) + : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); + c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000; + } + + while (l + 6 > max) u = realloc(u, max += EZXML_BUFSIZE); + if (c < 0x80) u[l++] = (char)c; // US-ASCII subset + else { // multi-byte UTF-8 sequence + for (b = 0, d = c; d; d /= 2) b++; // bits in c + b = (b - 2) / 5; // bytes in payload + u[l++] = (char)((0xFF << (7 - b)) | (c >> (6 * b))); // head + while (b) u[l++] = (char)(0x80 | ((c >> (6 * --b)) & 0x3F)); // payload + } + } + return *s = realloc(u, *len = l); +} + +// frees a tag attribute list +void ezxml_free_attr(char **attr) { + int i = 0; + char *m; + + if (! attr || attr == EZXML_NIL) return; // nothing to free + while (attr[i]) i += 2; // find end of attribute list + m = attr[i + 1]; // list of which names and values are malloced + for (i = 0; m[i]; i++) { + if (m[i] & EZXML_NAMEM) free(attr[i * 2]); + if (m[i] & EZXML_TXTM) free(attr[(i * 2) + 1]); + } + free(m); + free(attr); +} + +// parse the given xml string and return an ezxml structure +ezxml_t ezxml_parse_str(char *s, size_t len) +{ + ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL); + char q, e, *d, **attr, **a = NULL; // initialize a to avoid compile warning + int l, i, j; + + root->m = s; + if (! len) return ezxml_err(root, NULL, "root tag missing"); + root->u = ezxml_str2utf8(&s, &len); // convert utf-16 to utf-8 + root->e = (root->s = s) + len; // record start and end of work area + + e = s[len - 1]; // save end char + s[len - 1] = '\0'; // turn end char into null terminator + + while (*s && *s != '<') s++; // find first tag + if (! *s) return ezxml_err(root, s, "root tag missing"); + + for (; ; ) { + attr = (char **)EZXML_NIL; + d = ++s; + + if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { // new tag + if (! root->cur) + return ezxml_err(root, d, "markup outside of root element"); + + s += strcspn(s, EZXML_WS "/>"); + while (isspace(*s)) *(s++) = '\0'; // null terminate tag name + + if (*s && *s != '/' && *s != '>') // find tag in default attr list + for (i = 0; (a = root->attr[i]) && strcmp(a[0], d); i++); + + for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { // new attrib + attr = (l) ? realloc(attr, (l + 4) * sizeof(char *)) + : malloc(4 * sizeof(char *)); // allocate space + attr[l + 3] = (l) ? realloc(attr[l + 1], (l / 2) + 2) + : malloc(2); // mem for list of maloced vals + strcpy(attr[l + 3] + (l / 2), " "); // value is not malloced + attr[l + 2] = NULL; // null terminate list + attr[l + 1] = ""; // temporary attribute value + attr[l] = s; // set attribute name + + s += strcspn(s, EZXML_WS "=/>"); + if (*s == '=' || isspace(*s)) { + *(s++) = '\0'; // null terminate tag attribute name + q = *(s += strspn(s, EZXML_WS "=")); + if (q == '"' || q == '\'') { // attribute value + attr[l + 1] = ++s; + while (*s && *s != q) s++; + if (*s) *(s++) = '\0'; // null terminate attribute val + else { + ezxml_free_attr(attr); + return ezxml_err(root, d, "missing %c", q); + } + + for (j = 1; a && a[j] && strcmp(a[j], attr[l]); j +=3); + attr[l + 1] = ezxml_decode(attr[l + 1], root->ent, + (char)((a && a[j]) ? *a[j + 2] : ' ')); + if (attr[l + 1] < d || attr[l + 1] > s) + attr[l + 3][l / 2] = EZXML_TXTM; // value malloced + } + } + while (isspace(*s)) s++; + } + + if (*s == '/') { // self closing tag + *(s++) = '\0'; + if ((*s && *s != '>') || (! *s && e != '>')) { + if (l) ezxml_free_attr(attr); + return ezxml_err(root, d, "missing >"); + } + ezxml_open_tag(root, d, attr); + ezxml_close_tag(root, d, s); + } + else if ((q = *s) == '>' || (! *s && e == '>')) { // open tag + *s = '\0'; // temporarily null terminate tag name + ezxml_open_tag(root, d, attr); + *s = q; + } + else { + if (l) ezxml_free_attr(attr); + return ezxml_err(root, d, "missing >"); + } + } + else if (*s == '/') { // close tag + s += strcspn(d = s + 1, EZXML_WS ">") + 1; + if (! (q = *s) && e != '>') return ezxml_err(root, d, "missing >"); + *s = '\0'; // temporarily null terminate tag name + if (ezxml_close_tag(root, d, s)) return &root->xml; + if (isspace(*s = q)) s += strspn(s, EZXML_WS); + } + else if (! strncmp(s, "!--", 3)) { // xml comment + if (! (s = strstr(s + 3, "--")) || (*(s += 2) != '>' && *s) || + (! *s && e != '>')) return ezxml_err(root, d, "unclosed