diff --git a/xflaim/src/fxml.cpp b/xflaim/src/fxml.cpp index c935a54..7d25ce5 100644 --- a/xflaim/src/fxml.cpp +++ b/xflaim/src/fxml.cpp @@ -1,7168 +1,7170 @@ -//------------------------------------------------------------------------------ -// Desc: XML parser -// -// Tabs: 3 -// -// Copyright (c) 2000-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fxml.cpp 3115 2006-01-19 13:24:39 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------------ - -#include "flaimsys.h" - -// Constants - -#define FLM_XML_BASE_CHAR 0x01 -#define FLM_XML_IDEOGRAPHIC 0x02 -#define FLM_XML_COMBINING_CHAR 0x04 -#define FLM_XML_DIGIT 0x08 -#define FLM_XML_EXTENDER 0x10 -#define FLM_XML_WHITESPACE 0x20 - -#if defined( FLM_WIN) - - // VISIT: When doing a release build, we use the /O2 compiler switch, - // which turns on various optimizations. However, for some strange - // reason, the compiler (versions vc7 and vc8) hangs when compiling this - // file with the /O2 switch. This pragma below essentially disables the - // /O2 switch for this file. -- This file compiled just fine under vc6 - // without having to disable optimizations. Therefore, when the next - // version of the Microsoft compiler comes out, it would be worth - // trying it again without this pragma to see if the compiler still - // hangs. - - #pragma optimize("", off) - #pragma warning (disable: 4748) // /GS security check option disabled -#endif - -// Local typedefs - -typedef struct -{ - char * pszEntity; - FLMUINT uiValue; -} CharEntity; - -// Global data - -extern FLMUNICODE gv_uzXFLAIMNamespace[]; - -static FLMUNICODE gv_puzNamespaceDeclPrefix[] = -{ - FLM_UNICODE_x, - FLM_UNICODE_m, - FLM_UNICODE_l, - FLM_UNICODE_n, - FLM_UNICODE_s, - 0 -}; - -static FLMUNICODE gv_puzXMLPrefix[] = -{ - FLM_UNICODE_x, - FLM_UNICODE_m, - FLM_UNICODE_l, - 0 -}; - -FLMUNICODE gv_puzXMLNSURI[] = -{ - FLM_UNICODE_h, - FLM_UNICODE_t, - FLM_UNICODE_t, - FLM_UNICODE_p, - FLM_UNICODE_COLON, - FLM_UNICODE_FSLASH, - FLM_UNICODE_FSLASH, - FLM_UNICODE_w, - FLM_UNICODE_w, - FLM_UNICODE_w, - FLM_UNICODE_PERIOD, - FLM_UNICODE_w, - FLM_UNICODE_3, - FLM_UNICODE_c, - FLM_UNICODE_PERIOD, - FLM_UNICODE_o, - FLM_UNICODE_r, - FLM_UNICODE_g, - FLM_UNICODE_FSLASH, - FLM_UNICODE_T, - FLM_UNICODE_R, - FLM_UNICODE_FSLASH, - FLM_UNICODE_1, - FLM_UNICODE_9, - FLM_UNICODE_9, - FLM_UNICODE_9, - FLM_UNICODE_FSLASH, - FLM_UNICODE_R, - FLM_UNICODE_E, - FLM_UNICODE_C, - FLM_UNICODE_HYPHEN, - FLM_UNICODE_x, - FLM_UNICODE_m, - FLM_UNICODE_l, - FLM_UNICODE_HYPHEN, - FLM_UNICODE_n, - FLM_UNICODE_a, - FLM_UNICODE_m, - FLM_UNICODE_e, - FLM_UNICODE_s, - FLM_UNICODE_HYPHEN, - FLM_UNICODE_1, - FLM_UNICODE_9, - FLM_UNICODE_9, - FLM_UNICODE_9, - FLM_UNICODE_0, - FLM_UNICODE_1, - FLM_UNICODE_1, - FLM_UNICODE_4, - 0 -}; - -FSTATIC RCODE exportUniValue( - IF_OStream * pOStream, - FLMUNICODE * puzStr, - FLMUINT uiStrChars, - FLMBOOL bEncodeSpecialChars, - FLMUINT uiIndentCount); - -// Function / Method Implementations - -/**************************************************************************** -Desc: Constructor -****************************************************************************/ -F_XML::F_XML() -{ - m_pCharTable = NULL; -} - -/**************************************************************************** -Desc: Destructor -****************************************************************************/ -F_XML::~F_XML() -{ - if( m_pCharTable) - { - f_free( &m_pCharTable); - } -} - -/**************************************************************************** -Desc: Sets a character's type flag in the character lookup table -****************************************************************************/ -void F_XML::setCharFlag( - FLMUNICODE uLowChar, - FLMUNICODE uHighChar, - FLMUINT16 ui16Flag) -{ - FLMUINT uiLoop; - - flmAssert( uLowChar <= uHighChar); - - for( uiLoop = (FLMUINT)uLowChar; uiLoop <= (FLMUINT)uHighChar; uiLoop++) - { - m_pCharTable[ uiLoop].ucFlags |= (FLMBYTE)ui16Flag; - } -} - -/**************************************************************************** -Desc: Builds a character lookup table -****************************************************************************/ -RCODE F_XML::buildCharTable( void) -{ - RCODE rc = NE_XFLM_OK; - - if( m_pCharTable) - { - f_free( &m_pCharTable); - } - - if( RC_BAD( rc = f_calloc( sizeof( XMLCHAR) * 0xFFFF, &m_pCharTable))) - { - goto Exit; - } - - setCharFlag( 0x0041, 0x005A, FLM_XML_BASE_CHAR); - setCharFlag( 0x0061, 0x007A, FLM_XML_BASE_CHAR); - setCharFlag( 0x00C0, 0x00D6, FLM_XML_BASE_CHAR); - setCharFlag( 0x00D8, 0x00F6, FLM_XML_BASE_CHAR); - setCharFlag( 0x00F8, 0x00FF, FLM_XML_BASE_CHAR); - setCharFlag( 0x0100, 0x0131, FLM_XML_BASE_CHAR); - setCharFlag( 0x0134, 0x013E, FLM_XML_BASE_CHAR); - setCharFlag( 0x0141, 0x0148, FLM_XML_BASE_CHAR); - setCharFlag( 0x014A, 0x017E, FLM_XML_BASE_CHAR); - setCharFlag( 0x0180, 0x01C3, FLM_XML_BASE_CHAR); - setCharFlag( 0x01CD, 0x01F0, FLM_XML_BASE_CHAR); - setCharFlag( 0x01F4, 0x01F5, FLM_XML_BASE_CHAR); - setCharFlag( 0x01FA, 0x0217, FLM_XML_BASE_CHAR); - setCharFlag( 0x0250, 0x02A8, FLM_XML_BASE_CHAR); - setCharFlag( 0x02BB, 0x02C1, FLM_XML_BASE_CHAR); - setCharFlag( 0x0386, 0x0386, FLM_XML_BASE_CHAR); - setCharFlag( 0x0388, 0x038A, FLM_XML_BASE_CHAR); - setCharFlag( 0x038C, 0x038C, FLM_XML_BASE_CHAR); - setCharFlag( 0x038E, 0x03A1, FLM_XML_BASE_CHAR); - setCharFlag( 0x03A3, 0x03CE, FLM_XML_BASE_CHAR); - setCharFlag( 0x03D0, 0x03D6, FLM_XML_BASE_CHAR); - setCharFlag( 0x03DA, 0x03DA, FLM_XML_BASE_CHAR); - setCharFlag( 0x03DC, 0x03DC, FLM_XML_BASE_CHAR); - setCharFlag( 0x03DE, 0x03DE, FLM_XML_BASE_CHAR); - setCharFlag( 0x03E0, 0x03E0, FLM_XML_BASE_CHAR); - setCharFlag( 0x03E2, 0x03F3, FLM_XML_BASE_CHAR); - setCharFlag( 0x0401, 0x040C, FLM_XML_BASE_CHAR); - setCharFlag( 0x040E, 0x044F, FLM_XML_BASE_CHAR); - setCharFlag( 0x0451, 0x045C, FLM_XML_BASE_CHAR); - setCharFlag( 0x045E, 0x0481, FLM_XML_BASE_CHAR); - setCharFlag( 0x0490, 0x04C4, FLM_XML_BASE_CHAR); - setCharFlag( 0x04C7, 0x04C8, FLM_XML_BASE_CHAR); - setCharFlag( 0x04CB, 0x04CC, FLM_XML_BASE_CHAR); - setCharFlag( 0x04D0, 0x04EB, FLM_XML_BASE_CHAR); - setCharFlag( 0x04EE, 0x04F5, FLM_XML_BASE_CHAR); - setCharFlag( 0x04F8, 0x04F9, FLM_XML_BASE_CHAR); - setCharFlag( 0x0531, 0x0556, FLM_XML_BASE_CHAR); - setCharFlag( 0x0559, 0x0559, FLM_XML_BASE_CHAR); - setCharFlag( 0x0561, 0x0586, FLM_XML_BASE_CHAR); - setCharFlag( 0x05D0, 0x05EA, FLM_XML_BASE_CHAR); - setCharFlag( 0x05F0, 0x05F2, FLM_XML_BASE_CHAR); - setCharFlag( 0x0621, 0x063A, FLM_XML_BASE_CHAR); - setCharFlag( 0x0641, 0x06B7, FLM_XML_BASE_CHAR); - setCharFlag( 0x06BA, 0x06BE, FLM_XML_BASE_CHAR); - setCharFlag( 0x06C0, 0x06CE, FLM_XML_BASE_CHAR); - setCharFlag( 0x06D0, 0x06D3, FLM_XML_BASE_CHAR); - setCharFlag( 0x06D5, 0x06D5, FLM_XML_BASE_CHAR); - setCharFlag( 0x06E5, 0x06E6, FLM_XML_BASE_CHAR); - setCharFlag( 0x0905, 0x0939, FLM_XML_BASE_CHAR); - setCharFlag( 0x093D, 0x093D, FLM_XML_BASE_CHAR); - setCharFlag( 0x0958, 0x0961, FLM_XML_BASE_CHAR); - setCharFlag( 0x0985, 0x098C, FLM_XML_BASE_CHAR); - setCharFlag( 0x098F, 0x0990, FLM_XML_BASE_CHAR); - setCharFlag( 0x0993, 0x09A8, FLM_XML_BASE_CHAR); - setCharFlag( 0x09AA, 0x09B0, FLM_XML_BASE_CHAR); - setCharFlag( 0x09B2, 0x09B2, FLM_XML_BASE_CHAR); - setCharFlag( 0x09B6, 0x09B9, FLM_XML_BASE_CHAR); - setCharFlag( 0x0061, 0x007A, FLM_XML_BASE_CHAR); - setCharFlag( 0x09DC, 0x09DD, FLM_XML_BASE_CHAR); - setCharFlag( 0x09DF, 0x09E1, FLM_XML_BASE_CHAR); - setCharFlag( 0x09F0, 0x09F1, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A05, 0x0A0A, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A0F, 0x0A10, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A13, 0x0A28, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A2A, 0x0A30, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A32, 0x0A33, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A35, 0x0A36, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A38, 0x0A39, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A59, 0x0A5C, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A5E, 0x0A5E, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A72, 0x0A74, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A85, 0x0A8B, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A8D, 0x0A8D, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A8F, 0x0A91, FLM_XML_BASE_CHAR); - setCharFlag( 0x0A93, 0x0AA8, FLM_XML_BASE_CHAR); - setCharFlag( 0x0AAA, 0x0AB0, FLM_XML_BASE_CHAR); - setCharFlag( 0x0AB2, 0x0AB3, FLM_XML_BASE_CHAR); - setCharFlag( 0x0AB5, 0x0AB9, FLM_XML_BASE_CHAR); - setCharFlag( 0x0ABD, 0x0ABD, FLM_XML_BASE_CHAR); - setCharFlag( 0x0AE0, 0x0AE0, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B05, 0x0B0C, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B0F, 0x0B10, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B13, 0x0B28, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B2A, 0x0B30, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B32, 0x0B33, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B36, 0x0B39, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B3D, 0x0B3D, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B5C, 0x0B5D, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B5F, 0x0B61, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B85, 0x0B8A, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B8E, 0x0B90, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B92, 0x0B95, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B99, 0x0B9A, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B9C, 0x0B9C, FLM_XML_BASE_CHAR); - setCharFlag( 0x0B9E, 0x0B9F, FLM_XML_BASE_CHAR); - setCharFlag( 0x0BA3, 0x0BA4, FLM_XML_BASE_CHAR); - setCharFlag( 0x0BA8, 0x0BAA, FLM_XML_BASE_CHAR); - setCharFlag( 0x0BAE, 0x0BB5, FLM_XML_BASE_CHAR); - setCharFlag( 0x0BB7, 0x0BB9, FLM_XML_BASE_CHAR); - setCharFlag( 0x0C05, 0x0C0C, FLM_XML_BASE_CHAR); - setCharFlag( 0x0C0E, 0x0C10, FLM_XML_BASE_CHAR); - setCharFlag( 0x0C12, 0x0C28, FLM_XML_BASE_CHAR); - setCharFlag( 0x0C2A, 0x0C33, FLM_XML_BASE_CHAR); - setCharFlag( 0x0C35, 0x0C39, FLM_XML_BASE_CHAR); - setCharFlag( 0x0C60, 0x0C61, FLM_XML_BASE_CHAR); - setCharFlag( 0x0C85, 0x0C8C, FLM_XML_BASE_CHAR); - setCharFlag( 0x0C8E, 0x0C90, FLM_XML_BASE_CHAR); - setCharFlag( 0x0C92, 0x0CA8, FLM_XML_BASE_CHAR); - setCharFlag( 0x0CAA, 0x0CB3, FLM_XML_BASE_CHAR); - setCharFlag( 0x0CB5, 0x0CB9, FLM_XML_BASE_CHAR); - setCharFlag( 0x0CDE, 0x0CDE, FLM_XML_BASE_CHAR); - setCharFlag( 0x0CE0, 0x0CE1, FLM_XML_BASE_CHAR); - setCharFlag( 0x0D05, 0x0D0C, FLM_XML_BASE_CHAR); - setCharFlag( 0x0D0E, 0x0D10, FLM_XML_BASE_CHAR); - setCharFlag( 0x0D12, 0x0D28, FLM_XML_BASE_CHAR); - setCharFlag( 0x0D2A, 0x0D39, FLM_XML_BASE_CHAR); - setCharFlag( 0x0D60, 0x0D61, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E01, 0x0E2E, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E30, 0x0E30, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E32, 0x0E33, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E40, 0x0E45, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E81, 0x0E82, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E84, 0x0E84, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E87, 0x0E88, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E8A, 0x0E8A, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E8D, 0x0E8D, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E94, 0x0E97, FLM_XML_BASE_CHAR); - setCharFlag( 0x0E99, 0x0E9F, FLM_XML_BASE_CHAR); - setCharFlag( 0x0EA1, 0x0EA3, FLM_XML_BASE_CHAR); - setCharFlag( 0x0EA5, 0x0EA5, FLM_XML_BASE_CHAR); - setCharFlag( 0x0EA7, 0x0EA7, FLM_XML_BASE_CHAR); - setCharFlag( 0x0EAA, 0x0EAB, FLM_XML_BASE_CHAR); - setCharFlag( 0x0EAD, 0x0EAE, FLM_XML_BASE_CHAR); - setCharFlag( 0x0EB0, 0x0EB0, FLM_XML_BASE_CHAR); - setCharFlag( 0x0EB2, 0x0EB3, FLM_XML_BASE_CHAR); - setCharFlag( 0x0EBD, 0x0EBD, FLM_XML_BASE_CHAR); - setCharFlag( 0x0EC0, 0x0EC4, FLM_XML_BASE_CHAR); - setCharFlag( 0x0F40, 0x0F47, FLM_XML_BASE_CHAR); - setCharFlag( 0x0F49, 0x0F69, FLM_XML_BASE_CHAR); - setCharFlag( 0x10A0, 0x10C5, FLM_XML_BASE_CHAR); - setCharFlag( 0x10D0, 0x10F6, FLM_XML_BASE_CHAR); - setCharFlag( 0x1100, 0x1100, FLM_XML_BASE_CHAR); - setCharFlag( 0x1102, 0x1103, FLM_XML_BASE_CHAR); - setCharFlag( 0x1105, 0x1107, FLM_XML_BASE_CHAR); - setCharFlag( 0x1109, 0x1109, FLM_XML_BASE_CHAR); - setCharFlag( 0x110B, 0x110C, FLM_XML_BASE_CHAR); - setCharFlag( 0x110E, 0x1112, FLM_XML_BASE_CHAR); - setCharFlag( 0x113C, 0x113C, FLM_XML_BASE_CHAR); - setCharFlag( 0x113E, 0x113E, FLM_XML_BASE_CHAR); - setCharFlag( 0x1140, 0x1140, FLM_XML_BASE_CHAR); - setCharFlag( 0x114C, 0x114C, FLM_XML_BASE_CHAR); - setCharFlag( 0x114E, 0x114E, FLM_XML_BASE_CHAR); - setCharFlag( 0x1150, 0x1150, FLM_XML_BASE_CHAR); - setCharFlag( 0x1154, 0x1155, FLM_XML_BASE_CHAR); - setCharFlag( 0x1159, 0x1159, FLM_XML_BASE_CHAR); - setCharFlag( 0x115F, 0x1161, FLM_XML_BASE_CHAR); - setCharFlag( 0x1163, 0x1163, FLM_XML_BASE_CHAR); - setCharFlag( 0x1165, 0x1165, FLM_XML_BASE_CHAR); - setCharFlag( 0x1167, 0x1167, FLM_XML_BASE_CHAR); - setCharFlag( 0x1169, 0x1169, FLM_XML_BASE_CHAR); - setCharFlag( 0x116D, 0x116E, FLM_XML_BASE_CHAR); - setCharFlag( 0x1172, 0x1173, FLM_XML_BASE_CHAR); - setCharFlag( 0x1175, 0x1175, FLM_XML_BASE_CHAR); - setCharFlag( 0x119E, 0x119E, FLM_XML_BASE_CHAR); - setCharFlag( 0x11A8, 0x11A8, FLM_XML_BASE_CHAR); - setCharFlag( 0x11AB, 0x11AB, FLM_XML_BASE_CHAR); - setCharFlag( 0x11AE, 0x11AF, FLM_XML_BASE_CHAR); - setCharFlag( 0x11B7, 0x11B8, FLM_XML_BASE_CHAR); - setCharFlag( 0x11BA, 0x11BA, FLM_XML_BASE_CHAR); - setCharFlag( 0x11BC, 0x11C2, FLM_XML_BASE_CHAR); - setCharFlag( 0x11EB, 0x11EB, FLM_XML_BASE_CHAR); - setCharFlag( 0x11F0, 0x11F0, FLM_XML_BASE_CHAR); - setCharFlag( 0x11F9, 0x11F9, FLM_XML_BASE_CHAR); - setCharFlag( 0x1E00, 0x1E9B, FLM_XML_BASE_CHAR); - setCharFlag( 0x1EA0, 0x1EF9, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F00, 0x1F15, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F18, 0x1F1D, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F20, 0x1F45, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F48, 0x1F4D, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F50, 0x1F57, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F59, 0x1F59, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F5B, 0x1F5B, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F5D, 0x1F5D, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F5F, 0x1F7D, FLM_XML_BASE_CHAR); - setCharFlag( 0x1F80, 0x1FB4, FLM_XML_BASE_CHAR); - setCharFlag( 0x1FB6, 0x1FBC, FLM_XML_BASE_CHAR); - setCharFlag( 0x1FBE, 0x1FBE, FLM_XML_BASE_CHAR); - setCharFlag( 0x1FC2, 0x1FC4, FLM_XML_BASE_CHAR); - setCharFlag( 0x1FC6, 0x1FCC, FLM_XML_BASE_CHAR); - setCharFlag( 0x1FD0, 0x1FD3, FLM_XML_BASE_CHAR); - setCharFlag( 0x1FD6, 0x1FDB, FLM_XML_BASE_CHAR); - setCharFlag( 0x1FE0, 0x1FEC, FLM_XML_BASE_CHAR); - setCharFlag( 0x1FF2, 0x1FF4, FLM_XML_BASE_CHAR); - setCharFlag( 0x1FF6, 0x1FFC, FLM_XML_BASE_CHAR); - setCharFlag( 0x2126, 0x2126, FLM_XML_BASE_CHAR); - setCharFlag( 0x212A, 0x212B, FLM_XML_BASE_CHAR); - setCharFlag( 0x212E, 0x212E, FLM_XML_BASE_CHAR); - setCharFlag( 0x2180, 0x2182, FLM_XML_BASE_CHAR); - setCharFlag( 0x3041, 0x3094, FLM_XML_BASE_CHAR); - setCharFlag( 0x30A1, 0x30FA, FLM_XML_BASE_CHAR); - setCharFlag( 0x3105, 0x312C, FLM_XML_BASE_CHAR); - setCharFlag( 0xAC00, 0xD7A3, FLM_XML_BASE_CHAR); - - setCharFlag( 0x4E00, 0x9FA5, FLM_XML_IDEOGRAPHIC); - setCharFlag( 0x3007, 0x3007, FLM_XML_IDEOGRAPHIC); - setCharFlag( 0x3021, 0x3029, FLM_XML_IDEOGRAPHIC); - - setCharFlag( 0x0300, 0x0345, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0360, 0x0361, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0483, 0x0486, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0591, 0x05A1, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x05A3, 0x05B9, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x05BB, 0x05BD, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x05BF, 0x05BF, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x05C1, 0x05C2, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x05C4, 0x05C4, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x064B, 0x0652, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0670, 0x0670, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x06D6, 0x06DC, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x06DD, 0x06DF, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x06E0, 0x06E4, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x06E7, 0x06E8, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x06EA, 0x06ED, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0901, 0x0903, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x093C, 0x093C, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x093E, 0x094C, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x094D, 0x094D, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0951, 0x0954, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0962, 0x0963, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0981, 0x0983, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x09BC, 0x09BC, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x09BE, 0x09BE, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x09BF, 0x09BF, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x09C0, 0x09C4, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x09C7, 0x09C8, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x09CB, 0x09CD, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x09D7, 0x09D7, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x09E2, 0x09E3, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0A02, 0x0A02, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0A3C, 0x0A3C, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0A3E, 0x0A3E, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0A3F, 0x0A3F, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0A40, 0x0A42, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0A47, 0x0A48, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0A4B, 0x0A4D, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0A70, 0x0A71, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0A81, 0x0A83, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0ABC, 0x0ABC, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0ABE, 0x0AC5, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0AC7, 0x0AC9, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0ACB, 0x0ACD, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0B01, 0x0B03, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0B3C, 0x0B3C, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0B3E, 0x0B43, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0B47, 0x0B48, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0B4B, 0x0B4D, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0B56, 0x0B57, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0B82, 0x0B83, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0BBE, 0x0BC2, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0BC6, 0x0BC8, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0BCA, 0x0BCD, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0BD7, 0x0BD7, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0C01, 0x0C03, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0C3E, 0x0C44, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0C46, 0x0C48, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0C4A, 0x0C4D, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0C55, 0x0C56, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0C82, 0x0C83, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0CBE, 0x0CC4, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0CC6, 0x0CC8, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0CCA, 0x0CCD, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0CD5, 0x0CD6, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0D02, 0x0D03, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0D3E, 0x0D43, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0D46, 0x0D48, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0D4A, 0x0D4D, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0D57, 0x0D57, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0E31, 0x0E31, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0E34, 0x0E3A, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0E47, 0x0E4E, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0EB1, 0x0EB1, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0EB4, 0x0EB9, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0EBB, 0x0EBC, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0EC8, 0x0ECD, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F18, 0x0F19, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F35, 0x0F35, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F37, 0x0F37, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F39, 0x0F39, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F3E, 0x0F3E, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F3F, 0x0F3F, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F71, 0x0F84, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F86, 0x0F8B, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F90, 0x0F95, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F97, 0x0F97, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0F99, 0x0FAD, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0FB1, 0x0FB7, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x0FB9, 0x0FB9, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x20D0, 0x20DC, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x20E1, 0x20E1, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x302A, 0x302F, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x3099, 0x3099, FLM_XML_COMBINING_CHAR); - setCharFlag( 0x309A, 0x309A, FLM_XML_COMBINING_CHAR); - - setCharFlag( 0x0030, 0x0039, FLM_XML_DIGIT); - setCharFlag( 0x0660, 0x0669, FLM_XML_DIGIT); - setCharFlag( 0x06F0, 0x06F9, FLM_XML_DIGIT); - setCharFlag( 0x0966, 0x096F, FLM_XML_DIGIT); - setCharFlag( 0x09E6, 0x09EF, FLM_XML_DIGIT); - setCharFlag( 0x0A66, 0x0A6F, FLM_XML_DIGIT); - setCharFlag( 0x0AE6, 0x0AEF, FLM_XML_DIGIT); - setCharFlag( 0x0B66, 0x0B6F, FLM_XML_DIGIT); - setCharFlag( 0x0BE7, 0x0BEF, FLM_XML_DIGIT); - setCharFlag( 0x0C66, 0x0C6F, FLM_XML_DIGIT); - setCharFlag( 0x0CE6, 0x0CEF, FLM_XML_DIGIT); - setCharFlag( 0x0D66, 0x0D6F, FLM_XML_DIGIT); - setCharFlag( 0x0E50, 0x0E59, FLM_XML_DIGIT); - setCharFlag( 0x0ED0, 0x0ED9, FLM_XML_DIGIT); - setCharFlag( 0x0F20, 0x0F29, FLM_XML_DIGIT); - - setCharFlag( 0x00B7, 0x00B7, FLM_XML_EXTENDER); - setCharFlag( 0x02D0, 0x02D0, FLM_XML_EXTENDER); - setCharFlag( 0x02D1, 0x02D1, FLM_XML_EXTENDER); - setCharFlag( 0x0387, 0x0387, FLM_XML_EXTENDER); - setCharFlag( 0x0640, 0x0640, FLM_XML_EXTENDER); - setCharFlag( 0x0E46, 0x0E46, FLM_XML_EXTENDER); - setCharFlag( 0x0EC6, 0x0EC6, FLM_XML_EXTENDER); - setCharFlag( 0x3005, 0x3005, FLM_XML_EXTENDER); - setCharFlag( 0x3031, 0x3035, FLM_XML_EXTENDER); - setCharFlag( 0x309D, 0x309E, FLM_XML_EXTENDER); - setCharFlag( 0x30FC, 0x30FE, FLM_XML_EXTENDER); - - setCharFlag( 0x0009, 0x0009, FLM_XML_WHITESPACE); - setCharFlag( 0x000A, 0x000A, FLM_XML_WHITESPACE); - setCharFlag( 0x000D, 0x000D, FLM_XML_WHITESPACE); - setCharFlag( 0x0020, 0x0020, FLM_XML_WHITESPACE); - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is a valid XML PubID character -****************************************************************************/ -FLMBOOL F_XML::isPubidChar( - FLMUNICODE uChar) -{ - if( uChar == FLM_UNICODE_SPACE || - uChar == FLM_UNICODE_LINEFEED || - (uChar >= FLM_UNICODE_a && uChar <= FLM_UNICODE_z) || - (uChar >= FLM_UNICODE_A && uChar <= FLM_UNICODE_Z) || - (uChar >= FLM_UNICODE_0 && uChar <= FLM_UNICODE_9) || - uChar == FLM_UNICODE_HYPHEN || - uChar == FLM_UNICODE_APOS || - uChar == FLM_UNICODE_LPAREN || - uChar == FLM_UNICODE_RPAREN || - uChar == FLM_UNICODE_PLUS || - uChar == FLM_UNICODE_COMMA || - uChar == FLM_UNICODE_PERIOD || - uChar == FLM_UNICODE_FSLASH || - uChar == FLM_UNICODE_COLON || - uChar == FLM_UNICODE_EQ || - uChar == FLM_UNICODE_QUEST || - uChar == FLM_UNICODE_SEMI || - uChar == FLM_UNICODE_BANG || - uChar == FLM_UNICODE_ASTERISK || - uChar == FLM_UNICODE_POUND || - uChar == FLM_UNICODE_ATSIGN || - uChar == FLM_UNICODE_DOLLAR || - uChar == FLM_UNICODE_UNDERSCORE || - uChar == FLM_UNICODE_PERCENT) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is a single or double quote character -****************************************************************************/ -FLMBOOL F_XML::isQuoteChar( - FLMUNICODE uChar) -{ - if( uChar == FLM_UNICODE_QUOTE || uChar == FLM_UNICODE_APOS) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is a whitespace character -****************************************************************************/ -FLMBOOL F_XML::isWhitespace( - FLMUNICODE uChar) -{ - if( (m_pCharTable[ uChar].ucFlags & FLM_XML_WHITESPACE) != 0) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is an extender character -****************************************************************************/ -FLMBOOL F_XML::isExtender( - FLMUNICODE uChar) -{ - if( (m_pCharTable[ uChar].ucFlags & FLM_XML_EXTENDER) != 0) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is a combining character -****************************************************************************/ -FLMBOOL F_XML::isCombiningChar( - FLMUNICODE uChar) -{ - if( (m_pCharTable[ uChar].ucFlags & FLM_XML_COMBINING_CHAR) != 0) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is a valid XML naming character -****************************************************************************/ -FLMBOOL F_XML::isNCNameChar( - FLMUNICODE uChar) -{ - if( isLetter( uChar) || - isDigit( uChar) || - uChar == FLM_UNICODE_PERIOD || - uChar == FLM_UNICODE_HYPHEN || - uChar == FLM_UNICODE_UNDERSCORE || - isCombiningChar( uChar) || isExtender( uChar)) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is a valid XML naming character -****************************************************************************/ -FLMBOOL F_XML::isNameChar( - FLMUNICODE uChar) -{ - if( isNCNameChar( uChar) || - uChar == FLM_UNICODE_COLON) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is an ideographic character -****************************************************************************/ -FLMBOOL F_XML::isIdeographic( - FLMUNICODE uChar) -{ - if( (m_pCharTable[ uChar].ucFlags & FLM_XML_IDEOGRAPHIC) != 0) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is a base character -****************************************************************************/ -FLMBOOL F_XML::isBaseChar( - FLMUNICODE uChar) -{ - if( (m_pCharTable[ uChar].ucFlags & FLM_XML_BASE_CHAR) != 0) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is a digit -****************************************************************************/ -FLMBOOL F_XML::isDigit( - FLMUNICODE uChar) -{ - if( (m_pCharTable[ uChar].ucFlags & FLM_XML_DIGIT) != 0) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the character is a letter -****************************************************************************/ -FLMBOOL F_XML::isLetter( - FLMUNICODE uChar) -{ - if( isBaseChar( uChar) || isIdeographic( uChar)) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Returns TRUE if the name is a valid XML name -****************************************************************************/ -FLMBOOL F_XML::isNameValid( - FLMUNICODE * puzName, - FLMBYTE * pszName) -{ - FLMBOOL bValid = FALSE; - - if( puzName) - { - FLMUNICODE * puzTmp; - - if( !isLetter( *puzName) && *puzName != FLM_UNICODE_UNDERSCORE && - *puzName != FLM_UNICODE_COLON) - { - goto Exit; - } - - puzTmp = &puzName[ 1]; - while( *puzTmp) - { - if( !isNameChar( *puzTmp)) - { - goto Exit; - } - puzTmp++; - } - } - - if( pszName) - { - FLMBYTE * pszTmp; - - if( !isLetter( *pszName) && *pszName != FLM_UNICODE_UNDERSCORE && - *pszName != FLM_UNICODE_COLON) - { - goto Exit; - } - - pszTmp = &pszName[ 1]; - while( *pszTmp) - { - if( !isNameChar( *pszTmp)) - { - goto Exit; - } - pszTmp++; - } - } - - bValid = TRUE; - -Exit: - - return( bValid); -} - -/**************************************************************************** -Desc: Constructor -****************************************************************************/ -F_XMLImport::F_XMLImport() -{ - m_uiValBufSize = 0; - m_pucValBuf = NULL; - m_bSetup = FALSE; - m_fnStatus = NULL; - m_pvCallbackData = NULL; - m_tmpPool.poolInit( 4096); - m_attrPool.poolInit( 4096); - m_puzCurrLineBuf = NULL; - m_uiCurrLineBufMaxChars = 0; - reset(); -} - -/**************************************************************************** -Desc: Destructor -****************************************************************************/ -F_XMLImport::~F_XMLImport() -{ - reset(); - - if( m_pucValBuf) - { - f_free( &m_pucValBuf); - } - if (m_puzCurrLineBuf) - { - f_free( &m_puzCurrLineBuf); - } -} - -/**************************************************************************** -Desc: Resets member variables so the object can be reused -****************************************************************************/ -void F_XMLImport::reset( void) -{ - m_uiCurrLineNum = 0; - m_uiCurrLineNumChars = 0; - m_uiCurrLineOffset = 0; - m_ucUngetByte = 0; - m_uiCurrLineFilePos = 0; - m_uiCurrLineBytes = 0; - m_pStream = NULL; - m_uiFlags = 0; - m_eXMLEncoding = XFLM_XML_USASCII_ENCODING; - m_pDb = NULL; - m_uiCollection = 0; - f_memset( &m_importStats, 0, sizeof( XFLM_IMPORT_STATS)); - - popNamespaces( getNamespaceCount()); - m_tmpPool.poolReset( NULL); - resetAttrList(); -} - -/**************************************************************************** -Desc: Initializes the object (allocates buffers, etc.) -****************************************************************************/ -RCODE F_XMLImport::setup( void) -{ - RCODE rc = NE_XFLM_OK; - - flmAssert( !m_bSetup); - - if( RC_BAD( rc = resizeValBuffer( 2048))) - { - goto Exit; - } - - if( RC_BAD( rc = buildCharTable())) - { - goto Exit; - } - - m_bSetup = TRUE; - -Exit: - - if( RC_BAD( rc)) - { - if( m_pucValBuf) - { - f_free( &m_pucValBuf); - m_pucValBuf = NULL; - } - } - - return( rc); -} - -/**************************************************************************** -Desc: Reads data from the input stream and builds a FLAIM record -****************************************************************************/ -RCODE F_XMLImport::import( - F_IStream * pStream, - F_Db * pDb, - FLMUINT uiCollection, - FLMUINT uiFlags, - F_DOMNode * pNodeToLinkTo, - eNodeInsertLoc eInsertLoc, - F_DOMNode ** ppNewNode, - XFLM_IMPORT_STATS * pImportStats) -{ - RCODE rc = NE_XFLM_OK; - - // Reset the state of the parser - - reset(); - - // If a root element was passed in, do some sanity checks - // before importing the XML stream - - if (pNodeToLinkTo) - { - FLMUINT uiTmp; - - if( RC_BAD( rc = pNodeToLinkTo->getCollection( pDb, &uiTmp))) - { - goto Exit; - } - - if( uiTmp != uiCollection) - { - rc = RC_SET( NE_XFLM_ILLEGAL_OP); - goto Exit; - } - } - - m_pDb = pDb; - m_uiCollection = uiCollection; - - // Set up namespace support. Un-prefixed names (NULL prefix) are - // not bound to a namespace (NULL URI). The 'xml' namespace prefix - // is, by definition, bound to 'http://www.w3.org/XML/1998/namespace' - - if( RC_BAD( rc = pushNamespace( NULL, NULL))) - { - goto Exit; - } - - if( RC_BAD( rc = pushNamespace( - gv_puzXMLPrefix, gv_puzXMLNSURI))) - { - goto Exit; - } - - m_pStream = pStream; - m_uiFlags = uiFlags; - - if( RC_BAD( rc = processProlog())) - { - goto Exit; - } - - if( RC_BAD( rc = processElement( pNodeToLinkTo, eInsertLoc, ppNewNode))) - { - goto Exit; - } - - // Call the status hook one last time - - m_importStats.uiDocuments++; - if( m_fnStatus) - { - m_fnStatus( XML_STATS, - (void *)&m_importStats, NULL, NULL, m_pvCallbackData); - } - - // Tally and return the import stats - - if( pImportStats) - { - pImportStats->uiChars += m_importStats.uiChars; - pImportStats->uiAttributes += m_importStats.uiAttributes; - pImportStats->uiElements += m_importStats.uiElements; - pImportStats->uiText += m_importStats.uiText; - pImportStats->uiDocuments += m_importStats.uiDocuments; - } - -Exit: - - if( RC_BAD( rc) && pImportStats) - { - pImportStats->uiErrLineNum = m_importStats.uiErrLineNum - ? m_importStats.uiErrLineNum - : m_uiCurrLineNum; - - pImportStats->uiErrLineOffset = m_importStats.uiErrLineOffset - ? m_importStats.uiErrLineOffset - : m_uiCurrLineOffset; - - pImportStats->eErrorType = ( XMLParseError)( m_importStats.eErrorType); - - pImportStats->uiErrLineFilePos = m_importStats.uiErrLineFilePos; - pImportStats->uiErrLineBytes = m_importStats.uiErrLineBytes; - pImportStats->eXMLEncoding = m_importStats.eXMLEncoding; - } - - m_pDb = NULL; - m_uiCollection = 0; - return( rc); -} - -/**************************************************************************** -Desc: Process an XML prolog -****************************************************************************/ -RCODE F_XMLImport::processProlog( void) -{ - RCODE rc = NE_XFLM_OK; - - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - if (lineHasToken( "createNode( m_pDb, DATA_NODE, 0, - XFLM_LAST_CHILD, (IF_DOMNode **)&pData))) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset, - XML_ERR_CREATING_DATA_NODE, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - goto Exit; - } - - switch( pParent->m_pCachedNode->getDataType()) - { - case XFLM_TEXT_TYPE: - { - if( RC_BAD( rc = pData->setUnicode( m_pDb, puzTextStart))) - { - goto Exit; - } - - m_importStats.uiText++; - if( m_fnStatus && (m_importStats.uiText % 50) == 0) - { - m_fnStatus( XML_STATS, - (void *)&m_importStats, NULL, NULL, m_pvCallbackData); - } - - break; - } - - case XFLM_NUMBER_TYPE: - { - FLMUINT64 ui64Val; - FLMBOOL bNeg; - - if( RC_BAD( rc = unicodeToNumber64( puzTextStart, &ui64Val, &bNeg))) - { - goto Exit; - } - - if( !bNeg) - { - if( RC_BAD( rc = pData->setUINT64( m_pDb, ui64Val))) - { - goto Exit; - } - } - else - { - if( RC_BAD( rc = pData->setINT64( m_pDb, -((FLMINT64)ui64Val)))) - { - goto Exit; - } - } - break; - } - - case XFLM_BINARY_TYPE: - { - if( RC_BAD( rc = pData->setBinary( m_pDb, pucValue, uiValueLen))) - { - goto Exit; - } - break; - } - - default: - { - rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED); - goto Exit; - } - } - -Exit: - - if( pData) - { - pData->Release(); - } - - return( rc); -} - -/**************************************************************************** -Desc: Processes an XML element -****************************************************************************/ -RCODE F_XMLImport::processElement( - F_DOMNode * pNodeToLinkTo, - eNodeInsertLoc eInsertLoc, - F_DOMNode ** ppNewNode) -{ - RCODE rc = NE_XFLM_OK; - FLMBOOL bHasContent; - FLMBOOL bFlushedValue = FALSE; - FLMUINT uiChars; - FLMUINT uiOffset = 0; - FLMUNICODE uChar; - F_DOMNode * pElement = NULL; - F_XMLNamespace * pNamespace = NULL; - FLMUNICODE * puzPrefix; - FLMUNICODE * puzLocal; - FLMUINT uiStartNSCount = getNamespaceCount(); - FLMUINT uiTmp; - FLMUINT uiWhitespaceStartOffset = 0; - FLMBOOL bNamespaceDecl; - FLMUINT uiSavedLineNum = 0; - FLMUINT uiSavedOffset = 0; - FLMUINT uiSavedFilePos = 0; - FLMUINT uiSavedLineBytes = 0; - - if( RC_BAD( rc = processSTag( pNodeToLinkTo, eInsertLoc, &bHasContent, &pElement))) - { - goto Exit; - } - if (ppNewNode) - { - *ppNewNode = pElement; - (*ppNewNode)->AddRef(); - } - - if( !bHasContent) - { - goto Exit; - } - - for( ;;) - { - if ((uChar = getChar()) == 0) - { - uChar = ASCII_NEWLINE; - if (RC_BAD( rc = getLine())) - { - goto Exit; - } - } - - if( uChar == FLM_UNICODE_LT) - { - if( uiWhitespaceStartOffset) - { - // Set the offset to where the whitespace would - // have started. - - flmAssert( uiWhitespaceStartOffset <= uiOffset); - uiOffset = uiWhitespaceStartOffset; - uiWhitespaceStartOffset = 0; - } - - if( uiOffset) - { - // Flush the value - - if( pElement) - { - if( pElement->m_pCachedNode->getDataType() == XFLM_TEXT_TYPE || - pElement->m_pCachedNode->getDataType() == XFLM_NUMBER_TYPE) - { - if( uiOffset + 1 >= m_uiValBufSize) - { - if( RC_BAD( rc = resizeValBuffer( uiOffset + 2))) - { - goto Exit; - } - } - - m_pucValBuf[ uiOffset] = 0; - m_pucValBuf[ uiOffset + 1] = 0; - } - - if( RC_BAD( rc = flushElementValue( - pElement, m_pucValBuf, uiOffset))) - { - goto Exit; - } - } - - bFlushedValue = TRUE; - uiOffset = 0; - } - - // Preserve start location for error handling if necessary - - uiSavedLineNum = m_uiCurrLineNum; - uiSavedOffset = m_uiCurrLineOffset; - uiSavedFilePos = m_uiCurrLineFilePos; - uiSavedLineBytes = m_uiCurrLineBytes; - - if (lineHasToken( "?")) - { - if( RC_BAD( rc = processPI( pElement, - uiSavedLineNum, - uiSavedOffset, - uiSavedFilePos, - uiSavedLineBytes))) - { - goto Exit; - } - } - else if (lineHasToken( "!--")) - { - if( RC_BAD( rc = processComment( pElement, - uiSavedLineNum, - uiSavedOffset, - uiSavedFilePos, - uiSavedLineBytes))) - { - goto Exit; - } - } - else if (lineHasToken( "![CDATA[")) - { - if( RC_BAD( rc = processCDATA( pElement, - uiSavedLineNum, - uiSavedOffset, - uiSavedFilePos, - uiSavedLineBytes))) - { - goto Exit; - } - } - else if (lineHasToken( "/")) - { - break; - } - else if( isNameChar( peekChar())) - { - - // Unget the "<" - because processElement expect to see - // "m_pCachedNode->getDataType() == XFLM_BINARY_TYPE) - { - ungetChar(); - - if( RC_BAD( rc = getBinaryVal( &uiOffset))) - { - goto Exit; - } - } - else if (uChar == FLM_UNICODE_AMP) - { - if( RC_BAD( rc = processReference( &uChar))) - { - goto Exit; - } - - flmAssert( uChar); - if (pElement->m_pCachedNode->getDataType() != XFLM_NODATA_TYPE) - { - *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar; - uiOffset += sizeof( FLMUNICODE); - uiWhitespaceStartOffset = 0; - - if( uiOffset >= m_uiValBufSize) - { - if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) - { - goto Exit; - } - } - } - } - else - { - if( pElement->m_pCachedNode->getDataType() != XFLM_NODATA_TYPE) - { - if( m_uiFlags & FLM_XML_COMPRESS_WHITESPACE_FLAG) - { - if( isWhitespace( uChar)) - { - // If uiOffset is zero, this is still leading - // white space, and we should ignore it. - // Otherwise, we need to keep track of where - // whitespace began. - - if( !uiOffset) - { - uChar = 0; - } - else - { - uiWhitespaceStartOffset = uiOffset; - } - } - else - { - - // Last character is not whitespace. - - uiWhitespaceStartOffset = 0; - } - } - - if( uChar) - { - *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar; - uiOffset += sizeof( FLMUNICODE); - if( uiOffset >= m_uiValBufSize) - { - if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) - { - goto Exit; - } - } - } - } - } - } - - flmAssert( !uiOffset); - - - uiSavedOffset = m_uiCurrLineOffset; - if( RC_BAD( rc = getQualifiedName( &uiChars, - &puzPrefix, &puzLocal, &bNamespaceDecl, NULL))) - { - goto Exit; - } - - // Validate that the end tag matches the start tag - - if( pElement) - { - - // Element names cannot be "xmlns" or begin with "xmlns:" - - if (bNamespaceDecl) - { - setErrInfo( m_uiCurrLineNum, - uiSavedOffset, - XML_ERR_XMLNS_IN_ELEMENT_NAME, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - if( puzPrefix) - { - FLMUINT uiPrefixId1; - FLMUINT uiPrefixId2; - - if( RC_BAD( rc = m_pDb->m_pDict->getPrefixId( - m_pDb, puzPrefix, &uiPrefixId1))) - { - goto Exit; - } - - if( RC_BAD( rc = pElement->getPrefixId( m_pDb, &uiPrefixId2))) - { - goto Exit; - } - - if( uiPrefixId1 != uiPrefixId2) - { - setErrInfo( m_uiCurrLineNum, - uiSavedOffset, - XML_ERR_ELEMENT_NAME_MISMATCH, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - } - else - { - if( RC_BAD( rc = pElement->getPrefixId( m_pDb, &uiTmp))) - { - goto Exit; - } - - if( uiTmp) - { - setErrInfo( m_uiCurrLineNum, - uiSavedOffset, - XML_ERR_ELEMENT_NAME_MISMATCH, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - } - - if( RC_BAD( rc = findNamespace( puzPrefix, &pNamespace))) - { - if( rc == NE_XFLM_NOT_FOUND) - { - setErrInfo( m_uiCurrLineNum, - uiSavedOffset, - XML_ERR_PREFIX_NOT_DEFINED, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - } - goto Exit; - } - - if( RC_BAD( rc = m_pDb->getElementNameId( - pNamespace->getURIPtr(), puzLocal, &uiTmp))) - { - if( rc == NE_XFLM_NOT_FOUND) - { - setErrInfo( m_uiCurrLineNum, - uiSavedOffset, - XML_ERR_ELEMENT_NAME_MISMATCH, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - } - goto Exit; - } - - if( pElement->getNameId() != uiTmp) - { - setErrInfo( m_uiCurrLineNum, - uiSavedOffset, - XML_ERR_ELEMENT_NAME_MISMATCH, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - } - - // Skip any whitespace after the name - - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - // Get the ending ">" - - if( getChar() != FLM_UNICODE_GT) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_GT, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - -Exit: - - if( pNamespace) - { - pNamespace->Release(); - } - - popNamespaces( getNamespaceCount() - uiStartNSCount); - - if( pElement) - { - pElement->Release(); - } - - return( rc); -} - -/**************************************************************************** -Desc: Processes an XML STag -****************************************************************************/ -RCODE F_XMLImport::processSTag( - F_DOMNode * pNodeToLinkTo, - eNodeInsertLoc eInsertLoc, - FLMBOOL * pbHasContent, - F_DOMNode ** ppElement) -{ - FLMUNICODE uChar; - FLMUINT uiChars; - F_DOMNode * pElement = NULL; - F_XMLNamespace * pNamespace = NULL; - FLMUNICODE * puzTmpPrefix; - FLMUNICODE * puzPrefix = NULL; - FLMUNICODE * puzTmpLocal; - FLMUNICODE * puzLocal = NULL; - FLMUINT uiNameId; - FLMUINT uiAllocSize; - void * pvMark = m_tmpPool.poolMark(); - RCODE rc = NE_XFLM_OK; - FLMBOOL bNamespaceDecl; - FLMUINT uiSavedLineNum; - FLMUINT uiSavedOffset; - FLMUINT uiSavedFilePos; - FLMUINT uiSavedLineBytes; - - *pbHasContent = FALSE; - - if( getChar() != FLM_UNICODE_LT) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_ELEMENT_LT, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - uiSavedLineNum = m_uiCurrLineNum; - uiSavedOffset = m_uiCurrLineOffset; - uiSavedFilePos = m_uiCurrLineFilePos; - uiSavedLineBytes = m_uiCurrLineBytes; - if( RC_BAD( rc = getQualifiedName( &uiChars, &puzTmpPrefix, &puzTmpLocal, - &bNamespaceDecl, NULL))) - { - goto Exit; - } - - // Element names cannot be "xmlns" or begin with "xmlns:" - - if (bNamespaceDecl) - { - setErrInfo( uiSavedLineNum, - uiSavedOffset, - XML_ERR_XMLNS_IN_ELEMENT_NAME, - uiSavedFilePos, - uiSavedLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - uiAllocSize = (f_unilen( puzTmpLocal) + 1) * sizeof( FLMUNICODE); - if( RC_BAD( rc = m_tmpPool.poolAlloc( uiAllocSize, (void **)&puzLocal))) - { - goto Exit; - } - f_unicpy( puzLocal, puzTmpLocal); - - if( puzTmpPrefix) - { - - // Need to save the prefix, because as parsing - // continues, the scratch buffer will be overwritten - - uiAllocSize = (f_unilen( puzTmpPrefix) + 1) * sizeof( FLMUNICODE); - if( RC_BAD( rc = m_tmpPool.poolAlloc( uiAllocSize, (void **)&puzPrefix))) - { - goto Exit; - } - f_unicpy( puzPrefix, puzTmpPrefix); - } - - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - // Read the attributes - - resetAttrList(); - - uChar = peekChar(); - if( uChar != FLM_UNICODE_GT && uChar != FLM_UNICODE_FSLASH) - { - if( RC_BAD( rc = processAttributeList())) - { - goto Exit; - } - } - - // Find or create the element's name ID - - if( RC_BAD( rc = findNamespace( puzPrefix, &pNamespace))) - { - if( rc == NE_XFLM_NOT_FOUND) - { - setErrInfo( uiSavedLineNum, - uiSavedOffset, - XML_ERR_PREFIX_NOT_DEFINED, - uiSavedFilePos, - uiSavedLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - } - goto Exit; - } - - if( RC_BAD( rc = m_pDb->getElementNameId( - pNamespace->getURIPtr(), puzLocal, &uiNameId))) - { - if( rc != NE_XFLM_NOT_FOUND) - { - goto Exit; - } - - if( !(m_uiFlags & FLM_XML_EXTEND_DICT_FLAG) || - (pNamespace->getURIPtr() && - f_unicmp( pNamespace->getURIPtr(), gv_uzXFLAIMNamespace) == 0)) - { - rc = RC_SET( NE_XFLM_UNDEFINED_ELEMENT_NAME); - goto Exit; - } - - // Automatically extend the schema - - uiNameId = 0; - if( RC_BAD( rc = m_pDb->createElementDef( - pNamespace->getURIPtr(), - puzLocal, XFLM_TEXT_TYPE, &uiNameId))) - { - goto Exit; - } - } - - // Create the element node - - if( pNodeToLinkTo) - { - if( RC_BAD( rc = pNodeToLinkTo->createNode( m_pDb, ELEMENT_NODE, - uiNameId, eInsertLoc, (IF_DOMNode **)&pElement))) - { - setErrInfo( uiSavedLineNum, - uiSavedOffset, - XML_ERR_CREATING_ELEMENT_NODE, - uiSavedFilePos, - uiSavedLineBytes); - goto Exit; - } - } - else - { - if( RC_BAD( rc = m_pDb->createRootElement( m_uiCollection, - uiNameId, (IF_DOMNode **)&pElement))) - { - setErrInfo( uiSavedLineNum, - uiSavedOffset, - XML_ERR_CREATING_ROOT_ELEMENT, - uiSavedFilePos, - uiSavedLineBytes); - goto Exit; - } - } - - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - // Need to end with ">" or "/>" - - uChar = getChar(); - if( uChar == FLM_UNICODE_GT) - { - *pbHasContent = TRUE; - } - else if( uChar == FLM_UNICODE_FSLASH) - { - if( getChar() != FLM_UNICODE_GT) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_GT, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - } - else - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_GT, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - // Set the element's prefix - - if( RC_BAD( rc = addAttributesToElement( pElement))) - { - goto Exit; - } - - if( puzPrefix) - { - if( RC_BAD( rc = pElement->setPrefix( m_pDb, puzPrefix))) - { - goto Exit; - } - } - - if( ppElement) - { - *ppElement = pElement; - pElement = NULL; - } - - m_importStats.uiElements++; - if( m_fnStatus && (m_importStats.uiElements % 50) == 0) - { - m_fnStatus( XML_STATS, - (void *)&m_importStats, NULL, NULL, m_pvCallbackData); - } - -Exit: - - if( pElement) - { - pElement->Release(); - } - - if( pNamespace) - { - pNamespace->Release(); - } - - m_tmpPool.poolReset( pvMark); - return( rc); -} - -/**************************************************************************** -Desc: Processes an element's attributes -****************************************************************************/ -RCODE F_XMLImport::processAttributeList( void) -{ - RCODE rc = NE_XFLM_OK; - FLMUINT uiChars; - FLMUNICODE * puzLocal; - FLMUNICODE * puzPrefix; - XML_ATTR * pAttr = NULL; - FLMBOOL bFoundDefaultNamespace = FALSE; - FLMUINT uiNamespaceCount = 0; - FLMBOOL bNamespaceDecl; - FLMBOOL bDefaultNamespaceDecl; - FLMUINT uiSavedLineNum; - FLMUINT uiSavedOffset; - FLMUINT uiSavedFilePos; - FLMUINT uiSavedLineBytes; - - for( ;;) - { - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - if( !isNameChar( peekChar())) - { - break; - } - - uiSavedLineNum = m_uiCurrLineNum; - uiSavedOffset = m_uiCurrLineOffset; - uiSavedFilePos = m_uiCurrLineFilePos; - uiSavedLineBytes = m_uiCurrLineBytes; - if( RC_BAD( rc = getQualifiedName( &uiChars, - &puzPrefix, &puzLocal, &bNamespaceDecl, - &bDefaultNamespaceDecl))) - { - goto Exit; - } - - if( RC_BAD( rc = allocAttribute( &pAttr))) - { - goto Exit; - } - pAttr->uiLineNum = uiSavedLineNum; - pAttr->uiLineOffset = uiSavedOffset; - pAttr->uiLineFilePos = uiSavedFilePos; - pAttr->uiLineBytes = uiSavedLineBytes; - - if( RC_BAD( rc = setPrefix( pAttr, puzPrefix))) - { - goto Exit; - } - - if( RC_BAD( rc = setLocalName( pAttr, puzLocal))) - { - goto Exit; - } - if (bNamespaceDecl) - { - if (bDefaultNamespaceDecl) - { - pAttr->uiFlags |= F_DEFAULT_NS_DECL; - } - else - { - pAttr->uiFlags |= F_PREFIXED_NS_DECL; - } - } - - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - // Attribute name must be followed by an "=" - - if( getChar() != FLM_UNICODE_EQ) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_EQ, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - pAttr->uiValueLineNum = m_uiCurrLineNum; - pAttr->uiValueLineOffset = m_uiCurrLineOffset; - if( RC_BAD( rc = processAttValue( pAttr))) - { - goto Exit; - } - - m_importStats.uiAttributes++; - if( m_fnStatus && (m_importStats.uiAttributes % 50) == 0) - { - m_fnStatus( XML_STATS, - (void *)&m_importStats, NULL, NULL, m_pvCallbackData); - } - } - - // Push any namespace declarations onto the stack - - for( pAttr = m_pFirstAttr; pAttr; pAttr = pAttr->pNext) - { - // Duplicate namespace declarations are not allowed within a single element. - // So, multiple default namespace declarations or multiple uses of the same - // prefix in will result in a syntax error. - - if( pAttr->uiFlags & F_DEFAULT_NS_DECL) - { - // Default namespace declaration - - if( bFoundDefaultNamespace) - { - setErrInfo( pAttr->uiLineNum, - pAttr->uiLineOffset, - XML_ERR_MULTIPLE_XMLNS_DECLS, - pAttr->uiLineFilePos, - pAttr->uiLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - if( !pAttr->puzVal || *pAttr->puzVal == 0) - { - // No namespace - - if( RC_BAD( rc = pushNamespace( NULL, NULL))) - { - goto Exit; - } - } - else - { - if( RC_BAD( rc = pushNamespace( NULL, pAttr->puzVal))) - { - goto Exit; - } - } - - uiNamespaceCount++; - bFoundDefaultNamespace = TRUE; - } - else if( pAttr->uiFlags & F_PREFIXED_NS_DECL) - { - // Check for a unique prefix within current element - - if( RC_OK( rc = findNamespace( &pAttr->puzLocalName [6], - NULL, uiNamespaceCount))) - { - setErrInfo( pAttr->uiLineNum, - pAttr->uiLineOffset, - XML_ERR_MULTIPLE_PREFIX_DECLS, - pAttr->uiLineFilePos, - pAttr->uiLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - else if( rc != NE_XFLM_NOT_FOUND) - { - goto Exit; - } - else - { - rc = NE_XFLM_OK; - } - - if( RC_BAD( rc = pushNamespace( - &pAttr->puzLocalName [6], pAttr->puzVal))) - { - goto Exit; - } - - uiNamespaceCount++; - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Processes an XML declaration -****************************************************************************/ -RCODE F_XMLImport::processXMLDecl( void) -{ - RCODE rc = NE_XFLM_OK; - FLMUNICODE uChar; - - // Have already eaten the "")) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset, - XML_ERR_EXPECTING_QUEST_GT, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Processes an XML document type declaration -****************************************************************************/ -RCODE F_XMLImport::processDocTypeDecl( void) -{ - RCODE rc = NE_XFLM_OK; - FLMUNICODE uChar; - - // Have already eaten the "' - - if( RC_BAD( rc = skipWhitespace( TRUE))) - { - goto Exit; - } - } - - // Get the system ID - - if (RC_BAD( rc = getSystemLiteral())) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Processes a notation declaration -****************************************************************************/ -RCODE F_XMLImport::processNotationDecl( void) -{ - RCODE rc = NE_XFLM_OK; - - // Have already eaten up the "#PCDATA" - - for( ;;) - { - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - uChar = getChar(); - if( uChar == FLM_UNICODE_RPAREN) - { - break; - } - else if( uChar == FLM_UNICODE_PIPE) - { - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - if( RC_BAD( rc = getName( NULL))) - { - goto Exit; - } - - bExpectingAsterisk = TRUE; - } - else - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_RPAREN_OR_PIPE, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - } - - if( bExpectingAsterisk) - { - if( getChar() != FLM_UNICODE_ASTERISK) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_ASTERISK, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Processes child content -****************************************************************************/ -RCODE F_XMLImport::processChildContent( void) -{ - FLMUNICODE uChar; - FLMUINT uiItemCount = 0; - FLMUINT uiDelimCount = 0; - FLMBOOL bChoice = FALSE; - FLMBOOL bSeq = FALSE; - RCODE rc = NE_XFLM_OK; - - // Have eaten up the "(" - - for( ;;) - { - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - uChar = getChar(); - if( uChar == FLM_UNICODE_LPAREN) - { - if( RC_BAD( rc = processChildContent())) - { - goto Exit; - } - - uiItemCount++; - } - else if (uChar == FLM_UNICODE_RPAREN) - { - if( !uiItemCount || (uiItemCount - 1) != uiDelimCount) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EMPTY_CONTENT_INVALID, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - break; - } - else if (uChar == FLM_UNICODE_PIPE) - { - if( bSeq) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_CANNOT_MIX_CHOICE_AND_SEQ, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - bChoice = TRUE; - uiDelimCount++; - } - else if (uChar == FLM_UNICODE_COMMA) - { - if (bChoice) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_CANNOT_MIX_CHOICE_AND_SEQ, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - bSeq = TRUE; - uiDelimCount++; - } - else - { - ungetChar(); - if( RC_BAD( rc = getName( NULL))) - { - goto Exit; - } - uiItemCount++; - - uChar = peekChar(); - if (uChar == FLM_UNICODE_QUEST || - uChar == FLM_UNICODE_ASTERISK || - uChar == FLM_UNICODE_PLUS) - { - - // Eat up a "?", "*", or "+" - - (void)getChar(); - } - } - } - - uChar = peekChar(); - if( uChar == FLM_UNICODE_QUEST || - uChar == FLM_UNICODE_ASTERISK || - uChar == FLM_UNICODE_PLUS) - { - // Eat up a "?", "*", or "+" - - (void)getChar(); - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Processes a misc. declaration -****************************************************************************/ -RCODE F_XMLImport::processMisc( void) -{ - RCODE rc = NE_XFLM_OK; - - for( ;;) - { - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - if( rc == NE_XFLM_IO_END_OF_FILE || rc == NE_XFLM_EOF_HIT) - { - rc = NE_XFLM_OK; - } - goto Exit; - } - - if (lineHasToken( "")) - { - break; - } - - if ((uChar = getChar()) == 0) - { - if (RC_BAD( rc = getLine())) - { - goto Exit; - } - uChar = ASCII_NEWLINE; - } - - *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar; - uiOffset += sizeof( FLMUNICODE); - - if( uiOffset >= uiMaxOffset) - { - if (RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) - { - goto Exit; - } - uiMaxOffset = m_uiValBufSize; - } - } - - if( pParent) - { - if( RC_BAD( rc = pParent->createNode( m_pDb, COMMENT_NODE, 0, - XFLM_LAST_CHILD, (IF_DOMNode **)&pComment))) - { - setErrInfo( uiSavedLineNum, - uiSavedOffset, - XML_ERR_CREATING_COMMENT_NODE, - uiSavedFilePos, - uiSavedLineBytes); - goto Exit; - } - - *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = 0; - - if( RC_BAD( rc = pComment->setUnicode( - m_pDb, (FLMUNICODE *)m_pucValBuf))) - { - goto Exit; - } - - pComment->Release(); - pComment = NULL; - } - -Exit: - - if( pComment) - { - pComment->Release(); - } - - return( rc); -} - -/**************************************************************************** -Desc: Processes a CDATA tag -****************************************************************************/ -RCODE F_XMLImport::processCDATA( - F_DOMNode * pParent, - FLMUINT uiSavedLineNum, - FLMUINT uiSavedOffset, - FLMUINT uiSavedFilePos, - FLMUINT uiSavedLineBytes) -{ - FLMUNICODE uChar; - FLMUINT uiOffset = 0; - F_DOMNode * pCData = NULL; - RCODE rc = NE_XFLM_OK; - - // Have already eaten up the "")) - { - break; - } - if ((uChar = getChar()) == 0) - { - if (RC_BAD( rc = getLine())) - { - goto Exit; - } - uChar = ASCII_NEWLINE; - } - - *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar; - uiOffset += sizeof( FLMUNICODE); - - if( uiOffset >= m_uiValBufSize) - { - if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) - { - goto Exit; - } - } - } - - if( pParent) - { - if( RC_BAD( rc = pParent->createNode( m_pDb, CDATA_SECTION_NODE, 0, - XFLM_LAST_CHILD, (IF_DOMNode **)&pCData))) - { - setErrInfo( uiSavedLineNum, - uiSavedOffset, - XML_ERR_CREATING_CDATA_NODE, - uiSavedFilePos, - uiSavedLineBytes); - goto Exit; - } - - *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = 0; - if( RC_BAD( rc = pCData->setUnicode( m_pDb, (FLMUNICODE *)m_pucValBuf))) - { - goto Exit; - } - - pCData->Release(); - pCData = NULL; - } - -Exit: - - if( pCData) - { - pCData->Release(); - } - - return( rc); -} - -/**************************************************************************** -Desc: Skips any whitespace characters in the input stream -****************************************************************************/ -RCODE F_XMLImport::skipWhitespace( - FLMBOOL bRequired) -{ - FLMUNICODE uChar; - FLMUINT uiCount = 0; - RCODE rc = NE_XFLM_OK; - - for( ;;) - { - if ((uChar = getChar()) == 0) - { - uiCount++; - if (RC_BAD( rc = getLine())) - { - goto Exit; - } - continue; - } - - if( !isWhitespace( uChar)) - { - ungetChar(); - break; - } - uiCount++; - } - - if( !uiCount && bRequired) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset, - XML_ERR_EXPECTING_WHITESPACE, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: -******************************************************************************/ -RCODE F_XMLImport::resizeValBuffer( - FLMUINT uiSize) -{ - RCODE rc = NE_XFLM_OK; - - if( uiSize == m_uiValBufSize) - { - goto Exit; - } - - if( uiSize == ~((FLMUINT)0)) - { - uiSize = m_uiValBufSize + 2048; - } - - if( m_pucValBuf) - { - if( uiSize) - { - if( RC_BAD( rc = f_realloc( uiSize, &m_pucValBuf))) - { - goto Exit; - } - } - else - { - f_free( &m_pucValBuf); - m_pucValBuf = NULL; - } - } - else - { - flmAssert( !m_pucValBuf); - - if( RC_BAD( rc = f_alloc( uiSize, &m_pucValBuf))) - { - goto Exit; - } - } - - m_uiValBufSize = uiSize; - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: -******************************************************************************/ -RCODE F_XMLImport::getBinaryVal( - FLMUINT * puiLength) -{ - RCODE rc = NE_XFLM_OK; - FLMUNICODE uChar; - FLMUNICODE uChar2; - FLMUINT uiOffset = 0; - FLMBOOL bHavePreamble; - - flmAssert( *puiLength == 0); - - for( ;;) - { - bHavePreamble = FALSE; - - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - -Retry: - - uChar = getChar(); - if( !f_isHexChar( uChar)) - { - if( uChar != FLM_UNICODE_LT) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_HEX_DIGIT, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - ungetChar(); - break; - } - - uChar2 = getChar(); - if( uChar == FLM_UNICODE_0 && - (uChar2 == FLM_UNICODE_X || uChar2 == FLM_UNICODE_x)) - { - if( bHavePreamble) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_HEX_DIGIT, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - bHavePreamble = TRUE; - goto Retry; - } - - if( !f_isHexChar( uChar2)) - { - setErrInfo( m_uiCurrLineNum, - m_uiCurrLineOffset - 1, - XML_ERR_EXPECTING_HEX_DIGIT, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - if( uiOffset >= m_uiValBufSize) - { - if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) - { - goto Exit; - } - } - - m_pucValBuf[ uiOffset++] = - (f_getHexVal( uChar) << 4) | f_getHexVal( uChar2); - - if( RC_BAD( rc = skipWhitespace( FALSE))) - { - goto Exit; - } - - uChar = getChar(); - if( uChar != FLM_UNICODE_COMMA) - { - ungetChar(); - } - } - - *puiLength = uiOffset; - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Constructor -****************************************************************************/ -F_XMLNamespaceMgr::F_XMLNamespaceMgr() -{ - m_pFirstNamespace = NULL; - m_uiNamespaceCount = 0; -} - -/**************************************************************************** -Desc: Destructor -****************************************************************************/ -F_XMLNamespaceMgr::~F_XMLNamespaceMgr() -{ - popNamespaces( m_uiNamespaceCount); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_XMLNamespaceMgr::popNamespaces( - FLMUINT uiCount) -{ - F_XMLNamespace * pTmpNamespace; - - flmAssert( uiCount <= m_uiNamespaceCount); - - while( uiCount && m_pFirstNamespace) - { - pTmpNamespace = m_pFirstNamespace; - m_pFirstNamespace = m_pFirstNamespace->m_pNext; - pTmpNamespace->m_pNext = NULL; - pTmpNamespace->Release(); - m_uiNamespaceCount--; - uiCount--; - } -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_XMLNamespaceMgr::findNamespace( - FLMUNICODE * puzPrefix, - F_XMLNamespace ** ppNamespace, - FLMUINT uiMaxSearchSize) -{ - F_XMLNamespace * pTmpNamespace = m_pFirstNamespace; - RCODE rc = NE_XFLM_OK; - - while( pTmpNamespace) - { - if( !uiMaxSearchSize) - { - pTmpNamespace = NULL; - break; - } - - if( !puzPrefix && !pTmpNamespace->m_puzPrefix) - { - break; - } - else if( puzPrefix && pTmpNamespace->m_puzPrefix) - { - if( f_unicmp( puzPrefix, pTmpNamespace->m_puzPrefix) == 0) - { - break; - } - } - - pTmpNamespace = pTmpNamespace->m_pNext; - uiMaxSearchSize--; - } - - if( !pTmpNamespace) - { - rc = RC_SET( NE_XFLM_NOT_FOUND); - goto Exit; - } - - if( ppNamespace) - { - if( *ppNamespace) - { - (*ppNamespace)->Release(); - } - - pTmpNamespace->AddRef(); - *ppNamespace = pTmpNamespace; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_XMLNamespaceMgr::pushNamespace( - FLMUNICODE * puzPrefix, - FLMUNICODE * puzNamespaceURI) -{ - F_XMLNamespace * pNewNamespace = NULL; - RCODE rc = NE_XFLM_OK; - - if( (pNewNamespace = f_new F_XMLNamespace) == NULL) - { - rc = RC_SET( NE_XFLM_MEM); - goto Exit; - } - - if( RC_BAD( rc = pNewNamespace->setPrefix( puzPrefix))) - { - goto Exit; - } - - if( RC_BAD( rc = pNewNamespace->setURI( puzNamespaceURI))) - { - goto Exit; - } - - pNewNamespace->m_pNext = m_pFirstNamespace; - m_pFirstNamespace = pNewNamespace; - pNewNamespace = NULL; - m_uiNamespaceCount++; - -Exit: - - if( pNewNamespace) - { - pNewNamespace->Release(); - } - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_XMLNamespaceMgr::pushNamespace( - F_XMLNamespace * pNamespace) -{ - flmAssert( m_pFirstNamespace != pNamespace && - !pNamespace->m_pNext); - - pNamespace->AddRef(); - pNamespace->m_pNext = m_pFirstNamespace; - m_pFirstNamespace = pNamespace; - m_uiNamespaceCount++; - - return( NE_XFLM_OK); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_XMLNamespace::setPrefix( - FLMUNICODE * puzPrefix) -{ - FLMUINT uiLen; - RCODE rc = NE_XFLM_OK; - - if( m_puzPrefix) - { - f_free( &m_puzPrefix); - } - - if( puzPrefix) - { - uiLen = f_unilen( puzPrefix); - if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE) * (uiLen + 1), - &m_puzPrefix))) - { - goto Exit; - } - - f_unicpy( m_puzPrefix, puzPrefix); - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_XMLNamespace::setURI( - FLMUNICODE * puzURI) -{ - FLMUINT uiLen; - RCODE rc = NE_XFLM_OK; - - if( m_puzURI) - { - f_free( &m_puzURI); - } - - if( puzURI) - { - uiLen = f_unilen( puzURI); - if( RC_BAD( rc = f_alloc( - sizeof( FLMUNICODE) * (uiLen + 1), &m_puzURI))) - { - goto Exit; - } - - f_unicpy( m_puzURI, puzURI); - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_XMLNamespace::setup( - FLMUNICODE * puzPrefix, - FLMUNICODE * puzURI, - F_XMLNamespace * pNext) -{ - FLMUINT uiLen; - RCODE rc = NE_XFLM_OK; - - flmAssert( !m_puzPrefix); - flmAssert( !m_puzURI); - flmAssert( !m_pNext); - - if( puzPrefix) - { - uiLen = f_unilen( puzPrefix); - if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE) * (uiLen + 1), - &m_puzPrefix))) - { - goto Exit; - } - - f_unicpy( m_puzPrefix, puzPrefix); - } - - if( puzURI) - { - uiLen = f_unilen( puzURI); - if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE) * (uiLen + 1), - &m_puzURI))) - { - goto Exit; - } - - f_unicpy( m_puzURI, puzURI); - } - - m_pNext = pNext; - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_XMLImport::addAttributesToElement( - F_DOMNode * pElement) -{ - RCODE rc = NE_XFLM_OK; - XML_ATTR * pAttr; - F_XMLNamespace * pNamespace = NULL; - F_DOMNode * pTmpNode = NULL; - FLMUINT uiNameId; - FLMUINT uiAttrDataType; - - // Make sure any prefixes (e.g., xmlns:xxxx) are added to the database - // before they are used - in case they are used by the attributes - // themselves. - - for( pAttr = m_pFirstAttr; pAttr; pAttr = pAttr->pNext) - { - if( pAttr->uiFlags & F_PREFIXED_NS_DECL) - { - FLMUINT uiPrefixId; - - // Create the prefix (stored in &puzLocalName [6]) if it doesn't - // already exist - - if( RC_BAD( rc = m_pDb->m_pDict->getPrefixId( m_pDb, - &pAttr->puzLocalName [6], &uiPrefixId))) - { - if( rc != NE_XFLM_NOT_FOUND) - { - goto Exit; - } - - uiPrefixId = 0; - if( RC_BAD( rc = m_pDb->createPrefixDef( TRUE, - &pAttr->puzLocalName [6], &uiPrefixId))) - { - goto Exit; - } - } - } - } - - // Add the attributes to the element - // - // NOTE: The XML namespace specification states that the names - // of all unqualified attributes are assigned to the - // appropriate per-element-type partition. This means that - // the combination of the attribute name with the parent - // element's type and namespace name is used to uniquely - // identify each unqualified attribute. - // - // For sake of clarity and useability, however, the parser - // deviates from the namespace specification. Each unprefixed - // attribute encountered by the parser will inherit the - // namespace of the parent element, even if the namespace - // is a default namespace. - - for( pAttr = m_pFirstAttr; pAttr; pAttr = pAttr->pNext) - { - if( pAttr->uiFlags & F_DEFAULT_NS_DECL) - { - // Add the namespace declaration to the element - - if( RC_BAD( rc = pElement->createAttribute( m_pDb, ATTR_XMLNS_TAG, - (IF_DOMNode **)&pTmpNode))) - { - goto Exit; - } - - if( RC_BAD( rc = pTmpNode->setUnicode( m_pDb, pAttr->puzVal))) - { - goto Exit; - } - - if( RC_BAD( rc = pTmpNode->addModeFlags( m_pDb, FDOM_READ_ONLY))) - { - goto Exit; - } - } - else if( pAttr->uiFlags & F_PREFIXED_NS_DECL) - { - // Find the attribute definition - - if( RC_BAD( rc = m_pDb->getAttributeNameId( - NULL, pAttr->puzLocalName, &uiNameId))) - { - if( rc != NE_XFLM_NOT_FOUND) - { - goto Exit; - } - - if( !(m_uiFlags & FLM_XML_EXTEND_DICT_FLAG)) - { - rc = RC_SET( NE_XFLM_UNDEFINED_ATTRIBUTE_NAME); - goto Exit; - } - - uiNameId = 0; - if( RC_BAD( rc = m_pDb->createAttributeDef( - NULL, pAttr->puzLocalName, XFLM_TEXT_TYPE, &uiNameId, - (IF_DOMNode **)&pTmpNode))) - { - goto Exit; - } - } - - // Add the namespace declaration to the element - - if( RC_BAD( rc = pElement->createAttribute( m_pDb, uiNameId, - (IF_DOMNode **)&pTmpNode))) - { - goto Exit; - } - - if( RC_BAD( rc = pTmpNode->setUnicode( m_pDb, pAttr->puzVal))) - { - goto Exit; - } - - if( RC_BAD( rc = pTmpNode->addModeFlags( m_pDb, FDOM_READ_ONLY))) - { - goto Exit; - } - } - else - { - if( pAttr->puzPrefix) - { - if( RC_BAD( rc = findNamespace( pAttr->puzPrefix, &pNamespace))) - { - if( rc == NE_XFLM_NOT_FOUND) - { - setErrInfo( pAttr->uiLineNum, pAttr->uiLineOffset, - XML_ERR_PREFIX_NOT_DEFINED, pAttr->uiLineFilePos, - pAttr->uiLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - } - - goto Exit; - } - } - else - { - if( pNamespace) - { - pNamespace->Release(); - } - pNamespace = NULL; - } - - if( RC_BAD( rc = m_pDb->getAttributeNameId( - pNamespace ? pNamespace->getURIPtr() : NULL, - pAttr->puzLocalName, &uiNameId))) - { - if( rc != NE_XFLM_NOT_FOUND) - { - goto Exit; - } - - if( !(m_uiFlags & FLM_XML_EXTEND_DICT_FLAG) || - (pNamespace && - f_unicmp( pNamespace->getURIPtr(), gv_uzXFLAIMNamespace) == 0)) - { - rc = RC_SET( NE_XFLM_UNDEFINED_ATTRIBUTE_NAME); - goto Exit; - } - - uiNameId = 0; - if( RC_BAD( rc = m_pDb->createAttributeDef( - pNamespace ? pNamespace->getURIPtr() : NULL, - pAttr->puzLocalName, XFLM_TEXT_TYPE, &uiNameId))) - { - goto Exit; - } - } - - if( RC_BAD( rc = pElement->createAttribute( m_pDb, uiNameId, - (IF_DOMNode **)&pTmpNode))) - { - goto Exit; - } - - if (pAttr->puzPrefix) - { - if( RC_BAD( rc = pTmpNode->setPrefix( m_pDb, pAttr->puzPrefix))) - { - if( rc == NE_XFLM_NOT_FOUND) - { - setErrInfo( pAttr->uiLineNum, - pAttr->uiLineOffset, - XML_ERR_PREFIX_NOT_DEFINED, - pAttr->uiLineFilePos, - pAttr->uiLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - } - goto Exit; - } - } - - if( RC_BAD( rc = pTmpNode->getDataType( m_pDb, &uiAttrDataType))) - { - goto Exit; - } - - switch( uiAttrDataType) - { - case XFLM_TEXT_TYPE: - { - if( RC_BAD( rc = pTmpNode->setUnicode( - m_pDb, pAttr->puzVal))) - { - goto Exit; - } - break; - } - - case XFLM_NUMBER_TYPE: - { - FLMUINT64 ui64Val; - FLMBOOL bNeg; - - if( RC_BAD( rc = unicodeToNumber64( - pAttr->puzVal, &ui64Val, &bNeg))) - { - goto Exit; - } - - if( !bNeg) - { - if( RC_BAD( rc = pTmpNode->setUINT64( m_pDb, ui64Val))) - { - goto Exit; - } - } - else - { - if( RC_BAD( rc = pTmpNode->setINT64( m_pDb, -((FLMINT64)ui64Val)))) - { - goto Exit; - } - } - - break; - } - - case XFLM_BINARY_TYPE: - { - FLMBOOL bHavePreamble; - FLMUNICODE * puzStr = pAttr->puzVal; - FLMUINT uiOffset = 0; - - // Convert the Unicode value to binary - - while( puzStr && *puzStr) - { - bHavePreamble = FALSE; - - while( gv_XFlmSysData.pXml->isWhitespace( *puzStr)) - { - puzStr++; - } - - Retry: - - if( !f_isHexChar( *puzStr)) - { - break; - } - - if( *puzStr == FLM_UNICODE_0 && - (puzStr[ 1] == FLM_UNICODE_X || puzStr[ 1] == FLM_UNICODE_x)) - { - if( bHavePreamble) - { - setErrInfo( pAttr->uiValueLineNum, - pAttr->uiValueLineOffset, - XML_ERR_INVALID_BINARY_ATTR_VALUE, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - bHavePreamble = TRUE; - puzStr += 2; - goto Retry; - } - - if( !f_isHexChar( puzStr[ 1])) - { - setErrInfo( pAttr->uiValueLineNum, - pAttr->uiValueLineOffset, - XML_ERR_INVALID_BINARY_ATTR_VALUE, - m_uiCurrLineFilePos, - m_uiCurrLineBytes); - rc = RC_SET( NE_XFLM_INVALID_XML); - goto Exit; - } - - if( uiOffset >= m_uiValBufSize) - { - if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) - { - goto Exit; - } - } - - m_pucValBuf[ uiOffset++] = - (f_getHexVal( *puzStr) << 4) | f_getHexVal( puzStr[ 1]); - - puzStr += 2; - - while( gv_XFlmSysData.pXml->isWhitespace( *puzStr)) - { - puzStr++; - } - - if( *puzStr == FLM_UNICODE_COMMA) - { - puzStr++; - } - } - - if( RC_BAD( rc = pTmpNode->setBinary( - m_pDb, m_pucValBuf, uiOffset))) - { - goto Exit; - } - break; - } - - default: - { - rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED); - goto Exit; - } - } - } - } - -Exit: - - if( pTmpNode) - { - pTmpNode->Release(); - } - - if( pNamespace) - { - pNamespace->Release(); - } - - return( rc); -} - -// Some forward declarations - -class F_Element; -class F_Attribute; - -/***************************************************************************** -Desc: Keeps track of an attribute that we are going to output -*****************************************************************************/ -class F_Attribute : public XF_Base -{ -public: - F_Attribute( - F_Element * pElement) - { - m_uiTmpSpaceSize = sizeof( m_uzTmpSpace); - m_puzName = &m_uzTmpSpace [0]; - reset( pElement); - } - - ~F_Attribute(); - - FINLINE void reset( - F_Element * pElement) - { - m_uiNameChars = 0; - m_bIsNamespaceDecl = FALSE; - m_bDefaultNamespaceDecl = FALSE; - m_uiNamespaceChars = 0; - m_uiValueChars = 0; - m_uiPrefixChars = 0; - m_pElement = pElement; - } - - RCODE allocNameSpace( void); - - RCODE setupAttribute( - IF_Db * pDb, - IF_DOMNode * pNode); - - RCODE setPrefix( void); - - RCODE outputAttr( - IF_OStream * pOStream); - - FINLINE F_Attribute * getNext( void) - { - return( m_pNext); - } - -private: - FLMUNICODE m_uzTmpSpace [150]; - FLMUINT m_uiTmpSpaceSize; - FLMBOOL m_bIsNamespaceDecl; - FLMBOOL m_bDefaultNamespaceDecl; - FLMUNICODE * m_puzName; - FLMUINT m_uiNameChars; - FLMUNICODE * m_puzNamespace; - FLMUINT m_uiNamespaceChars; - FLMUNICODE * m_puzValue; - FLMUINT m_uiValueChars; - FLMUNICODE * m_puzPrefix; - FLMUINT m_uiPrefixChars; - F_Element * m_pElement; - F_Attribute * m_pNext; - -friend class F_Element; -}; - -/***************************************************************************** -Desc: Destructor for F_Attribute class. -*****************************************************************************/ -F_Attribute::~F_Attribute() -{ - if (m_puzName != &m_uzTmpSpace [0]) - { - f_free( &m_puzName); - } -} - -/***************************************************************************** -Desc: Keeps track of an element that we are going to output -*****************************************************************************/ -class F_Element : public XF_Base -{ -public: - F_Element( - F_Element * pParentElement, - F_Attribute ** ppAvailAttrs, - FLMUINT * puiNextPrefixNum) - { - m_uiTmpSpaceSize = sizeof( m_uzTmpSpace); - m_puzName = &m_uzTmpSpace [0]; - m_pFirstAttr = NULL; - m_pLastAttr = NULL; - m_pNext = NULL; - m_uiIndentCount = 0; - m_bIsDocumentRoot = FALSE; - reset( pParentElement, ppAvailAttrs, puiNextPrefixNum); - } - - ~F_Element() - { - F_Attribute * pAttr; - F_Attribute * pTmpAttr; - - // Delete all of the attributes - - pAttr = m_pFirstAttr; - while (pAttr) - { - pTmpAttr = pAttr; - pAttr = pAttr->m_pNext; - delete pTmpAttr; - } - - if (m_puzName != &m_uzTmpSpace [0]) - { - f_free( &m_puzName); - } - } - - FINLINE void reset( - F_Element * pParentElement, - F_Attribute ** ppAvailAttrs, - FLMUINT * puiNextPrefixNum) - { - m_uiNameChars = 0; - m_uiNamespaceChars = 0; - m_uiPrefixChars = 0; - m_pParentElement = pParentElement; - m_puiNextPrefixNum = puiNextPrefixNum; - m_ppAvailAttrs = ppAvailAttrs; - m_pNext = NULL; - m_uiIndentCount = 0; - m_bIsDocumentRoot = FALSE; - } - - FINLINE void setIndentCount( - FLMUINT uiIndentCount) - { - m_uiIndentCount = uiIndentCount; - } - - FINLINE void setDocumentRoot( - FLMBOOL bIsDocumentRoot) - { - m_bIsDocumentRoot = bIsDocumentRoot; - } - - RCODE allocAttr( - F_Attribute ** ppAttr); - - FINLINE void makeAttrAvail( - F_Attribute * pAttr) - { - pAttr->m_pNext = *m_ppAvailAttrs; - *m_ppAvailAttrs = pAttr; - } - - FINLINE void makeAllAttrsAvail( void) - { - if (m_pFirstAttr) - { - m_pLastAttr->m_pNext = *m_ppAvailAttrs; - *m_ppAvailAttrs = m_pFirstAttr; - m_pFirstAttr = NULL; - m_pLastAttr = NULL; - } - } - - RCODE saveAttribute( - IF_Db * pDb, - IF_DOMNode * pNode); - - RCODE allocNameSpace( void); - - RCODE setupElement( - IF_Db * pDb, - IF_DOMNode * pNode); - - RCODE addNamespaceDecl( - FLMUNICODE * puzPrefix, - FLMUINT uiPrefixChars, - FLMUNICODE * puzNamespace, - FLMUINT uiNamespaceChars, - F_Attribute ** ppAttr); - - void genPrefix( - FLMUNICODE * puzPrefix, - FLMUINT * puiPrefixChars); - - RCODE findPrefix( - FLMUNICODE * puzNamespace, - FLMUINT uiNamespaceChars, - FLMBOOL bForElement, - FLMUNICODE ** ppuzPrefix, - FLMUINT * puiPrefixChars); - - FINLINE RCODE setPrefix( void) - { - return( findPrefix( m_puzNamespace, m_uiNamespaceChars, TRUE, - &m_puzPrefix, &m_uiPrefixChars)); - } - - FINLINE F_Element * getParentElement( void) - { - return( m_pParentElement); - } - - RCODE outputElem( - IF_OStream * pOStream, - FLMBOOL bStartOfElement, - FLMBOOL bEndOfElement, - FLMBOOL bAddNewLine); - - RCODE outputLocalData( - IF_OStream * pOStream, - IF_DOMNode * pDbNode, - IF_Db * ifpDb, - eExportFormatType eFormatType, - FLMUINT uiIndentCount); - - FINLINE F_Element * getNext( void) - { - return( m_pNext); - } - - FINLINE void makeAvail( - F_Element ** ppAvailElements) - { - m_pNext = *ppAvailElements; - *ppAvailElements = this; - } - -private: - FLMUNICODE m_uzTmpSpace [100]; - FLMUINT m_uiTmpSpaceSize; - FLMUNICODE * m_puzName; - FLMUINT m_uiNameChars; - FLMUNICODE * m_puzNamespace; - FLMUINT m_uiNamespaceChars; - FLMUNICODE * m_puzPrefix; - FLMUINT m_uiPrefixChars; - F_Attribute * m_pFirstAttr; - F_Attribute * m_pLastAttr; - F_Element * m_pParentElement; - F_Element * m_pNext; - FLMUINT * m_puiNextPrefixNum; - F_Attribute ** m_ppAvailAttrs; - FLMBOOL m_bIsDocumentRoot; - FLMUINT m_uiIndentCount; - -friend class F_Attribute; -}; - -/***************************************************************************** -Desc: Allocate space to hold the name, namespace, and value for an attribute. -*****************************************************************************/ -RCODE F_Attribute::allocNameSpace( void) -{ - RCODE rc = NE_XFLM_OK; - FLMUINT uiSpaceNeeded; - FLMUNICODE * puzTmp; - - uiSpaceNeeded = (m_uiNameChars + - m_uiNamespaceChars + - m_uiValueChars + 3) * sizeof( FLMUNICODE); - if (uiSpaceNeeded > m_uiTmpSpaceSize) - { - if (RC_BAD( rc = f_alloc( uiSpaceNeeded, &puzTmp))) - { - goto Exit; - } - if (m_puzName != &m_uzTmpSpace [0]) - { - f_free( &m_puzName); - } - m_puzName = puzTmp; - m_uiTmpSpaceSize = uiSpaceNeeded; - } - m_puzNamespace = &m_puzName [m_uiNameChars + 1]; - m_puzValue = &m_puzNamespace [m_uiNamespaceChars + 1]; - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: Setup an attribute with its namespace, etc. -*****************************************************************************/ -RCODE F_Attribute::setupAttribute( - IF_Db * pDb, - IF_DOMNode * pNode - ) -{ - RCODE rc = NE_XFLM_OK; - - // Determine if the attribute is a namespace declaration - - if (RC_BAD( rc = pNode->isNamespaceDecl( pDb, &m_bIsNamespaceDecl))) - { - goto Exit; - } - - // Get the length of the name of the attribute - - if (RC_BAD( rc = pNode->getLocalName( pDb, (FLMUNICODE *)NULL, - 0, &m_uiNameChars))) - { - goto Exit; - } - - // If it is a namespace declaration, no need to get the namespace URI, - // we already know what it is, and we will output it with an xmlns prefix - // Otherwise, we need to get the namespace so we can determine a prefix, - // if any. If the namespace is the same namespace as the enclosing - // element, we do not need to output a prefix. - - if (!m_bIsNamespaceDecl) - { - - // Get the number of characters in the namespace of the attribute - - if (RC_BAD( rc = pNode->getNamespaceURI( pDb, (FLMUNICODE *)NULL, - 0, &m_uiNamespaceChars))) - { - goto Exit; - } - } - - // Get the number of characters in the attribute's value. - - if (RC_BAD( rc = pNode->getUnicodeChars( pDb, &m_uiValueChars))) - { - goto Exit; - } - - // Allocate space for the name, namespace, and value - - if (RC_BAD( rc = allocNameSpace())) - { - goto Exit; - } - - // Get the attribute name. - - if (RC_BAD( rc = pNode->getLocalName( pDb, m_puzName, - (m_uiNameChars + 1) * sizeof( FLMUNICODE), - &m_uiNameChars))) - { - goto Exit; - } - - // Get the namespace, if necessary - - if (m_uiNamespaceChars) - { - if (RC_BAD( rc = pNode->getNamespaceURI( pDb, m_puzNamespace, - (m_uiNamespaceChars + 1) * sizeof( FLMUNICODE), - &m_uiNamespaceChars))) - { - goto Exit; - } - } - - // Get the value, if any - - if (m_uiValueChars) - { - if (RC_BAD( rc = pNode->getUnicode( pDb, m_puzValue, - (m_uiValueChars + 1) * sizeof( FLMUNICODE), - 0, m_uiValueChars, &m_uiValueChars))) - { - goto Exit; - } - } - - // If it is a namespace declaration, the local name must either be - // "xmlns" or begin with "xmlns:" - - if (m_bIsNamespaceDecl) - { - - // Make sure name is "xmlns" or begins with "xmlns:" - - if (m_uiNameChars != 5 && m_uiNameChars <= 6) - { - rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_NAMESPACE_DECL); - goto Exit; - } - - if (!isXMLNS( m_puzName)) - { - rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_NAMESPACE_DECL); - goto Exit; - } - else if (m_uiNameChars == 5) - { - m_bDefaultNamespaceDecl = TRUE; - } - else if (m_puzName [5] != ':') - { - rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_NAMESPACE_DECL); - goto Exit; - } - } - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: Set the prefix for an attribute. -*****************************************************************************/ -RCODE F_Attribute::setPrefix( void) -{ - RCODE rc = NE_XFLM_OK; - - // If this is a namespace declaration, there should be no prefix in the name. - - if (m_bIsNamespaceDecl) - { - flmAssert( !m_uiPrefixChars); - } - - // Only need to set a prefix on an attribute if it has a namespace - // Otherwise, leave it alone - no prefix. - - else if (m_uiNamespaceChars) - { - - - // See if we can find a namespace declaration in either - // this element's attributes, or any of its parent element - // attributes. - - if (RC_BAD( rc = m_pElement->findPrefix( m_puzNamespace, - m_uiNamespaceChars, FALSE, - &m_puzPrefix, &m_uiPrefixChars))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: Export a unicode string to the string buffer - as UTF8. -*****************************************************************************/ -FSTATIC RCODE exportUniValue( - IF_OStream * pOStream, - FLMUNICODE * puzStr, - FLMUINT uiStrChars, - FLMBOOL bEncodeSpecialChars, - FLMUINT uiIndentCount - ) -{ - RCODE rc = NE_XFLM_OK; - FLMBYTE ucTmp [4]; - FLMUINT uiLen; - FLMUINT uiCharOffset = 0; - FLMUNICODE uzChar; - FLMBOOL bIndent = FALSE; - FLMUINT uiICount = 0; - - while ( *puzStr && uiCharOffset < uiStrChars) - { - uzChar = *puzStr; - - // Handle encoding of special characters - - if (bEncodeSpecialChars) - { - if (uzChar == '<') - { - if (RC_BAD( rc = pOStream->write( (void *)"<", 4))) - { - goto Exit; - } - } - else if (uzChar == '>') - { - if (RC_BAD( rc = pOStream->write( (void *)">", 4))) - { - goto Exit; - } - } - else if (uzChar == '&') - { - if (RC_BAD( rc = pOStream->write( (void *)"&", 5))) - { - goto Exit; - } - } - else if (uzChar == '\'') - { - if (RC_BAD( rc = pOStream->write( (void *)"'", 6))) - { - goto Exit; - } - } - else if (uzChar == '"') - { - if (RC_BAD( rc = pOStream->write( (void *)""", 6))) - { - goto Exit; - } - } - else - { - goto Normal_Encoding; - } - } - else - { - -Normal_Encoding: - - // Output the character as UTF8. - - if (uzChar <= 0x007F) - { - // New Line char found. Need to indent. - if( uzChar == ASCII_NEWLINE) - { - bIndent = TRUE; - } - ucTmp [0] = (FLMBYTE)uzChar; - uiLen = 1; - } - else if (*puzStr <= 0x07FF) - { - ucTmp [0] = (FLMBYTE)(0xC0 | (FLMBYTE)(uzChar >> 6)); - ucTmp [1] = (FLMBYTE)(0x80 | (FLMBYTE)(uzChar & 0x003F)); - uiLen = 2; - } - else - { - ucTmp [0] = (FLMBYTE)(0xE0 | (FLMBYTE)(uzChar >> 12)); - ucTmp [1] = (FLMBYTE)(0x80 | (FLMBYTE)((uzChar & 0x0FC0) >> 6)); - ucTmp [2] = (FLMBYTE)(0x80 | (FLMBYTE)(uzChar & 0x003F)); - uiLen = 3; - } - if (RC_BAD( rc = pOStream->write( (void *)&ucTmp[0], uiLen))) - { - goto Exit; - } - - if( bIndent && uiIndentCount) - { - for( uiICount = uiIndentCount; uiICount; uiICount--) - { - if (RC_BAD( rc = pOStream->write( (void *)"\t", 1))) - { - goto Exit; - } - } - bIndent = FALSE; - } - } - puzStr++; - uiCharOffset++; - } - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: Output an attribute to the string buffer. -*****************************************************************************/ -RCODE F_Attribute::outputAttr( - IF_OStream * pOStream) -{ - RCODE rc = NE_XFLM_OK; - - if (RC_BAD( rc = pOStream->write( (void *)" ", 1))) - { - goto Exit; - } - if (m_uiPrefixChars) - { - if (RC_BAD( rc = exportUniValue( pOStream, m_puzPrefix, m_uiPrefixChars, FALSE, 0))) - { - goto Exit; - } - if (RC_BAD( rc = pOStream->write( (void *)":", 1))) - { - goto Exit; - } - } - - if (RC_BAD( rc = exportUniValue( pOStream, m_puzName, m_uiNameChars, FALSE, 0))) - { - goto Exit; - } - - if (RC_BAD( rc = pOStream->write( (void *)"=\"", 2))) - { - goto Exit; - } - - if (RC_BAD( rc = exportUniValue( pOStream, m_puzValue, m_uiValueChars, TRUE, 0))) - { - goto Exit; - } - - if (RC_BAD( rc = pOStream->write( (void *)"\"", 1))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: Allocate a new attribute. -*****************************************************************************/ -RCODE F_Element::allocAttr( - F_Attribute ** ppAttr - ) -{ - RCODE rc = NE_XFLM_OK; - - if ((*ppAttr = *m_ppAvailAttrs) != NULL) - { - *m_ppAvailAttrs = (*ppAttr)->m_pNext; - (*ppAttr)->reset( this); - } - else - { - if ((*ppAttr = f_new F_Attribute( this)) == NULL) - { - rc = RC_SET( NE_XFLM_MEM); - goto Exit; - } - } - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: Save an attribute in an element. Put at end of list. -*****************************************************************************/ -RCODE F_Element::saveAttribute( - IF_Db * pDb, - IF_DOMNode * pNode - ) -{ - RCODE rc = NE_XFLM_OK; - F_Attribute * pAttr = NULL; - - if (RC_BAD( rc = allocAttr( &pAttr))) - { - goto Exit; - } - - // Set up the attribute - - if (RC_BAD( rc = pAttr->setupAttribute( pDb, pNode))) - { - goto Exit; - } - - // Put attribute at end of list of attributes. - - pAttr->m_pNext = NULL; - if (m_pLastAttr) - { - m_pLastAttr->m_pNext = pAttr; - } - else - { - m_pFirstAttr = pAttr; - } - m_pLastAttr = pAttr; - - // Set pAttr to NULL so it won't be made available at exit. - - pAttr = NULL; - -Exit: - - if (pAttr) - { - makeAttrAvail( pAttr); - } - - return( rc); -} - -/***************************************************************************** -Desc: Allocate space for the element's name and namespace. -*****************************************************************************/ -RCODE F_Element::allocNameSpace( void) -{ - RCODE rc = NE_XFLM_OK; - FLMUINT uiSpaceNeeded; - FLMUNICODE * puzTmp; - - uiSpaceNeeded = (m_uiNameChars + m_uiNamespaceChars + 2) * sizeof( FLMUNICODE); - - // Allocate space for the name and namespace - - if (uiSpaceNeeded > m_uiTmpSpaceSize) - { - - if (RC_BAD( rc = f_alloc( uiSpaceNeeded, &puzTmp))) - { - goto Exit; - } - if (m_puzName != &m_uzTmpSpace [0]) - { - f_free( &m_puzName); - } - m_puzName = puzTmp; - m_uiTmpSpaceSize = uiSpaceNeeded; - } - m_puzNamespace = &m_puzName [m_uiNameChars + 1]; - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: Setup an element with its namespace, etc. -*****************************************************************************/ -RCODE F_Element::setupElement( - IF_Db * pDb, - IF_DOMNode * pNode - ) -{ - RCODE rc = NE_XFLM_OK; - IF_DOMNode * pAttrNode = NULL; - F_Attribute * pAttr; - - // Get the length of the name of the element - - if (RC_BAD( rc = pNode->getLocalName( pDb, (FLMUNICODE *)NULL, - 0, &m_uiNameChars))) - { - goto Exit; - } - - // Get the number of characters in the namespace of the element - - if (RC_BAD( rc = pNode->getNamespaceURI( pDb, (FLMUNICODE *)NULL, - 0, &m_uiNamespaceChars))) - { - goto Exit; - } - - if (RC_BAD( rc = allocNameSpace())) - { - goto Exit; - } - - // Get the element name. - - if (RC_BAD( rc = pNode->getLocalName( pDb, m_puzName, - (m_uiNameChars + 1) * sizeof( FLMUNICODE), - &m_uiNameChars))) - { - goto Exit; - } - - // Get the namespace, if necessary - - if (m_uiNamespaceChars) - { - if (RC_BAD( rc = pNode->getNamespaceURI( pDb, m_puzNamespace, - (m_uiNamespaceChars + 1) * sizeof( FLMUNICODE), - &m_uiNamespaceChars))) - { - goto Exit; - } - } - - // See if the node has any attributes. - - for (;;) - { - rc = (RCODE)(pAttrNode - ? pAttrNode->getNextSibling( pDb, &pAttrNode) - : pNode->getFirstAttribute( pDb, &pAttrNode)); - if (RC_BAD( rc)) - { - if (rc == NE_XFLM_DOM_NODE_NOT_FOUND) - { - rc = NE_XFLM_OK; - break; - } - else - { - goto Exit; - } - } - if (RC_BAD( rc = saveAttribute( pDb, pAttrNode))) - { - goto Exit; - } - } - - // Get the prefix for the element - - if (RC_BAD( rc = setPrefix())) - { - goto Exit; - } - - // Set the prefix for every attribute - - pAttr = m_pFirstAttr; - while (pAttr) - { - if (RC_BAD( rc = pAttr->setPrefix())) - { - goto Exit; - } - pAttr = pAttr->m_pNext; - } - -Exit: - - if (pAttrNode) - { - pAttrNode->Release(); - } - - return( rc); -} - -/***************************************************************************** -Desc: Add an attribute that is a namespace to an element. -*****************************************************************************/ -RCODE F_Element::addNamespaceDecl( - FLMUNICODE * puzPrefix, - FLMUINT uiPrefixChars, - FLMUNICODE * puzNamespace, - FLMUINT uiNamespaceChars, - F_Attribute ** ppAttr - ) -{ - RCODE rc = NE_XFLM_OK; - F_Attribute * pAttr = NULL; - - // If uiPrefixChars is zero, we are being asked to create a default - // namespace. But that can only be output once in the element, - // so make sure it is not already declared. If it is, do nothing. - - if (!uiPrefixChars) - { - pAttr = m_pFirstAttr; - while (pAttr && !pAttr->m_bDefaultNamespaceDecl) - { - pAttr = pAttr->m_pNext; - } - if (pAttr) - { - goto Exit; - } - } - - if (RC_BAD( rc = allocAttr( &pAttr))) - { - goto Exit; - } - pAttr->m_bIsNamespaceDecl = TRUE; - - // name will be "xmlns:" or, in the case of no namespace, "xmlns" - - if (!uiPrefixChars) - { - - // "xmlns" - but make sure not already declared. - - pAttr->m_uiNameChars = 5; - pAttr->m_bDefaultNamespaceDecl = TRUE; - } - else - { - - // "xmlns:" - - pAttr->m_uiNameChars = uiPrefixChars + 6; - } - pAttr->m_uiNamespaceChars = 0; - pAttr->m_uiValueChars = uiNamespaceChars; - - if (RC_BAD( rc = pAttr->allocNameSpace())) - { - goto Exit; - } - - // Always output "xmlns" as the first part of the name - - f_memcpy( pAttr->m_puzName, gv_puzNamespaceDeclPrefix, 5 * sizeof( FLMUNICODE)); - if (uiPrefixChars) - { - pAttr->m_puzName [5] = ':'; - f_memcpy( &pAttr->m_puzName [6], puzPrefix, uiPrefixChars * sizeof( FLMUNICODE)); - pAttr->m_puzName [6 + uiPrefixChars] = 0; - } - else - { - pAttr->m_puzName [5] = 0; - } - if (uiNamespaceChars) - { - f_memcpy( pAttr->m_puzValue, puzNamespace, - uiNamespaceChars * sizeof( FLMUNICODE)); - } - pAttr->m_puzValue [pAttr->m_uiValueChars] = 0; - - // Put new namespace decl at front of list of attributes. - - if ((pAttr->m_pNext = m_pFirstAttr) == NULL) - { - m_pLastAttr = pAttr; - } - m_pFirstAttr = pAttr; - *ppAttr = pAttr; - - // Set pAttr to NULL so that it won't be made available at exit. - - pAttr = NULL; - -Exit: - - if (pAttr) - { - makeAttrAvail( pAttr); - } - return( rc); -} - -/***************************************************************************** -Desc: Generate a random prefix, ensure that it is not defined anywhere - in the path. -*****************************************************************************/ -void F_Element::genPrefix( - FLMUNICODE * puzPrefix, - FLMUINT * puiPrefixChars - ) -{ - FLMUINT uiTmp; - FLMUINT uiPrefixChars; - FLMUNICODE * puzTmp; - F_Attribute * pAttr; - F_Element * pElement; - - puzPrefix [0] = 'p'; - puzPrefix [1] = 'r'; - puzPrefix [2] = 'f'; - puzPrefix [3] = 'x'; - for (;;) - { - - // Append the number in reverse digit order - it really doesn't matter - // because we're just trying to generate a unique prefix number. - - puzTmp = &puzPrefix [4]; - uiPrefixChars = 4; - uiTmp = *m_puiNextPrefixNum; - do - { - *puzTmp++ = (FLMUNICODE)((uiTmp % 10) + '0'); - uiPrefixChars++; - uiTmp /= 10; - } while (uiTmp); - - // See if the prefix is defined. - - pAttr = m_pFirstAttr; - pElement = this; - while (pAttr) - { - if (pAttr->m_bIsNamespaceDecl && - pAttr->m_uiNameChars > 6 && - pAttr->m_uiNameChars - 6 == uiPrefixChars && - f_memcmp( puzPrefix, &pAttr->m_puzName [6], - uiPrefixChars * sizeof( FLMUNICODE)) == 0) - { - break; - } - if ((pAttr = pAttr->m_pNext) == NULL) - { - pElement = pElement->m_pParentElement; - while (pElement && !pElement->m_pFirstAttr) - { - pElement = pElement->m_pParentElement; - } - if (!pElement) - { - break; - } - pAttr = pElement->m_pFirstAttr; - } - } - - // If the prefix was not defined, we can use it. - - if (!pAttr) - { - break; - } - (*m_puiNextPrefixNum)++; - } - puzPrefix [uiPrefixChars] = 0; - *puiPrefixChars = uiPrefixChars; -} - -/***************************************************************************** -Desc: Find a prefix for a namespace -*****************************************************************************/ -RCODE F_Element::findPrefix( - FLMUNICODE * puzNamespace, - FLMUINT uiNamespaceChars, - FLMBOOL bForElement, - FLMUNICODE ** ppuzPrefix, - FLMUINT * puiPrefixChars) -{ - RCODE rc = NE_XFLM_OK; - F_Attribute * pAttr = m_pFirstAttr; - F_Element * pElement = this; - FLMUNICODE uzPrefix [50]; - FLMUINT uiPrefixChars; - - for (;;) - { - if ( pAttr) - { - if (pAttr->m_bIsNamespaceDecl && - uiNamespaceChars == pAttr->m_uiValueChars && - (!uiNamespaceChars || - f_memcmp( puzNamespace, pAttr->m_puzValue, - uiNamespaceChars * sizeof( FLMUNICODE)) == 0)) - { - - // Don't set the prefix if it is the default namespace. - - if (!pAttr->m_bDefaultNamespaceDecl) - { - // Prefix comes after the "xmlns:" - - *ppuzPrefix = &pAttr->m_puzName [6]; - *puiPrefixChars = pAttr->m_uiNameChars - 6; - goto Exit; - } - - // Default namespace is only OK for elements, - // but not attributes. We don't want to count - // attributes as having been "found" if they matched - // the default namespace. This routine is only called - // for attributes if the attribute namepace is non-empty. - - else if (bForElement) - { - goto Exit; - } - } - pAttr = pAttr->m_pNext; - } - if ( !pAttr) - { - pElement = pElement->m_pParentElement; - while (pElement && !pElement->m_pFirstAttr) - { - pElement = pElement->m_pParentElement; - } - if (!pElement) - { - break; - } - pAttr = pElement->m_pFirstAttr; - } - } - - // If namespaces is empty, the only declaration that is legal is - // a default namespace declaration. - - if (!uiNamespaceChars) - { - if (RC_BAD( rc = addNamespaceDecl( NULL, 0, NULL, 0, &pAttr))) - { - goto Exit; - } - } - else - { - - // Manufacture a prefix that is not used in the hierarchy yet. - - genPrefix( uzPrefix, &uiPrefixChars); - if (RC_BAD( rc = addNamespaceDecl( uzPrefix, uiPrefixChars, puzNamespace, - uiNamespaceChars, &pAttr))) - { - goto Exit; - } - - *ppuzPrefix = &pAttr->m_puzName [6]; - *puiPrefixChars = pAttr->m_uiNameChars - 6; - } - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: Output the element name, with its attributes - this marks the - beginning of the element. -*****************************************************************************/ -RCODE F_Element::outputElem( - IF_OStream * pOStream, - FLMBOOL bStartOfElement, - FLMBOOL bEndOfElement, - FLMBOOL bAddNewLine) -{ - RCODE rc = NE_XFLM_OK; - F_Attribute * pAttr; - F_Attribute * pPrevAttr; - FLMUINT uiIndentCount = 0; - FLMBOOL bEndNode; - - bEndNode = ( m_bIsDocumentRoot && !bStartOfElement); - if( bAddNewLine && ( !m_bIsDocumentRoot || bEndNode)) - { - if (RC_BAD( rc = pOStream->write( (void *)"\n", 1))) - { - goto Exit; - } - for( uiIndentCount = 0; uiIndentCount < m_uiIndentCount; uiIndentCount++) - { - if (RC_BAD( rc = pOStream->write( (void *)"\t", 1))) - { - goto Exit; - } - } - } - - // Output the element name - if ( bStartOfElement) - { - - if (RC_BAD( rc = pOStream->write( (void *)"<", 1))) - { - goto Exit; - } - } - else - { - - if (RC_BAD( rc = pOStream->write( (void *)"write( (void *)":", 1))) - { - goto Exit; - } - } - - if (RC_BAD( rc = exportUniValue( pOStream, m_puzName, m_uiNameChars, FALSE, 0))) - { - goto Exit; - } - - if (bStartOfElement) - { - - // Output the attributes. As we go, remove any attributes that are - // not namespace declarations. They are not needed after this. - - pPrevAttr = NULL; - pAttr = m_pFirstAttr; - while (pAttr) - { - if (RC_BAD( rc = pAttr->outputAttr( pOStream))) - { - goto Exit; - } - - if (!pAttr->m_bIsNamespaceDecl) - { - if (pPrevAttr) - { - pPrevAttr->m_pNext = pAttr->m_pNext; - makeAttrAvail( pAttr); - pAttr = pPrevAttr->m_pNext; - } - else - { - m_pFirstAttr = pAttr->m_pNext; - makeAttrAvail( pAttr); - pAttr = m_pFirstAttr; - } - - // See if we deleted the last attribute in the list. - - if (!pAttr) - { - m_pLastAttr = pPrevAttr; - } - } - else - { - pPrevAttr = pAttr; - pAttr = pAttr->m_pNext; - } - } - } - - // Close out the element - if (RC_BAD( rc = (RCODE)(bStartOfElement && bEndOfElement - ? pOStream->write( (void *)"/>", 2) - : pOStream->write( (void *)">", 1)))) - { - goto Exit; - } - - if ( bAddNewLine && bEndNode) - { - if (RC_BAD( rc = pOStream->write( (void *)"\n", 1))) - { - goto Exit; - } - } - - -Exit: - - return( rc); -} - -/***************************************************************************** -Desc: Output Data that is contained on an element node. -*****************************************************************************/ - -RCODE F_Element::outputLocalData( - IF_OStream * pOStream, - IF_DOMNode * pDbNode, - IF_Db * ifpDb, - eExportFormatType eFormatType, - FLMUINT uiIndentCount) -{ - RCODE rc = NE_XFLM_OK; - FLMUNICODE uzTmpData [150]; - FLMUNICODE * puzData = &uzTmpData [0]; - FLMUINT uiDataBufSize = sizeof( uzTmpData); - FLMUINT uiChars; - - if (RC_BAD( rc = pDbNode->getUnicodeChars( ifpDb, &uiChars))) - { - goto Exit; - } - - - if (uiDataBufSize < (uiChars + 1) * sizeof( FLMUNICODE)) - { - FLMUNICODE * puzNew; - - if (RC_BAD( rc = f_alloc( (uiChars + 1) * sizeof( FLMUNICODE), - &puzNew))) - { - goto Exit; - } - if (puzData != &uzTmpData [0]) - { - f_free( &puzData); - } - puzData = puzNew; - uiDataBufSize = (uiChars + 1) * sizeof( FLMUNICODE); - } - if (RC_BAD( rc = pDbNode->getUnicode( ifpDb, puzData, - uiDataBufSize, 0, uiChars, &uiChars))) - { - goto Exit; - } - - // Output the value. - if (RC_BAD( rc = exportUniValue( pOStream, puzData, uiChars, TRUE, - eFormatType >= XFLM_EXPORT_INDENT_DATA ? uiIndentCount : 0))) - { - goto Exit; - } - -Exit: - - return ( rc); -} - -/***************************************************************************** -Desc: Outputs a UTF8 stream of XML, starting at the specified node. Node and - all of its descendant nodes are output. -*****************************************************************************/ -RCODE XFLMAPI F_Db::exportXML( - IF_DOMNode * pStartNode, - IF_OStream * pOStream, - eExportFormatType eFormatType) -{ - RCODE rc = NE_XFLM_OK; - F_Element * pAvailElements = NULL; - F_Element * pTmpElement; - F_Attribute * pAvailAttrs = NULL; - F_Attribute * pTmpAttr; - FLMUNICODE uzTmpData [150]; - FLMUNICODE * puzData = &uzTmpData [0]; - FLMUINT uiDataBufSize = sizeof( uzTmpData); - IF_DOMNode * pDbNode = NULL; - eDomNodeType ePrevNodeType; - F_Element * pCurrElement = NULL; - FLMUINT uiNextPrefixNum = 0; - FLMBOOL bStartOfDocument = TRUE; - FLMBOOL bShouldFormat = FALSE; - FLMBOOL bIsDataLocal = FALSE; - FLMUINT uiIndentCount = 0; - FLMUINT uiICount = 0; - - // This routine should only be called if the node type is element node. - - flmAssert( pStartNode->getNodeType() == ELEMENT_NODE); - - ePrevNodeType = ELEMENT_NODE; - pDbNode = pStartNode; - pDbNode->AddRef(); - - for (;;) - { - // Output the current node, depending on its type. - - if( pDbNode->getNodeType() == ELEMENT_NODE) - { - if (pAvailElements) - { - pTmpElement = pAvailElements; - pAvailElements = pAvailElements->getNext(); - pTmpElement->reset( pCurrElement, &pAvailAttrs, &uiNextPrefixNum); - } - else - { - if ((pTmpElement = f_new F_Element( pCurrElement, &pAvailAttrs, - &uiNextPrefixNum)) == NULL) - { - rc = RC_SET( NE_XFLM_MEM); - goto Exit; - } - } - - pCurrElement = pTmpElement; - - if (RC_BAD( rc = pCurrElement->setupElement( (IF_Db *)this, pDbNode))) - { - goto Exit; - } - - if( eFormatType >= XFLM_EXPORT_INDENT) - { - pCurrElement->setIndentCount(uiIndentCount); - } - - if( pDbNode == pStartNode) - { - pCurrElement->setDocumentRoot( TRUE); - } - - // Only want a New Line and tabs for Element if: - // 1) New Line format is indicated - // 2) Previous Element Was NOT Data - bShouldFormat = ( (eFormatType >= XFLM_EXPORT_NEW_LINE) && - (ePrevNodeType != DATA_NODE)) - ? TRUE - : FALSE; - - if( RC_BAD( rc = pDbNode->isDataLocalToNode( (IF_Db *)this, - &bIsDataLocal))) - { - goto Exit; - } - - if( bIsDataLocal) - { - if( RC_BAD( rc = pCurrElement->outputElem( pOStream, - TRUE, FALSE, bShouldFormat))) - { - goto Exit; - } - - pCurrElement->outputLocalData( pOStream, - pDbNode, - (IF_Db *)this, - eFormatType, - uiIndentCount); - - } - - if( RC_OK( rc = pDbNode->getFirstChild( (IF_Db *)this, &pDbNode))) - { - if( !bIsDataLocal && RC_BAD( rc = pCurrElement->outputElem( - pOStream, TRUE, FALSE, bShouldFormat))) - { - goto Exit; - } - - bStartOfDocument = FALSE; - uiIndentCount++; - ePrevNodeType = ELEMENT_NODE; - continue; - } - - if( rc != NE_XFLM_DOM_NODE_NOT_FOUND) - { - goto Exit; - } - - // Write out the "/>" for the element, because it had no - // child nodes. - - if( bIsDataLocal) - { - if( RC_BAD( rc = pCurrElement->outputElem( pOStream, - FALSE, TRUE, bShouldFormat))) - { - goto Exit; - } - } - else - { - if( RC_BAD( rc = pCurrElement->outputElem( pOStream, - TRUE, TRUE, bShouldFormat))) - { - goto Exit; - } - } - - // We are now done with this element - - ePrevNodeType = ELEMENT_NODE; - pTmpElement = pCurrElement; - pCurrElement = pCurrElement->getParentElement(); - pTmpElement->makeAvail( &pAvailElements); - - if( !pCurrElement) - { - break; - } - -Get_Element_Sibling: - - // See if we have a sibling. Go up tree until we find - // a node that has a sibling. - - for( ;;) - { - if( RC_OK( rc = pDbNode->getNextSibling( (IF_Db *)this, &pDbNode))) - { - break; - } - - if( rc != NE_XFLM_DOM_NODE_NOT_FOUND) - { - goto Exit; - } - - // Need to close previous element - - if( uiIndentCount) - { - uiIndentCount--; - } - - if( RC_BAD( rc = pCurrElement->outputElem( pOStream, FALSE, TRUE, - eFormatType >= XFLM_EXPORT_NEW_LINE - ? TRUE - : FALSE))) - { - goto Exit; - } - - if( RC_BAD( rc = pDbNode->getParentNode( (IF_Db *)this, &pDbNode))) - { - if( rc == NE_XFLM_DOM_NODE_NOT_FOUND) - { - // There should be a parent node at this point! - - rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR); - } - - goto Exit; - } - - pTmpElement = pCurrElement; - pCurrElement = pCurrElement->getParentElement(); - pTmpElement->makeAvail( &pAvailElements); - - if( !pCurrElement) - { - pDbNode->Release(); - pDbNode = NULL; - goto Exit; - } - } - } - else - { - // Only output data, comment, and cdata nodes. - - if( pDbNode->getNodeType() == DATA_NODE || - pDbNode->getNodeType() == COMMENT_NODE || - pDbNode->getNodeType() == CDATA_SECTION_NODE) - { - FLMUINT uiChars; - - if( RC_BAD( rc = pDbNode->getUnicodeChars( (IF_Db *)this, - &uiChars))) - { - goto Exit; - } - - if( uiDataBufSize < (uiChars + 1) * sizeof( FLMUNICODE)) - { - FLMUNICODE * puzNew; - - if( RC_BAD( rc = f_alloc( (uiChars + 1) * sizeof( FLMUNICODE), - &puzNew))) - { - goto Exit; - } - - if( puzData != &uzTmpData [0]) - { - f_free( &puzData); - } - - puzData = puzNew; - uiDataBufSize = (uiChars + 1) * sizeof( FLMUNICODE); - } - - if( RC_BAD( rc = pDbNode->getUnicode( (IF_Db *)this, puzData, - uiDataBufSize, 0, uiChars, &uiChars))) - { - goto Exit; - } - - if( pDbNode->getNodeType() == DATA_NODE) - { - // Output the value - - if (RC_BAD( rc = exportUniValue( pOStream, puzData, uiChars, - TRUE, eFormatType >= XFLM_EXPORT_INDENT_DATA - ? uiIndentCount - : 0))) - { - goto Exit; - } - - ePrevNodeType = DATA_NODE; - } - else if( pDbNode->getNodeType() == COMMENT_NODE) - { - //If Comment Node follows Data Node do not add new line - - if( eFormatType >= XFLM_EXPORT_INDENT_DATA && - ePrevNodeType != DATA_NODE) - { - if (RC_BAD( rc = pOStream->write( (void *)"\n", 1))) - { - goto Exit; - } - - for( uiICount = 0; uiICount < uiIndentCount; uiICount++) - { - if (RC_BAD( rc = pOStream->write( (void *)"\t", 1))) - { - goto Exit; - } - } - } - - // Output the beginning of a comment - - if (RC_BAD( rc = pOStream->write( (void *)"", 3))) - { - goto Exit; - } - - ePrevNodeType = COMMENT_NODE; - } - else - { - // Output the beginning of a cdata section - - if( RC_BAD( rc = pOStream->write( (void *)"write( (void *)"]]>", 3))) - { - goto Exit; - } - - ePrevNodeType = CDATA_SECTION_NODE; - } - } - - // Have a data node, or comment node probably - // In any case, see if there are any sibling nodes. - // If not, go back to enclosing element node. - - if( RC_OK( rc = pDbNode->getNextSibling( (IF_Db *)this, &pDbNode))) - { - continue; - } - - if( rc != NE_XFLM_DOM_NODE_NOT_FOUND) - { - goto Exit; - } - - // Go back up to enclosing element - - if( RC_BAD( rc = pDbNode->getParentNode( (IF_Db *)this, &pDbNode))) - { - // There better be a parent node or we have a corruption! - - if( rc == NE_XFLM_DOM_NODE_NOT_FOUND) - { - rc = RC_SET( NE_XFLM_DATA_ERROR); - } - - goto Exit; - } - - // Parent node better be an element - - if( pDbNode->getNodeType() != ELEMENT_NODE) - { - rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR); - goto Exit; - } - - // If we were traversing the attributes of an element, - // we need to now go back and get its child nodes. - - // Write out the for the element - - if( RC_BAD( rc = pCurrElement->outputElem( pOStream, - FALSE, TRUE, FALSE))) - { - goto Exit; - } - - // We are now done with this element - - if( uiIndentCount) - { - uiIndentCount--; - } - - ePrevNodeType = ELEMENT_NODE; - pTmpElement = pCurrElement; - pCurrElement = pCurrElement->getParentElement(); - pTmpElement->makeAvail( &pAvailElements); - - if( !pCurrElement) - { - break; - } - - goto Get_Element_Sibling; - } - } - -Exit: - - if( puzData != &uzTmpData [0]) - { - f_free( &puzData); - } - - while( pCurrElement) - { - pTmpElement = pCurrElement; - pCurrElement = pCurrElement->getParentElement(); - delete pTmpElement; - } - - while( pAvailElements) - { - pTmpElement = pAvailElements; - pAvailElements = pAvailElements->getNext(); - delete pTmpElement; - } - - while( pAvailAttrs) - { - pTmpAttr = pAvailAttrs; - pAvailAttrs = pAvailAttrs->getNext(); - delete pTmpAttr; - } - - if( pDbNode) - { - pDbNode->Release(); - } - - return( rc); -} +//------------------------------------------------------------------------------ +// Desc: XML parser +// +// Tabs: 3 +// +// Copyright (c) 2000-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fxml.cpp 3115 2006-01-19 13:24:39 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------------ + +#include "flaimsys.h" + +// Constants + +#define FLM_XML_BASE_CHAR 0x01 +#define FLM_XML_IDEOGRAPHIC 0x02 +#define FLM_XML_COMBINING_CHAR 0x04 +#define FLM_XML_DIGIT 0x08 +#define FLM_XML_EXTENDER 0x10 +#define FLM_XML_WHITESPACE 0x20 + +// Local typedefs + +typedef struct +{ + char * pszEntity; + FLMUINT uiValue; +} CharEntity; + +// Global data + +extern FLMUNICODE gv_uzXFLAIMNamespace[]; + +static FLMUNICODE gv_puzNamespaceDeclPrefix[] = +{ + FLM_UNICODE_x, + FLM_UNICODE_m, + FLM_UNICODE_l, + FLM_UNICODE_n, + FLM_UNICODE_s, + 0 +}; + +static FLMUNICODE gv_puzXMLPrefix[] = +{ + FLM_UNICODE_x, + FLM_UNICODE_m, + FLM_UNICODE_l, + 0 +}; + +FLMUNICODE gv_puzXMLNSURI[] = +{ + FLM_UNICODE_h, + FLM_UNICODE_t, + FLM_UNICODE_t, + FLM_UNICODE_p, + FLM_UNICODE_COLON, + FLM_UNICODE_FSLASH, + FLM_UNICODE_FSLASH, + FLM_UNICODE_w, + FLM_UNICODE_w, + FLM_UNICODE_w, + FLM_UNICODE_PERIOD, + FLM_UNICODE_w, + FLM_UNICODE_3, + FLM_UNICODE_c, + FLM_UNICODE_PERIOD, + FLM_UNICODE_o, + FLM_UNICODE_r, + FLM_UNICODE_g, + FLM_UNICODE_FSLASH, + FLM_UNICODE_T, + FLM_UNICODE_R, + FLM_UNICODE_FSLASH, + FLM_UNICODE_1, + FLM_UNICODE_9, + FLM_UNICODE_9, + FLM_UNICODE_9, + FLM_UNICODE_FSLASH, + FLM_UNICODE_R, + FLM_UNICODE_E, + FLM_UNICODE_C, + FLM_UNICODE_HYPHEN, + FLM_UNICODE_x, + FLM_UNICODE_m, + FLM_UNICODE_l, + FLM_UNICODE_HYPHEN, + FLM_UNICODE_n, + FLM_UNICODE_a, + FLM_UNICODE_m, + FLM_UNICODE_e, + FLM_UNICODE_s, + FLM_UNICODE_HYPHEN, + FLM_UNICODE_1, + FLM_UNICODE_9, + FLM_UNICODE_9, + FLM_UNICODE_9, + FLM_UNICODE_0, + FLM_UNICODE_1, + FLM_UNICODE_1, + FLM_UNICODE_4, + 0 +}; + +FSTATIC RCODE exportUniValue( + IF_OStream * pOStream, + FLMUNICODE * puzStr, + FLMUINT uiStrChars, + FLMBOOL bEncodeSpecialChars, + FLMUINT uiIndentCount); + +// Function / Method Implementations + +/**************************************************************************** +Desc: Constructor +****************************************************************************/ +F_XML::F_XML() +{ + m_pCharTable = NULL; +} + +/**************************************************************************** +Desc: Destructor +****************************************************************************/ +F_XML::~F_XML() +{ + if( m_pCharTable) + { + f_free( &m_pCharTable); + } +} + +typedef struct +{ + FLMUNICODE uLowChar; + FLMUNICODE uHighChar; + FLMUINT16 ui16Flag; +} CHAR_TBL; + +static CHAR_TBL charTbl[] = +{ + { 0x0041, 0x005A, FLM_XML_BASE_CHAR}, + { 0x0061, 0x007A, FLM_XML_BASE_CHAR}, + { 0x00C0, 0x00D6, FLM_XML_BASE_CHAR}, + { 0x00D8, 0x00F6, FLM_XML_BASE_CHAR}, + { 0x00F8, 0x00FF, FLM_XML_BASE_CHAR}, + { 0x0100, 0x0131, FLM_XML_BASE_CHAR}, + { 0x0134, 0x013E, FLM_XML_BASE_CHAR}, + { 0x0141, 0x0148, FLM_XML_BASE_CHAR}, + { 0x014A, 0x017E, FLM_XML_BASE_CHAR}, + { 0x0180, 0x01C3, FLM_XML_BASE_CHAR}, + { 0x01CD, 0x01F0, FLM_XML_BASE_CHAR}, + { 0x01F4, 0x01F5, FLM_XML_BASE_CHAR}, + { 0x01FA, 0x0217, FLM_XML_BASE_CHAR}, + { 0x0250, 0x02A8, FLM_XML_BASE_CHAR}, + { 0x02BB, 0x02C1, FLM_XML_BASE_CHAR}, + { 0x0386, 0x0386, FLM_XML_BASE_CHAR}, + { 0x0388, 0x038A, FLM_XML_BASE_CHAR}, + { 0x038C, 0x038C, FLM_XML_BASE_CHAR}, + { 0x038E, 0x03A1, FLM_XML_BASE_CHAR}, + { 0x03A3, 0x03CE, FLM_XML_BASE_CHAR}, + { 0x03D0, 0x03D6, FLM_XML_BASE_CHAR}, + { 0x03DA, 0x03DA, FLM_XML_BASE_CHAR}, + { 0x03DC, 0x03DC, FLM_XML_BASE_CHAR}, + { 0x03DE, 0x03DE, FLM_XML_BASE_CHAR}, + { 0x03E0, 0x03E0, FLM_XML_BASE_CHAR}, + { 0x03E2, 0x03F3, FLM_XML_BASE_CHAR}, + { 0x0401, 0x040C, FLM_XML_BASE_CHAR}, + { 0x040E, 0x044F, FLM_XML_BASE_CHAR}, + { 0x0451, 0x045C, FLM_XML_BASE_CHAR}, + { 0x045E, 0x0481, FLM_XML_BASE_CHAR}, + { 0x0490, 0x04C4, FLM_XML_BASE_CHAR}, + { 0x04C7, 0x04C8, FLM_XML_BASE_CHAR}, + { 0x04CB, 0x04CC, FLM_XML_BASE_CHAR}, + { 0x04D0, 0x04EB, FLM_XML_BASE_CHAR}, + { 0x04EE, 0x04F5, FLM_XML_BASE_CHAR}, + { 0x04F8, 0x04F9, FLM_XML_BASE_CHAR}, + { 0x0531, 0x0556, FLM_XML_BASE_CHAR}, + { 0x0559, 0x0559, FLM_XML_BASE_CHAR}, + { 0x0561, 0x0586, FLM_XML_BASE_CHAR}, + { 0x05D0, 0x05EA, FLM_XML_BASE_CHAR}, + { 0x05F0, 0x05F2, FLM_XML_BASE_CHAR}, + { 0x0621, 0x063A, FLM_XML_BASE_CHAR}, + { 0x0641, 0x06B7, FLM_XML_BASE_CHAR}, + { 0x06BA, 0x06BE, FLM_XML_BASE_CHAR}, + { 0x06C0, 0x06CE, FLM_XML_BASE_CHAR}, + { 0x06D0, 0x06D3, FLM_XML_BASE_CHAR}, + { 0x06D5, 0x06D5, FLM_XML_BASE_CHAR}, + { 0x06E5, 0x06E6, FLM_XML_BASE_CHAR}, + { 0x0905, 0x0939, FLM_XML_BASE_CHAR}, + { 0x093D, 0x093D, FLM_XML_BASE_CHAR}, + { 0x0958, 0x0961, FLM_XML_BASE_CHAR}, + { 0x0985, 0x098C, FLM_XML_BASE_CHAR}, + { 0x098F, 0x0990, FLM_XML_BASE_CHAR}, + { 0x0993, 0x09A8, FLM_XML_BASE_CHAR}, + { 0x09AA, 0x09B0, FLM_XML_BASE_CHAR}, + { 0x09B2, 0x09B2, FLM_XML_BASE_CHAR}, + { 0x09B6, 0x09B9, FLM_XML_BASE_CHAR}, + { 0x0061, 0x007A, FLM_XML_BASE_CHAR}, + { 0x09DC, 0x09DD, FLM_XML_BASE_CHAR}, + { 0x09DF, 0x09E1, FLM_XML_BASE_CHAR}, + { 0x09F0, 0x09F1, FLM_XML_BASE_CHAR}, + { 0x0A05, 0x0A0A, FLM_XML_BASE_CHAR}, + { 0x0A0F, 0x0A10, FLM_XML_BASE_CHAR}, + { 0x0A13, 0x0A28, FLM_XML_BASE_CHAR}, + { 0x0A2A, 0x0A30, FLM_XML_BASE_CHAR}, + { 0x0A32, 0x0A33, FLM_XML_BASE_CHAR}, + { 0x0A35, 0x0A36, FLM_XML_BASE_CHAR}, + { 0x0A38, 0x0A39, FLM_XML_BASE_CHAR}, + { 0x0A59, 0x0A5C, FLM_XML_BASE_CHAR}, + { 0x0A5E, 0x0A5E, FLM_XML_BASE_CHAR}, + { 0x0A72, 0x0A74, FLM_XML_BASE_CHAR}, + { 0x0A85, 0x0A8B, FLM_XML_BASE_CHAR}, + { 0x0A8D, 0x0A8D, FLM_XML_BASE_CHAR}, + { 0x0A8F, 0x0A91, FLM_XML_BASE_CHAR}, + { 0x0A93, 0x0AA8, FLM_XML_BASE_CHAR}, + { 0x0AAA, 0x0AB0, FLM_XML_BASE_CHAR}, + { 0x0AB2, 0x0AB3, FLM_XML_BASE_CHAR}, + { 0x0AB5, 0x0AB9, FLM_XML_BASE_CHAR}, + { 0x0ABD, 0x0ABD, FLM_XML_BASE_CHAR}, + { 0x0AE0, 0x0AE0, FLM_XML_BASE_CHAR}, + { 0x0B05, 0x0B0C, FLM_XML_BASE_CHAR}, + { 0x0B0F, 0x0B10, FLM_XML_BASE_CHAR}, + { 0x0B13, 0x0B28, FLM_XML_BASE_CHAR}, + { 0x0B2A, 0x0B30, FLM_XML_BASE_CHAR}, + { 0x0B32, 0x0B33, FLM_XML_BASE_CHAR}, + { 0x0B36, 0x0B39, FLM_XML_BASE_CHAR}, + { 0x0B3D, 0x0B3D, FLM_XML_BASE_CHAR}, + { 0x0B5C, 0x0B5D, FLM_XML_BASE_CHAR}, + { 0x0B5F, 0x0B61, FLM_XML_BASE_CHAR}, + { 0x0B85, 0x0B8A, FLM_XML_BASE_CHAR}, + { 0x0B8E, 0x0B90, FLM_XML_BASE_CHAR}, + { 0x0B92, 0x0B95, FLM_XML_BASE_CHAR}, + { 0x0B99, 0x0B9A, FLM_XML_BASE_CHAR}, + { 0x0B9C, 0x0B9C, FLM_XML_BASE_CHAR}, + { 0x0B9E, 0x0B9F, FLM_XML_BASE_CHAR}, + { 0x0BA3, 0x0BA4, FLM_XML_BASE_CHAR}, + { 0x0BA8, 0x0BAA, FLM_XML_BASE_CHAR}, + { 0x0BAE, 0x0BB5, FLM_XML_BASE_CHAR}, + { 0x0BB7, 0x0BB9, FLM_XML_BASE_CHAR}, + { 0x0C05, 0x0C0C, FLM_XML_BASE_CHAR}, + { 0x0C0E, 0x0C10, FLM_XML_BASE_CHAR}, + { 0x0C12, 0x0C28, FLM_XML_BASE_CHAR}, + { 0x0C2A, 0x0C33, FLM_XML_BASE_CHAR}, + { 0x0C35, 0x0C39, FLM_XML_BASE_CHAR}, + { 0x0C60, 0x0C61, FLM_XML_BASE_CHAR}, + { 0x0C85, 0x0C8C, FLM_XML_BASE_CHAR}, + { 0x0C8E, 0x0C90, FLM_XML_BASE_CHAR}, + { 0x0C92, 0x0CA8, FLM_XML_BASE_CHAR}, + { 0x0CAA, 0x0CB3, FLM_XML_BASE_CHAR}, + { 0x0CB5, 0x0CB9, FLM_XML_BASE_CHAR}, + { 0x0CDE, 0x0CDE, FLM_XML_BASE_CHAR}, + { 0x0CE0, 0x0CE1, FLM_XML_BASE_CHAR}, + { 0x0D05, 0x0D0C, FLM_XML_BASE_CHAR}, + { 0x0D0E, 0x0D10, FLM_XML_BASE_CHAR}, + { 0x0D12, 0x0D28, FLM_XML_BASE_CHAR}, + { 0x0D2A, 0x0D39, FLM_XML_BASE_CHAR}, + { 0x0D60, 0x0D61, FLM_XML_BASE_CHAR}, + { 0x0E01, 0x0E2E, FLM_XML_BASE_CHAR}, + { 0x0E30, 0x0E30, FLM_XML_BASE_CHAR}, + { 0x0E32, 0x0E33, FLM_XML_BASE_CHAR}, + { 0x0E40, 0x0E45, FLM_XML_BASE_CHAR}, + { 0x0E81, 0x0E82, FLM_XML_BASE_CHAR}, + { 0x0E84, 0x0E84, FLM_XML_BASE_CHAR}, + { 0x0E87, 0x0E88, FLM_XML_BASE_CHAR}, + { 0x0E8A, 0x0E8A, FLM_XML_BASE_CHAR}, + { 0x0E8D, 0x0E8D, FLM_XML_BASE_CHAR}, + { 0x0E94, 0x0E97, FLM_XML_BASE_CHAR}, + { 0x0E99, 0x0E9F, FLM_XML_BASE_CHAR}, + { 0x0EA1, 0x0EA3, FLM_XML_BASE_CHAR}, + { 0x0EA5, 0x0EA5, FLM_XML_BASE_CHAR}, + { 0x0EA7, 0x0EA7, FLM_XML_BASE_CHAR}, + { 0x0EAA, 0x0EAB, FLM_XML_BASE_CHAR}, + { 0x0EAD, 0x0EAE, FLM_XML_BASE_CHAR}, + { 0x0EB0, 0x0EB0, FLM_XML_BASE_CHAR}, + { 0x0EB2, 0x0EB3, FLM_XML_BASE_CHAR}, + { 0x0EBD, 0x0EBD, FLM_XML_BASE_CHAR}, + { 0x0EC0, 0x0EC4, FLM_XML_BASE_CHAR}, + { 0x0F40, 0x0F47, FLM_XML_BASE_CHAR}, + { 0x0F49, 0x0F69, FLM_XML_BASE_CHAR}, + { 0x10A0, 0x10C5, FLM_XML_BASE_CHAR}, + { 0x10D0, 0x10F6, FLM_XML_BASE_CHAR}, + { 0x1100, 0x1100, FLM_XML_BASE_CHAR}, + { 0x1102, 0x1103, FLM_XML_BASE_CHAR}, + { 0x1105, 0x1107, FLM_XML_BASE_CHAR}, + { 0x1109, 0x1109, FLM_XML_BASE_CHAR}, + { 0x110B, 0x110C, FLM_XML_BASE_CHAR}, + { 0x110E, 0x1112, FLM_XML_BASE_CHAR}, + { 0x113C, 0x113C, FLM_XML_BASE_CHAR}, + { 0x113E, 0x113E, FLM_XML_BASE_CHAR}, + { 0x1140, 0x1140, FLM_XML_BASE_CHAR}, + { 0x114C, 0x114C, FLM_XML_BASE_CHAR}, + { 0x114E, 0x114E, FLM_XML_BASE_CHAR}, + { 0x1150, 0x1150, FLM_XML_BASE_CHAR}, + { 0x1154, 0x1155, FLM_XML_BASE_CHAR}, + { 0x1159, 0x1159, FLM_XML_BASE_CHAR}, + { 0x115F, 0x1161, FLM_XML_BASE_CHAR}, + { 0x1163, 0x1163, FLM_XML_BASE_CHAR}, + { 0x1165, 0x1165, FLM_XML_BASE_CHAR}, + { 0x1167, 0x1167, FLM_XML_BASE_CHAR}, + { 0x1169, 0x1169, FLM_XML_BASE_CHAR}, + { 0x116D, 0x116E, FLM_XML_BASE_CHAR}, + { 0x1172, 0x1173, FLM_XML_BASE_CHAR}, + { 0x1175, 0x1175, FLM_XML_BASE_CHAR}, + { 0x119E, 0x119E, FLM_XML_BASE_CHAR}, + { 0x11A8, 0x11A8, FLM_XML_BASE_CHAR}, + { 0x11AB, 0x11AB, FLM_XML_BASE_CHAR}, + { 0x11AE, 0x11AF, FLM_XML_BASE_CHAR}, + { 0x11B7, 0x11B8, FLM_XML_BASE_CHAR}, + { 0x11BA, 0x11BA, FLM_XML_BASE_CHAR}, + { 0x11BC, 0x11C2, FLM_XML_BASE_CHAR}, + { 0x11EB, 0x11EB, FLM_XML_BASE_CHAR}, + { 0x11F0, 0x11F0, FLM_XML_BASE_CHAR}, + { 0x11F9, 0x11F9, FLM_XML_BASE_CHAR}, + { 0x1E00, 0x1E9B, FLM_XML_BASE_CHAR}, + { 0x1EA0, 0x1EF9, FLM_XML_BASE_CHAR}, + { 0x1F00, 0x1F15, FLM_XML_BASE_CHAR}, + { 0x1F18, 0x1F1D, FLM_XML_BASE_CHAR}, + { 0x1F20, 0x1F45, FLM_XML_BASE_CHAR}, + { 0x1F48, 0x1F4D, FLM_XML_BASE_CHAR}, + { 0x1F50, 0x1F57, FLM_XML_BASE_CHAR}, + { 0x1F59, 0x1F59, FLM_XML_BASE_CHAR}, + { 0x1F5B, 0x1F5B, FLM_XML_BASE_CHAR}, + { 0x1F5D, 0x1F5D, FLM_XML_BASE_CHAR}, + { 0x1F5F, 0x1F7D, FLM_XML_BASE_CHAR}, + { 0x1F80, 0x1FB4, FLM_XML_BASE_CHAR}, + { 0x1FB6, 0x1FBC, FLM_XML_BASE_CHAR}, + { 0x1FBE, 0x1FBE, FLM_XML_BASE_CHAR}, + { 0x1FC2, 0x1FC4, FLM_XML_BASE_CHAR}, + { 0x1FC6, 0x1FCC, FLM_XML_BASE_CHAR}, + { 0x1FD0, 0x1FD3, FLM_XML_BASE_CHAR}, + { 0x1FD6, 0x1FDB, FLM_XML_BASE_CHAR}, + { 0x1FE0, 0x1FEC, FLM_XML_BASE_CHAR}, + { 0x1FF2, 0x1FF4, FLM_XML_BASE_CHAR}, + { 0x1FF6, 0x1FFC, FLM_XML_BASE_CHAR}, + { 0x2126, 0x2126, FLM_XML_BASE_CHAR}, + { 0x212A, 0x212B, FLM_XML_BASE_CHAR}, + { 0x212E, 0x212E, FLM_XML_BASE_CHAR}, + { 0x2180, 0x2182, FLM_XML_BASE_CHAR}, + { 0x3041, 0x3094, FLM_XML_BASE_CHAR}, + { 0x30A1, 0x30FA, FLM_XML_BASE_CHAR}, + { 0x3105, 0x312C, FLM_XML_BASE_CHAR}, + { 0xAC00, 0xD7A3, FLM_XML_BASE_CHAR}, + + { 0x4E00, 0x9FA5, FLM_XML_IDEOGRAPHIC}, + { 0x3007, 0x3007, FLM_XML_IDEOGRAPHIC}, + { 0x3021, 0x3029, FLM_XML_IDEOGRAPHIC}, + + { 0x0300, 0x0345, FLM_XML_COMBINING_CHAR}, + { 0x0360, 0x0361, FLM_XML_COMBINING_CHAR}, + { 0x0483, 0x0486, FLM_XML_COMBINING_CHAR}, + { 0x0591, 0x05A1, FLM_XML_COMBINING_CHAR}, + { 0x05A3, 0x05B9, FLM_XML_COMBINING_CHAR}, + { 0x05BB, 0x05BD, FLM_XML_COMBINING_CHAR}, + { 0x05BF, 0x05BF, FLM_XML_COMBINING_CHAR}, + { 0x05C1, 0x05C2, FLM_XML_COMBINING_CHAR}, + { 0x05C4, 0x05C4, FLM_XML_COMBINING_CHAR}, + { 0x064B, 0x0652, FLM_XML_COMBINING_CHAR}, + { 0x0670, 0x0670, FLM_XML_COMBINING_CHAR}, + { 0x06D6, 0x06DC, FLM_XML_COMBINING_CHAR}, + { 0x06DD, 0x06DF, FLM_XML_COMBINING_CHAR}, + { 0x06E0, 0x06E4, FLM_XML_COMBINING_CHAR}, + { 0x06E7, 0x06E8, FLM_XML_COMBINING_CHAR}, + { 0x06EA, 0x06ED, FLM_XML_COMBINING_CHAR}, + { 0x0901, 0x0903, FLM_XML_COMBINING_CHAR}, + { 0x093C, 0x093C, FLM_XML_COMBINING_CHAR}, + { 0x093E, 0x094C, FLM_XML_COMBINING_CHAR}, + { 0x094D, 0x094D, FLM_XML_COMBINING_CHAR}, + { 0x0951, 0x0954, FLM_XML_COMBINING_CHAR}, + { 0x0962, 0x0963, FLM_XML_COMBINING_CHAR}, + { 0x0981, 0x0983, FLM_XML_COMBINING_CHAR}, + { 0x09BC, 0x09BC, FLM_XML_COMBINING_CHAR}, + { 0x09BE, 0x09BE, FLM_XML_COMBINING_CHAR}, + { 0x09BF, 0x09BF, FLM_XML_COMBINING_CHAR}, + { 0x09C0, 0x09C4, FLM_XML_COMBINING_CHAR}, + { 0x09C7, 0x09C8, FLM_XML_COMBINING_CHAR}, + { 0x09CB, 0x09CD, FLM_XML_COMBINING_CHAR}, + { 0x09D7, 0x09D7, FLM_XML_COMBINING_CHAR}, + { 0x09E2, 0x09E3, FLM_XML_COMBINING_CHAR}, + { 0x0A02, 0x0A02, FLM_XML_COMBINING_CHAR}, + { 0x0A3C, 0x0A3C, FLM_XML_COMBINING_CHAR}, + { 0x0A3E, 0x0A3E, FLM_XML_COMBINING_CHAR}, + { 0x0A3F, 0x0A3F, FLM_XML_COMBINING_CHAR}, + { 0x0A40, 0x0A42, FLM_XML_COMBINING_CHAR}, + { 0x0A47, 0x0A48, FLM_XML_COMBINING_CHAR}, + { 0x0A4B, 0x0A4D, FLM_XML_COMBINING_CHAR}, + { 0x0A70, 0x0A71, FLM_XML_COMBINING_CHAR}, + { 0x0A81, 0x0A83, FLM_XML_COMBINING_CHAR}, + { 0x0ABC, 0x0ABC, FLM_XML_COMBINING_CHAR}, + { 0x0ABE, 0x0AC5, FLM_XML_COMBINING_CHAR}, + { 0x0AC7, 0x0AC9, FLM_XML_COMBINING_CHAR}, + { 0x0ACB, 0x0ACD, FLM_XML_COMBINING_CHAR}, + { 0x0B01, 0x0B03, FLM_XML_COMBINING_CHAR}, + { 0x0B3C, 0x0B3C, FLM_XML_COMBINING_CHAR}, + { 0x0B3E, 0x0B43, FLM_XML_COMBINING_CHAR}, + { 0x0B47, 0x0B48, FLM_XML_COMBINING_CHAR}, + { 0x0B4B, 0x0B4D, FLM_XML_COMBINING_CHAR}, + { 0x0B56, 0x0B57, FLM_XML_COMBINING_CHAR}, + { 0x0B82, 0x0B83, FLM_XML_COMBINING_CHAR}, + { 0x0BBE, 0x0BC2, FLM_XML_COMBINING_CHAR}, + { 0x0BC6, 0x0BC8, FLM_XML_COMBINING_CHAR}, + { 0x0BCA, 0x0BCD, FLM_XML_COMBINING_CHAR}, + { 0x0BD7, 0x0BD7, FLM_XML_COMBINING_CHAR}, + { 0x0C01, 0x0C03, FLM_XML_COMBINING_CHAR}, + { 0x0C3E, 0x0C44, FLM_XML_COMBINING_CHAR}, + { 0x0C46, 0x0C48, FLM_XML_COMBINING_CHAR}, + { 0x0C4A, 0x0C4D, FLM_XML_COMBINING_CHAR}, + { 0x0C55, 0x0C56, FLM_XML_COMBINING_CHAR}, + { 0x0C82, 0x0C83, FLM_XML_COMBINING_CHAR}, + { 0x0CBE, 0x0CC4, FLM_XML_COMBINING_CHAR}, + { 0x0CC6, 0x0CC8, FLM_XML_COMBINING_CHAR}, + { 0x0CCA, 0x0CCD, FLM_XML_COMBINING_CHAR}, + { 0x0CD5, 0x0CD6, FLM_XML_COMBINING_CHAR}, + { 0x0D02, 0x0D03, FLM_XML_COMBINING_CHAR}, + { 0x0D3E, 0x0D43, FLM_XML_COMBINING_CHAR}, + { 0x0D46, 0x0D48, FLM_XML_COMBINING_CHAR}, + { 0x0D4A, 0x0D4D, FLM_XML_COMBINING_CHAR}, + { 0x0D57, 0x0D57, FLM_XML_COMBINING_CHAR}, + { 0x0E31, 0x0E31, FLM_XML_COMBINING_CHAR}, + { 0x0E34, 0x0E3A, FLM_XML_COMBINING_CHAR}, + { 0x0E47, 0x0E4E, FLM_XML_COMBINING_CHAR}, + { 0x0EB1, 0x0EB1, FLM_XML_COMBINING_CHAR}, + { 0x0EB4, 0x0EB9, FLM_XML_COMBINING_CHAR}, + { 0x0EBB, 0x0EBC, FLM_XML_COMBINING_CHAR}, + { 0x0EC8, 0x0ECD, FLM_XML_COMBINING_CHAR}, + { 0x0F18, 0x0F19, FLM_XML_COMBINING_CHAR}, + { 0x0F35, 0x0F35, FLM_XML_COMBINING_CHAR}, + { 0x0F37, 0x0F37, FLM_XML_COMBINING_CHAR}, + { 0x0F39, 0x0F39, FLM_XML_COMBINING_CHAR}, + { 0x0F3E, 0x0F3E, FLM_XML_COMBINING_CHAR}, + { 0x0F3F, 0x0F3F, FLM_XML_COMBINING_CHAR}, + { 0x0F71, 0x0F84, FLM_XML_COMBINING_CHAR}, + { 0x0F86, 0x0F8B, FLM_XML_COMBINING_CHAR}, + { 0x0F90, 0x0F95, FLM_XML_COMBINING_CHAR}, + { 0x0F97, 0x0F97, FLM_XML_COMBINING_CHAR}, + { 0x0F99, 0x0FAD, FLM_XML_COMBINING_CHAR}, + { 0x0FB1, 0x0FB7, FLM_XML_COMBINING_CHAR}, + { 0x0FB9, 0x0FB9, FLM_XML_COMBINING_CHAR}, + { 0x20D0, 0x20DC, FLM_XML_COMBINING_CHAR}, + { 0x20E1, 0x20E1, FLM_XML_COMBINING_CHAR}, + { 0x302A, 0x302F, FLM_XML_COMBINING_CHAR}, + { 0x3099, 0x3099, FLM_XML_COMBINING_CHAR}, + { 0x309A, 0x309A, FLM_XML_COMBINING_CHAR}, + + { 0x0030, 0x0039, FLM_XML_DIGIT}, + { 0x0660, 0x0669, FLM_XML_DIGIT}, + { 0x06F0, 0x06F9, FLM_XML_DIGIT}, + { 0x0966, 0x096F, FLM_XML_DIGIT}, + { 0x09E6, 0x09EF, FLM_XML_DIGIT}, + { 0x0A66, 0x0A6F, FLM_XML_DIGIT}, + { 0x0AE6, 0x0AEF, FLM_XML_DIGIT}, + { 0x0B66, 0x0B6F, FLM_XML_DIGIT}, + { 0x0BE7, 0x0BEF, FLM_XML_DIGIT}, + { 0x0C66, 0x0C6F, FLM_XML_DIGIT}, + { 0x0CE6, 0x0CEF, FLM_XML_DIGIT}, + { 0x0D66, 0x0D6F, FLM_XML_DIGIT}, + { 0x0E50, 0x0E59, FLM_XML_DIGIT}, + { 0x0ED0, 0x0ED9, FLM_XML_DIGIT}, + { 0x0F20, 0x0F29, FLM_XML_DIGIT}, + + { 0x00B7, 0x00B7, FLM_XML_EXTENDER}, + { 0x02D0, 0x02D0, FLM_XML_EXTENDER}, + { 0x02D1, 0x02D1, FLM_XML_EXTENDER}, + { 0x0387, 0x0387, FLM_XML_EXTENDER}, + { 0x0640, 0x0640, FLM_XML_EXTENDER}, + { 0x0E46, 0x0E46, FLM_XML_EXTENDER}, + { 0x0EC6, 0x0EC6, FLM_XML_EXTENDER}, + { 0x3005, 0x3005, FLM_XML_EXTENDER}, + { 0x3031, 0x3035, FLM_XML_EXTENDER}, + { 0x309D, 0x309E, FLM_XML_EXTENDER}, + { 0x30FC, 0x30FE, FLM_XML_EXTENDER}, + + { 0x0009, 0x0009, FLM_XML_WHITESPACE}, + { 0x000A, 0x000A, FLM_XML_WHITESPACE}, + { 0x000D, 0x000D, FLM_XML_WHITESPACE}, + { 0x0020, 0x0020, FLM_XML_WHITESPACE}, + { 0, 0, 0} +}; + +/**************************************************************************** +Desc: Sets a character's type flag in the character lookup table +****************************************************************************/ +void F_XML::setCharFlag( + FLMUNICODE uLowChar, + FLMUNICODE uHighChar, + FLMUINT16 ui16Flag) +{ + FLMUINT uiLoop; + + flmAssert( uLowChar <= uHighChar); + + for( uiLoop = (FLMUINT)uLowChar; uiLoop <= (FLMUINT)uHighChar; uiLoop++) + { + m_pCharTable[ uiLoop].ucFlags |= (FLMBYTE)ui16Flag; + } +} + +/**************************************************************************** +Desc: Builds a character lookup table +****************************************************************************/ +RCODE F_XML::buildCharTable( void) +{ + RCODE rc = NE_XFLM_OK; + + if( m_pCharTable) + { + f_free( &m_pCharTable); + } + + if( RC_BAD( rc = f_calloc( sizeof( XMLCHAR) * 0xFFFF, &m_pCharTable))) + { + goto Exit; + } + + for (FLMUINT uiLoop = 0; charTbl[uiLoop].ui16Flag; uiLoop++) + { + setCharFlag( charTbl[uiLoop].uLowChar, + charTbl[uiLoop].uHighChar, + charTbl[uiLoop].ui16Flag); + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is a valid XML PubID character +****************************************************************************/ +FLMBOOL F_XML::isPubidChar( + FLMUNICODE uChar) +{ + if( uChar == FLM_UNICODE_SPACE || + uChar == FLM_UNICODE_LINEFEED || + (uChar >= FLM_UNICODE_a && uChar <= FLM_UNICODE_z) || + (uChar >= FLM_UNICODE_A && uChar <= FLM_UNICODE_Z) || + (uChar >= FLM_UNICODE_0 && uChar <= FLM_UNICODE_9) || + uChar == FLM_UNICODE_HYPHEN || + uChar == FLM_UNICODE_APOS || + uChar == FLM_UNICODE_LPAREN || + uChar == FLM_UNICODE_RPAREN || + uChar == FLM_UNICODE_PLUS || + uChar == FLM_UNICODE_COMMA || + uChar == FLM_UNICODE_PERIOD || + uChar == FLM_UNICODE_FSLASH || + uChar == FLM_UNICODE_COLON || + uChar == FLM_UNICODE_EQ || + uChar == FLM_UNICODE_QUEST || + uChar == FLM_UNICODE_SEMI || + uChar == FLM_UNICODE_BANG || + uChar == FLM_UNICODE_ASTERISK || + uChar == FLM_UNICODE_POUND || + uChar == FLM_UNICODE_ATSIGN || + uChar == FLM_UNICODE_DOLLAR || + uChar == FLM_UNICODE_UNDERSCORE || + uChar == FLM_UNICODE_PERCENT) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is a single or double quote character +****************************************************************************/ +FLMBOOL F_XML::isQuoteChar( + FLMUNICODE uChar) +{ + if( uChar == FLM_UNICODE_QUOTE || uChar == FLM_UNICODE_APOS) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is a whitespace character +****************************************************************************/ +FLMBOOL F_XML::isWhitespace( + FLMUNICODE uChar) +{ + if( (m_pCharTable[ uChar].ucFlags & FLM_XML_WHITESPACE) != 0) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is an extender character +****************************************************************************/ +FLMBOOL F_XML::isExtender( + FLMUNICODE uChar) +{ + if( (m_pCharTable[ uChar].ucFlags & FLM_XML_EXTENDER) != 0) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is a combining character +****************************************************************************/ +FLMBOOL F_XML::isCombiningChar( + FLMUNICODE uChar) +{ + if( (m_pCharTable[ uChar].ucFlags & FLM_XML_COMBINING_CHAR) != 0) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is a valid XML naming character +****************************************************************************/ +FLMBOOL F_XML::isNCNameChar( + FLMUNICODE uChar) +{ + if( isLetter( uChar) || + isDigit( uChar) || + uChar == FLM_UNICODE_PERIOD || + uChar == FLM_UNICODE_HYPHEN || + uChar == FLM_UNICODE_UNDERSCORE || + isCombiningChar( uChar) || isExtender( uChar)) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is a valid XML naming character +****************************************************************************/ +FLMBOOL F_XML::isNameChar( + FLMUNICODE uChar) +{ + if( isNCNameChar( uChar) || + uChar == FLM_UNICODE_COLON) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is an ideographic character +****************************************************************************/ +FLMBOOL F_XML::isIdeographic( + FLMUNICODE uChar) +{ + if( (m_pCharTable[ uChar].ucFlags & FLM_XML_IDEOGRAPHIC) != 0) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is a base character +****************************************************************************/ +FLMBOOL F_XML::isBaseChar( + FLMUNICODE uChar) +{ + if( (m_pCharTable[ uChar].ucFlags & FLM_XML_BASE_CHAR) != 0) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is a digit +****************************************************************************/ +FLMBOOL F_XML::isDigit( + FLMUNICODE uChar) +{ + if( (m_pCharTable[ uChar].ucFlags & FLM_XML_DIGIT) != 0) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the character is a letter +****************************************************************************/ +FLMBOOL F_XML::isLetter( + FLMUNICODE uChar) +{ + if( isBaseChar( uChar) || isIdeographic( uChar)) + { + return( TRUE); + } + + return( FALSE); +} + +/**************************************************************************** +Desc: Returns TRUE if the name is a valid XML name +****************************************************************************/ +FLMBOOL F_XML::isNameValid( + FLMUNICODE * puzName, + FLMBYTE * pszName) +{ + FLMBOOL bValid = FALSE; + + if( puzName) + { + FLMUNICODE * puzTmp; + + if( !isLetter( *puzName) && *puzName != FLM_UNICODE_UNDERSCORE && + *puzName != FLM_UNICODE_COLON) + { + goto Exit; + } + + puzTmp = &puzName[ 1]; + while( *puzTmp) + { + if( !isNameChar( *puzTmp)) + { + goto Exit; + } + puzTmp++; + } + } + + if( pszName) + { + FLMBYTE * pszTmp; + + if( !isLetter( *pszName) && *pszName != FLM_UNICODE_UNDERSCORE && + *pszName != FLM_UNICODE_COLON) + { + goto Exit; + } + + pszTmp = &pszName[ 1]; + while( *pszTmp) + { + if( !isNameChar( *pszTmp)) + { + goto Exit; + } + pszTmp++; + } + } + + bValid = TRUE; + +Exit: + + return( bValid); +} + +/**************************************************************************** +Desc: Constructor +****************************************************************************/ +F_XMLImport::F_XMLImport() +{ + m_uiValBufSize = 0; + m_pucValBuf = NULL; + m_bSetup = FALSE; + m_fnStatus = NULL; + m_pvCallbackData = NULL; + m_tmpPool.poolInit( 4096); + m_attrPool.poolInit( 4096); + m_puzCurrLineBuf = NULL; + m_uiCurrLineBufMaxChars = 0; + reset(); +} + +/**************************************************************************** +Desc: Destructor +****************************************************************************/ +F_XMLImport::~F_XMLImport() +{ + reset(); + + if( m_pucValBuf) + { + f_free( &m_pucValBuf); + } + if (m_puzCurrLineBuf) + { + f_free( &m_puzCurrLineBuf); + } +} + +/**************************************************************************** +Desc: Resets member variables so the object can be reused +****************************************************************************/ +void F_XMLImport::reset( void) +{ + m_uiCurrLineNum = 0; + m_uiCurrLineNumChars = 0; + m_uiCurrLineOffset = 0; + m_ucUngetByte = 0; + m_uiCurrLineFilePos = 0; + m_uiCurrLineBytes = 0; + m_pStream = NULL; + m_uiFlags = 0; + m_eXMLEncoding = XFLM_XML_USASCII_ENCODING; + m_pDb = NULL; + m_uiCollection = 0; + f_memset( &m_importStats, 0, sizeof( XFLM_IMPORT_STATS)); + + popNamespaces( getNamespaceCount()); + m_tmpPool.poolReset( NULL); + resetAttrList(); +} + +/**************************************************************************** +Desc: Initializes the object (allocates buffers, etc.) +****************************************************************************/ +RCODE F_XMLImport::setup( void) +{ + RCODE rc = NE_XFLM_OK; + + flmAssert( !m_bSetup); + + if( RC_BAD( rc = resizeValBuffer( 2048))) + { + goto Exit; + } + + if( RC_BAD( rc = buildCharTable())) + { + goto Exit; + } + + m_bSetup = TRUE; + +Exit: + + if( RC_BAD( rc)) + { + if( m_pucValBuf) + { + f_free( &m_pucValBuf); + m_pucValBuf = NULL; + } + } + + return( rc); +} + +/**************************************************************************** +Desc: Reads data from the input stream and builds a FLAIM record +****************************************************************************/ +RCODE F_XMLImport::import( + F_IStream * pStream, + F_Db * pDb, + FLMUINT uiCollection, + FLMUINT uiFlags, + F_DOMNode * pNodeToLinkTo, + eNodeInsertLoc eInsertLoc, + F_DOMNode ** ppNewNode, + XFLM_IMPORT_STATS * pImportStats) +{ + RCODE rc = NE_XFLM_OK; + + // Reset the state of the parser + + reset(); + + // If a root element was passed in, do some sanity checks + // before importing the XML stream + + if (pNodeToLinkTo) + { + FLMUINT uiTmp; + + if( RC_BAD( rc = pNodeToLinkTo->getCollection( pDb, &uiTmp))) + { + goto Exit; + } + + if( uiTmp != uiCollection) + { + rc = RC_SET( NE_XFLM_ILLEGAL_OP); + goto Exit; + } + } + + m_pDb = pDb; + m_uiCollection = uiCollection; + + // Set up namespace support. Un-prefixed names (NULL prefix) are + // not bound to a namespace (NULL URI). The 'xml' namespace prefix + // is, by definition, bound to 'http://www.w3.org/XML/1998/namespace' + + if( RC_BAD( rc = pushNamespace( NULL, NULL))) + { + goto Exit; + } + + if( RC_BAD( rc = pushNamespace( + gv_puzXMLPrefix, gv_puzXMLNSURI))) + { + goto Exit; + } + + m_pStream = pStream; + m_uiFlags = uiFlags; + + if( RC_BAD( rc = processProlog())) + { + goto Exit; + } + + if( RC_BAD( rc = processElement( pNodeToLinkTo, eInsertLoc, ppNewNode))) + { + goto Exit; + } + + // Call the status hook one last time + + m_importStats.uiDocuments++; + if( m_fnStatus) + { + m_fnStatus( XML_STATS, + (void *)&m_importStats, NULL, NULL, m_pvCallbackData); + } + + // Tally and return the import stats + + if( pImportStats) + { + pImportStats->uiChars += m_importStats.uiChars; + pImportStats->uiAttributes += m_importStats.uiAttributes; + pImportStats->uiElements += m_importStats.uiElements; + pImportStats->uiText += m_importStats.uiText; + pImportStats->uiDocuments += m_importStats.uiDocuments; + } + +Exit: + + if( RC_BAD( rc) && pImportStats) + { + pImportStats->uiErrLineNum = m_importStats.uiErrLineNum + ? m_importStats.uiErrLineNum + : m_uiCurrLineNum; + + pImportStats->uiErrLineOffset = m_importStats.uiErrLineOffset + ? m_importStats.uiErrLineOffset + : m_uiCurrLineOffset; + + pImportStats->eErrorType = ( XMLParseError)( m_importStats.eErrorType); + + pImportStats->uiErrLineFilePos = m_importStats.uiErrLineFilePos; + pImportStats->uiErrLineBytes = m_importStats.uiErrLineBytes; + pImportStats->eXMLEncoding = m_importStats.eXMLEncoding; + } + + m_pDb = NULL; + m_uiCollection = 0; + return( rc); +} + +/**************************************************************************** +Desc: Process an XML prolog +****************************************************************************/ +RCODE F_XMLImport::processProlog( void) +{ + RCODE rc = NE_XFLM_OK; + + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + if (lineHasToken( "createNode( m_pDb, DATA_NODE, 0, + XFLM_LAST_CHILD, (IF_DOMNode **)&pData))) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset, + XML_ERR_CREATING_DATA_NODE, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + goto Exit; + } + + switch( pParent->m_pCachedNode->getDataType()) + { + case XFLM_TEXT_TYPE: + { + if( RC_BAD( rc = pData->setUnicode( m_pDb, puzTextStart))) + { + goto Exit; + } + + m_importStats.uiText++; + if( m_fnStatus && (m_importStats.uiText % 50) == 0) + { + m_fnStatus( XML_STATS, + (void *)&m_importStats, NULL, NULL, m_pvCallbackData); + } + + break; + } + + case XFLM_NUMBER_TYPE: + { + FLMUINT64 ui64Val; + FLMBOOL bNeg; + + if( RC_BAD( rc = unicodeToNumber64( puzTextStart, &ui64Val, &bNeg))) + { + goto Exit; + } + + if( !bNeg) + { + if( RC_BAD( rc = pData->setUINT64( m_pDb, ui64Val))) + { + goto Exit; + } + } + else + { + if( RC_BAD( rc = pData->setINT64( m_pDb, -((FLMINT64)ui64Val)))) + { + goto Exit; + } + } + break; + } + + case XFLM_BINARY_TYPE: + { + if( RC_BAD( rc = pData->setBinary( m_pDb, pucValue, uiValueLen))) + { + goto Exit; + } + break; + } + + default: + { + rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED); + goto Exit; + } + } + +Exit: + + if( pData) + { + pData->Release(); + } + + return( rc); +} + +/**************************************************************************** +Desc: Processes an XML element +****************************************************************************/ +RCODE F_XMLImport::processElement( + F_DOMNode * pNodeToLinkTo, + eNodeInsertLoc eInsertLoc, + F_DOMNode ** ppNewNode) +{ + RCODE rc = NE_XFLM_OK; + FLMBOOL bHasContent; + FLMBOOL bFlushedValue = FALSE; + FLMUINT uiChars; + FLMUINT uiOffset = 0; + FLMUNICODE uChar; + F_DOMNode * pElement = NULL; + F_XMLNamespace * pNamespace = NULL; + FLMUNICODE * puzPrefix; + FLMUNICODE * puzLocal; + FLMUINT uiStartNSCount = getNamespaceCount(); + FLMUINT uiTmp; + FLMUINT uiWhitespaceStartOffset = 0; + FLMBOOL bNamespaceDecl; + FLMUINT uiSavedLineNum = 0; + FLMUINT uiSavedOffset = 0; + FLMUINT uiSavedFilePos = 0; + FLMUINT uiSavedLineBytes = 0; + + if( RC_BAD( rc = processSTag( pNodeToLinkTo, eInsertLoc, &bHasContent, &pElement))) + { + goto Exit; + } + if (ppNewNode) + { + *ppNewNode = pElement; + (*ppNewNode)->AddRef(); + } + + if( !bHasContent) + { + goto Exit; + } + + for( ;;) + { + if ((uChar = getChar()) == 0) + { + uChar = ASCII_NEWLINE; + if (RC_BAD( rc = getLine())) + { + goto Exit; + } + } + + if( uChar == FLM_UNICODE_LT) + { + if( uiWhitespaceStartOffset) + { + // Set the offset to where the whitespace would + // have started. + + flmAssert( uiWhitespaceStartOffset <= uiOffset); + uiOffset = uiWhitespaceStartOffset; + uiWhitespaceStartOffset = 0; + } + + if( uiOffset) + { + // Flush the value + + if( pElement) + { + if( pElement->m_pCachedNode->getDataType() == XFLM_TEXT_TYPE || + pElement->m_pCachedNode->getDataType() == XFLM_NUMBER_TYPE) + { + if( uiOffset + 1 >= m_uiValBufSize) + { + if( RC_BAD( rc = resizeValBuffer( uiOffset + 2))) + { + goto Exit; + } + } + + m_pucValBuf[ uiOffset] = 0; + m_pucValBuf[ uiOffset + 1] = 0; + } + + if( RC_BAD( rc = flushElementValue( + pElement, m_pucValBuf, uiOffset))) + { + goto Exit; + } + } + + bFlushedValue = TRUE; + uiOffset = 0; + } + + // Preserve start location for error handling if necessary + + uiSavedLineNum = m_uiCurrLineNum; + uiSavedOffset = m_uiCurrLineOffset; + uiSavedFilePos = m_uiCurrLineFilePos; + uiSavedLineBytes = m_uiCurrLineBytes; + + if (lineHasToken( "?")) + { + if( RC_BAD( rc = processPI( pElement, + uiSavedLineNum, + uiSavedOffset, + uiSavedFilePos, + uiSavedLineBytes))) + { + goto Exit; + } + } + else if (lineHasToken( "!--")) + { + if( RC_BAD( rc = processComment( pElement, + uiSavedLineNum, + uiSavedOffset, + uiSavedFilePos, + uiSavedLineBytes))) + { + goto Exit; + } + } + else if (lineHasToken( "![CDATA[")) + { + if( RC_BAD( rc = processCDATA( pElement, + uiSavedLineNum, + uiSavedOffset, + uiSavedFilePos, + uiSavedLineBytes))) + { + goto Exit; + } + } + else if (lineHasToken( "/")) + { + break; + } + else if( isNameChar( peekChar())) + { + + // Unget the "<" - because processElement expect to see + // "m_pCachedNode->getDataType() == XFLM_BINARY_TYPE) + { + ungetChar(); + + if( RC_BAD( rc = getBinaryVal( &uiOffset))) + { + goto Exit; + } + } + else if (uChar == FLM_UNICODE_AMP) + { + if( RC_BAD( rc = processReference( &uChar))) + { + goto Exit; + } + + flmAssert( uChar); + if (pElement->m_pCachedNode->getDataType() != XFLM_NODATA_TYPE) + { + *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar; + uiOffset += sizeof( FLMUNICODE); + uiWhitespaceStartOffset = 0; + + if( uiOffset >= m_uiValBufSize) + { + if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) + { + goto Exit; + } + } + } + } + else + { + if( pElement->m_pCachedNode->getDataType() != XFLM_NODATA_TYPE) + { + if( m_uiFlags & FLM_XML_COMPRESS_WHITESPACE_FLAG) + { + if( isWhitespace( uChar)) + { + // If uiOffset is zero, this is still leading + // white space, and we should ignore it. + // Otherwise, we need to keep track of where + // whitespace began. + + if( !uiOffset) + { + uChar = 0; + } + else + { + uiWhitespaceStartOffset = uiOffset; + } + } + else + { + + // Last character is not whitespace. + + uiWhitespaceStartOffset = 0; + } + } + + if( uChar) + { + *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar; + uiOffset += sizeof( FLMUNICODE); + if( uiOffset >= m_uiValBufSize) + { + if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) + { + goto Exit; + } + } + } + } + } + } + + flmAssert( !uiOffset); + + + uiSavedOffset = m_uiCurrLineOffset; + if( RC_BAD( rc = getQualifiedName( &uiChars, + &puzPrefix, &puzLocal, &bNamespaceDecl, NULL))) + { + goto Exit; + } + + // Validate that the end tag matches the start tag + + if( pElement) + { + + // Element names cannot be "xmlns" or begin with "xmlns:" + + if (bNamespaceDecl) + { + setErrInfo( m_uiCurrLineNum, + uiSavedOffset, + XML_ERR_XMLNS_IN_ELEMENT_NAME, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + if( puzPrefix) + { + FLMUINT uiPrefixId1; + FLMUINT uiPrefixId2; + + if( RC_BAD( rc = m_pDb->m_pDict->getPrefixId( + m_pDb, puzPrefix, &uiPrefixId1))) + { + goto Exit; + } + + if( RC_BAD( rc = pElement->getPrefixId( m_pDb, &uiPrefixId2))) + { + goto Exit; + } + + if( uiPrefixId1 != uiPrefixId2) + { + setErrInfo( m_uiCurrLineNum, + uiSavedOffset, + XML_ERR_ELEMENT_NAME_MISMATCH, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + } + else + { + if( RC_BAD( rc = pElement->getPrefixId( m_pDb, &uiTmp))) + { + goto Exit; + } + + if( uiTmp) + { + setErrInfo( m_uiCurrLineNum, + uiSavedOffset, + XML_ERR_ELEMENT_NAME_MISMATCH, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + } + + if( RC_BAD( rc = findNamespace( puzPrefix, &pNamespace))) + { + if( rc == NE_XFLM_NOT_FOUND) + { + setErrInfo( m_uiCurrLineNum, + uiSavedOffset, + XML_ERR_PREFIX_NOT_DEFINED, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + } + goto Exit; + } + + if( RC_BAD( rc = m_pDb->getElementNameId( + pNamespace->getURIPtr(), puzLocal, &uiTmp))) + { + if( rc == NE_XFLM_NOT_FOUND) + { + setErrInfo( m_uiCurrLineNum, + uiSavedOffset, + XML_ERR_ELEMENT_NAME_MISMATCH, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + } + goto Exit; + } + + if( pElement->getNameId() != uiTmp) + { + setErrInfo( m_uiCurrLineNum, + uiSavedOffset, + XML_ERR_ELEMENT_NAME_MISMATCH, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + } + + // Skip any whitespace after the name + + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + // Get the ending ">" + + if( getChar() != FLM_UNICODE_GT) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_GT, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + +Exit: + + if( pNamespace) + { + pNamespace->Release(); + } + + popNamespaces( getNamespaceCount() - uiStartNSCount); + + if( pElement) + { + pElement->Release(); + } + + return( rc); +} + +/**************************************************************************** +Desc: Processes an XML STag +****************************************************************************/ +RCODE F_XMLImport::processSTag( + F_DOMNode * pNodeToLinkTo, + eNodeInsertLoc eInsertLoc, + FLMBOOL * pbHasContent, + F_DOMNode ** ppElement) +{ + FLMUNICODE uChar; + FLMUINT uiChars; + F_DOMNode * pElement = NULL; + F_XMLNamespace * pNamespace = NULL; + FLMUNICODE * puzTmpPrefix; + FLMUNICODE * puzPrefix = NULL; + FLMUNICODE * puzTmpLocal; + FLMUNICODE * puzLocal = NULL; + FLMUINT uiNameId; + FLMUINT uiAllocSize; + void * pvMark = m_tmpPool.poolMark(); + RCODE rc = NE_XFLM_OK; + FLMBOOL bNamespaceDecl; + FLMUINT uiSavedLineNum; + FLMUINT uiSavedOffset; + FLMUINT uiSavedFilePos; + FLMUINT uiSavedLineBytes; + + *pbHasContent = FALSE; + + if( getChar() != FLM_UNICODE_LT) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_ELEMENT_LT, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + uiSavedLineNum = m_uiCurrLineNum; + uiSavedOffset = m_uiCurrLineOffset; + uiSavedFilePos = m_uiCurrLineFilePos; + uiSavedLineBytes = m_uiCurrLineBytes; + if( RC_BAD( rc = getQualifiedName( &uiChars, &puzTmpPrefix, &puzTmpLocal, + &bNamespaceDecl, NULL))) + { + goto Exit; + } + + // Element names cannot be "xmlns" or begin with "xmlns:" + + if (bNamespaceDecl) + { + setErrInfo( uiSavedLineNum, + uiSavedOffset, + XML_ERR_XMLNS_IN_ELEMENT_NAME, + uiSavedFilePos, + uiSavedLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + uiAllocSize = (f_unilen( puzTmpLocal) + 1) * sizeof( FLMUNICODE); + if( RC_BAD( rc = m_tmpPool.poolAlloc( uiAllocSize, (void **)&puzLocal))) + { + goto Exit; + } + f_unicpy( puzLocal, puzTmpLocal); + + if( puzTmpPrefix) + { + + // Need to save the prefix, because as parsing + // continues, the scratch buffer will be overwritten + + uiAllocSize = (f_unilen( puzTmpPrefix) + 1) * sizeof( FLMUNICODE); + if( RC_BAD( rc = m_tmpPool.poolAlloc( uiAllocSize, (void **)&puzPrefix))) + { + goto Exit; + } + f_unicpy( puzPrefix, puzTmpPrefix); + } + + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + // Read the attributes + + resetAttrList(); + + uChar = peekChar(); + if( uChar != FLM_UNICODE_GT && uChar != FLM_UNICODE_FSLASH) + { + if( RC_BAD( rc = processAttributeList())) + { + goto Exit; + } + } + + // Find or create the element's name ID + + if( RC_BAD( rc = findNamespace( puzPrefix, &pNamespace))) + { + if( rc == NE_XFLM_NOT_FOUND) + { + setErrInfo( uiSavedLineNum, + uiSavedOffset, + XML_ERR_PREFIX_NOT_DEFINED, + uiSavedFilePos, + uiSavedLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + } + goto Exit; + } + + if( RC_BAD( rc = m_pDb->getElementNameId( + pNamespace->getURIPtr(), puzLocal, &uiNameId))) + { + if( rc != NE_XFLM_NOT_FOUND) + { + goto Exit; + } + + if( !(m_uiFlags & FLM_XML_EXTEND_DICT_FLAG) || + (pNamespace->getURIPtr() && + f_unicmp( pNamespace->getURIPtr(), gv_uzXFLAIMNamespace) == 0)) + { + rc = RC_SET( NE_XFLM_UNDEFINED_ELEMENT_NAME); + goto Exit; + } + + // Automatically extend the schema + + uiNameId = 0; + if( RC_BAD( rc = m_pDb->createElementDef( + pNamespace->getURIPtr(), + puzLocal, XFLM_TEXT_TYPE, &uiNameId))) + { + goto Exit; + } + } + + // Create the element node + + if( pNodeToLinkTo) + { + if( RC_BAD( rc = pNodeToLinkTo->createNode( m_pDb, ELEMENT_NODE, + uiNameId, eInsertLoc, (IF_DOMNode **)&pElement))) + { + setErrInfo( uiSavedLineNum, + uiSavedOffset, + XML_ERR_CREATING_ELEMENT_NODE, + uiSavedFilePos, + uiSavedLineBytes); + goto Exit; + } + } + else + { + if( RC_BAD( rc = m_pDb->createRootElement( m_uiCollection, + uiNameId, (IF_DOMNode **)&pElement))) + { + setErrInfo( uiSavedLineNum, + uiSavedOffset, + XML_ERR_CREATING_ROOT_ELEMENT, + uiSavedFilePos, + uiSavedLineBytes); + goto Exit; + } + } + + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + // Need to end with ">" or "/>" + + uChar = getChar(); + if( uChar == FLM_UNICODE_GT) + { + *pbHasContent = TRUE; + } + else if( uChar == FLM_UNICODE_FSLASH) + { + if( getChar() != FLM_UNICODE_GT) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_GT, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + } + else + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_GT, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + // Set the element's prefix + + if( RC_BAD( rc = addAttributesToElement( pElement))) + { + goto Exit; + } + + if( puzPrefix) + { + if( RC_BAD( rc = pElement->setPrefix( m_pDb, puzPrefix))) + { + goto Exit; + } + } + + if( ppElement) + { + *ppElement = pElement; + pElement = NULL; + } + + m_importStats.uiElements++; + if( m_fnStatus && (m_importStats.uiElements % 50) == 0) + { + m_fnStatus( XML_STATS, + (void *)&m_importStats, NULL, NULL, m_pvCallbackData); + } + +Exit: + + if( pElement) + { + pElement->Release(); + } + + if( pNamespace) + { + pNamespace->Release(); + } + + m_tmpPool.poolReset( pvMark); + return( rc); +} + +/**************************************************************************** +Desc: Processes an element's attributes +****************************************************************************/ +RCODE F_XMLImport::processAttributeList( void) +{ + RCODE rc = NE_XFLM_OK; + FLMUINT uiChars; + FLMUNICODE * puzLocal; + FLMUNICODE * puzPrefix; + XML_ATTR * pAttr = NULL; + FLMBOOL bFoundDefaultNamespace = FALSE; + FLMUINT uiNamespaceCount = 0; + FLMBOOL bNamespaceDecl; + FLMBOOL bDefaultNamespaceDecl; + FLMUINT uiSavedLineNum; + FLMUINT uiSavedOffset; + FLMUINT uiSavedFilePos; + FLMUINT uiSavedLineBytes; + + for( ;;) + { + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + if( !isNameChar( peekChar())) + { + break; + } + + uiSavedLineNum = m_uiCurrLineNum; + uiSavedOffset = m_uiCurrLineOffset; + uiSavedFilePos = m_uiCurrLineFilePos; + uiSavedLineBytes = m_uiCurrLineBytes; + if( RC_BAD( rc = getQualifiedName( &uiChars, + &puzPrefix, &puzLocal, &bNamespaceDecl, + &bDefaultNamespaceDecl))) + { + goto Exit; + } + + if( RC_BAD( rc = allocAttribute( &pAttr))) + { + goto Exit; + } + pAttr->uiLineNum = uiSavedLineNum; + pAttr->uiLineOffset = uiSavedOffset; + pAttr->uiLineFilePos = uiSavedFilePos; + pAttr->uiLineBytes = uiSavedLineBytes; + + if( RC_BAD( rc = setPrefix( pAttr, puzPrefix))) + { + goto Exit; + } + + if( RC_BAD( rc = setLocalName( pAttr, puzLocal))) + { + goto Exit; + } + if (bNamespaceDecl) + { + if (bDefaultNamespaceDecl) + { + pAttr->uiFlags |= F_DEFAULT_NS_DECL; + } + else + { + pAttr->uiFlags |= F_PREFIXED_NS_DECL; + } + } + + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + // Attribute name must be followed by an "=" + + if( getChar() != FLM_UNICODE_EQ) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_EQ, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + pAttr->uiValueLineNum = m_uiCurrLineNum; + pAttr->uiValueLineOffset = m_uiCurrLineOffset; + if( RC_BAD( rc = processAttValue( pAttr))) + { + goto Exit; + } + + m_importStats.uiAttributes++; + if( m_fnStatus && (m_importStats.uiAttributes % 50) == 0) + { + m_fnStatus( XML_STATS, + (void *)&m_importStats, NULL, NULL, m_pvCallbackData); + } + } + + // Push any namespace declarations onto the stack + + for( pAttr = m_pFirstAttr; pAttr; pAttr = pAttr->pNext) + { + // Duplicate namespace declarations are not allowed within a single element. + // So, multiple default namespace declarations or multiple uses of the same + // prefix in will result in a syntax error. + + if( pAttr->uiFlags & F_DEFAULT_NS_DECL) + { + // Default namespace declaration + + if( bFoundDefaultNamespace) + { + setErrInfo( pAttr->uiLineNum, + pAttr->uiLineOffset, + XML_ERR_MULTIPLE_XMLNS_DECLS, + pAttr->uiLineFilePos, + pAttr->uiLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + if( !pAttr->puzVal || *pAttr->puzVal == 0) + { + // No namespace + + if( RC_BAD( rc = pushNamespace( NULL, NULL))) + { + goto Exit; + } + } + else + { + if( RC_BAD( rc = pushNamespace( NULL, pAttr->puzVal))) + { + goto Exit; + } + } + + uiNamespaceCount++; + bFoundDefaultNamespace = TRUE; + } + else if( pAttr->uiFlags & F_PREFIXED_NS_DECL) + { + // Check for a unique prefix within current element + + if( RC_OK( rc = findNamespace( &pAttr->puzLocalName [6], + NULL, uiNamespaceCount))) + { + setErrInfo( pAttr->uiLineNum, + pAttr->uiLineOffset, + XML_ERR_MULTIPLE_PREFIX_DECLS, + pAttr->uiLineFilePos, + pAttr->uiLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + else if( rc != NE_XFLM_NOT_FOUND) + { + goto Exit; + } + else + { + rc = NE_XFLM_OK; + } + + if( RC_BAD( rc = pushNamespace( + &pAttr->puzLocalName [6], pAttr->puzVal))) + { + goto Exit; + } + + uiNamespaceCount++; + } + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Processes an XML declaration +****************************************************************************/ +RCODE F_XMLImport::processXMLDecl( void) +{ + RCODE rc = NE_XFLM_OK; + FLMUNICODE uChar; + + // Have already eaten the "")) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset, + XML_ERR_EXPECTING_QUEST_GT, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Processes an XML document type declaration +****************************************************************************/ +RCODE F_XMLImport::processDocTypeDecl( void) +{ + RCODE rc = NE_XFLM_OK; + FLMUNICODE uChar; + + // Have already eaten the "' + + if( RC_BAD( rc = skipWhitespace( TRUE))) + { + goto Exit; + } + } + + // Get the system ID + + if (RC_BAD( rc = getSystemLiteral())) + { + goto Exit; + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Processes a notation declaration +****************************************************************************/ +RCODE F_XMLImport::processNotationDecl( void) +{ + RCODE rc = NE_XFLM_OK; + + // Have already eaten up the "#PCDATA" + + for( ;;) + { + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + uChar = getChar(); + if( uChar == FLM_UNICODE_RPAREN) + { + break; + } + else if( uChar == FLM_UNICODE_PIPE) + { + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + if( RC_BAD( rc = getName( NULL))) + { + goto Exit; + } + + bExpectingAsterisk = TRUE; + } + else + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_RPAREN_OR_PIPE, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + } + + if( bExpectingAsterisk) + { + if( getChar() != FLM_UNICODE_ASTERISK) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_ASTERISK, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Processes child content +****************************************************************************/ +RCODE F_XMLImport::processChildContent( void) +{ + FLMUNICODE uChar; + FLMUINT uiItemCount = 0; + FLMUINT uiDelimCount = 0; + FLMBOOL bChoice = FALSE; + FLMBOOL bSeq = FALSE; + RCODE rc = NE_XFLM_OK; + + // Have eaten up the "(" + + for( ;;) + { + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + uChar = getChar(); + if( uChar == FLM_UNICODE_LPAREN) + { + if( RC_BAD( rc = processChildContent())) + { + goto Exit; + } + + uiItemCount++; + } + else if (uChar == FLM_UNICODE_RPAREN) + { + if( !uiItemCount || (uiItemCount - 1) != uiDelimCount) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EMPTY_CONTENT_INVALID, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + break; + } + else if (uChar == FLM_UNICODE_PIPE) + { + if( bSeq) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_CANNOT_MIX_CHOICE_AND_SEQ, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + bChoice = TRUE; + uiDelimCount++; + } + else if (uChar == FLM_UNICODE_COMMA) + { + if (bChoice) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_CANNOT_MIX_CHOICE_AND_SEQ, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + bSeq = TRUE; + uiDelimCount++; + } + else + { + ungetChar(); + if( RC_BAD( rc = getName( NULL))) + { + goto Exit; + } + uiItemCount++; + + uChar = peekChar(); + if (uChar == FLM_UNICODE_QUEST || + uChar == FLM_UNICODE_ASTERISK || + uChar == FLM_UNICODE_PLUS) + { + + // Eat up a "?", "*", or "+" + + (void)getChar(); + } + } + } + + uChar = peekChar(); + if( uChar == FLM_UNICODE_QUEST || + uChar == FLM_UNICODE_ASTERISK || + uChar == FLM_UNICODE_PLUS) + { + // Eat up a "?", "*", or "+" + + (void)getChar(); + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Processes a misc. declaration +****************************************************************************/ +RCODE F_XMLImport::processMisc( void) +{ + RCODE rc = NE_XFLM_OK; + + for( ;;) + { + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + if( rc == NE_XFLM_IO_END_OF_FILE || rc == NE_XFLM_EOF_HIT) + { + rc = NE_XFLM_OK; + } + goto Exit; + } + + if (lineHasToken( "")) + { + break; + } + + if ((uChar = getChar()) == 0) + { + if (RC_BAD( rc = getLine())) + { + goto Exit; + } + uChar = ASCII_NEWLINE; + } + + *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar; + uiOffset += sizeof( FLMUNICODE); + + if( uiOffset >= uiMaxOffset) + { + if (RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) + { + goto Exit; + } + uiMaxOffset = m_uiValBufSize; + } + } + + if( pParent) + { + if( RC_BAD( rc = pParent->createNode( m_pDb, COMMENT_NODE, 0, + XFLM_LAST_CHILD, (IF_DOMNode **)&pComment))) + { + setErrInfo( uiSavedLineNum, + uiSavedOffset, + XML_ERR_CREATING_COMMENT_NODE, + uiSavedFilePos, + uiSavedLineBytes); + goto Exit; + } + + *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = 0; + + if( RC_BAD( rc = pComment->setUnicode( + m_pDb, (FLMUNICODE *)m_pucValBuf))) + { + goto Exit; + } + + pComment->Release(); + pComment = NULL; + } + +Exit: + + if( pComment) + { + pComment->Release(); + } + + return( rc); +} + +/**************************************************************************** +Desc: Processes a CDATA tag +****************************************************************************/ +RCODE F_XMLImport::processCDATA( + F_DOMNode * pParent, + FLMUINT uiSavedLineNum, + FLMUINT uiSavedOffset, + FLMUINT uiSavedFilePos, + FLMUINT uiSavedLineBytes) +{ + FLMUNICODE uChar; + FLMUINT uiOffset = 0; + F_DOMNode * pCData = NULL; + RCODE rc = NE_XFLM_OK; + + // Have already eaten up the "")) + { + break; + } + if ((uChar = getChar()) == 0) + { + if (RC_BAD( rc = getLine())) + { + goto Exit; + } + uChar = ASCII_NEWLINE; + } + + *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = uChar; + uiOffset += sizeof( FLMUNICODE); + + if( uiOffset >= m_uiValBufSize) + { + if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) + { + goto Exit; + } + } + } + + if( pParent) + { + if( RC_BAD( rc = pParent->createNode( m_pDb, CDATA_SECTION_NODE, 0, + XFLM_LAST_CHILD, (IF_DOMNode **)&pCData))) + { + setErrInfo( uiSavedLineNum, + uiSavedOffset, + XML_ERR_CREATING_CDATA_NODE, + uiSavedFilePos, + uiSavedLineBytes); + goto Exit; + } + + *((FLMUNICODE *)(&m_pucValBuf[ uiOffset])) = 0; + if( RC_BAD( rc = pCData->setUnicode( m_pDb, (FLMUNICODE *)m_pucValBuf))) + { + goto Exit; + } + + pCData->Release(); + pCData = NULL; + } + +Exit: + + if( pCData) + { + pCData->Release(); + } + + return( rc); +} + +/**************************************************************************** +Desc: Skips any whitespace characters in the input stream +****************************************************************************/ +RCODE F_XMLImport::skipWhitespace( + FLMBOOL bRequired) +{ + FLMUNICODE uChar; + FLMUINT uiCount = 0; + RCODE rc = NE_XFLM_OK; + + for( ;;) + { + if ((uChar = getChar()) == 0) + { + uiCount++; + if (RC_BAD( rc = getLine())) + { + goto Exit; + } + continue; + } + + if( !isWhitespace( uChar)) + { + ungetChar(); + break; + } + uiCount++; + } + + if( !uiCount && bRequired) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset, + XML_ERR_EXPECTING_WHITESPACE, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: +******************************************************************************/ +RCODE F_XMLImport::resizeValBuffer( + FLMUINT uiSize) +{ + RCODE rc = NE_XFLM_OK; + + if( uiSize == m_uiValBufSize) + { + goto Exit; + } + + if( uiSize == ~((FLMUINT)0)) + { + uiSize = m_uiValBufSize + 2048; + } + + if( m_pucValBuf) + { + if( uiSize) + { + if( RC_BAD( rc = f_realloc( uiSize, &m_pucValBuf))) + { + goto Exit; + } + } + else + { + f_free( &m_pucValBuf); + m_pucValBuf = NULL; + } + } + else + { + flmAssert( !m_pucValBuf); + + if( RC_BAD( rc = f_alloc( uiSize, &m_pucValBuf))) + { + goto Exit; + } + } + + m_uiValBufSize = uiSize; + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: +******************************************************************************/ +RCODE F_XMLImport::getBinaryVal( + FLMUINT * puiLength) +{ + RCODE rc = NE_XFLM_OK; + FLMUNICODE uChar; + FLMUNICODE uChar2; + FLMUINT uiOffset = 0; + FLMBOOL bHavePreamble; + + flmAssert( *puiLength == 0); + + for( ;;) + { + bHavePreamble = FALSE; + + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + +Retry: + + uChar = getChar(); + if( !f_isHexChar( uChar)) + { + if( uChar != FLM_UNICODE_LT) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_HEX_DIGIT, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + ungetChar(); + break; + } + + uChar2 = getChar(); + if( uChar == FLM_UNICODE_0 && + (uChar2 == FLM_UNICODE_X || uChar2 == FLM_UNICODE_x)) + { + if( bHavePreamble) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_HEX_DIGIT, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + bHavePreamble = TRUE; + goto Retry; + } + + if( !f_isHexChar( uChar2)) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + XML_ERR_EXPECTING_HEX_DIGIT, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + if( uiOffset >= m_uiValBufSize) + { + if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) + { + goto Exit; + } + } + + m_pucValBuf[ uiOffset++] = + (f_getHexVal( uChar) << 4) | f_getHexVal( uChar2); + + if( RC_BAD( rc = skipWhitespace( FALSE))) + { + goto Exit; + } + + uChar = getChar(); + if( uChar != FLM_UNICODE_COMMA) + { + ungetChar(); + } + } + + *puiLength = uiOffset; + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Constructor +****************************************************************************/ +F_XMLNamespaceMgr::F_XMLNamespaceMgr() +{ + m_pFirstNamespace = NULL; + m_uiNamespaceCount = 0; +} + +/**************************************************************************** +Desc: Destructor +****************************************************************************/ +F_XMLNamespaceMgr::~F_XMLNamespaceMgr() +{ + popNamespaces( m_uiNamespaceCount); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_XMLNamespaceMgr::popNamespaces( + FLMUINT uiCount) +{ + F_XMLNamespace * pTmpNamespace; + + flmAssert( uiCount <= m_uiNamespaceCount); + + while( uiCount && m_pFirstNamespace) + { + pTmpNamespace = m_pFirstNamespace; + m_pFirstNamespace = m_pFirstNamespace->m_pNext; + pTmpNamespace->m_pNext = NULL; + pTmpNamespace->Release(); + m_uiNamespaceCount--; + uiCount--; + } +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_XMLNamespaceMgr::findNamespace( + FLMUNICODE * puzPrefix, + F_XMLNamespace ** ppNamespace, + FLMUINT uiMaxSearchSize) +{ + F_XMLNamespace * pTmpNamespace = m_pFirstNamespace; + RCODE rc = NE_XFLM_OK; + + while( pTmpNamespace) + { + if( !uiMaxSearchSize) + { + pTmpNamespace = NULL; + break; + } + + if( !puzPrefix && !pTmpNamespace->m_puzPrefix) + { + break; + } + else if( puzPrefix && pTmpNamespace->m_puzPrefix) + { + if( f_unicmp( puzPrefix, pTmpNamespace->m_puzPrefix) == 0) + { + break; + } + } + + pTmpNamespace = pTmpNamespace->m_pNext; + uiMaxSearchSize--; + } + + if( !pTmpNamespace) + { + rc = RC_SET( NE_XFLM_NOT_FOUND); + goto Exit; + } + + if( ppNamespace) + { + if( *ppNamespace) + { + (*ppNamespace)->Release(); + } + + pTmpNamespace->AddRef(); + *ppNamespace = pTmpNamespace; + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_XMLNamespaceMgr::pushNamespace( + FLMUNICODE * puzPrefix, + FLMUNICODE * puzNamespaceURI) +{ + F_XMLNamespace * pNewNamespace = NULL; + RCODE rc = NE_XFLM_OK; + + if( (pNewNamespace = f_new F_XMLNamespace) == NULL) + { + rc = RC_SET( NE_XFLM_MEM); + goto Exit; + } + + if( RC_BAD( rc = pNewNamespace->setPrefix( puzPrefix))) + { + goto Exit; + } + + if( RC_BAD( rc = pNewNamespace->setURI( puzNamespaceURI))) + { + goto Exit; + } + + pNewNamespace->m_pNext = m_pFirstNamespace; + m_pFirstNamespace = pNewNamespace; + pNewNamespace = NULL; + m_uiNamespaceCount++; + +Exit: + + if( pNewNamespace) + { + pNewNamespace->Release(); + } + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_XMLNamespaceMgr::pushNamespace( + F_XMLNamespace * pNamespace) +{ + flmAssert( m_pFirstNamespace != pNamespace && + !pNamespace->m_pNext); + + pNamespace->AddRef(); + pNamespace->m_pNext = m_pFirstNamespace; + m_pFirstNamespace = pNamespace; + m_uiNamespaceCount++; + + return( NE_XFLM_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_XMLNamespace::setPrefix( + FLMUNICODE * puzPrefix) +{ + FLMUINT uiLen; + RCODE rc = NE_XFLM_OK; + + if( m_puzPrefix) + { + f_free( &m_puzPrefix); + } + + if( puzPrefix) + { + uiLen = f_unilen( puzPrefix); + if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE) * (uiLen + 1), + &m_puzPrefix))) + { + goto Exit; + } + + f_unicpy( m_puzPrefix, puzPrefix); + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_XMLNamespace::setURI( + FLMUNICODE * puzURI) +{ + FLMUINT uiLen; + RCODE rc = NE_XFLM_OK; + + if( m_puzURI) + { + f_free( &m_puzURI); + } + + if( puzURI) + { + uiLen = f_unilen( puzURI); + if( RC_BAD( rc = f_alloc( + sizeof( FLMUNICODE) * (uiLen + 1), &m_puzURI))) + { + goto Exit; + } + + f_unicpy( m_puzURI, puzURI); + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_XMLNamespace::setup( + FLMUNICODE * puzPrefix, + FLMUNICODE * puzURI, + F_XMLNamespace * pNext) +{ + FLMUINT uiLen; + RCODE rc = NE_XFLM_OK; + + flmAssert( !m_puzPrefix); + flmAssert( !m_puzURI); + flmAssert( !m_pNext); + + if( puzPrefix) + { + uiLen = f_unilen( puzPrefix); + if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE) * (uiLen + 1), + &m_puzPrefix))) + { + goto Exit; + } + + f_unicpy( m_puzPrefix, puzPrefix); + } + + if( puzURI) + { + uiLen = f_unilen( puzURI); + if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE) * (uiLen + 1), + &m_puzURI))) + { + goto Exit; + } + + f_unicpy( m_puzURI, puzURI); + } + + m_pNext = pNext; + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_XMLImport::addAttributesToElement( + F_DOMNode * pElement) +{ + RCODE rc = NE_XFLM_OK; + XML_ATTR * pAttr; + F_XMLNamespace * pNamespace = NULL; + F_DOMNode * pTmpNode = NULL; + FLMUINT uiNameId; + FLMUINT uiAttrDataType; + + // Make sure any prefixes (e.g., xmlns:xxxx) are added to the database + // before they are used - in case they are used by the attributes + // themselves. + + for( pAttr = m_pFirstAttr; pAttr; pAttr = pAttr->pNext) + { + if( pAttr->uiFlags & F_PREFIXED_NS_DECL) + { + FLMUINT uiPrefixId; + + // Create the prefix (stored in &puzLocalName [6]) if it doesn't + // already exist + + if( RC_BAD( rc = m_pDb->m_pDict->getPrefixId( m_pDb, + &pAttr->puzLocalName [6], &uiPrefixId))) + { + if( rc != NE_XFLM_NOT_FOUND) + { + goto Exit; + } + + uiPrefixId = 0; + if( RC_BAD( rc = m_pDb->createPrefixDef( TRUE, + &pAttr->puzLocalName [6], &uiPrefixId))) + { + goto Exit; + } + } + } + } + + // Add the attributes to the element + // + // NOTE: The XML namespace specification states that the names + // of all unqualified attributes are assigned to the + // appropriate per-element-type partition. This means that + // the combination of the attribute name with the parent + // element's type and namespace name is used to uniquely + // identify each unqualified attribute. + // + // For sake of clarity and useability, however, the parser + // deviates from the namespace specification. Each unprefixed + // attribute encountered by the parser will inherit the + // namespace of the parent element, even if the namespace + // is a default namespace. + + for( pAttr = m_pFirstAttr; pAttr; pAttr = pAttr->pNext) + { + if( pAttr->uiFlags & F_DEFAULT_NS_DECL) + { + // Add the namespace declaration to the element + + if( RC_BAD( rc = pElement->createAttribute( m_pDb, ATTR_XMLNS_TAG, + (IF_DOMNode **)&pTmpNode))) + { + goto Exit; + } + + if( RC_BAD( rc = pTmpNode->setUnicode( m_pDb, pAttr->puzVal))) + { + goto Exit; + } + + if( RC_BAD( rc = pTmpNode->addModeFlags( m_pDb, FDOM_READ_ONLY))) + { + goto Exit; + } + } + else if( pAttr->uiFlags & F_PREFIXED_NS_DECL) + { + // Find the attribute definition + + if( RC_BAD( rc = m_pDb->getAttributeNameId( + NULL, pAttr->puzLocalName, &uiNameId))) + { + if( rc != NE_XFLM_NOT_FOUND) + { + goto Exit; + } + + if( !(m_uiFlags & FLM_XML_EXTEND_DICT_FLAG)) + { + rc = RC_SET( NE_XFLM_UNDEFINED_ATTRIBUTE_NAME); + goto Exit; + } + + uiNameId = 0; + if( RC_BAD( rc = m_pDb->createAttributeDef( + NULL, pAttr->puzLocalName, XFLM_TEXT_TYPE, &uiNameId, + (IF_DOMNode **)&pTmpNode))) + { + goto Exit; + } + } + + // Add the namespace declaration to the element + + if( RC_BAD( rc = pElement->createAttribute( m_pDb, uiNameId, + (IF_DOMNode **)&pTmpNode))) + { + goto Exit; + } + + if( RC_BAD( rc = pTmpNode->setUnicode( m_pDb, pAttr->puzVal))) + { + goto Exit; + } + + if( RC_BAD( rc = pTmpNode->addModeFlags( m_pDb, FDOM_READ_ONLY))) + { + goto Exit; + } + } + else + { + if( pAttr->puzPrefix) + { + if( RC_BAD( rc = findNamespace( pAttr->puzPrefix, &pNamespace))) + { + if( rc == NE_XFLM_NOT_FOUND) + { + setErrInfo( pAttr->uiLineNum, pAttr->uiLineOffset, + XML_ERR_PREFIX_NOT_DEFINED, pAttr->uiLineFilePos, + pAttr->uiLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + } + + goto Exit; + } + } + else + { + if( pNamespace) + { + pNamespace->Release(); + } + pNamespace = NULL; + } + + if( RC_BAD( rc = m_pDb->getAttributeNameId( + pNamespace ? pNamespace->getURIPtr() : NULL, + pAttr->puzLocalName, &uiNameId))) + { + if( rc != NE_XFLM_NOT_FOUND) + { + goto Exit; + } + + if( !(m_uiFlags & FLM_XML_EXTEND_DICT_FLAG) || + (pNamespace && + f_unicmp( pNamespace->getURIPtr(), gv_uzXFLAIMNamespace) == 0)) + { + rc = RC_SET( NE_XFLM_UNDEFINED_ATTRIBUTE_NAME); + goto Exit; + } + + uiNameId = 0; + if( RC_BAD( rc = m_pDb->createAttributeDef( + pNamespace ? pNamespace->getURIPtr() : NULL, + pAttr->puzLocalName, XFLM_TEXT_TYPE, &uiNameId))) + { + goto Exit; + } + } + + if( RC_BAD( rc = pElement->createAttribute( m_pDb, uiNameId, + (IF_DOMNode **)&pTmpNode))) + { + goto Exit; + } + + if (pAttr->puzPrefix) + { + if( RC_BAD( rc = pTmpNode->setPrefix( m_pDb, pAttr->puzPrefix))) + { + if( rc == NE_XFLM_NOT_FOUND) + { + setErrInfo( pAttr->uiLineNum, + pAttr->uiLineOffset, + XML_ERR_PREFIX_NOT_DEFINED, + pAttr->uiLineFilePos, + pAttr->uiLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + } + goto Exit; + } + } + + if( RC_BAD( rc = pTmpNode->getDataType( m_pDb, &uiAttrDataType))) + { + goto Exit; + } + + switch( uiAttrDataType) + { + case XFLM_TEXT_TYPE: + { + if( RC_BAD( rc = pTmpNode->setUnicode( + m_pDb, pAttr->puzVal))) + { + goto Exit; + } + break; + } + + case XFLM_NUMBER_TYPE: + { + FLMUINT64 ui64Val; + FLMBOOL bNeg; + + if( RC_BAD( rc = unicodeToNumber64( + pAttr->puzVal, &ui64Val, &bNeg))) + { + goto Exit; + } + + if( !bNeg) + { + if( RC_BAD( rc = pTmpNode->setUINT64( m_pDb, ui64Val))) + { + goto Exit; + } + } + else + { + if( RC_BAD( rc = pTmpNode->setINT64( m_pDb, -((FLMINT64)ui64Val)))) + { + goto Exit; + } + } + + break; + } + + case XFLM_BINARY_TYPE: + { + FLMBOOL bHavePreamble; + FLMUNICODE * puzStr = pAttr->puzVal; + FLMUINT uiOffset = 0; + + // Convert the Unicode value to binary + + while( puzStr && *puzStr) + { + bHavePreamble = FALSE; + + while( gv_XFlmSysData.pXml->isWhitespace( *puzStr)) + { + puzStr++; + } + + Retry: + + if( !f_isHexChar( *puzStr)) + { + break; + } + + if( *puzStr == FLM_UNICODE_0 && + (puzStr[ 1] == FLM_UNICODE_X || puzStr[ 1] == FLM_UNICODE_x)) + { + if( bHavePreamble) + { + setErrInfo( pAttr->uiValueLineNum, + pAttr->uiValueLineOffset, + XML_ERR_INVALID_BINARY_ATTR_VALUE, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + bHavePreamble = TRUE; + puzStr += 2; + goto Retry; + } + + if( !f_isHexChar( puzStr[ 1])) + { + setErrInfo( pAttr->uiValueLineNum, + pAttr->uiValueLineOffset, + XML_ERR_INVALID_BINARY_ATTR_VALUE, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_XFLM_INVALID_XML); + goto Exit; + } + + if( uiOffset >= m_uiValBufSize) + { + if( RC_BAD( rc = resizeValBuffer( ~((FLMUINT)0)))) + { + goto Exit; + } + } + + m_pucValBuf[ uiOffset++] = + (f_getHexVal( *puzStr) << 4) | f_getHexVal( puzStr[ 1]); + + puzStr += 2; + + while( gv_XFlmSysData.pXml->isWhitespace( *puzStr)) + { + puzStr++; + } + + if( *puzStr == FLM_UNICODE_COMMA) + { + puzStr++; + } + } + + if( RC_BAD( rc = pTmpNode->setBinary( + m_pDb, m_pucValBuf, uiOffset))) + { + goto Exit; + } + break; + } + + default: + { + rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED); + goto Exit; + } + } + } + } + +Exit: + + if( pTmpNode) + { + pTmpNode->Release(); + } + + if( pNamespace) + { + pNamespace->Release(); + } + + return( rc); +} + +// Some forward declarations + +class F_Element; +class F_Attribute; + +/***************************************************************************** +Desc: Keeps track of an attribute that we are going to output +*****************************************************************************/ +class F_Attribute : public XF_Base +{ +public: + F_Attribute( + F_Element * pElement) + { + m_uiTmpSpaceSize = sizeof( m_uzTmpSpace); + m_puzName = &m_uzTmpSpace [0]; + reset( pElement); + } + + ~F_Attribute(); + + FINLINE void reset( + F_Element * pElement) + { + m_uiNameChars = 0; + m_bIsNamespaceDecl = FALSE; + m_bDefaultNamespaceDecl = FALSE; + m_uiNamespaceChars = 0; + m_uiValueChars = 0; + m_uiPrefixChars = 0; + m_pElement = pElement; + } + + RCODE allocNameSpace( void); + + RCODE setupAttribute( + IF_Db * pDb, + IF_DOMNode * pNode); + + RCODE setPrefix( void); + + RCODE outputAttr( + IF_OStream * pOStream); + + FINLINE F_Attribute * getNext( void) + { + return( m_pNext); + } + +private: + FLMUNICODE m_uzTmpSpace [150]; + FLMUINT m_uiTmpSpaceSize; + FLMBOOL m_bIsNamespaceDecl; + FLMBOOL m_bDefaultNamespaceDecl; + FLMUNICODE * m_puzName; + FLMUINT m_uiNameChars; + FLMUNICODE * m_puzNamespace; + FLMUINT m_uiNamespaceChars; + FLMUNICODE * m_puzValue; + FLMUINT m_uiValueChars; + FLMUNICODE * m_puzPrefix; + FLMUINT m_uiPrefixChars; + F_Element * m_pElement; + F_Attribute * m_pNext; + +friend class F_Element; +}; + +/***************************************************************************** +Desc: Destructor for F_Attribute class. +*****************************************************************************/ +F_Attribute::~F_Attribute() +{ + if (m_puzName != &m_uzTmpSpace [0]) + { + f_free( &m_puzName); + } +} + +/***************************************************************************** +Desc: Keeps track of an element that we are going to output +*****************************************************************************/ +class F_Element : public XF_Base +{ +public: + F_Element( + F_Element * pParentElement, + F_Attribute ** ppAvailAttrs, + FLMUINT * puiNextPrefixNum) + { + m_uiTmpSpaceSize = sizeof( m_uzTmpSpace); + m_puzName = &m_uzTmpSpace [0]; + m_pFirstAttr = NULL; + m_pLastAttr = NULL; + m_pNext = NULL; + m_uiIndentCount = 0; + m_bIsDocumentRoot = FALSE; + reset( pParentElement, ppAvailAttrs, puiNextPrefixNum); + } + + ~F_Element() + { + F_Attribute * pAttr; + F_Attribute * pTmpAttr; + + // Delete all of the attributes + + pAttr = m_pFirstAttr; + while (pAttr) + { + pTmpAttr = pAttr; + pAttr = pAttr->m_pNext; + delete pTmpAttr; + } + + if (m_puzName != &m_uzTmpSpace [0]) + { + f_free( &m_puzName); + } + } + + FINLINE void reset( + F_Element * pParentElement, + F_Attribute ** ppAvailAttrs, + FLMUINT * puiNextPrefixNum) + { + m_uiNameChars = 0; + m_uiNamespaceChars = 0; + m_uiPrefixChars = 0; + m_pParentElement = pParentElement; + m_puiNextPrefixNum = puiNextPrefixNum; + m_ppAvailAttrs = ppAvailAttrs; + m_pNext = NULL; + m_uiIndentCount = 0; + m_bIsDocumentRoot = FALSE; + } + + FINLINE void setIndentCount( + FLMUINT uiIndentCount) + { + m_uiIndentCount = uiIndentCount; + } + + FINLINE void setDocumentRoot( + FLMBOOL bIsDocumentRoot) + { + m_bIsDocumentRoot = bIsDocumentRoot; + } + + RCODE allocAttr( + F_Attribute ** ppAttr); + + FINLINE void makeAttrAvail( + F_Attribute * pAttr) + { + pAttr->m_pNext = *m_ppAvailAttrs; + *m_ppAvailAttrs = pAttr; + } + + FINLINE void makeAllAttrsAvail( void) + { + if (m_pFirstAttr) + { + m_pLastAttr->m_pNext = *m_ppAvailAttrs; + *m_ppAvailAttrs = m_pFirstAttr; + m_pFirstAttr = NULL; + m_pLastAttr = NULL; + } + } + + RCODE saveAttribute( + IF_Db * pDb, + IF_DOMNode * pNode); + + RCODE allocNameSpace( void); + + RCODE setupElement( + IF_Db * pDb, + IF_DOMNode * pNode); + + RCODE addNamespaceDecl( + FLMUNICODE * puzPrefix, + FLMUINT uiPrefixChars, + FLMUNICODE * puzNamespace, + FLMUINT uiNamespaceChars, + F_Attribute ** ppAttr); + + void genPrefix( + FLMUNICODE * puzPrefix, + FLMUINT * puiPrefixChars); + + RCODE findPrefix( + FLMUNICODE * puzNamespace, + FLMUINT uiNamespaceChars, + FLMBOOL bForElement, + FLMUNICODE ** ppuzPrefix, + FLMUINT * puiPrefixChars); + + FINLINE RCODE setPrefix( void) + { + return( findPrefix( m_puzNamespace, m_uiNamespaceChars, TRUE, + &m_puzPrefix, &m_uiPrefixChars)); + } + + FINLINE F_Element * getParentElement( void) + { + return( m_pParentElement); + } + + RCODE outputElem( + IF_OStream * pOStream, + FLMBOOL bStartOfElement, + FLMBOOL bEndOfElement, + FLMBOOL bAddNewLine); + + RCODE outputLocalData( + IF_OStream * pOStream, + IF_DOMNode * pDbNode, + IF_Db * ifpDb, + eExportFormatType eFormatType, + FLMUINT uiIndentCount); + + FINLINE F_Element * getNext( void) + { + return( m_pNext); + } + + FINLINE void makeAvail( + F_Element ** ppAvailElements) + { + m_pNext = *ppAvailElements; + *ppAvailElements = this; + } + +private: + FLMUNICODE m_uzTmpSpace [100]; + FLMUINT m_uiTmpSpaceSize; + FLMUNICODE * m_puzName; + FLMUINT m_uiNameChars; + FLMUNICODE * m_puzNamespace; + FLMUINT m_uiNamespaceChars; + FLMUNICODE * m_puzPrefix; + FLMUINT m_uiPrefixChars; + F_Attribute * m_pFirstAttr; + F_Attribute * m_pLastAttr; + F_Element * m_pParentElement; + F_Element * m_pNext; + FLMUINT * m_puiNextPrefixNum; + F_Attribute ** m_ppAvailAttrs; + FLMBOOL m_bIsDocumentRoot; + FLMUINT m_uiIndentCount; + +friend class F_Attribute; +}; + +/***************************************************************************** +Desc: Allocate space to hold the name, namespace, and value for an attribute. +*****************************************************************************/ +RCODE F_Attribute::allocNameSpace( void) +{ + RCODE rc = NE_XFLM_OK; + FLMUINT uiSpaceNeeded; + FLMUNICODE * puzTmp; + + uiSpaceNeeded = (m_uiNameChars + + m_uiNamespaceChars + + m_uiValueChars + 3) * sizeof( FLMUNICODE); + if (uiSpaceNeeded > m_uiTmpSpaceSize) + { + if (RC_BAD( rc = f_alloc( uiSpaceNeeded, &puzTmp))) + { + goto Exit; + } + if (m_puzName != &m_uzTmpSpace [0]) + { + f_free( &m_puzName); + } + m_puzName = puzTmp; + m_uiTmpSpaceSize = uiSpaceNeeded; + } + m_puzNamespace = &m_puzName [m_uiNameChars + 1]; + m_puzValue = &m_puzNamespace [m_uiNamespaceChars + 1]; + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: Setup an attribute with its namespace, etc. +*****************************************************************************/ +RCODE F_Attribute::setupAttribute( + IF_Db * pDb, + IF_DOMNode * pNode + ) +{ + RCODE rc = NE_XFLM_OK; + + // Determine if the attribute is a namespace declaration + + if (RC_BAD( rc = pNode->isNamespaceDecl( pDb, &m_bIsNamespaceDecl))) + { + goto Exit; + } + + // Get the length of the name of the attribute + + if (RC_BAD( rc = pNode->getLocalName( pDb, (FLMUNICODE *)NULL, + 0, &m_uiNameChars))) + { + goto Exit; + } + + // If it is a namespace declaration, no need to get the namespace URI, + // we already know what it is, and we will output it with an xmlns prefix + // Otherwise, we need to get the namespace so we can determine a prefix, + // if any. If the namespace is the same namespace as the enclosing + // element, we do not need to output a prefix. + + if (!m_bIsNamespaceDecl) + { + + // Get the number of characters in the namespace of the attribute + + if (RC_BAD( rc = pNode->getNamespaceURI( pDb, (FLMUNICODE *)NULL, + 0, &m_uiNamespaceChars))) + { + goto Exit; + } + } + + // Get the number of characters in the attribute's value. + + if (RC_BAD( rc = pNode->getUnicodeChars( pDb, &m_uiValueChars))) + { + goto Exit; + } + + // Allocate space for the name, namespace, and value + + if (RC_BAD( rc = allocNameSpace())) + { + goto Exit; + } + + // Get the attribute name. + + if (RC_BAD( rc = pNode->getLocalName( pDb, m_puzName, + (m_uiNameChars + 1) * sizeof( FLMUNICODE), + &m_uiNameChars))) + { + goto Exit; + } + + // Get the namespace, if necessary + + if (m_uiNamespaceChars) + { + if (RC_BAD( rc = pNode->getNamespaceURI( pDb, m_puzNamespace, + (m_uiNamespaceChars + 1) * sizeof( FLMUNICODE), + &m_uiNamespaceChars))) + { + goto Exit; + } + } + + // Get the value, if any + + if (m_uiValueChars) + { + if (RC_BAD( rc = pNode->getUnicode( pDb, m_puzValue, + (m_uiValueChars + 1) * sizeof( FLMUNICODE), + 0, m_uiValueChars, &m_uiValueChars))) + { + goto Exit; + } + } + + // If it is a namespace declaration, the local name must either be + // "xmlns" or begin with "xmlns:" + + if (m_bIsNamespaceDecl) + { + + // Make sure name is "xmlns" or begins with "xmlns:" + + if (m_uiNameChars != 5 && m_uiNameChars <= 6) + { + rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_NAMESPACE_DECL); + goto Exit; + } + + if (!isXMLNS( m_puzName)) + { + rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_NAMESPACE_DECL); + goto Exit; + } + else if (m_uiNameChars == 5) + { + m_bDefaultNamespaceDecl = TRUE; + } + else if (m_puzName [5] != ':') + { + rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_NAMESPACE_DECL); + goto Exit; + } + } + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: Set the prefix for an attribute. +*****************************************************************************/ +RCODE F_Attribute::setPrefix( void) +{ + RCODE rc = NE_XFLM_OK; + + // If this is a namespace declaration, there should be no prefix in the name. + + if (m_bIsNamespaceDecl) + { + flmAssert( !m_uiPrefixChars); + } + + // Only need to set a prefix on an attribute if it has a namespace + // Otherwise, leave it alone - no prefix. + + else if (m_uiNamespaceChars) + { + + + // See if we can find a namespace declaration in either + // this element's attributes, or any of its parent element + // attributes. + + if (RC_BAD( rc = m_pElement->findPrefix( m_puzNamespace, + m_uiNamespaceChars, FALSE, + &m_puzPrefix, &m_uiPrefixChars))) + { + goto Exit; + } + } + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: Export a unicode string to the string buffer - as UTF8. +*****************************************************************************/ +FSTATIC RCODE exportUniValue( + IF_OStream * pOStream, + FLMUNICODE * puzStr, + FLMUINT uiStrChars, + FLMBOOL bEncodeSpecialChars, + FLMUINT uiIndentCount + ) +{ + RCODE rc = NE_XFLM_OK; + FLMBYTE ucTmp [4]; + FLMUINT uiLen; + FLMUINT uiCharOffset = 0; + FLMUNICODE uzChar; + FLMBOOL bIndent = FALSE; + FLMUINT uiICount = 0; + + while ( *puzStr && uiCharOffset < uiStrChars) + { + uzChar = *puzStr; + + // Handle encoding of special characters + + if (bEncodeSpecialChars) + { + if (uzChar == '<') + { + if (RC_BAD( rc = pOStream->write( (void *)"<", 4))) + { + goto Exit; + } + } + else if (uzChar == '>') + { + if (RC_BAD( rc = pOStream->write( (void *)">", 4))) + { + goto Exit; + } + } + else if (uzChar == '&') + { + if (RC_BAD( rc = pOStream->write( (void *)"&", 5))) + { + goto Exit; + } + } + else if (uzChar == '\'') + { + if (RC_BAD( rc = pOStream->write( (void *)"'", 6))) + { + goto Exit; + } + } + else if (uzChar == '"') + { + if (RC_BAD( rc = pOStream->write( (void *)""", 6))) + { + goto Exit; + } + } + else + { + goto Normal_Encoding; + } + } + else + { + +Normal_Encoding: + + // Output the character as UTF8. + + if (uzChar <= 0x007F) + { + // New Line char found. Need to indent. + if( uzChar == ASCII_NEWLINE) + { + bIndent = TRUE; + } + ucTmp [0] = (FLMBYTE)uzChar; + uiLen = 1; + } + else if (*puzStr <= 0x07FF) + { + ucTmp [0] = (FLMBYTE)(0xC0 | (FLMBYTE)(uzChar >> 6)); + ucTmp [1] = (FLMBYTE)(0x80 | (FLMBYTE)(uzChar & 0x003F)); + uiLen = 2; + } + else + { + ucTmp [0] = (FLMBYTE)(0xE0 | (FLMBYTE)(uzChar >> 12)); + ucTmp [1] = (FLMBYTE)(0x80 | (FLMBYTE)((uzChar & 0x0FC0) >> 6)); + ucTmp [2] = (FLMBYTE)(0x80 | (FLMBYTE)(uzChar & 0x003F)); + uiLen = 3; + } + if (RC_BAD( rc = pOStream->write( (void *)&ucTmp[0], uiLen))) + { + goto Exit; + } + + if( bIndent && uiIndentCount) + { + for( uiICount = uiIndentCount; uiICount; uiICount--) + { + if (RC_BAD( rc = pOStream->write( (void *)"\t", 1))) + { + goto Exit; + } + } + bIndent = FALSE; + } + } + puzStr++; + uiCharOffset++; + } + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: Output an attribute to the string buffer. +*****************************************************************************/ +RCODE F_Attribute::outputAttr( + IF_OStream * pOStream) +{ + RCODE rc = NE_XFLM_OK; + + if (RC_BAD( rc = pOStream->write( (void *)" ", 1))) + { + goto Exit; + } + if (m_uiPrefixChars) + { + if (RC_BAD( rc = exportUniValue( pOStream, m_puzPrefix, m_uiPrefixChars, FALSE, 0))) + { + goto Exit; + } + if (RC_BAD( rc = pOStream->write( (void *)":", 1))) + { + goto Exit; + } + } + + if (RC_BAD( rc = exportUniValue( pOStream, m_puzName, m_uiNameChars, FALSE, 0))) + { + goto Exit; + } + + if (RC_BAD( rc = pOStream->write( (void *)"=\"", 2))) + { + goto Exit; + } + + if (RC_BAD( rc = exportUniValue( pOStream, m_puzValue, m_uiValueChars, TRUE, 0))) + { + goto Exit; + } + + if (RC_BAD( rc = pOStream->write( (void *)"\"", 1))) + { + goto Exit; + } + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: Allocate a new attribute. +*****************************************************************************/ +RCODE F_Element::allocAttr( + F_Attribute ** ppAttr + ) +{ + RCODE rc = NE_XFLM_OK; + + if ((*ppAttr = *m_ppAvailAttrs) != NULL) + { + *m_ppAvailAttrs = (*ppAttr)->m_pNext; + (*ppAttr)->reset( this); + } + else + { + if ((*ppAttr = f_new F_Attribute( this)) == NULL) + { + rc = RC_SET( NE_XFLM_MEM); + goto Exit; + } + } + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: Save an attribute in an element. Put at end of list. +*****************************************************************************/ +RCODE F_Element::saveAttribute( + IF_Db * pDb, + IF_DOMNode * pNode + ) +{ + RCODE rc = NE_XFLM_OK; + F_Attribute * pAttr = NULL; + + if (RC_BAD( rc = allocAttr( &pAttr))) + { + goto Exit; + } + + // Set up the attribute + + if (RC_BAD( rc = pAttr->setupAttribute( pDb, pNode))) + { + goto Exit; + } + + // Put attribute at end of list of attributes. + + pAttr->m_pNext = NULL; + if (m_pLastAttr) + { + m_pLastAttr->m_pNext = pAttr; + } + else + { + m_pFirstAttr = pAttr; + } + m_pLastAttr = pAttr; + + // Set pAttr to NULL so it won't be made available at exit. + + pAttr = NULL; + +Exit: + + if (pAttr) + { + makeAttrAvail( pAttr); + } + + return( rc); +} + +/***************************************************************************** +Desc: Allocate space for the element's name and namespace. +*****************************************************************************/ +RCODE F_Element::allocNameSpace( void) +{ + RCODE rc = NE_XFLM_OK; + FLMUINT uiSpaceNeeded; + FLMUNICODE * puzTmp; + + uiSpaceNeeded = (m_uiNameChars + m_uiNamespaceChars + 2) * sizeof( FLMUNICODE); + + // Allocate space for the name and namespace + + if (uiSpaceNeeded > m_uiTmpSpaceSize) + { + + if (RC_BAD( rc = f_alloc( uiSpaceNeeded, &puzTmp))) + { + goto Exit; + } + if (m_puzName != &m_uzTmpSpace [0]) + { + f_free( &m_puzName); + } + m_puzName = puzTmp; + m_uiTmpSpaceSize = uiSpaceNeeded; + } + m_puzNamespace = &m_puzName [m_uiNameChars + 1]; + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: Setup an element with its namespace, etc. +*****************************************************************************/ +RCODE F_Element::setupElement( + IF_Db * pDb, + IF_DOMNode * pNode + ) +{ + RCODE rc = NE_XFLM_OK; + IF_DOMNode * pAttrNode = NULL; + F_Attribute * pAttr; + + // Get the length of the name of the element + + if (RC_BAD( rc = pNode->getLocalName( pDb, (FLMUNICODE *)NULL, + 0, &m_uiNameChars))) + { + goto Exit; + } + + // Get the number of characters in the namespace of the element + + if (RC_BAD( rc = pNode->getNamespaceURI( pDb, (FLMUNICODE *)NULL, + 0, &m_uiNamespaceChars))) + { + goto Exit; + } + + if (RC_BAD( rc = allocNameSpace())) + { + goto Exit; + } + + // Get the element name. + + if (RC_BAD( rc = pNode->getLocalName( pDb, m_puzName, + (m_uiNameChars + 1) * sizeof( FLMUNICODE), + &m_uiNameChars))) + { + goto Exit; + } + + // Get the namespace, if necessary + + if (m_uiNamespaceChars) + { + if (RC_BAD( rc = pNode->getNamespaceURI( pDb, m_puzNamespace, + (m_uiNamespaceChars + 1) * sizeof( FLMUNICODE), + &m_uiNamespaceChars))) + { + goto Exit; + } + } + + // See if the node has any attributes. + + for (;;) + { + rc = (RCODE)(pAttrNode + ? pAttrNode->getNextSibling( pDb, &pAttrNode) + : pNode->getFirstAttribute( pDb, &pAttrNode)); + if (RC_BAD( rc)) + { + if (rc == NE_XFLM_DOM_NODE_NOT_FOUND) + { + rc = NE_XFLM_OK; + break; + } + else + { + goto Exit; + } + } + if (RC_BAD( rc = saveAttribute( pDb, pAttrNode))) + { + goto Exit; + } + } + + // Get the prefix for the element + + if (RC_BAD( rc = setPrefix())) + { + goto Exit; + } + + // Set the prefix for every attribute + + pAttr = m_pFirstAttr; + while (pAttr) + { + if (RC_BAD( rc = pAttr->setPrefix())) + { + goto Exit; + } + pAttr = pAttr->m_pNext; + } + +Exit: + + if (pAttrNode) + { + pAttrNode->Release(); + } + + return( rc); +} + +/***************************************************************************** +Desc: Add an attribute that is a namespace to an element. +*****************************************************************************/ +RCODE F_Element::addNamespaceDecl( + FLMUNICODE * puzPrefix, + FLMUINT uiPrefixChars, + FLMUNICODE * puzNamespace, + FLMUINT uiNamespaceChars, + F_Attribute ** ppAttr + ) +{ + RCODE rc = NE_XFLM_OK; + F_Attribute * pAttr = NULL; + + // If uiPrefixChars is zero, we are being asked to create a default + // namespace. But that can only be output once in the element, + // so make sure it is not already declared. If it is, do nothing. + + if (!uiPrefixChars) + { + pAttr = m_pFirstAttr; + while (pAttr && !pAttr->m_bDefaultNamespaceDecl) + { + pAttr = pAttr->m_pNext; + } + if (pAttr) + { + goto Exit; + } + } + + if (RC_BAD( rc = allocAttr( &pAttr))) + { + goto Exit; + } + pAttr->m_bIsNamespaceDecl = TRUE; + + // name will be "xmlns:" or, in the case of no namespace, "xmlns" + + if (!uiPrefixChars) + { + + // "xmlns" - but make sure not already declared. + + pAttr->m_uiNameChars = 5; + pAttr->m_bDefaultNamespaceDecl = TRUE; + } + else + { + + // "xmlns:" + + pAttr->m_uiNameChars = uiPrefixChars + 6; + } + pAttr->m_uiNamespaceChars = 0; + pAttr->m_uiValueChars = uiNamespaceChars; + + if (RC_BAD( rc = pAttr->allocNameSpace())) + { + goto Exit; + } + + // Always output "xmlns" as the first part of the name + + f_memcpy( pAttr->m_puzName, gv_puzNamespaceDeclPrefix, 5 * sizeof( FLMUNICODE)); + if (uiPrefixChars) + { + pAttr->m_puzName [5] = ':'; + f_memcpy( &pAttr->m_puzName [6], puzPrefix, uiPrefixChars * sizeof( FLMUNICODE)); + pAttr->m_puzName [6 + uiPrefixChars] = 0; + } + else + { + pAttr->m_puzName [5] = 0; + } + if (uiNamespaceChars) + { + f_memcpy( pAttr->m_puzValue, puzNamespace, + uiNamespaceChars * sizeof( FLMUNICODE)); + } + pAttr->m_puzValue [pAttr->m_uiValueChars] = 0; + + // Put new namespace decl at front of list of attributes. + + if ((pAttr->m_pNext = m_pFirstAttr) == NULL) + { + m_pLastAttr = pAttr; + } + m_pFirstAttr = pAttr; + *ppAttr = pAttr; + + // Set pAttr to NULL so that it won't be made available at exit. + + pAttr = NULL; + +Exit: + + if (pAttr) + { + makeAttrAvail( pAttr); + } + return( rc); +} + +/***************************************************************************** +Desc: Generate a random prefix, ensure that it is not defined anywhere + in the path. +*****************************************************************************/ +void F_Element::genPrefix( + FLMUNICODE * puzPrefix, + FLMUINT * puiPrefixChars + ) +{ + FLMUINT uiTmp; + FLMUINT uiPrefixChars; + FLMUNICODE * puzTmp; + F_Attribute * pAttr; + F_Element * pElement; + + puzPrefix [0] = 'p'; + puzPrefix [1] = 'r'; + puzPrefix [2] = 'f'; + puzPrefix [3] = 'x'; + for (;;) + { + + // Append the number in reverse digit order - it really doesn't matter + // because we're just trying to generate a unique prefix number. + + puzTmp = &puzPrefix [4]; + uiPrefixChars = 4; + uiTmp = *m_puiNextPrefixNum; + do + { + *puzTmp++ = (FLMUNICODE)((uiTmp % 10) + '0'); + uiPrefixChars++; + uiTmp /= 10; + } while (uiTmp); + + // See if the prefix is defined. + + pAttr = m_pFirstAttr; + pElement = this; + while (pAttr) + { + if (pAttr->m_bIsNamespaceDecl && + pAttr->m_uiNameChars > 6 && + pAttr->m_uiNameChars - 6 == uiPrefixChars && + f_memcmp( puzPrefix, &pAttr->m_puzName [6], + uiPrefixChars * sizeof( FLMUNICODE)) == 0) + { + break; + } + if ((pAttr = pAttr->m_pNext) == NULL) + { + pElement = pElement->m_pParentElement; + while (pElement && !pElement->m_pFirstAttr) + { + pElement = pElement->m_pParentElement; + } + if (!pElement) + { + break; + } + pAttr = pElement->m_pFirstAttr; + } + } + + // If the prefix was not defined, we can use it. + + if (!pAttr) + { + break; + } + (*m_puiNextPrefixNum)++; + } + puzPrefix [uiPrefixChars] = 0; + *puiPrefixChars = uiPrefixChars; +} + +/***************************************************************************** +Desc: Find a prefix for a namespace +*****************************************************************************/ +RCODE F_Element::findPrefix( + FLMUNICODE * puzNamespace, + FLMUINT uiNamespaceChars, + FLMBOOL bForElement, + FLMUNICODE ** ppuzPrefix, + FLMUINT * puiPrefixChars) +{ + RCODE rc = NE_XFLM_OK; + F_Attribute * pAttr = m_pFirstAttr; + F_Element * pElement = this; + FLMUNICODE uzPrefix [50]; + FLMUINT uiPrefixChars; + + for (;;) + { + if ( pAttr) + { + if (pAttr->m_bIsNamespaceDecl && + uiNamespaceChars == pAttr->m_uiValueChars && + (!uiNamespaceChars || + f_memcmp( puzNamespace, pAttr->m_puzValue, + uiNamespaceChars * sizeof( FLMUNICODE)) == 0)) + { + + // Don't set the prefix if it is the default namespace. + + if (!pAttr->m_bDefaultNamespaceDecl) + { + // Prefix comes after the "xmlns:" + + *ppuzPrefix = &pAttr->m_puzName [6]; + *puiPrefixChars = pAttr->m_uiNameChars - 6; + goto Exit; + } + + // Default namespace is only OK for elements, + // but not attributes. We don't want to count + // attributes as having been "found" if they matched + // the default namespace. This routine is only called + // for attributes if the attribute namepace is non-empty. + + else if (bForElement) + { + goto Exit; + } + } + pAttr = pAttr->m_pNext; + } + if ( !pAttr) + { + pElement = pElement->m_pParentElement; + while (pElement && !pElement->m_pFirstAttr) + { + pElement = pElement->m_pParentElement; + } + if (!pElement) + { + break; + } + pAttr = pElement->m_pFirstAttr; + } + } + + // If namespaces is empty, the only declaration that is legal is + // a default namespace declaration. + + if (!uiNamespaceChars) + { + if (RC_BAD( rc = addNamespaceDecl( NULL, 0, NULL, 0, &pAttr))) + { + goto Exit; + } + } + else + { + + // Manufacture a prefix that is not used in the hierarchy yet. + + genPrefix( uzPrefix, &uiPrefixChars); + if (RC_BAD( rc = addNamespaceDecl( uzPrefix, uiPrefixChars, puzNamespace, + uiNamespaceChars, &pAttr))) + { + goto Exit; + } + + *ppuzPrefix = &pAttr->m_puzName [6]; + *puiPrefixChars = pAttr->m_uiNameChars - 6; + } + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: Output the element name, with its attributes - this marks the + beginning of the element. +*****************************************************************************/ +RCODE F_Element::outputElem( + IF_OStream * pOStream, + FLMBOOL bStartOfElement, + FLMBOOL bEndOfElement, + FLMBOOL bAddNewLine) +{ + RCODE rc = NE_XFLM_OK; + F_Attribute * pAttr; + F_Attribute * pPrevAttr; + FLMUINT uiIndentCount = 0; + FLMBOOL bEndNode; + + bEndNode = ( m_bIsDocumentRoot && !bStartOfElement); + if( bAddNewLine && ( !m_bIsDocumentRoot || bEndNode)) + { + if (RC_BAD( rc = pOStream->write( (void *)"\n", 1))) + { + goto Exit; + } + for( uiIndentCount = 0; uiIndentCount < m_uiIndentCount; uiIndentCount++) + { + if (RC_BAD( rc = pOStream->write( (void *)"\t", 1))) + { + goto Exit; + } + } + } + + // Output the element name + if ( bStartOfElement) + { + + if (RC_BAD( rc = pOStream->write( (void *)"<", 1))) + { + goto Exit; + } + } + else + { + + if (RC_BAD( rc = pOStream->write( (void *)"write( (void *)":", 1))) + { + goto Exit; + } + } + + if (RC_BAD( rc = exportUniValue( pOStream, m_puzName, m_uiNameChars, FALSE, 0))) + { + goto Exit; + } + + if (bStartOfElement) + { + + // Output the attributes. As we go, remove any attributes that are + // not namespace declarations. They are not needed after this. + + pPrevAttr = NULL; + pAttr = m_pFirstAttr; + while (pAttr) + { + if (RC_BAD( rc = pAttr->outputAttr( pOStream))) + { + goto Exit; + } + + if (!pAttr->m_bIsNamespaceDecl) + { + if (pPrevAttr) + { + pPrevAttr->m_pNext = pAttr->m_pNext; + makeAttrAvail( pAttr); + pAttr = pPrevAttr->m_pNext; + } + else + { + m_pFirstAttr = pAttr->m_pNext; + makeAttrAvail( pAttr); + pAttr = m_pFirstAttr; + } + + // See if we deleted the last attribute in the list. + + if (!pAttr) + { + m_pLastAttr = pPrevAttr; + } + } + else + { + pPrevAttr = pAttr; + pAttr = pAttr->m_pNext; + } + } + } + + // Close out the element + if (RC_BAD( rc = (RCODE)(bStartOfElement && bEndOfElement + ? pOStream->write( (void *)"/>", 2) + : pOStream->write( (void *)">", 1)))) + { + goto Exit; + } + + if ( bAddNewLine && bEndNode) + { + if (RC_BAD( rc = pOStream->write( (void *)"\n", 1))) + { + goto Exit; + } + } + + +Exit: + + return( rc); +} + +/***************************************************************************** +Desc: Output Data that is contained on an element node. +*****************************************************************************/ + +RCODE F_Element::outputLocalData( + IF_OStream * pOStream, + IF_DOMNode * pDbNode, + IF_Db * ifpDb, + eExportFormatType eFormatType, + FLMUINT uiIndentCount) +{ + RCODE rc = NE_XFLM_OK; + FLMUNICODE uzTmpData [150]; + FLMUNICODE * puzData = &uzTmpData [0]; + FLMUINT uiDataBufSize = sizeof( uzTmpData); + FLMUINT uiChars; + + if (RC_BAD( rc = pDbNode->getUnicodeChars( ifpDb, &uiChars))) + { + goto Exit; + } + + + if (uiDataBufSize < (uiChars + 1) * sizeof( FLMUNICODE)) + { + FLMUNICODE * puzNew; + + if (RC_BAD( rc = f_alloc( (uiChars + 1) * sizeof( FLMUNICODE), + &puzNew))) + { + goto Exit; + } + if (puzData != &uzTmpData [0]) + { + f_free( &puzData); + } + puzData = puzNew; + uiDataBufSize = (uiChars + 1) * sizeof( FLMUNICODE); + } + if (RC_BAD( rc = pDbNode->getUnicode( ifpDb, puzData, + uiDataBufSize, 0, uiChars, &uiChars))) + { + goto Exit; + } + + // Output the value. + if (RC_BAD( rc = exportUniValue( pOStream, puzData, uiChars, TRUE, + eFormatType >= XFLM_EXPORT_INDENT_DATA ? uiIndentCount : 0))) + { + goto Exit; + } + +Exit: + + return ( rc); +} + +/***************************************************************************** +Desc: Outputs a UTF8 stream of XML, starting at the specified node. Node and + all of its descendant nodes are output. +*****************************************************************************/ +RCODE XFLMAPI F_Db::exportXML( + IF_DOMNode * pStartNode, + IF_OStream * pOStream, + eExportFormatType eFormatType) +{ + RCODE rc = NE_XFLM_OK; + F_Element * pAvailElements = NULL; + F_Element * pTmpElement; + F_Attribute * pAvailAttrs = NULL; + F_Attribute * pTmpAttr; + FLMUNICODE uzTmpData [150]; + FLMUNICODE * puzData = &uzTmpData [0]; + FLMUINT uiDataBufSize = sizeof( uzTmpData); + IF_DOMNode * pDbNode = NULL; + eDomNodeType ePrevNodeType; + F_Element * pCurrElement = NULL; + FLMUINT uiNextPrefixNum = 0; + FLMBOOL bStartOfDocument = TRUE; + FLMBOOL bShouldFormat = FALSE; + FLMBOOL bIsDataLocal = FALSE; + FLMUINT uiIndentCount = 0; + FLMUINT uiICount = 0; + + // This routine should only be called if the node type is element node. + + flmAssert( pStartNode->getNodeType() == ELEMENT_NODE); + + ePrevNodeType = ELEMENT_NODE; + pDbNode = pStartNode; + pDbNode->AddRef(); + + for (;;) + { + // Output the current node, depending on its type. + + if( pDbNode->getNodeType() == ELEMENT_NODE) + { + if (pAvailElements) + { + pTmpElement = pAvailElements; + pAvailElements = pAvailElements->getNext(); + pTmpElement->reset( pCurrElement, &pAvailAttrs, &uiNextPrefixNum); + } + else + { + if ((pTmpElement = f_new F_Element( pCurrElement, &pAvailAttrs, + &uiNextPrefixNum)) == NULL) + { + rc = RC_SET( NE_XFLM_MEM); + goto Exit; + } + } + + pCurrElement = pTmpElement; + + if (RC_BAD( rc = pCurrElement->setupElement( (IF_Db *)this, pDbNode))) + { + goto Exit; + } + + if( eFormatType >= XFLM_EXPORT_INDENT) + { + pCurrElement->setIndentCount(uiIndentCount); + } + + if( pDbNode == pStartNode) + { + pCurrElement->setDocumentRoot( TRUE); + } + + // Only want a New Line and tabs for Element if: + // 1) New Line format is indicated + // 2) Previous Element Was NOT Data + bShouldFormat = ( (eFormatType >= XFLM_EXPORT_NEW_LINE) && + (ePrevNodeType != DATA_NODE)) + ? TRUE + : FALSE; + + if( RC_BAD( rc = pDbNode->isDataLocalToNode( (IF_Db *)this, + &bIsDataLocal))) + { + goto Exit; + } + + if( bIsDataLocal) + { + if( RC_BAD( rc = pCurrElement->outputElem( pOStream, + TRUE, FALSE, bShouldFormat))) + { + goto Exit; + } + + pCurrElement->outputLocalData( pOStream, + pDbNode, + (IF_Db *)this, + eFormatType, + uiIndentCount); + + } + + if( RC_OK( rc = pDbNode->getFirstChild( (IF_Db *)this, &pDbNode))) + { + if( !bIsDataLocal && RC_BAD( rc = pCurrElement->outputElem( + pOStream, TRUE, FALSE, bShouldFormat))) + { + goto Exit; + } + + bStartOfDocument = FALSE; + uiIndentCount++; + ePrevNodeType = ELEMENT_NODE; + continue; + } + + if( rc != NE_XFLM_DOM_NODE_NOT_FOUND) + { + goto Exit; + } + + // Write out the "/>" for the element, because it had no + // child nodes. + + if( bIsDataLocal) + { + if( RC_BAD( rc = pCurrElement->outputElem( pOStream, + FALSE, TRUE, bShouldFormat))) + { + goto Exit; + } + } + else + { + if( RC_BAD( rc = pCurrElement->outputElem( pOStream, + TRUE, TRUE, bShouldFormat))) + { + goto Exit; + } + } + + // We are now done with this element + + ePrevNodeType = ELEMENT_NODE; + pTmpElement = pCurrElement; + pCurrElement = pCurrElement->getParentElement(); + pTmpElement->makeAvail( &pAvailElements); + + if( !pCurrElement) + { + break; + } + +Get_Element_Sibling: + + // See if we have a sibling. Go up tree until we find + // a node that has a sibling. + + for( ;;) + { + if( RC_OK( rc = pDbNode->getNextSibling( (IF_Db *)this, &pDbNode))) + { + break; + } + + if( rc != NE_XFLM_DOM_NODE_NOT_FOUND) + { + goto Exit; + } + + // Need to close previous element + + if( uiIndentCount) + { + uiIndentCount--; + } + + if( RC_BAD( rc = pCurrElement->outputElem( pOStream, FALSE, TRUE, + eFormatType >= XFLM_EXPORT_NEW_LINE + ? TRUE + : FALSE))) + { + goto Exit; + } + + if( RC_BAD( rc = pDbNode->getParentNode( (IF_Db *)this, &pDbNode))) + { + if( rc == NE_XFLM_DOM_NODE_NOT_FOUND) + { + // There should be a parent node at this point! + + rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR); + } + + goto Exit; + } + + pTmpElement = pCurrElement; + pCurrElement = pCurrElement->getParentElement(); + pTmpElement->makeAvail( &pAvailElements); + + if( !pCurrElement) + { + pDbNode->Release(); + pDbNode = NULL; + goto Exit; + } + } + } + else + { + // Only output data, comment, and cdata nodes. + + if( pDbNode->getNodeType() == DATA_NODE || + pDbNode->getNodeType() == COMMENT_NODE || + pDbNode->getNodeType() == CDATA_SECTION_NODE) + { + FLMUINT uiChars; + + if( RC_BAD( rc = pDbNode->getUnicodeChars( (IF_Db *)this, + &uiChars))) + { + goto Exit; + } + + if( uiDataBufSize < (uiChars + 1) * sizeof( FLMUNICODE)) + { + FLMUNICODE * puzNew; + + if( RC_BAD( rc = f_alloc( (uiChars + 1) * sizeof( FLMUNICODE), + &puzNew))) + { + goto Exit; + } + + if( puzData != &uzTmpData [0]) + { + f_free( &puzData); + } + + puzData = puzNew; + uiDataBufSize = (uiChars + 1) * sizeof( FLMUNICODE); + } + + if( RC_BAD( rc = pDbNode->getUnicode( (IF_Db *)this, puzData, + uiDataBufSize, 0, uiChars, &uiChars))) + { + goto Exit; + } + + if( pDbNode->getNodeType() == DATA_NODE) + { + // Output the value + + if (RC_BAD( rc = exportUniValue( pOStream, puzData, uiChars, + TRUE, eFormatType >= XFLM_EXPORT_INDENT_DATA + ? uiIndentCount + : 0))) + { + goto Exit; + } + + ePrevNodeType = DATA_NODE; + } + else if( pDbNode->getNodeType() == COMMENT_NODE) + { + //If Comment Node follows Data Node do not add new line + + if( eFormatType >= XFLM_EXPORT_INDENT_DATA && + ePrevNodeType != DATA_NODE) + { + if (RC_BAD( rc = pOStream->write( (void *)"\n", 1))) + { + goto Exit; + } + + for( uiICount = 0; uiICount < uiIndentCount; uiICount++) + { + if (RC_BAD( rc = pOStream->write( (void *)"\t", 1))) + { + goto Exit; + } + } + } + + // Output the beginning of a comment + + if (RC_BAD( rc = pOStream->write( (void *)"", 3))) + { + goto Exit; + } + + ePrevNodeType = COMMENT_NODE; + } + else + { + // Output the beginning of a cdata section + + if( RC_BAD( rc = pOStream->write( (void *)"write( (void *)"]]>", 3))) + { + goto Exit; + } + + ePrevNodeType = CDATA_SECTION_NODE; + } + } + + // Have a data node, or comment node probably + // In any case, see if there are any sibling nodes. + // If not, go back to enclosing element node. + + if( RC_OK( rc = pDbNode->getNextSibling( (IF_Db *)this, &pDbNode))) + { + continue; + } + + if( rc != NE_XFLM_DOM_NODE_NOT_FOUND) + { + goto Exit; + } + + // Go back up to enclosing element + + if( RC_BAD( rc = pDbNode->getParentNode( (IF_Db *)this, &pDbNode))) + { + // There better be a parent node or we have a corruption! + + if( rc == NE_XFLM_DOM_NODE_NOT_FOUND) + { + rc = RC_SET( NE_XFLM_DATA_ERROR); + } + + goto Exit; + } + + // Parent node better be an element + + if( pDbNode->getNodeType() != ELEMENT_NODE) + { + rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR); + goto Exit; + } + + // If we were traversing the attributes of an element, + // we need to now go back and get its child nodes. + + // Write out the for the element + + if( RC_BAD( rc = pCurrElement->outputElem( pOStream, + FALSE, TRUE, FALSE))) + { + goto Exit; + } + + // We are now done with this element + + if( uiIndentCount) + { + uiIndentCount--; + } + + ePrevNodeType = ELEMENT_NODE; + pTmpElement = pCurrElement; + pCurrElement = pCurrElement->getParentElement(); + pTmpElement->makeAvail( &pAvailElements); + + if( !pCurrElement) + { + break; + } + + goto Get_Element_Sibling; + } + } + +Exit: + + if( puzData != &uzTmpData [0]) + { + f_free( &puzData); + } + + while( pCurrElement) + { + pTmpElement = pCurrElement; + pCurrElement = pCurrElement->getParentElement(); + delete pTmpElement; + } + + while( pAvailElements) + { + pTmpElement = pAvailElements; + pAvailElements = pAvailElements->getNext(); + delete pTmpElement; + } + + while( pAvailAttrs) + { + pTmpAttr = pAvailAttrs; + pAvailAttrs = pAvailAttrs->getNext(); + delete pTmpAttr; + } + + if( pDbNode) + { + pDbNode->Release(); + } + + return( rc); +}