Archive for November, 2007

2007软件开发2.0大会-29日

Friday, November 30th, 2007

很兴奋能参加这个会议,可惜公司这面早上只有我一个人去,大清早收拾好就在楼下的 984 车站等车,结果等了好久才来车,车上好几个人都是同去开会的,有两位先生还不错,下车后给我领了路,在开会过程中还见过几回,好像是 TechExcel 公司的(希望没有记错),先表示感谢一下吧。

还好没有迟到很多,蒋总(总裁 蒋涛)刚上台,我就进入主会场了。蒋总的开幕辞解释了为什么要办这次会议,以及这次会议的主题《揭示下一代软件开发趋势》。

查看 报道 >> 【SD2.0大会】CSDN总裁蒋涛致大会开幕辞

第一场孟岩( & 《程序员》总编)和Jon Erickson(DDJ杂志主编)讨论了一下什么是软件开发2.0,很可惜,进去时太匆忙,忘了向工作MM要同声传译的耳机了,本来我的听力就巨烂无比,再加上做在我旁边和后台的几位仁兄肆无忌惮的聊天,让我感觉像在菜市场里看哑剧一样。我只注意到了一个词组,“Tipping Point”,关键点?顶点?突破点?

查看 报道 >> 【SD2.0大会】DDJ总编与程序员总编孟岩对话SD2.0

第二场Ivar Jacobson(现代软件开发之父)的《软件开发大趋势》也不错,主要阐述了三个观点。

1、如何开发更优秀、高效和低成本的软件?
高效由多构件和积极主动的开发者来完成,低成本由大规模的构件重用实现,优秀的软件必然是实用性强,可扩展性高和稳定的产品。

2、软件开发,实践为王
程序员需要更多的高级技术实践。重要的构件重用技术包括工程流,SOA,企业架构技术。实践是过程的基础,过程只是组成实践的一个元素。优秀的实践之所以成本低是由大规模的构件重用来实现。

3、如何获得实践
传统的方法是通过书籍和网络,这样获得的数据相关性不够。先进的实践来源是没有限制的,包多基本和高级的方式,但只要是实用的就可以自由选择并合并这些实践组成一个新的过程。这种方法为开发人员提供了一种比较新的模式。

查看 报道 >> 【SD2.0大会】Ivar:为什么我做的架构比你的年龄还长

 

第三场林斌(谷歌工程研究院副院长)介绍了 Google 的新手机平台 Android。之前我仅因为 Android 开源免费,并且出于对 Google 产品先量一贯的信任也装了一个 SDK 和 emulator 来玩一下,今天开会才了解到,Android 相对于其它平台的四个优势:及时响应;不会死机;通话切换;保存状态。不过同时公布的几项数据很有趣。“发布前两周,共250,000下载;下载量中国第一,超过美国1.5倍;”不知道 Google 用于奖励 Android 开发的一千万美元会有多少被中国人拿到?

查看 报道 >> 【SD2.0大会】数据现Andriod惊人影响力,Google林斌公布架构图

茶歇时外面的展台也不出,可惜送的东西太少,广告性质的东西太多。中途问过几次是否可以使用 wi-fi ,结果被告知因为太多的媒体在使用 wi-fi 造成网络拥挤。我在主会场内开机试了几回,也始终无法连上,本来手机欠费,准备有什么事再从网上通知其它人,或者先在淘宝上充下话费,唉。总能在不经意的回头间看到李梁一闪而过的身影,每当我再凝神寻找时又不见踪影,还好茶歇时在外面看到了,当我在展台转了一圈,他又不见了,不知道是我眼神不好,还是他“打一枪换一个地方”、“四处流窜”。几次去会场服务区询问,恰恰每次都是总到同一个MM,结果当我最后一次询问完后离开时,那个MM注视我好长一段时间,旁边有人询问她问题时,那个MM也没有反应,让我小小的陶醉了一下,俺也终于能吸引别人的眼球了。(早上起得太早,顶着鸡窝头去的,希望不是这个原因吸引她的目光)

第四场Jim Douglas(CodeGear公司CEO)……i forget……明天再去找别人的笔记回忆一下吧。

第五场陈榕(北京科泰世纪科技有限公司首席科学家、技术总监)对手机的独到见解让我眼前为之一亮。陈总认为计算机内部只有两样东西,数据和处理数据的程序,那么,既然数据可以通过短信、红外和蓝牙等方式传递,那么程序也可以。在陈总的话语中多次听到 1-click,即用户通过一次点击来使用某个服务,而这个服务处理数据的程序是在后台执行,让程序对用户是不可见的,也就没办法要求用户来为程序付费,仅会对服务消费。并且通过一定的方式,比如 metadata 的方式,可以使 handset 自动的去执行一些操作。比如 A 给 B 发送了一个视频文件,但是 B 的手机上没有这个解码器,如果 A 的视频文件的 metadata 中有一个类似于 URL 或者 URI 的东西能指定到解码器的 dll ,那么 B 机器会在后台自动下载安装。正如某位通过叽歪与现场互动的那位朋友说的,如果手机可以 DIY ,那么按照陈总的想法,手机可以和新组装的电脑一样,是裸机,通过我们安装服务来使用,这样大大的扩展了手机的功能。

查看 报道 >> 【软件开发2.0大会】陈榕:让软件消失在用户面前

第五场Jim Reinders(Intel软件产品部首席宣传官居兼市场总监)讲的内容好像是关于并行计算这方面的,不过因为我在考虑其它事情,所以内容记得不是很清,也得明天找别人去“补课”了。

第六场Andrie Alexandrescu(C++天才作家、D语言领袖人物,华尔街咨询师)给我的感觉就是风趣……并且他那一长串长场介绍时的 title 也吸引了我,“某国伞兵”。

中午的午餐不过,就是同时就餐的人太多,要排好长的队,流量大,并发高,这也是我们这次会议要解决的问题。伙食不错,不过因为时间太紧,我也没有多吃,可能是因为菜有点咸,口味有点重(某些人看到这里不要误会,p囧q )。

下午第一场听的范路(Product Evangelist, China Mainland CodeGear)的《2.0时代软件开发新方法、新工具》,对 RAD STUDIO 2007 有了一些初步的了解。不过范路对软件体系结构、开发过程、语言以及开发工具的演变做了一些很有意思的分析和讲解。

查看 报道 >> 【SD2.0大会】2.0开发时代的四大特性改变

在听下午第一场的中间,去洗手间的时候,顺路去博文视点的展台看了一下,看到一堆书上放了“请赐名片”和一位老兄把一张名片给了博文的工作人员,然后拿起一本书就走了,我以为是“以名片免费换书”,因为之前博文的传单上有写“免费赠书”。我兴致勃勃的回去找杨恺和老高要名牌,准备回来领书,结果回来一问,原来书是卖的,名片给不给都行……我被鄙视了……我看到的那个人之前给付钱了,不过我没看到。T_T

第二场幺宝刚讲解 Google Gear,之前有了解过 Gear 所以没有用太多的注意力来听,一直在紧紧的盯着“老钱”(钱宏武),期待着下一场他的演讲。

第三场,终于等到钱宏武演讲了,上回在悠视(悠视网 www.uusee.com)听他讲的时候,就感觉比较有内容,不像其它人讲的都是空泛的概念之类的,而他讲的是经验、问题和方法。其实,我这回自费来参加 SD2.0 大会,就是想来听他的演讲。钱宏武针对以前在 SOHU 做互动产品的经验介绍了如何开发和维护。其中他对于团队的构成和任务分配的特殊见解真是让我眼前豁然开朗,“给开发人员定一个稍高一点的目标”,“培养水平低的员工”等等……

查看 报道 >> 【SD2.0大会】钱宏武谈做互联网产品就像娶老婆 贤惠又要好看

第四场听了前一半的董大伟的《ASP.NET AJAX 与 Silverlight 的完美结合》和冯彦文的《利用 Ajax/ 技术建立高流量的即时双向沟通网站》。

终于等到我发挥特长的时候了,吃……晚宴时间。

晚上的沙龙算是这些大会给我的一个惊喜,原本订课时的沙龙是管理方面的,但是上午突然看到传单上有临时安排 Ben Wang(王文斌?当时离得太远,没看清,Taobao 首席架构师)、老钱(钱宏武)、雷鸣(前 Baidu 架构师)、汤道生(腾讯开发副总裁)四人合讲的《大型网站架构》收益良多啊……

总的来看 这次举办的活动还是不错,真希望能坚持下去。

有几点让我感觉不太爽的地方:
1、每个人太早的发包,以至于,包比人多(有人来的时候自己本身就带包了,比如我),所以好多座位上都是放的包,让一些人没有地方座,吃饭、听课时都有这种情况。
2、经常在开会过程中听到手机响,真是搞不懂,开会前明明主持人已经让大家把手机都调成振动了。并且有人接到电话后还在原位置大声的煲电话粥,如果是工作就算了,竟然长时间打电话,还在闲聊!真是损人不利已。
3、原本晚上的沙龙是 VIP 才有的?但是看到好像没有什么限制,大家随便听。然后领东西时 VIP 也没有什么多的,就是一本增刊还是外面可以买到的,让我郁闷不已,VIP 和普通的没有什么区别嘛。
4、开会时,一直有人在下边聊天、拉关系,无比烦人!

[转] MTK平台芯片概说

Monday, November 26th, 2007

转至 http://blog.sina.com.cn/mobliephone

目前联发科技已开发出MT6205、MT6217、MT6218、MT6219、MT6226、MT6227、MT6228等系列平台,其中MT6205、MT6217、MT6218、MT6219、MT6226、MT6227、MT6228、MT6229、MT6225、MT6223、MT6230均为基带芯片,所有芯片均采用ARM7的核。
MT6305为电源管理芯片,有MT6305、MT6305N、MT6305BN;

MT6129、MT6139是射频芯片。MT6129为早期的射频RF芯片,一般与MT6205的CPU一起使用。现在用的多的是MT6129C、MT6129N、MT6129D,其中MT6129C、MT6129N一般用在MT6217、MT6218、MT6219的CPU的机器上,MT6129D一般用在MT6226、MT6227的CPU的机器上。RF3146(7×7mm)、RF3146D(双频)、RF3166(6×6mm)为RFMD的PA。

MT6205为最早的方案,只有GSM的基本功能,不支持GPRS、WAP、MP3等功能。(2003年MP);
MT6218为在MT6205基础上增加GPRS、WAP、MP3功能。MT6217为MT6218的cost down方案,与MT6128 PIN TO PIN,只是软件不同而已,另外MT6217支持16bit数据。(2004年MP)
MT6219为MT6218上增加内置AIT的1.3M camera处理IC,增加MP4功能。8bit数据。(2005年MP)
MT6226为MT6219 cost 升级产品,内置0.3M 摄相处理IC,支持GPRS、WAP、MP3、MP4等,内部配置比MT6219优化及改善,比如配蓝牙是可用很便宜的芯片CSR的BC03模块USD3即可支持数据传输(如听立体声MP3等)功能。
MT6226M为MT6226高配置设计,内置的是1.3M摄像处理IC。(2006年MP)
MT6227与MT6226功能基本一样,PIN TO PIN,只是内置的是2.0M 摄像处理IC。(2006年MP)
MT6228比MT6227增加TV OUT功能,内置3.0M 摄像处理IC,支持支持GPRS、WAP、MP3、MP4。(2006年MP)
从MT6226后软件均可支持网络摄像头功能,也就是说你的机子可以用于QQ视频。

MT6229平台支持EDGE功能,其他功能和6228基本一致。

MT6225是6217的代替产品,可以接cam但是没有isp,也就是没有特效,变焦,但是其主频很高和6228/6229一样达到了104mhz,可以接wifi,并且给设计公司提出了更高的要求——如何利用104m的资源去实现mp4的编解码,如何用104m的资源跑更多的应用,这些都是设计公司做的,对设计公司的要求也非常得高。

MT6223是6205的替代,支持语音,短信,MP3,不支持T_F卡,USB盘,没有集成ISP,PMIC内签。

目前市面上出的双卡双待手机,一般是采取的方案分为以下几种:MT6226+6205,MT6225+6205和MT6225+6223

[分享] 某知名手机平台的XML Parser源代码

Sunday, November 25th, 2007

    今天心情不错~ 分享一下小弟06年在某手机公司写的 .
虽然当时脑子里还没有FSM的概念, 但代码逻辑还算清晰, 颇有成就感!
结构比较简单, 按DOM方式把指定文件解析成节点树, 另外提供几个简单的查找函数.
部分功能等完善, 过段时间再发一份功能比较完善的C++版本.

PLX_XMLParser.h

#if _MSC_VER > 1000
#pragma once
#endif

#ifndef __XMLPARSE_H
#define __XMLPARSE_H

#include

//////////////////////////////
// Configure

#define USE_INLINE_FUNCTION
#define USE_FILEBUFFER

//////////////////////////////
// Constants

typedef enum {
XMLERR_OK       = 0×0,
XMLERR_EFILE,       // failed to open file
XMLERR_ALRDOPEN,    // already opened
XMLERR_EDOC,
XMLERR_EPARSE,
} XMLERR;

typedef enum {
NODETYPE_UNKN    = 0×0,
NODETYPE_ELEM   = 0×1,
NODETYPE_TEXT   = 0×2,
NODETYPE_COMM   = 0×4,
NODETYPE_INST   = 0×8, // Not support
//NODETYPE_USEFUL = NODETYPE_ELEM|NODETYPE_TEXT,
//NODETYPE_ALL    = NODETYPE_ELEM|NODETYPE_TEXT|NODETYPE_COMM|NODETYPE_INST,
} NODETYPE;

typedef enum {
DSTAT_UNOPEN    = 0×0,
DSTAT_OPENED    = 0×1,
} DOCSTAT;

typedef enum {
ISTAT_STOP      = 0×0,
ISTAT_CONTINUE  = 0×1,
ISTAT_PASS      = 0×2,
} ITERSTAT;

enum {    MAXLEN_BSTR    = 256 };

//////////////////////////////
// Structures

struct tagBString
{
LONG    m_lLength;
union   {
CHAR    m_paStr[1];
LPCSTR  m_pszStr;
};
};

typedef struct tagBString       BSTRING;
typedef struct tagBString       *LPBSTRING;
typedef struct tagBString const *LPCBSTRING;

struct tagXMLAttrib;
typedef struct tagXMLAttrib            XMLATTRIB;
typedef struct tagXMLAttrib            *LPXMLATTRIB;
typedef struct tagXMLAttrib    const    *LPCXMLATTRIB;

struct tagXMLAttrib
{
LPBSTRING   m_pbstrName;
LPBSTRING   m_pbstrValue;
LPXMLATTRIB    m_pNext;
};

struct tagXMLNode;
typedef struct tagXMLNode       XMLNODE;
typedef struct tagXMLNode       *LPXMLNODE;
typedef struct tagXMLNode const *LPCXMLNODE;

struct tagXMLNode
{
NODETYPE    m_eNodeType;
LONG        m_lDepth;

LPBSTRING   m_pbstrTag;

LONG        m_lChildNum;
LONG        m_lChildNum_Elem;

LPXMLNODE    m_pRoot;
LPXMLNODE   m_pParent;
LPXMLNODE   m_pFirstChild;
LPXMLNODE   m_pLastChild;
LPXMLNODE   m_pPrevSibling;
LPXMLNODE   m_pNextSibling;

LONG        m_lAttribNum;
LPXMLATTRIB m_pFirstAttrib;
};

struct tagXMLDocument
{
DOCSTAT     m_eDocStat;
LPXMLNODE   m_lpRootNode;
};

typedef struct tagXMLDocument       XMLDOCUMENT;
typedef struct tagXMLDocument       *LPXMLDOCUMENT;
typedef struct tagXMLDocument const *LPCXMLDOCUMENT;

//////////////////////////////
// Types

typedef ITERSTAT    (CALLBACK *LPFNNODEPROC)( LPCXMLNODE pNode, LPVOID pvParam );

//////////////////////////////
// Macros

#if    defined(USE_INLINE_FUNCTION)

#define BSTR_C( pBStr )                     (&((pBStr)->m_paStr[0]))
#define BSTR_CAST( pvAnyType )              ((LPBSTRING)pvAnyType)
#define    BSTR_LEN( pBStr )                   ((pBStr)->m_lLength)
#define BSTR_ALLOC( pszStr )                AllocBString( pszStr, (NULL != (pszStr) ? ((LONG)strlen(pszStr)) : (0L)) )
#define BSTR_ALLOCEX( pszStr, nLen )        AllocBString( pszStr, (LONG)nLen )
#define BSTR_FREE( pBStr )                  free( pBStr )
#define BSTR_SAFEFREE( pBStr )              if ( NULL != pBStr ) { free( pBStr ); pBStr = NULL; }
#define BSTR_EQUAL( pBStrL, pBStrR ) \
( (BSTR_LEN(pBStrL) == BSTR_LEN(pBStrR) && 0 == strcmp(BSTR_C(pBStrL), BSTR_C(pBStrL))) ? \
TRUE : FALSE )
#define BSTR_EQUAL_STATIC( pBStr, szStatic ) \
( (BSTR_LEN(pBStr) == (LONG)(sizeof(szStatic) - 1) && 0 == strcmp(BSTR_C(pBStr), szStatic)) ? \
TRUE : FALSE )
#define BSTR_EQUAL_CSTR( pBStr, pszStr ) \
( (BSTR_LEN(pBStr) == (LONG)strlen(pszStr) && 0 == strcmp(BSTR_C(pBStr), pszStr)) ? \
TRUE : FALSE )

#define    XML_GetRootNode( pDoc )             ((NULL == (pDoc) || (pDoc)->m_eDocStat != DSTAT_OPENED) ? NULL : (pDoc)->m_lpRootNode)
#define    XML_GetNodeType( pNode )             (NULL != (pNode) ? (pNode)->m_eNodeType : NODETYPE_UNKN)
#define    XML_GetNodeDepth( pNode )            (NULL != (pNode) ? (pNode)->m_lDepth : (-1L))
#define    XML_GetNodeParent( pNode )             (NULL != (pNode) ? (pNode)->m_pParent : NULL)
#define    XML_GetNodeFirstChild( pNode )         (NULL != (pNode) ? (pNode)->m_pFirstChild : NULL)
#define    XML_GetNodeLastChild( pNode )         (NULL != (pNode) ? (pNode)->m_pLastChild : NULL)
#define    XML_GetNodeChildNum( pNode )         (NULL != (pNode) ? (pNode)->m_lChildNum : (0L))
#define    XML_GetNodeChildNum_Elem( pNode )     (NULL != (pNode) ? (pNode)->m_lChildNum_Elem : (0L))
#define    XML_GetNodePrevSibling( pNode )     (NULL != (pNode) ? (pNode)->m_pPrevSibling : NULL)
#define    XML_GetNodeNextSibling( pNode )     (NULL != (pNode) ? (pNode)->m_pNextSibling : NULL)
#define    XML_GetNodeTagName( pNode )         (NULL != (pNode) ? (pNode)->m_pbstrTag : NULL)
#define    XML_GetNodeAttribNum( pNode )         (NULL != (pNode) ? (pNode)->m_lAttribNum : (0L))
#define    XML_GetNodeFirstAttrib( pNode )     (NULL != (pNode) ? (pNode)->m_pFirstAttrib : NULL)
#define    XML_GetNodeNextAttrib( pAttr )         (NULL != (pAttr) ? (pAttr)->m_pNext : NULL)
#define XML_GetAttribValueBString( pAttr )  (NULL != (pAttr) ? (pAttr)->m_pbstrValue) : NULL)
#define XML_GetAttribValueCString( pAttr )  (NULL != (pAttr) ? BSTR_C((pAttr)->m_pbstrValue) : NULL)
#define XML_GetAttribValueLong( pAttr )     (NULL != (pAttr) ? (LONG)strtol(BSTR_C((pAttr)->m_pbstrValue), NULL, 0) : (0L))
#define XML_GetAttribValueInt( pAttr )      (NULL != (pAttr) ? (int)strtol(BSTR_C((pAttr)->m_pbstrValue), NULL, 0) : (0))

#endif

//////////////////////////////
// Function prototypes

#if defined(__cplusplus)
extern “C” {
#endif

size_t      strlen_when( LPCSTR lpszStr, CHAR ch );
size_t        strlen_notin( LPCSTR lpszStr, LPCSTR lpszSet );
LPCSTR        strchr_notin( LPCSTR lpszStr, LPCSTR lpszSet );
LPCSTR        strchr_skipws( LPCSTR lpszStr );

LPBSTRING   AllocBString( LPCSTR lpszStr, LONG lLen );

XMLERR      XML_OpenDocument( LPXMLDOCUMENT pDoc, LPCSTR lpszFileName, DWORD dwReserve );
XMLERR      XML_CloseDocument( LPXMLDOCUMENT pDoc );
LPXMLNODE    XML_GetNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPCSTR lpszTag, LONG lLen );
LPXMLATTRIB    XML_GetNodeAttrib( LPXMLNODE pNode, LPCSTR lpszAttr, LONG lLen );
LPXMLNODE    XML_GetNodeSibling( LPXMLNODE pNode, LPCSTR lpszTag, LONG lLen, BOOL IncludeThis );
LONG         XML_ForEachNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPFNNODEPROC pfnNodeProc, LPVOID pvParam );

#if defined(__cplusplus)
}   // extern “C” {
#endif

#endif // #ifndef __XMLPARSE_H

PLX_XMLParser.c

#include <assert.h>
#include <fcntl.h>
#include <io.h>
#if defined() || defined(_DEBUG)
#include <stdio.h>
#endif

#include “XMLParse.h”

//#pragma warning(disable:4305)

//////////////////////////////
// Configure

//#define  USE_MEMORY_HEAP

#ifdef  USE_FILEBUFFER  // Whether use file system with os-layer buffer

#define INVALID_FILE_HANDLE         ((int)-1)
#define FILE_HANDLE                 int

#define MODE_RDONLY                 (O_RDONLY)
#define FILE_OPEN(pszFile,mode)     open( pszFile, mode )
#define FILE_READ(hFile,pbuf,size)  read(hFile, (LPVOID)pbuf, size)
#define FILE_SEEK(hFile,off,pos)    lseek( hFile, off, pos )
#define FILE_CLOSE(hFile)           close( hFile )

#else

#define INVALID_FILE_HANDLE         ((FILE *)NULL)
#define FILE_HANDLE                 FILE *

#define MODE_RDONLY                 (”r”)
#define FILE_OPEN(pszFile,mode)     fopen( pszFile, mode )
#define FILE_READ(hFile,pbuf,size)  fread((LPVOID)pbuf, size, 1, hFile)
#define FILE_SEEK(hFile,off,pos)    fseek( hFile, off, pos )
#define FILE_CLOSE(hFile)           fclose( hFile )

#endif

//////////////////////////////
// Constants

enum {    MAXLEN_READBUF    = 1024 };

typedef enum {
PSTAT_STOP      = 0×0,
PSTAT_INITIAL,
PSTAT_FINAL,
PSTAT_DECL_BEG,
PSTAT_DECL_END,
PSTAT_ELEM_BEG,
PSTAT_ELEM_END,
PSTAT_TEXT_BEG,
PSTAT_TEXT_END,
PSTAT_CDATA_BEG,
PSTAT_CDATA_END,
PSTAT_COMM_BEG,
PSTAT_COMM_END,
PSTAT_ERROR,
} PARSESTAT;

//////////////////////////////
// Macros

#define ZERO_MEMORY(p, size) \
( memset((LPVOID)(p), 0×0, (size_t)size) )

#define is_WhiteSpace(ch)   (((ch) == ‘ ‘  || (ch) == ‘\t’) ? TRUE : FALSE)
#define is_LineBreak(ch)    (((ch) == ‘\r’ || (ch) == ‘\n’) ? TRUE : FALSE)
#define is_LeftBracket(ch)    ((ch) == ‘<’ ? TRUE : FALSE)
#define is_RightBracket(ch)    ((ch) == ‘>’ ? TRUE : FALSE)

#define is_BufferEmpty(ps)  ((ps)->m_lReadCursor >= (ps)->m_lReadSize ? TRUE : FALSE)
#define get_BufferChar(ps)  ((CHAR)((ps)->m_aReadBuf[(ps)->m_lReadCursor]))

#define is_FirstChild(pn)    ((pn)->m_pPrevSibling == NULL ? TRUE : FALSE)
#define is_LastChild(pn)    ((pn)->m_pNextSibling == NULL ? TRUE : FALSE)

//////////////////////////////
// Structures

struct tagXMLParseStat
{
PARSESTAT   m_eParseStat;
LONG        m_lDepth;
LPXMLNODE    m_pRootNode;
LPXMLNODE    m_pLastNode;

FILE_HANDLE    m_hOpenFile;
LONG        m_lFileCursor;
LONG        m_lFileLength;

LONG        m_lLineNo;
LONG        m_lReadCursor;
LONG        m_lReadSize;
BYTE        m_aReadBuf[MAXLEN_READBUF];
};
typedef struct tagXMLParseStat            XMLPARSESTAT;
typedef struct tagXMLParseStat            *LPXMLPARSESTAT;
typedef struct tagXMLParseStat    const    *LPCXMLPARSESTAT;

struct tagXMLIterator
{
LONG            m_lCount;
LPFNNODEPROC    m_pfnProc;
LPVOID          m_pvParam;
LPXMLNODE       m_pStation;
};
typedef struct tagXMLIterator       XMLITERFATOR;
typedef struct tagXMLIterator       *LPXMLITERFATOR;
typedef struct tagXMLIterator const *LPCXMLITERFATOR;

/*struct tagMemoryPage
{
LONG    lGranu ;
LONG    lSize;
LPVOID  pvPage;
BYTE    bUseFlags[1];
};
typedef struct tagMemoryPage        MEMORYPAGE;
typedef struct tagMemoryPage        *LPMEMORYPAGE;
typedef struct tagMemoryPage const  *LPCMEMORYPAGE;*/

//////////////////////////////
// Function prototypes

#if defined(__cplusplus)
extern “C” {
#endif

static void        XML_FreeNodeTree( LPXMLNODE pNode );
static void        XML_FreeAttribList( LPXMLATTRIB pAttrib );
static void     XML_IterateTree( LPXMLNODE pTree, LPXMLITERFATOR pIterator );
static BOOL     XMLCmpNode_EqualTag( LPCXMLNODE pNode, LPVOID pvParam );

static BOOL        Parser_RoutineStart( LPXMLPARSESTAT pParseStat, LPXMLDOCUMENT pResult );
static int        Parser_GetTagString( LPXMLPARSESTAT pParseStat, LPSTR lpszBuf );
static BOOL        Parser_ReadStream( LPXMLPARSESTAT pParseStat );
static void        Parser_OnInitial( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnElemBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnElemEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnTextBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnTextEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnCDATABegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnCDATAEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnCommBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnCommEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnDeclBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void        Parser_OnDeclEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static BOOL        Parser_OnFinal( LPXMLPARSESTAT pParseStat );
static BOOL        Parser_OnError( LPXMLPARSESTAT pParseStat );

//#if defined(USE_MEMORY_HEAP)
//static LPVOID   MemoryHeap_Create( LONG lInitialGranu, LONG lInitialSize );
//static BOOL     MemoryHeap_Destroy( LPVOID );
//static LPVOID   MemoryHeap_Alloc( void );
//static void     MemoryHeap_Free( LPVOID pvBlock );
//#endif

#if defined(__cplusplus)
}   // extern “C” {
#endif

//////////////////////////////
// Function implementations

#if defined(__cplusplus)
extern “C” {
#endif

/*********************************************************************\
* Function: strlen_when
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
size_t strlen_when( LPCSTR lpszStr, CHAR ch )
{
register size_t nLen;
assert( NULL != lpszStr );
for ( nLen = 0; *lpszStr != ch && *lpszStr != ‘\0′;    lpszStr++, nLen++ )
;
return nLen;
}

/*********************************************************************\
* Function: strlen_notin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
size_t strlen_notin( LPCSTR lpszStr, LPCSTR lpszSet )
{
register size_t nLen;
assert( NULL != lpszStr );
for ( nLen = 0; *lpszStr != ‘\0′ && NULL == strchr(lpszSet, *lpszStr); lpszStr++, nLen++ )
;
return nLen;
}

/*********************************************************************\
* Function: strchr_notin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPCSTR strchr_notin( LPCSTR lpszStr, LPCSTR lpszSet )
{
assert( NULL != lpszStr );
for ( ; *lpszStr != ‘\0′ && NULL == strchr(lpszSet, *lpszStr); lpszStr++ )
;
return lpszStr;
}

/*********************************************************************\
* Function: strchr_skipws
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPCSTR strchr_skipws( LPCSTR lpszStr )
{
assert( NULL != lpszStr );
for ( ; *lpszStr != ‘\0′ && is_WhiteSpace(*lpszStr); lpszStr++ )
;
return lpszStr;
}

/*********************************************************************\
* Function: AllocBString
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPBSTRING AllocBString( LPCSTR lpszStr, LONG lLen )
{
LPBSTRING pBStr = (LPBSTRING)malloc( sizeof(LONG) + lLen + 1 );
assert( NULL != pBStr );

pBStr->m_lLength = lLen;
strncpy( &pBStr->m_paStr[0], lpszStr, lLen );
pBStr->m_paStr[lLen] = ‘\0′;

return pBStr;
}

/*********************************************************************\
* Function: XML_OpenDocument
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
XMLERR XML_OpenDocument( LPXMLDOCUMENT pDoc, LPCSTR lpszFileName, DWORD dwReserve )
{
BOOL            bRet;
FILE_HANDLE        hFile;
XMLPARSESTAT    xmlParseStat;

assert( NULL != pDoc );
assert( NULL != lpszFileName );

if ( pDoc->m_eDocStat == DSTAT_OPENED )
return XMLERR_ALRDOPEN;

ZERO_MEMORY( &xmlParseStat, sizeof(XMLPARSESTAT) );

hFile = FILE_OPEN( lpszFileName, MODE_RDONLY );
if ( INVALID_FILE_HANDLE == hFile )
return XMLERR_EFILE;

xmlParseStat.m_hOpenFile    = hFile;
xmlParseStat.m_lFileCursor    = 0;
xmlParseStat.m_lFileLength    = FILE_SEEK( hFile, 0, SEEK_END );
FILE_SEEK( hFile, 0, SEEK_SET );

xmlParseStat.m_lDepth = 0;
xmlParseStat.m_lLineNo = 1;
bRet = Parser_RoutineStart( &xmlParseStat, pDoc );
if ( FALSE == bRet )
{
FILE_CLOSE( hFile );
return XMLERR_EPARSE;
}

pDoc->m_eDocStat    = DSTAT_OPENED;
pDoc->m_lpRootNode    = xmlParseStat.m_pRootNode;
FILE_CLOSE( hFile );
return XMLERR_OK;
}

/*********************************************************************\
* Function: XML_CloseDocument
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
XMLERR XML_CloseDocument( LPXMLDOCUMENT pDoc )
{
if ( NULL != pDoc && pDoc->m_eDocStat == DSTAT_OPENED )
{
XML_FreeNodeTree( pDoc->m_lpRootNode );
pDoc->m_lpRootNode = NULL;
pDoc->m_eDocStat = DSTAT_UNOPEN;
}
return XMLERR_OK;
}

/*********************************************************************\
* Function: Parser_GetTagString
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
int Parser_GetTagString( LPXMLPARSESTAT pParseStat, LPSTR lpszBuf )
{
int        nLen;
CHAR    ch;
CHAR    chTerm;
BOOL    bInclude;

// Should to ensure barket match Here!

nLen = 0;
for ( ;; )
{
if ( is_BufferEmpty(pParseStat) && FALSE == Parser_ReadStream(pParseStat) )
goto __RET;

ch = get_BufferChar(pParseStat);
if ( ch == ‘\n’ )
pParseStat->m_lLineNo++;

if ( !is_WhiteSpace(ch) && !is_LineBreak(ch) )
break;

pParseStat->m_lReadCursor++;
}

if ( is_LeftBracket(ch) )
{
chTerm = ‘>’;
bInclude = TRUE;
}
else
{
chTerm = ‘<’;
bInclude = FALSE;
}

for ( ;; )
{
if ( is_BufferEmpty(pParseStat) && FALSE == Parser_ReadStream(pParseStat) )
break;

ch = get_BufferChar(pParseStat);
if ( ch == ‘\n’ )
pParseStat->m_lLineNo++;

if ( ch == chTerm )
{
if ( FALSE != bInclude )
{
lpszBuf[nLen++] = chTerm;
pParseStat->m_lReadCursor++;
}
break;
}

lpszBuf[nLen++] = ch;
pParseStat->m_lReadCursor++;
}

__RET:
lpszBuf[nLen] = ‘\0′;
return nLen;
}

/*********************************************************************\
* Function: Parser_ReadStream
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_ReadStream( LPXMLPARSESTAT pParseStat )
{
size_t    nSize;

pParseStat->m_lReadCursor    = 0;
pParseStat->m_lReadSize    = 0;
nSize = FILE_READ( pParseStat->m_hOpenFile, (LPVOID)&pParseStat->m_aReadBuf[0], MAXLEN_READBUF );
if ( nSize <= 0 )
return FALSE;

pParseStat->m_lReadSize        = (LONG)nSize;
pParseStat->m_lFileCursor  += (LONG)nSize;
return TRUE;
}

/*********************************************************************\
* Function: Parser_RoutineStart
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_RoutineStart( LPXMLPARSESTAT pParseStat, LPXMLDOCUMENT pResult )
{
BOOL    bRet;
CHAR    szTag[256];

assert( NULL != pParseStat );

pParseStat->m_eParseStat = PSTAT_INITIAL;
while ( pParseStat->m_eParseStat != PSTAT_STOP )
{
switch ( pParseStat->m_eParseStat )
{
case PSTAT_INITIAL:     Parser_OnInitial( pParseStat, &szTag[0] );        break;

case PSTAT_DECL_BEG:    Parser_OnDeclBegin( pParseStat, &szTag[0] );    break;
case PSTAT_DECL_END:    Parser_OnDeclEnd( pParseStat, &szTag[0] );        break;

case PSTAT_ELEM_BEG:    Parser_OnElemBegin( pParseStat, &szTag[0] );    break;
case PSTAT_ELEM_END:    Parser_OnElemEnd( pParseStat, &szTag[0] );      break;

case PSTAT_TEXT_BEG:    Parser_OnTextBegin( pParseStat, &szTag[0] );    break;
case PSTAT_TEXT_END:    Parser_OnTextEnd( pParseStat, &szTag[0] );        break;

case PSTAT_CDATA_BEG:    Parser_OnCDATABegin( pParseStat, &szTag[0] );    break;
case PSTAT_CDATA_END:    Parser_OnCDATAEnd( pParseStat, &szTag[0] );        break;

case PSTAT_COMM_BEG:    Parser_OnCommBegin( pParseStat, &szTag[0] );    break;
case PSTAT_COMM_END:    Parser_OnCommEnd( pParseStat, &szTag[0] );        break;

case PSTAT_FINAL:        bRet = Parser_OnFinal( pParseStat );            break;
case PSTAT_ERROR:        bRet = Parser_OnError( pParseStat );            break;

default:
assert( !”Unknown parsing status!” );
break;
}
}
return bRet;
}

/*********************************************************************\
* Function: Parser_OnInitial
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnInitial( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
int     nLen;
assert( NULL != lpszTag );

lpszTag[0] = ‘\0′;

nLen = Parser_GetTagString( pParseStat, lpszTag );
if ( nLen <= 0 )
{
pParseStat->m_eParseStat = PSTAT_STOP;
return;
}

if ( lpszTag[0] == ‘<’  )
{
if ( lpszTag[1] == ‘?’)
{
pParseStat->m_eParseStat = PSTAT_DECL_BEG;
}
else if ( !strncmp(&lpszTag[1], “!–”, 3) )
{
pParseStat->m_eParseStat = PSTAT_COMM_BEG;
}
else if ( lpszTag[1] == ‘/’ )
{
pParseStat->m_eParseStat = PSTAT_ELEM_END;
}
else if ( isalpha(lpszTag[1]) )
{
pParseStat->m_eParseStat = PSTAT_ELEM_BEG;
}
else if ( !strncmp(&lpszTag[1], “![CDATA[", 8) )
{
pParseStat->m_eParseStat = PSTAT_CDATA_BEG;
}
else
{
pParseStat->m_eParseStat = PSTAT_ERROR;
}
}
else if ( NULL != pParseStat->m_pLastNode )
{
pParseStat->m_eParseStat = PSTAT_TEXT_BEG;
}
else
{
pParseStat->m_eParseStat = PSTAT_ERROR;
}
}

/*********************************************************************\
* Function: Parser_OnFinal
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_OnFinal( LPXMLPARSESTAT pParseStat )
{
pParseStat->m_eParseStat = PSTAT_STOP;
return TRUE;
}

/*********************************************************************\
* Function: Parser_OnError
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_OnError( LPXMLPARSESTAT pParseStat )
{
XML_FreeNodeTree( pParseStat->m_pRootNode );
pParseStat->m_pRootNode     = NULL;
pParseStat->m_eParseStat = PSTAT_STOP;
TRACE( "[ ]: Syntax error @ %s #%ld.\n”, “”, pParseStat->m_lLineNo);
return FALSE;
}

/*********************************************************************\
* Function: Parser_OnDeclBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnDeclBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
int nLenTag;

if ( NULL != pParseStat->m_pRootNode )
{
pParseStat->m_eParseStat = PSTAT_ERROR;
return;
}

lpszTag = (LPSTR)strchr_skipws( (LPCSTR)(lpszTag + 2) );
if ( lpszTag == ‘\0′ )
{
pParseStat->m_eParseStat = PSTAT_ERROR;
return;
}

nLenTag = (int)strlen_notin(lpszTag, ” \t\r\n>”);
if ( nLenTag == 3 && !strncmp(lpszTag, “”, 3) )
{
// Here, dispose version and coding infomation in document header
}
else if ( nLenTag == 14 && !strncmp(lpszTag, “-stylesheet”, 3) )
{
// Unsupport
}
else
{
// Unknown declaretion
}

pParseStat->m_eParseStat = PSTAT_INITIAL;
}

/*********************************************************************\
* Function: Parser_OnDeclEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnDeclEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
// Do noting
}

/*********************************************************************\
* Function: Parser_OnElemBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnElemBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
int         nLenTag;
int         nLenValue;
LPSTR       lpszValue;
LPXMLNODE   pNode;
LPXMLATTRIB    pAttrib;
LPXMLATTRIB pPrevAttr;

assert( is_LeftBracket(lpszTag[0]) );

// Multi-root node is not supproted
if ( 0 == pParseStat->m_lDepth && NULL != pParseStat->m_pRootNode )
goto __ERROR;

pNode = (LPXMLNODE)malloc(sizeof(XMLNODE));
if ( NULL == pNode )
goto __ERROR;

ZERO_MEMORY( pNode, sizeof(XMLNODE) );
pNode->m_eNodeType    = NODETYPE_ELEM;
pNode->m_lDepth        = pParseStat->m_lDepth;
if ( NULL != pParseStat->m_pLastNode )
{
assert( pNode->m_lDepth >= pParseStat->m_pLastNode->m_lDepth );
if ( pNode->m_lDepth > pParseStat->m_pLastNode->m_lDepth ) // new child
{
pNode->m_pParent = pParseStat->m_pLastNode;
pParseStat->m_pLastNode->m_pFirstChild = pNode;
}
else if ( pNode->m_lDepth == pParseStat->m_pLastNode->m_lDepth ) // new sibling
{
pNode->m_pParent = pParseStat->m_pLastNode->m_pParent;
pParseStat->m_pLastNode->m_pNextSibling = pNode;
pNode->m_pPrevSibling = pParseStat->m_pLastNode;
}

if ( NULL != pNode->m_pParent )
{
pNode->m_pParent->m_lChildNum++;
pNode->m_pParent->m_lChildNum_Elem++;
}
}

if ( NULL == pParseStat->m_pRootNode )
{
pParseStat->m_pRootNode = pNode;
}
pNode->m_pRoot = pParseStat->m_pRootNode;

pParseStat->m_pLastNode    = pNode;

lpszTag++;
nLenTag = (int)strlen_notin(lpszTag, ” \t\r\n>”);
if ( nLenTag <= 0 )
goto __ERROR;

pNode->m_pbstrTag = BSTR_ALLOCEX(lpszTag, nLenTag);
if ( NULL == pNode->m_pbstrTag )
goto __ERROR;

lpszTag = (LPSTR)(lpszTag + nLenTag);

for ( pPrevAttr = NULL;; )
{
lpszTag = (LPSTR)strchr_skipws( lpszTag );

if ( is_RightBracket(*lpszTag) )
{
pParseStat->m_lDepth++; // Move down one layer
pParseStat->m_eParseStat = PSTAT_INITIAL;
break;
}
else if ( !strncmp(lpszTag, “/>”, 2) )
{
//pParseStat->m_lDepth–; //
pParseStat->m_eParseStat = PSTAT_INITIAL;
break;
}

nLenTag = (int)strlen_when( lpszTag, ‘=’ );
if ( nLenTag <= 0 )
goto __ERROR;

lpszValue = strchr( (LPCSTR)(lpszTag + nLenTag), ‘\”‘ );
if ( NULL == lpszValue )
goto __ERROR;

lpszValue++;
nLenValue = (int)strlen_when( lpszValue, ‘\”‘ );

//if ( nLenValue <= 0 )
//    goto __ERROR;

pAttrib = (LPXMLATTRIB)malloc(sizeof(XMLATTRIB));
if ( NULL == pAttrib )
goto __ERROR;
ZERO_MEMORY( pAttrib, sizeof(XMLATTRIB) );

pAttrib->m_pbstrName    = BSTR_ALLOCEX( lpszTag, nLenTag );
pAttrib->m_pbstrValue    = BSTR_ALLOCEX( lpszValue, nLenValue );
if ( NULL == pAttrib->m_pbstrName || NULL == pAttrib->m_pbstrValue )
goto __ERROR;

if ( NULL == pNode->m_pFirstAttrib )
pNode->m_pFirstAttrib = pAttrib;

if ( NULL != pPrevAttr )
pPrevAttr->m_pNext = pAttrib;
pPrevAttr = pAttrib;

pNode->m_lAttribNum++;
lpszTag = lpszValue + nLenValue + 1;
}

return;

__ERROR:
XML_FreeNodeTree( pNode );
pParseStat->m_eParseStat = PSTAT_ERROR;
}

/*********************************************************************\
* Function: Parser_OnElemEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnElemEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
pParseStat->m_lDepth–;

if ( NULL != pParseStat->m_pLastNode )
{
if ( NULL != pParseStat->m_pLastNode->m_pParent )
pParseStat->m_pLastNode->m_pParent->m_pLastChild = pParseStat->m_pLastNode;

if ( pParseStat->m_pLastNode->m_lDepth > pParseStat->m_lDepth )
pParseStat->m_pLastNode = pParseStat->m_pLastNode->m_pParent;
}

if ( 0 == pParseStat->m_lDepth )
pParseStat->m_eParseStat = PSTAT_FINAL;
else
pParseStat->m_eParseStat = PSTAT_INITIAL;
}

/*********************************************************************\
* Function: Parser_OnTextBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnTextBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
LPXMLNODE pNode;

pNode = (LPXMLNODE)malloc(sizeof(XMLNODE));
if ( NULL == pParseStat->m_pLastNode )
goto __ERROR;

ZERO_MEMORY( pNode, sizeof(XMLNODE) );
pNode->m_eNodeType    = NODETYPE_TEXT;
pNode->m_lDepth        = pParseStat->m_lDepth;

if ( NULL != pParseStat->m_pLastNode )
{
assert( pNode->m_lDepth >= pParseStat->m_pLastNode->m_lDepth );
if ( pNode->m_lDepth > pParseStat->m_pLastNode->m_lDepth )
{
pNode->m_pParent = pParseStat->m_pLastNode;
pParseStat->m_pLastNode->m_pFirstChild = pNode;
}
else if ( pNode->m_lDepth == pParseStat->m_pLastNode->m_lDepth )
{
pNode->m_pParent = pParseStat->m_pLastNode->m_pParent;
pParseStat->m_pLastNode->m_pNextSibling = pNode;
pNode->m_pPrevSibling = pParseStat->m_pLastNode;
}

if ( NULL != pNode->m_pParent )
pNode->m_pParent->m_lChildNum++;

pNode->m_pRoot = pParseStat->m_pLastNode->m_pRoot;
}

pParseStat->m_pLastNode    = pNode;

pNode->m_pbstrTag = BSTR_ALLOC(lpszTag);
if ( NULL == pNode->m_pbstrTag )
goto __ERROR;

pParseStat->m_lDepth++; // Move down one layer
pParseStat->m_eParseStat = PSTAT_TEXT_END;
return;

__ERROR:
XML_FreeNodeTree( pNode );
pParseStat->m_eParseStat = PSTAT_ERROR;
}

/*********************************************************************\
* Function: Parser_OnTextEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnTextEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
// Move up one layer
pParseStat->m_lDepth–;

if ( NULL != pParseStat->m_pLastNode &&
pParseStat->m_pLastNode->m_lDepth > pParseStat->m_lDepth )
pParseStat->m_pLastNode = pParseStat->m_pLastNode->m_pParent;

pParseStat->m_eParseStat = PSTAT_INITIAL;
}

/*********************************************************************\
* Function: Parser_OnCommBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCommBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
pParseStat->m_eParseStat = PSTAT_INITIAL;
}

/*********************************************************************\
* Function: Parser_OnCommEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCommEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
}

/*********************************************************************\
* Function: Parser_OnCDATABegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCDATABegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
pParseStat->m_eParseStat = PSTAT_INITIAL;
// Should convert to text here
}

/*********************************************************************\
* Function: Parser_OnCDATAEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCDATAEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
}

/*********************************************************************\
* Function: XML_IterateTree
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void XML_IterateTree( LPXMLNODE pTree, LPXMLITERFATOR pIterator )
{
register ITERSTAT eStat;
if ( NULL != pTree )
{
pIterator->m_pStation = pTree;
eStat = pIterator->m_pfnProc( pTree, pIterator->m_pvParam );
if ( eStat == ISTAT_STOP )
return;
if ( eStat != ISTAT_PASS )
pIterator->m_lCount++;

XML_IterateTree( pTree->m_pFirstChild, pIterator );
XML_IterateTree( pTree->m_pNextSibling, pIterator );
}
}

/*********************************************************************\
* Function: XML_ForEachNode
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LONG XML_ForEachNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPFNNODEPROC pfnNodeProc, LPVOID pvParam )
{
XMLITERFATOR    iter;

assert( NULL != pDoc );
assert( NULL != pfnNodeProc );

if ( pDoc->m_eDocStat == DSTAT_UNOPEN || (NULL != pStartPoint && pStartPoint->m_pRoot != pDoc->m_lpRootNode) )
return 0;

iter.m_lCount   = 0;
iter.m_pStation = NULL;
iter.m_pvParam  = pvParam;
iter.m_pfnProc  = pfnNodeProc;

pStartPoint = (NULL == pStartPoint ? pDoc->m_lpRootNode : pStartPoint);
XML_IterateTree( pStartPoint, &iter );
return iter.m_lCount;
}

/*********************************************************************\
* Function: XMLCmpNode_EqualTag
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
ITERSTAT XMLCmpNode_EqualTag( LPCXMLNODE pNode, LPVOID pvParam )
{
if ( FALSE != BSTR_EQUAL(pNode->m_pbstrTag, BSTR_CAST(pvParam)) )
return ISTAT_STOP;
else
return ISTAT_CONTINUE;
}

/*********************************************************************\
* Function: XML_GetNode
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPXMLNODE XML_GetNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPCSTR lpszTag, LONG lLen )
{
BSTRING         bStr;
XMLITERFATOR    iter;

assert( NULL != lpszTag );
assert( NULL != pDoc );

if ( pDoc->m_eDocStat == DSTAT_UNOPEN || pStartPoint->m_pRoot != pDoc->m_lpRootNode )
return NULL;

bStr.m_lLength  = lLen;
bStr.m_pszStr   = lpszTag;

iter.m_lCount   = 0;
iter.m_pfnProc  = &XMLCmpNode_EqualTag;
iter.m_pStation = NULL;
iter.m_pvParam  = (LPVOID)&bStr;

pStartPoint = (NULL == pStartPoint ? pDoc->m_lpRootNode : pStartPoint);
XML_IterateTree( pStartPoint, &iter );
return (iter.m_pStation);
}

/*********************************************************************\
* Function: XML_GetNodeAttrib
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPXMLATTRIB    XML_GetNodeAttrib( LPXMLNODE pNode, LPCSTR lpszAttr, LONG lLen )
{
BSTRING     bStr;
LPXMLATTRIB pAttrib;

assert( NULL != lpszAttr );
assert( NULL != pNode );
bStr.m_lLength  = lLen;
bStr.m_pszStr   = lpszAttr;

for ( pAttrib = XML_GetNodeFirstAttrib(pNode); NULL != pAttrib; pAttrib = XML_GetNodeNextAttrib(pAttrib) )
{
if ( FALSE != BSTR_EQUAL(pAttrib->m_pbstrName, &bStr) )
break;
}

return pAttrib;
}

/*********************************************************************\
* Function: XML_GetNodeSibling
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPXMLNODE XML_GetNodeSibling( LPXMLNODE pNode, LPCSTR lpszTag, LONG lLen, BOOL bIncludeThis )
{
BSTRING     bStr;

assert( NULL != lpszTag );
assert( NULL != pNode );
bStr.m_lLength  = lLen;
bStr.m_pszStr   = lpszTag;

if ( FALSE != bIncludeThis && FALSE != BSTR_EQUAL(pNode->m_pbstrTag, &bStr) )
return pNode;

for ( pNode = XML_GetNodeNextSibling(pNode); NULL != pNode; pNode = XML_GetNodeNextSibling(pNode) )
{
if ( FALSE != BSTR_EQUAL(pNode->m_pbstrTag, &bStr) )
break;
}

return pNode;
}

/*********************************************************************\
* Function: XML_FreeNodeTree
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void XML_FreeNodeTree( LPXMLNODE pNode )
{
if ( NULL != pNode )
{
BSTR_FREE( pNode->m_pbstrTag );

XML_FreeAttribList( pNode->m_pFirstAttrib );

if ( is_FirstChild(pNode) && NULL != pNode->m_pParent )
pNode->m_pParent->m_pFirstChild = pNode->m_pNextSibling;

if ( NULL != pNode->m_pNextSibling )
pNode->m_pNextSibling->m_pPrevSibling = pNode->m_pPrevSibling;
if ( NULL != pNode->m_pPrevSibling )
pNode->m_pPrevSibling->m_pNextSibling = pNode->m_pNextSibling;

XML_FreeNodeTree( pNode->m_pFirstChild );
XML_FreeNodeTree( pNode->m_pNextSibling );

free( pNode );
}
}

/*********************************************************************\
* Function: XML_FreeAttribList
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void XML_FreeAttribList( LPXMLATTRIB pAttrib )
{
LPXMLATTRIB pNext;

while ( NULL != pAttrib )
{
pNext = pAttrib->m_pNext;
BSTR_FREE( pAttrib->m_pbstrName );
BSTR_FREE( pAttrib->m_pbstrValue );
free( pAttrib );
pAttrib = pNext;
}
}

#if defined(__cplusplus)
}   // extern “C” {
#endif