pplive for ubuntu linux
Posted: August 6, 2009 at 7:22 pm | Tags: class, flash, linux, 平台看到这条新闻有点唏嘘,多年以前做视频网站时和领导们聊过,为什么不去研究跨平台客户端,本地框架P2P Client + flash 在当时已经可以实现了……

看到这条新闻有点唏嘘,多年以前做视频网站时和领导们聊过,为什么不去研究跨平台客户端,本地框架P2P Client + flash 在当时已经可以实现了……

这个游戏太棒了,RTS + FPS ,并且还是跨 win , linux , mac 三个平台,并且还免费。爽~~~~
RTS 模式
FPS 模式
转载自http://android.hk.cn
本文将用老谋深算的Symbian平台、历史悠久的Windows Mobile平台、玲珑剔透的Mac OS X平台、前景光明的Android平台四个章节对目前市面上主流手机操作系统的优势和特色做一个详细的介绍。
老谋深算的Symbian平台
随着科技和信息技术的发展,人们对手机功能的要求也越来越高。现在,很多人对手机已不仅仅满足于打电话和发短信等基本功能,而是要求它能够播放音乐、上网聊天、安排日程甚至进行GPS导航。因此,很多人已经逐步抛弃传统固化软件的手机,改投智能手机的怀抱。目前,在智能手机市场上,销量最大的平台有三种,分别是Symbian、Windows Mobile和Mac OS X,其中前两种都有一种以上的手机品牌在使用,而Mac OS X仅为苹果iPhone和iPhone 3G独占使用。现在,基于Google Android平台的新一代智能手机T-Mobile G1马上就要上市,它几乎无可非议的会受到人们的追捧。这样一来,市场上便形成了四大智能手机操作平台鼎立的局面。
Symbian(塞班)
首先要提到的当然是Symbian(塞班)系统。使用在智能手机上的Symbian系统分为S60和UIQ两种用户界面,其中前者现已发展到v3版本。得益于世界手机老大诺基亚的大力支持,安装了Symbian S60系统的手机已经广为人们使用。而UIQ的主推者是索尼爱立信,虽然UIQ的界面更加华丽,但由于索尼爱立信自身和手机市场的原因,Symbian UIQ一直没有能够得到很好的发展。
由于Symbian由多家传统手机厂商联合研发,因此无论在运行速度还是易用性上跟其它的系统相比都有很大的优势,而且对移动通信协议,如GSM、GPRS、WCDMA和蓝牙等的支持要优于其它系统。由于发布时间较早,其第三方软件经过几年的发展数量已经非常之多,可以实现人们的大多数需求。
但遗憾的是,由于系统的先天限制,Symbian系统的多媒体性能并不突出。刷固件较为困难、内存紧张等问题是一直是人们所诟病的几大缺憾。S60 v3发布后诺基亚开始推行的签名策略也浇灭了很多人开发第三方软件的热情。而且,Symbian系统实现触摸操作相当困难,好在诺基亚拥有强大的研发实力。相信继5800 XpressMusic之后,诺基亚还会继续推出触摸屏机型。不过尽管如此,Symbian平台凭着强大的电话功能和较强的易用性,仍然博得了很多人的青睐。
历史悠久的Windows Mobile平台
Windows Mobile
作为微软下了血本研发的一个操作平台,Windows Mobile系统自然丝毫不能被轻视。Windows Mobile的前身是Windows CE,一个微软专为PDA和掌上电脑开发的嵌入式系统。后来随着智能手机的出现,Windows CE演变成了Windows Pocket PC。2003年,微软又开发了Pocket Phone Edition和Windows Powered Smart Phone操作系统,而这两者的融合,才是严格意义上的Windows Mobile。
目前,Windows Mobile最高版本为6.1。它最大的优势在于其PDA(个人数字助理)功能非常强大,并可通过ActiveSync或Windows Mobile Center和计算机中Outlook等程序保持同步,商务人士可使用该系统随时处理文件、邮件或进行日程安排。由于这个系统的历史非常悠久,和桌面版Windows系统也有异曲同工之处,其第三方软件的数量已经多到了一个令人难以想象的地步。通过各种第三方软件,安装了Windows Mobile系统的手机可以发挥几乎无限的用途。对于软件开发者来说,由于Windows Mobile系统的软件开发较为简单,再加上新版系统中增加了对.Net Framework的支持,使软件的开发相当便利。而对于最终用户来说,Windows Mobile系统的操作方式跟桌面版Windows非常类似,都有开始菜单等人们所熟悉的组件,熟悉计算机的人可以很快上手使用。
但Windows Mobile系统的缺陷也是显而易见的。按照通常的说法,它有着三大缺陷。其一是系统运行速度太慢。或许是微软往小小的系统中塞了很多东西,Windows Mobile也延续了Windows系统庞大臃肿的毛病,几乎可以算得上是反应最慢的智能手机操作系统。其二是支持的颜色数仅为65000色。关于这个问题很多年前人们就开始抱怨,到现在还是如此。不知道微软为什么不听听群众们的呼声。其三是系统操作过于复杂。它的很多设置都隐藏在层层菜单和选项下,有时甚至还需动用注册表修改器,仍然继承了桌面版Windows的传统。虽然这可能正好满足了少数人的“变态”控制欲。
但是总的来说,Windows Mobile以其强大的功能、便捷的信息管理以及第三方软件众多等优势,一直以来都为世人所喜爱。当然,更重要的是它还有微软这样一个重量级的后盾。可以说,只要微软不倒,Windows Mobile也将一直生存下去。
玲珑剔透的Mac OS X平台
Mac OS X
苹果的iPhone手机自从公布的那天起便一直受到人们的关注,现在的iPhone 3G也是如此。iPhone使用的操作系统为精简过的Mac OS X,最高版本为2.1,其很多特性与完整版的Mac OS X相类似。该系统使用的内核基于BSD Unix,具有抢占式多任务处理(pre-emptive multitasking)的特性。其内存管理功能非常优秀,具有强烈的Unix风格,允许同时运行很多软件,并从实质上消除了一个程序崩溃导致其它程序崩溃的可能性。
iPhone的Mac OS X系统更多的优势来自于与iTunes服务的紧密紧密。iTunes原先仅是一个媒体播放软件,后来当iPod和iPhone发布后,iTunes逐渐演变为苹果在Mac和Windows系统上的一个无穷无尽的媒体源。人们可以通过iTunes登录到苹果的在线商店,购买各种音乐、视频或程序。这也成为苹果的一个新的盈利增长点。
虽然iPhone和iPhone 3G的Mac OS X系统已被大大精简,但在苹果计算机的Mac OS X系统中广为人们熟知的Dock和Aqua等关键元素仍然存在。更重要的是,人们可以在安装特定程序后进入Unix命令行进行各种操作,并对系统底层进行控制。此时iPhone已不再是一台手机,它更像是台超便携的苹果电脑,能够处理很多普通人所意想不到的事情。
不久以前,苹果为iPhone和iPod Touch开放了App Store应用程序商店。手机用户可通过信用卡在商店中购买自己喜欢的程序,而开发者也能通过App Store发布自己编写的程序,其收益与苹果七三分成。苹果的这个创新构思马上得到了人们的响应,短短几个月的时间App Store中的程序便达到了惊人的数量。
前景光明的Android平台
Android
文章最后要提到的当然是本专题的主角——Google Android平台。Android 是一个真正意义上的开放性移动设备平台。它包括操作系统、用户界面和应用程序等移动电话工作所需的全部组件,而且不存在任何以往阻碍移动产业创新的专有权障碍。
说到Android,便不能不提OHA(Open Handset Alliance)开放手机联盟。去年,Google与包括中国移动、英特尔、摩托罗拉、高通在内的33家业内巨头成立了该组织,这个联盟将共同推动Google手机平台Android的发展。Android作为Google企业战略的重要组成部分,将进一步推进“随时随地为每个人提供信息”这一企业目标的实现。
跟iPhone相比,Android平台同样也拥有自己的在线应用程序商店,名为Android Market。这个在线商店仅需进行简单的注册后便可以自由上传程序。虽然这可能导致一些安全问题,但总的来说这种开放式的平台非常有利于第三方软件的发展。而Google在对这些软件进行幕后审查的同时,也采取了多项措施,最大限度的保证了软件开发者的利益。
Android与前面三种系统相比最大的特点在于其开放性。这里所指的开放性包括两个方面,其一是Android以开源Linux系统为基础,对于开源爱好者而言,他们会觉得Android平台更能满足自己的使用需求。其二是Android对第三方软件的开放程度。Google不会对Android系统的第三方应用程序像苹果那样严格把关,而仅是在用户自行发布之后进行审查。这样一来必将极大的促进该系统第三方软件的发展。
而就基于Android的第一款手机T-Mobile G1来说,其最不能令人忍受的缺陷恐怕就是没有3.5mm耳机插孔了。另外,由于T-Mobile背后使下的“阴招”,用户在用完1GB流量后带宽便会自动下降为50Kbps,这将大大影响人们的购买欲望。而且,Android系统目前还没有桌面同步软件,也不支持Exchange同步。虽然Google的很多在线服务都可以满足人们的需要,但总有上不了网的时候。况且,很多信息保存在计算机中要安全得多。
四款主流或将要成为主流的智能手机操作平台到这里就介绍完了。俗话说的好,尺有所短,寸有所长,每个平台都有其各自的优点和不足。大家在选择智能手机的时候,需要关注的重点是各种平台的侧重点,这样在今后的使用中才会得心应手。至于该如何选择,相信大家心中都已经有数了吧。
易观国际联合17173.com共同发起的网页游戏在线调研,根据在线调研有效回收样本分析并撰写的《中国网页游戏市场用户调研报告2008》中指出,玩家在对网页游戏各项指标的评价中:对“游戏活动”和“客服质量”表示“非常不满意”的分别达到了10.9%和11.7%。

易观国际认为主要原因是,在“赚快钱”的驱动下,很多运营商仓促的上线一些网页游戏。但是由于自身资源匮乏,缺乏资金、渠道,且缺乏运营经验,在运营过程中对玩家需求的反馈及玩家利益的保障做的很不够,大大影响了玩家的游戏体验。
在泛娱乐时代,玩家可以选择的娱乐项目已经非常多,网页游戏如果始终无法满足用户的体验,用户将很有可能流失到其他游戏或者其他的娱乐项目,例如传统的MMORPG或者休闲网络游戏等,这将非常不利于行业的发展。易观建议网页游戏运营商应从内部运营、客服等多个方面入手提升自身能力。
研究定义
网络游戏:网络游戏是一种依托于网络,可同时多人参与的电子游戏。它通过人与人之间的互动、对抗,达到交流、娱乐和休闲的目的。本报告中所指的网络游戏,特指以互联网为游戏平台,以PC为终端的网络游戏。
网页游戏:Web game,又称无端网游,是基于网络浏览器的多人在线互动游戏,用户无需下载客户端,只要打开网页就可以玩网页游戏。目前国内的网页游戏以战争策略类的为主,例如《纵横天下》、《部落战争》等。
MMORPG:Massive Multiplayer Online Role Playing Games,大型多人角色扮演游戏。用户在游戏创建并扮演一个虚拟角色,在一个模拟现实的虚拟世界游戏背景中与其他角色进行互动。MMORPG一般具有三大特点:(1)多人(往往几千上万人)同时参与一个游戏;(2)游戏是可持续发展的;(3)游戏具有显著的社会性和社区型。
休闲游戏:休闲游戏一般都有卡通风格,内容较为轻松,游戏连续性不强,且每局游戏的时间较短,对用户来说更多是一种操作技巧的较量。
虚拟物品:指游戏中的虚拟道具、装备等。玩家购买虚拟物品一般是为了提升游戏中的技能或通过使用虚拟物品提升游戏的趣味性。
研究方法:
本次调查数据通过网上联机问卷,问卷放置在17173.com网站上,由用户主动参与填写的方式获取。本次调查共回收有效问卷6074份,对于回收的有效数据通过统计分析软件SPSS进行数据分析处理,并在此基础上撰写研究报告。
欲了解中国网页游戏市场用户更多相关内容,请参阅易观国际《中国网页游戏市场用户调研报告2008》或联系易观国际客户服务部。
研究说明:
易观国际提供的产业分析,主要是在产业宏观数据、最终用户季度调研数据、厂商历史数据以及厂商季度业务监测信息等基础上,运用易观的产业分析模型,并结合市场研究、行业研究以及厂商研究方法得出的,主要反映了市场现状、趋势、拐点和规律,以及厂商的发展现状。
易观国际相信通过上述产业研究方法得出的数据在行业公认可接受误差范围内,可以准确反映行业走势与变化规律。
通过专业研究方法得到的研究结果,旨在供决策参考。厂商的实际数据请查询厂商发布的财务报告。
相关搜索
Google是与众不同的。它的独特不仅仅表现于革新的思维和充满创意的应用 (比如那个大堂里的地球模型),更在于其有别常规的IT策略……
加利福尼亚州山景城(Mountain View)Google公司(Google,下称Google)总部有一个43号大楼,该建筑的中央大屏幕上显示着一个与Google地球(Google Earth)相仿的世界地图,一个转动的地球上不停地闪动着五颜六色的光点,恍如罗马宫廷的千万烛灯,每一次闪动标志着地球的这个角落一名Google用 户发起了一次新的搜索。
这同时意味着Google又一次满足了人们对未知信息的好奇与渴望。
Google是与众不同的。它的独特不仅仅表现于革新的思维和充满创意的应用 (比如那个大堂里的地球模型),更在于其有别常规的IT策略。从人们的常理来看,简单的硬件商品和免费软件是无法构建出一个帝国的,但是Google做到 了。在性能调整后,Google把它们变成一个无可比拟的分布式计算平台,该平台能够支持大规模的搜索和不断涌现的新兴应用。我们原本认为这些应用都是个 人消费级别的,但是Google改变了这一切。现在商业世界也在使用它们,这就令这家搜索公司显得那么与众不同。
GoogleWeb 服务背后的IT架构对无数使用搜索引擎的用户来说也许并不是非常重要,但它是Google几百位致力于把全球信息组织起来,实现“随处可达,随时可用”目 标的工程师们的最核心工作。这就需要一个在覆盖范围和野心上都与Google的商业愿景完全相符的IT蓝图作为支撑。
Google 的经理们一直对公司的IT策略话题保持沉默,他们厌恶谈及特定的厂商或者产品,当被问到他们的服务器和数据中心时,他们总是闭口不谈。但与几位 Google的IT领导一起呆了一天后,我们最终得以揭示该公司的IT是如何运作的,那可不仅仅是一个运行在无数服务器集群上的、表面看来非常简单的搜索 引擎。在其简单的外表下,蕴涵着许多内部研发软件、定制硬件、人工智能,以及对性能的执着追求和打破常规的人力管理模式。
IT理念方面,Google对同行有一条建议:尽量避免那些人人都在使用的系统和软件,以自己的方式做事会更有独特的竞争优势。
“企业文化决定了你的做事方式。”道格拉斯”美林(Douglas Merrill),这位Google工程副总裁和事实上的首席信息官(CIO) 指出,“到了我们这样的发展阶段,企业观念和文化非常与众不同,这也反过来鞭策我们必须要采用与众不同的方式来运行那些他人看来很常规的系统。”
Google 最大的IT优势在于它能建造出既富于性价比(并非廉价)又能承受极高负载的高性能系统。因此IT顾问史蒂芬”阿诺德(Stephen Arnold)指出,Google与竞争对手,如亚马逊网站(Amazon)、电子港湾公司(eBay)、微软公司(Microsoft,下称微软)和雅 虎公司 (Yahoo,下称雅虎)等公司相比,具有更大的成本优势。Google程序员的效率比其他Web公司同行们高出50%~100%,原因是Google已 经开发出了一整套专用于支持大规模并行系统编程的定制软件库。据他估算,其他竞争公司可能要花上四倍的时间才能获得同等的效果。
打造服务器
Google 究竟是怎样做到这点的呢?其中一个手段,美林认为,“是因为我们自己动手打造硬件。”Google并不制造计算机系统,但它根据自己的参数定制硬件,然后 像MTV的节目“靓车打造”(Pimp My Ride)那样自己安装和调整硬件系统。开源程序经理克里斯”迪博纳(Chris DiBona)评论道:“我们很善于购买商业服务器,并且改造他们为我们所用,最后把性能压榨和发挥到极致,以致有时候他们热得像要融化了似的。”
这种亲手打造的方式,来源于Google从车库诞生时与生俱来的节俭风格,更与Google那超大型的系统规模息息相关,良好的习惯一直延续至 今。据说 Google在65个数据中心拥有20万~45万台服务器—这个数目会有偏差(取决于你如何定义服务器和由谁来做这项统计)。但是,不变的是持续上升的趋势。
Google不会去讨论这些资产,因为它认为保密也是一种竞争优势。事实上,Google之所以喜欢开源软件也是因为它的私密性。“如果我们购 买了软件许可或代码许可,人们只要对号入座,就可以猜出Google的IT基础架构。”迪博纳分析说, “使用开源软件,就使我们多了一条把握自己命运的途径。”
Google喜欢规模化的服务器运行方式。当有成百上千台机器时,定制服务器的优势也会成倍增加,效果也会更趋明显。Google正在俄勒冈州 哥伦比亚河边的达勒斯市建造一个占地30亩的数据中心,在那儿它可以获得运算和降温需要的低价水力电力能源(参见边栏《Google数据中心自有一套》)。
Google以“单元”(Cell)的形式组织这些运行 Linux操作系统的服务器,迪博纳把这种形式比喻成互联网服务的“磁盘驱动器”(但别和一直谣传的Google存储服务Gdrive混淆了,“并没有 Gdrive这回事。”一位Google女发言人明确表示。),公司的软件程序都驻扎在这些并不昂贵的电脑机箱里,由程序员决定它们的冗余工作量。这种由 很多单元组成的文件系统代替了商业存储设备;迪博纳表示Google这些单元设备更易于建造和维护,他还暗示他们能处理更大规模的数据。
Google 不会漏过对任何技术细节的关注。多年来,公司的工程师就在研究微处理器的内部工作机制,随着Google规模的持续壮大,必然会用到特别定制和调节过的芯 片。知名工程师路易斯”巴罗索(Luiz Barroso)去年在一篇发表在工业杂志上的论文中证实,近年来Google的主要负荷都由单核设计的系统承担着。但许多服务器端的应用,如 Google搜索索引服务,所需的并行计算在单核芯片的指令级别上执行得并不好。
曾在数据设备公司(Digital Equipment)和康柏公司(Compaq)当过芯片设计师的巴罗索认为,随着AMD公司、英特尔公司(Intel)、太阳计算机系统公司(Sun)开始制造多核芯片,必将会出现越来越多芯片级别的并行计算。
Google 也曾考虑过自己制造计算机芯片,但从业界潮流来看,这个冒险的举动似乎不是很必要。“微处理器的设计非常复杂而且成本昂贵,”运营高级副总裁乌尔斯”霍尔 茨勒(Urs Holzle)表示。Google宁愿与芯片制造商合作,让他们去理解自己的应用并设计适合的芯片。这是一种客户建议式的设计,其关注点在于总体吞吐量、 效能,以及耗电比,而不是看单线程的峰值性能。霍尔茨勒表示,“这也是最近多核CPU的设计潮流与未来方向。”
裁缝般地定制软件
为了能尽量压榨硬件性能,Google开发了相当数量的定制软件。创新产品主要包括用于简化处理和创建大规模数据集的编程模型 MapReduce;用于存储和管理大规模数据的系统BigTable;分析分布式运算环境中大规模数据集的解释编程语言Sawzall;用于数据密集型 应用的分布式文件系统的 “Google文件系统”(Google File System);还有为处理分布式系统队列分组和任务调度的“Google工作队列”(Google Workqueue)。
正是从Sawzall这些工具里体现出Google对计算效率的执著关注。并不是每家公司都能从底层去解决效率问题,但是对Google来说, 为常规关系型数据库无法容纳的大规模数据集专门设计一种编程语言是完全合理的。即使其他编程工具可以解决问题,Google的工程师们仍然会为了追求效率 而另外开发一套定制方案。Google工程师认为,Sawzall能与C++中的MapReduce相媲美,而且它更容易编写一些。
Google 对效率的关注使它不可能对标准Linux内核感到满意;Google会根据自己的需要运行修改过的内核版本。通过调整Linux的底层性能,Google 工程师们在提高了整体系统可靠性的基础上,还一并解决了数据损坏和数据瓶颈等一系列棘手问题。对内核的修改也使Google的计算机集群系统因为通信效率 的提高而运行得更快。
当然,Google偶尔也会出现系统故障,情况一旦发生,无数的用户就会受到影响了。三年前一次持续30分钟的系统故障使20%的搜索流量受到影响。
Google 开发了自己的网站服务器却没有使用开源的Apache服务器,尽管它在网站服务器的市场占有率超过60%。迪博纳认为,Google的网站服务器可以运行 在更多数量的主机上,对Google站点上内容庞大又彼此互相依赖的应用程序来说,这种服务器的负载均衡能力远比Apache的能力更高。同时,在用标准 公共网关接口(CGI)访问数据库动态网页方面,Google服务器的编程难度要比 Apache更高,但是最终运行速度却更快。“如果我们能够压榨出10%~20%的性能,我们就可以节省出更多系统资源、电量和人力了。”迪博纳在总结中指出。
Google还设计了自己的客户关系管理(CRM)系统用于支持自己基于竞价和点击的互联网广告收费业务。但对是否需要设计自己的工具,Google的态度也不是一成不变的。比如在财会软件上,它就使用了甲骨文公司(Oracle)的Financials软件。
美林拿着一只叉子举例说明现成的产品也可以带来价值。但在有些场合现成的软件产品就不一定适用了。“我们的文化在各个层面对我们的运作都有深远影响,”他表示,“所以我们不想让购买所得的工具改变我们的工作方式和文化层面。”
Google’s BigTable 原理 (翻译)
题记:google 的成功除了一个个出色的创意外,还因为有 Jeff Dean 这样的软件架构天才。
—— 编者
官方的 Google Reader blog 中有对BigTable 的解释。这是Google 内部开发的一个用来处理大数据量的系统。这种系统适合处理半结构化的数据比如 RSS 数据源。 以下发言 是 Andrew Hitchcock 在 2005 年10月18号 基于: Google 的工程师 Jeff Dean 在华盛顿大学的一次谈话 (Creative Commons License).
首先,BigTable 从 2004 年初就开始研发了,到现在为止已经用了将近8个月。(2005年2月)目前大概有100个左右的服务使用BigTable,比如: Print,Search History,Maps和 Orkut。根据Google的一贯做法,内部开发的BigTable是为跑在廉价的PC机上设计的。BigTable 让Google在提供新服务时的运行成本降低,最大限度地利用了计算能力。
BigTable 是建立在 GFS ,Scheduler ,Lock Service 和 MapReduce 之上的。
每个Table都是一个多维的稀疏图 sparse map。Table 由行和列组成,并且每个存储单元 cell 都有一个时间戳。在不同的时间对同一个存储单元cell有多份拷贝,这样就可以记录数据的变动情况。在他的例子中,行是URLs ,列可以定义一个名字,比如:contents。Contents 字段就可以存储文件的数据。或者列名是:”language”,可以存储一个“EN”的语言代码字符串。
为了管理巨大的Table,把Table根据行分割,这些分割后的数据统称为:Tablets。每 个Tablets大概有 100-200 MB,每个机器存储100个左右的 Tablets。底层的架构是:GFS。由于GFS是一种分布式的文件系统,采用Tablets的机制后,可以获得很好的负载均衡。比如:可以把经常响应 的表移动到其他空闲机器上,然后快速重建。
Tablets在系统中的存储方式是不可修改的 immutable 的SSTables,一台机器一个日志文件。当系统的内存满后,系统会压缩一些Tablets。由于Jeff在论述这点的时候说的很快,所以我没有时间把听到的都记录下来,因此下面是一个大概的说明:
压缩分为:主要和次要的两部分。次要的压缩仅仅包括几个Tablets,而主要的压缩时关于整个系统的压缩。主压缩有回收硬盘空间的功能。Tablets的位置实际上是存储在几个特殊的BigTable的存储单元cell中。看起来这是一个三层的系统。
客户端有一个指向METAO的Tablets的指针。如果METAO的Tablets被频繁使用,那个这台机器就会放弃其他的tablets专门支持 METAO这个Tablets。METAO tablets 保持着所有的META1的tablets的记录。这些tablets中包含着查找tablets的实际位置。(老实说翻译到这里,我也不太明白。)在这个系统中不存在大的瓶颈,因为被频繁调用的数据已经被提前获得并进行了缓存。
现在我们返回到对列的说明:列是类似下面的形式: family:optional_qualifier。在他的例子中,行:www.search-analysis.com 也许有列:”contents:其中包含html页面的代码。 “ anchor:cnn.com/news” 中包含着 相对应的url,”anchor:www.search-analysis.com/” 包含着链接的文字部分。列中包含着类型信息。
(翻译到这里我要插一句,以前我看过一个关于万能数据库的文章,当时很激动,就联系了作者,现在回想起来,或许google的 bigtable 才是更好的方案,切不说分布式的特性,就是这种建华的表结构就很有用处。)
注意这里说的是列信息,而不是列类型。列的信息是如下信息,一般是:属性/规则。 比如:保存n份数据的拷贝或者保存数据n天长等等。当 tablets 重新建立的时候,就运用上面的规则,剔出不符合条件的记录。由于设计上的原因,列本身的创建是很容易的,但是跟列相关的功能确实非常复杂的,比如上文提到 的 类型和规则信息等。为了优化读取速度,列的功能被分割然后以组的方式存储在所建索引的机器上。这些被分割后的组作用于 列 ,然后被分割成不同的 SSTables。这种方式可以提高系统的性能,因为小的,频繁读取的列可以被单独存储,和那些大的不经常访问的列隔离开来。
在一台机器上的所有的 tablets 共享一个log,在一个包含1亿的tablets的集群中,这将会导致非常多的文件被打开和写操作。新的log块经常被创建,一般是64M大小,这个GFS的块大小相等。当一个机器down掉后,控制机器就会重新发布他的log块到其他机器上继续进行处理。这台机器重建tablets然后询问控制机器处理结构的存储位置,然后直接对重建后的数据进行处理。这个系统中有很多冗余数据,因此在系统中大量使用了压缩技术。
Dean 对压缩的部分说的很快,我没有完全记下来,所以我还是说个大概吧:压缩前先寻找相似的 \行,列,和时间数据。
他们使用不同版本的: BMDiff 和 Zippy 技术。
BMDiff 提供给他们非常快的写速度: 100MB/s – 1000MB/s 。Zippy 是和 LZW 类似的。Zippy 并不像 LZW 或者 gzip 那样压缩比高,但是他处理速度非常快。
Dean 还给了一个关于压缩 web 蜘蛛数据的例子。这个例子的蜘蛛 包含 2.1B 的页面,行按照以下的方式命名:“com.cnn.www/index.html:http”.在未压缩前的web page 页面大小是:45.1 TB ,压缩后的大小是:4.2 TB , 只是原来的 9.2%。Links 数据压缩到原来的 13.9% , 链接文本数据压缩到原来的 12.7%。
Continue Reading
From: http://www.bouhe.com/mobile-marketing/1694
诺基亚、爱立信公司的首席技术技官都已驻扎在硅谷办公,他们不得不来到这里,因为他们突然发现苹果和谷歌已经开始威胁到他们的业务。2007年,iPhone、Gphone无疑是最热门的词汇,就连微软也提出了Mphone(Multi-phone)的概念,认为手机应该融合多种无线技术、多种输入技术和多种应用功能。
“2008年会成为MID(移动互联网设备)元年。”业内人士预测。这一判断主要是基于明年上半年英特尔公司即将推出可以放在口袋里的移动终端,而45纳米技术的突破以及多核技术的应用,可以满足MID芯片的移动性和无处不在的计算,并同时降低功耗和尺寸。作为PC互联网时代的最大赢家,英特尔希望将其霸主地位延伸到移动终端领域。就连全球最大的网络书店亚马逊也新推出了手持终端——电子书阅读器,开始软硬兼备。
随着手机和互联网的融合,越来越多的公司开始涉足手机及其他移动终端的生意,硅谷已然变成了手机谷。而围绕着终端的变革,原有的硬件、软件、服务、内容等公司都开始跨越产业链上的多个环节,致使原有的产业边界越来越模糊。以往我们耳熟能详的公司如诺基亚、苹果、谷歌等已经不能单一定位了,它们早已不单是手机、电脑和搜索公司了,而是在移动互联网的大背景下,走到了同一条竞争线上。
随着微软、英特尔、诺基亚、谷歌、苹果等全球巨头加入到移动互联网的战役中,既有的产业格局也会出现新的变化。苹果和谷歌已经成为事实上的虚拟运营商,在它们的平台上会开发和开放各种应用,移动运营商未来的地位会下降。事实上,苹果公司一直和AT&T等移动运营商捆绑销售,并和运营商进行分成。而谷歌打算用46亿美元竞拍美国700MHz的一个无线频段,更有传言,谷歌会收购美国第三大电信运营商Sprint Nextel。
相比苹果、谷歌对移动通信市场的入侵,中国的移动互联网行业还呈现比较封闭的状态,但这并没影响到国内众多创业公司的参与热情。曾有VC感慨,现在只要是和手机相关的商业计划书,十之八九都是手机客户端软件,例如手机聊天、手机下载等各色各样的手机软件。这些公司几乎百分之百都号称要做成手机平台,以黏住用户。
移动终端的影响力之大,在于其离用户最近。作为最终用户,人们与外界的联系节点已由最早家庭的邮政编码,到PC时代的一串IP地址,再转移到移动电话的手机号码。联系的终端越变越小,但却越来越跟随、紧贴用户。在众多公司抢占终端的过程中,用户需求成为最终的变量。在这一点上,无论是iPhone还是Wii的热卖,在于其最先洞察并引领用户需求,通过改善人际交互的界面方式,将用户从键盘中解放出来,满足用户对于自由的渴望。
但仅仅成为一个酷品还不足够,用户更需要终端上的服务和内容。在这一点上,iPhone还远远不够。移动互联网不仅仅是将互联网搬到手机上,看YouTube、上Facebook,随着医疗健康、教育、金融等服务在手机上实现,一定会诞生新的商业模式。
一台便携的移动终端,随时随地连接互联网,围绕这个目标,移动运营商、芯片厂商、终端厂商、互联网服务商、内容提供商史无前例地集体参战,成为过去一年最热闹的场景。而在这场战争背后,首先是对终端的争夺,人机交互界面从键盘到多点触控(multi-touch)率先成为风潮。
当苹果公司的iPhone在欧美手机市场刮起旋风的时候,另外一个手机“门外汉”也把自己的利益触角伸向了这个领域,这家公司就是全球最大的互联网公司谷歌。
对于这家在互联网上取得了巨大成就的公司来说,谷歌进入手机市场并不需要像苹果公司一样自己设计并制造出一款特立独行的酷品手机GPhone来争取用户,而是采用了它更为擅长的方式——用开放的软件平台使自己成为一个联盟的组织者,就像在互联网上用AdSense建立了自己的广告联盟一样。
在2007年11月5日谷歌宣布的手机联盟中有34家企业成员,包括摩托罗拉、T-Mobile、HTC(宏达电)、高通及中国移动等34家全世界不同国家和地区的移动运营商、手机芯片提供商和手机生产商等等。谷歌将为联盟的成员免费开放一个基于Linux的手机操作系统平台“Android”。谷歌称,这个平台是完全开放的综合性移动平台,供联盟成员在此基础上开发新产品、改进服务和压缩用户成本。
在互联网上,谷歌用这种免费提供软件的方式获得了大量的广告收入,2007年前三个季度,谷歌的广告收入达到了约118亿美元,它的这种模式将一直靠卖操作系统软件为生的微软搞得非常被动,如今谷歌又希望能在手机平台上重演这一幕。
在苹果、谷歌这样的新势力纷纷用新模式、新平台进入封闭的电信市场的背景下,以手机为最终表现形式的移动通信市场会发生怎样的深刻变化?也许我们可以从25年前发生在PC行业上的一切来寻找答案。
25年前,整个PC行业还处于群雄割据的状态,没有一个整体性的产业标准,各个PC制造商都有属于自己的一套独立的操作系统,他们靠自己强大的渠道和产品设计能力去争取用户,而微软在这个时候却用软件捆绑机器的销售方式统一了大多数的PC平台,一定意义上这也统一了PC行业。
回到现在正在发生剧烈变化的手机行业里,当手机作为基本语音通话工具时,固定标准是存在的,而当手机逐渐发展成为一个个人随身数据平台,类似于一台小型PC时,这似乎又回到了25年前PC行业的混乱时代,在这个混乱的各自为政的时代,用何种模式、何种平台来统一手机终端就成为了未来这个产业中最大的悬念,在这个悬念破解之后,又会在其背后引发一系列更大更复杂的产业变革。
统一平台下的入侵计划
中国是全球最大的移动市场,在2007年11月底,中国手机用户数已经超过了5.39亿。如此庞大的市场也驱使众多的风险投资及创业者在其中淘金,北京天腾时空信息科技有限公司就是其中之一。
这家由创业基金扶持的公司成立于 2005 年,号称拥有领先的移动多媒体通信和软件研发实力,他们正在开发适用于不同型号手机的第三方客户端软件。这项工作并不容易,因为中国市场上的手机型号实在是太多了,他们要根据系统的不同、机型的不同来对开发出的软件做出调整。尽管如此,天腾时空的CEO马腾对未来还是充满着信心:“我们正在构建一个移动生活圈,把互联网上的东西都带到手机上,我们的目标就是让所有人自由,让大家的网络生活摆脱那根网线和电源线。”
把互联网上的所有东西带进小小的手机终端,这个梦想驱使着中国无数的创业公司在其中寻找着机会,尽管他们坚信手机与互联网的结合是未来的趋势,但是以他们的力量,在中国移动把持的移动运营市场上还是显得太薄弱,现在有了全球最大的互联网公司谷歌的加入,互联网侵入手机的征程就显得不再那么坎坷了。
在谷歌看来,全球有30亿部手机,但是在大多数情况下,手机只被设定为语音通信和发送短消息的一种工具,通过手机上网获取及发布信息的功能被忽略掉了。“这给用户带来了不必要的麻烦,并限制了他们可以享用到的服务。”谷歌移动服务总监Andy Rubin认为,这样的缺陷实际上是过去几十年间移动通信行业迅猛发展的副产品,尤其是移动电话的市场割据更加深了这一点。在这种情况下,手机制造商有充足的商业理由来开发他们各自的受保护的软件,而且运营商也更在意他们眼前所能获得的利益。
这种“各自为政”的发展方式意味着应用服务的提供商必须花大量的精力来实现不同系统的兼容,他们大量的精力和技术人员都花在了如何让自己的软件能顺畅地运行在不同型号的手机上,而不是从用户的利益出发进行创新。
缺乏共享软件平台,也打击了移动领域外的商业力量的积极性,他们不愿意投入更多的时间和资金来挖掘手机更广泛的应用潜力。每当提起正在做手机客户端及免费WAP的公司,风险投资商们都会苦笑着摇摇头。“这种缺乏统一平台的做法使研发的成本居高不下,从而阻碍了创新。”Andy Rubin说。
谷歌的Android平台至少让我们能看到这样一种可能,即在开放的互联网运作模式下,一个如YouTube、Facebook这样的创意,都能通过一个统一的平台将服务惠泽于互联网上的每个人。这也是互联网上能产生对用户有利并促进商业公司收入增长的新服务及新模式的主要原因。
现在,要让互联网顺利的入侵进手机,谷歌所要做的就是用免费提供软件的方式先尽可能地统一手机的平台,然后再依托互联网向这个被自己洞开的门户源源不断地输入各种应用和内容。
“用这款诺基亚6131i手机坐公交车可以直接当公交卡使用”,“可以直接在诺基亚手机上学习新东方的英语课程。”2007年12月11日,在北京举办的诺基亚“完全互联生活2008”大会的一侧,众多诺基亚旗下的公司及合作伙伴展示着诺基亚基于移动互联网推出的新的应用服务。其全球副总裁邓元鋆也宣布诺基亚从2007年开始已经成为了一家互联网公司。2007年8月,诺基亚就已经在全球宣布推出了Ovi(芬兰语中意为“门户”)网络服务,服务内容包括了在线地图、在线游戏和在线音乐商店。
最近几年来,诺基亚在全球收购了一大批提供各种互联网应用服务的公司:2006年8月,斥资6000万美元收购了拥有160万首歌曲的音乐网站Loudeye;2007年7月,收购美国多媒体公司Twango,Twango主要提供为互联网上共享、发布多媒体信息搭建平台的服务;紧接着在9月份,他们又收购了一家名为Enpocket的移动广告公司;10月初,诺基亚又宣布以81亿美元收购美国的Navteq公司,Navteq是汽车导航系统、个人导航设备和其他企业数字地图及基于网络地图系统的主要供应商,同时还拥有提供美国交通信息的Traffic.com网站,这也是诺基亚迄今为止最大的一笔收购; 12月,诺基亚又收购了为手机用户提供共享电脑文件的Avvenu公司。
一系列的收购行动使这家全球最大的手机制造商逐渐成为了一家提供互联网综合服务的公司,通过整合一系列的应用,他们将互联网服务引入到了自己生产的手机平台上。
诺基亚是全球手机行业的霸主,在全球手机市场上的市场占有率接近40%,在中国,2007年的前三季度,他们就卖出了5050万部手机,目前约有超过1.3亿中国用户在使用诺基亚。作为一家处于产业链下游的公司,诺基亚已经不满足于只是制造和销售手机了,它不仅要牢牢掌握住终端,而且还想把握住这个未来的信息渠道。
谷歌成立的Android联盟在一定程度上也在威胁着诺基亚。诺基亚是另一个手机软件平台Symbian的控制者,虽然诺基亚控制的Symbian联盟不具备像Android联盟这样将移动终端、芯片、运营、软件应用、设计等产业链的各个层面的力量都集成在一起的能力。不过依靠市场占有率的绝对优势,诺基亚并不惧怕手机领域的新闯入者,2007年上半年Symbian智能手机在全球共出货3460万部,Symbian智能手机累计出货量已经达到1.45亿部,在智能手机市场的份额达到72%。目前诺基亚、摩托罗拉和索尼爱立信手握全球六成以上的市场占有率,这意味着Symbian至少将在相当一段时间内横行智能手机市场。
诺基亚想用自己的实际行动证明,诺基亚的手机霸主地位是任何一家公司都无法撼动的,现在它在维持霸主地位的同时正主动向互联网靠拢。显然不用怀疑诺基亚适应变化的能力,它已有将近140年的历史,之前卖过劳保用品,也制造过电视机,因此,诺基亚公司坚信,与其自身所经历过的困难相比,目前向互联网转型的所有困难都显得微不足道。
重构手机价值链
整个移动通信领域,2007年最受关注的公司是苹果。自从6月份推出iPhone以来,iPhone至今已销售了超过140万部。更为重要的是,iPhone的出现开启了一个新型的与电信运营商分享收益的模式。
苹果运用的是彻底封闭型平台策略,苹果通过与当地电信运营商的业务捆绑销售产品,从用户收入中抽取一定分成。苹果在美国与运营商AT&T、在德国与T-Mobile、在英国与O2、在法国与Orange都采取了这样的合作方式。以苹果与AT&T的合作为例:苹果公司每月从已经与AT&T签署iPhone服务协议的每位用户中可抽取3美元费用;而新用户,苹果每月则可从每位用户中抽取高达11美元的费用。
为什么苹果能与移动运营商分成?答案之一就是,苹果的iPhone能通过WiFi的方式接入互联网,使得每位用户的ARPU值增加,为运营商带来除语音通话之外的数据业务收入。
曾传言苹果在2007年11月份与中国移动探讨过这种合作模式,但是对于靠语音及短信业务为主、且在移动产业链中处于主导地位的中国移动来说,他们并不喜欢手机产业中新出现的一些商业模式。这也证明了谷歌移动服务总监Andy Rubin对封闭的电信行业的判断,利润流向了少数的几家具有垄断性质的手机制造商与移动运营商那里,这种方式有碍于这个行业创新应用的产生。
随着谷歌这样的互联网公司将触角逐渐伸向电信领域,并且诺基亚也在主动向着互联网转型,曾经强硬封闭的运营商也只能慢慢地走向开放。移动业务价值链势必会有一个重构的过程。
据悉,谷歌打算用46亿美元竞拍美国700MHz的一个无线频段,并向美国联邦通信委员会(FCC)提出了参加拍卖的四个条件:要求获胜者向手机用户开放应用,开放设备,向移动运营商开放批发服务,向内容提供商开放网络。这就意味着,谷歌决意要彻底改变原有电信业的商业模式。除此之外,又有传言说谷歌会收购美国第三大电信运营商Sprint Nextel。
全球最大的互联网公司反过来收购一家电信运营商,如果这样的事情真的在2008年发生,那整个电信行业就会步入一个新的时代,不管怎么说,互联网入侵移动通信市场的序幕已经真的拉开了。
狂欢吧,身体!
在电影《迷失东京》中,女主角斯佳丽·约翰逊用好奇的眼神观看着一名玩着跳舞游戏的日本男子,他大汗淋漓,正操作一种需要手舞足蹈甚至360度旋转身体才能配合画面节拍的游戏。在东京,拥有这种运动式大型游戏机的游戏厅非常多,电影选择这个场景也是有意突出西方人对奇特的日式娱乐的惊讶。
然而,从2006年底开始,一款由日本任天堂公司开发的名为“Wii”的游戏机迅速风靡欧美家庭,这款电视遥控器般大小的游戏机正像上世纪80年代的卡拉OK一样,它凭借更接近自然的交互方式让全家老少都能参与到游戏中来。一时间,自由交互式操控的复兴给整个游戏机产业注入了新的活力。
在Wii诞生之前,游戏业多少有些尴尬:上班族没时间玩,老年人上手又太难,小孩子受到家长的严格监督和管制。实际上,大多数人的游戏经验都只停留在童年,游戏随着玩家长大成人遭到放弃甚至厌恶和抵制。多数人后天的发展不仅没有打开体验的更广阔天地,反而是一步步进入专业化、职业化的路径,再也没机会感受自身生活范围以外的世界。
Wii的出现改变了这一切,Wii的设计师宫本茂也因此成为英国《经济学人》的“年度创新大奖”的获得者,“当今电子游戏界的关键人物”的评价也从另一个角度证明了Wii的创新价值。
Wii的重要性在于,设计者宫本茂坚信,游戏必须与每个人的日常生活发生联系;游戏必须更加深入社会,得到整个社会的理解。这可以看作这位游戏设计大师的游戏世界观,正是这样的信仰产生了Wii的颠覆性创想。这种信仰也正好道出了游戏的本质——游戏本来就是生活的延伸,是人们工作之余的一种经验扩展,游戏让人获得习以为常的生活里难以体会到的感受,甚至是经验和知识,怎么能将大部分人隔离于游戏之外呢?
被束缚的自由
“硅谷海盗”乔布斯似乎比一般人更加难以忍受密密麻麻的按键和狭小的屏幕给人的束缚感,素来爱凭自我感受来判断技术趋势的他坚信:技术进步不应该成为束缚人自由的枷锁。iPhone证明乔布斯又“赌”对了。这款手机在把实体按键简化到只剩一个之后,更是利用多点触控(multi-touch)屏幕让自由轻松的触控体验发挥到了极致。他曾经描述,自己过去在使用手机时,看着密密麻麻的按键却找不到一个简单的功能时,头脑中就只有把手机砸掉的冲动,何谈使用它正常工作。
交互设计大师、“Macintosh”之父杰夫·拉斯基(Jaf Raskin)早就指出,好的设计不会让使用者养成对今后工作不利的习惯,但设计人员却经常有意无意地给用户设下坏习惯的陷阱。事实上,良好的设计应该在给用户带来帮助的同时,把对其未来可能出现的限制性障碍降到最低,保持使用者自由的可扩展性。
实际上,界面的不自由长久以来是一个被忽视并且有点积重难返的问题,越来越复杂的设备和使用者界面,大大增加了拉斯基所说的陷阱的数量,而解放使用者自由就需要下更大的决心和冒更大的风险颠覆传统。
当互联网信息过载让人们淹没在信息海洋中时,谷歌充当了颠覆者的角色,它只在网页上显示一个输入框;当手机开始附加各种原来PC的功能而变得日益复杂,学习成本上升时,iPhone开创性地只保留一个实体按钮。大刀阔斧地删减界面信息、按钮和选项,使用户不用进行多余的思考,即可快速进入想要达成的任务。
Wii mote被设计成客厅里最具亲和力的电视遥控器样式,让你接触无距离感,拿起它你就知道如何使用,而玩好它却又需要时间和技巧。正如谷歌简单的输入框背后有复杂的运算;苹果电脑薄薄的《使用说明》上第一句话是,“你的苹果电脑被设计为你能很快设置并且马上开始使用”,说明书的封面上印着一行灰字:“Congratulations,you and your MacBook were made for each other.”很有从此“人机合一,形影相随,只有我懂你”的性感意味。
正是因为这样,根据互补资源价值相关的原理,心理需求上互补的、无线的、可移动的和能带来真实触感的资源将变得稀缺而更有价值。这就是解放四肢的Wii和自由触控的iPhone之所以获得极大成功的深层社会心理学原理。
从芯片到设备的连锁爆发
基于社会心理学上的新需求是商业应用市场爆发的充分而非必要条件,Wii、iPhone等颠覆键盘和鼠标操作方式的产品之所以在2007年爆发,也必须有一些上游技术方面的必要条件。
实际上,从1980年施乐实验室帕洛阿尔托研究中心(PARC)的计算机“STAR”算起,“鼠标+图像化界面”在计算机上的应用已经走过了37年历史,最早的鼠标连线还是在其后部,更像是老鼠的尾巴 。其实正是CPU芯片计算能力的增强,使得计算机可以模拟出更丰富的图形化界面效果,鼠标这种低技术含量但实用的发明才有用武之地。
同样,iPhone的多点触控技术和更简单的Wii mote手柄的单点触控技术都不是新发明,它们之所以在2007年大行其道,除了符合人们普遍对密密麻麻的键盘和狭小屏幕的厌烦心理,更根本的原因是芯片计算能力的进一步增强。 LUPA开源社区’B!I*G2^ m5T-P1^
英特尔高级副总裁、前CTO 帕特·基辛格在谈到45纳米芯片的突破以及“多核”技术的未来影响时表示,更低功耗、更强性能和更丰富功能的芯片为无线的、模拟图形的和能感知触觉的计算提供了更好的技术准备。用户可以不用为了机器刻意改变行为习惯,而机器具备了更精确的识别人的动作并做出更丰富反馈的能力。
简单说,计算能力的进步使得我们已经可以抛弃“计算机中古时代”的键盘和鼠标,拥抱更现代、更性感和更自由的多点触控技术。它为交互性更强的应用打开了新的天地,比如,当iPhone靠近人脸时,多点触控屏幕会自动感应,让触控点全部关闭,因为这时候你正在接听电话,不需要任何按键,而当机器感受到你进入其他场景的信号时,你正好需要的按键又会聪明地出现。当机器能以人的自然动作为中心时,机器的操作大大降低了门槛,几乎不需要学习。
从购买和使用Wii的人群也可以看出,难以掌握复杂操作的学龄前儿童和对新的电子设备接受度最差的中老年人,都可以轻松学会使用Wii。这更加证明了过去繁琐的操作和束缚自然动作的低级交互方式扼杀了许多人获得新鲜体验的自由。Wii也成为了圣诞节流行的一款送给小孩子的礼品。虽然这会让使用者耗费更多的动作及体力,不过,却能够在操控过程中获得更多的乐趣。这种操作方式抛弃了目前所使用的键盘(按钮)、鼠标,将进一步体现出人性化操控界面的未来趋势。
到目前为止,Wii已经销售了超过1300万台,Xbox360早推出1年,但是已经不敌Wii的风头,以几十万台的差距落后,而PS3则只有500多万台售出,而且增长缓慢。虽然市场上开始出现拙劣模仿者和盗版游戏,就像当初MP3厂商模仿iPod一样,而且同类厂商开始降价应对Wii的冲击,但Wii依然在营造产品紧缺的状态,坚持不降价,保证了极高的利润率。任天堂的市值也一路攀升,超过索尼近一倍,成为日本证券市场上仅次于丰田的第二大市值的公司。
宫本茂已经沿着解放身体的思路把Wii驶入家庭健身器市场,Wii fit系列游戏包括了滑雪、跳舞、瑜伽、俯卧撑、呼啦圈和英式足球等。设备上,Wii又推出了平衡板(Wii balance),可通过在上面运动和改变姿势来操控屏幕上的虚拟角色。
微软的客厅战争也打算以多点触控技术作为杀手锏。去年春天,网上开始流传一段Microsoft Surface的视频,其演示的多点触控技术令观者赞叹不已。Surface大大的触摸屏可以响应很多种手势,而且,当你把电子设备放在它的触摸屏上时,Surface电脑马上会“看到”你的设备(通过隐藏的多个摄像头),并即时在屏幕上展现出各种可能的操作。比如你放个数码相机上去,它就会问你是否要查看照片,这种简单的操作一旦推向市场很可能像Wii一样改变家庭PC产业。
苹果公司也已经展示了下一代应用触控屏幕的台式电脑iMac,惠普公司的PDA产品iPaq在触控技术上也做了独特的尝试,主要是实现了在小小屏幕上用手指实现精确到毫米的控制。三星电子全球CEO尹钟龙也认为下一代手机要性感并且易于操作,今年他们推出了触摸屏手机SGH-P520,以应对来势汹汹的iPhone。而iPhone也在触感互动上深入探索,在申请按压虚拟按钮仍然有弹回感觉的技术专利。
苹果公司预计iPhone的销量在2008年1月14日的Mac world大会之前达到500万部,但从近20%的产品被购买后没有开通AT&T的服务,可推测这些产品是流入了非美国市场破解后使用,看来iPhone病毒式的扩散威力还只是开了个头。
iPhone的热销引发了同类厂商的跟随效应。去年,在芯片技术领域,国内厂商美芯半导体的销售人员惊奇地发现,他们投资的适合计算空间平衡改变的芯片,其销售业绩大大高于其他芯片产品。这些芯片主要应用于交互式的游戏机、可感知使用者行为的手机等设备上。
实际上,通过iPhone的热卖我们完全可以预见到,下一阶段的芯片必须为下一代手机等电子产品的这些特点做足准备:用容量有限的电池(意味着芯片的功耗必须是低的),功能越来越丰富(意味着芯片支持更多任务同时运行),越来越便携(意味着更好的支持无线通信)而且更讲求视觉和触感体验(意味着模拟计算等能力更强)。目前,唯一独立存在的GPU(图形处理器)厂商Nvidia公司,就是由于专注于这个越来越重视视觉体验的消费电子市场,才取得了这两年的高速成长。可以预测适合这些特点的芯片的爆发性需求应该会在2008年日渐明显。
另外,IT咨询顾问公司InStart的殷建松认为,2008年值得期待的是46英寸屏幕的电子设备的出现,iPhone和iPod Touch的屏幕是3.5英寸,而46英寸的屏幕视觉和触觉体验效果更好,并且仍然能放入口袋中。像iPod Touch一样仅仅作为游戏、娱乐和信息浏览器的工具也是46英寸的屏幕最为合适,它恰好是体验和便携性的平衡。
以上种种都为我们描绘出一个能够更加全面和丰富地感知人的自然行为的未来世界,这个世界的基础应该是一种无所不在的感知、收集、识别,最后做出更丰富和人性化反馈的计算机。在这个用户体验极大丰富和更自由交互的世界面前,引领时代的厂商们已经占好了跑道,各就各位。
转至 http://www.upsdn.net/html/2004-11/47.html
在C标准库中有一对非常有趣的函数setjmp()函数与longjmp()函数,用来实现代替goto实现一些非常重要的功能,如异常处理。C语言中,标准库函数setjmp和longjmp形成了结构化异常工具的基础。简单的说即setjmp实例化异常处理程序,而longjmp产生异常。
先介绍setjmp
int setjmp(jmp_buf envbuf)
宏函数setjmp()在缓冲区envbuf中保存系统堆栈里的内容,供longjmp()以后使用,setjmp()必须使用头文件setjmp.h。
调用setjmp()宏时,返回值为0,然而longjmp()把一个变原传递给setjmp(),该值(恒不为0)就是调用longjmp()后出现的setjmp()的值。
setjmp函数用于保存程序的运行时的堆栈环境,接下来的其它地方,你可以通过调用longjmp函数来恢复先前被保存的程序堆栈环境。当setjmp和longjmp组合一起使用时,它们能提供一种在程序中实现“非本地局部跳转”(”non-local goto”)的机制。并且这种机制常常被用于来实现,把程序的控制流传递到错误处理模块之中;或者程序中不采用正常的返回(return)语句,或函数的正常调用等方法,而使程序能被恢复到先前的一个调用例程(也即函数)中。
对setjmp函数的调用时,会保存程序当前的堆栈环境到env参数中;接下来调用longjmp时,会根据这个曾经保存的变量来恢复先前的环境, 并且当前的程序控制流,会因此而返回到先前调用setjmp时的程序执行点。此时,在接下来的控制流的例程中,所能访问的所有的变量(除寄存器类型的变量 以外),包含了longjmp函数调用时,所拥有的变量。
void longjmp(jmp_buf envbuf,int status);
函数longjmp()使程序在最近一次调用setjmp()出重新执行。setjmp()和longjmp()提供了一种在函数间调转的手段,必须使用头部文件setjmp.h。
函数longjmp()通过把堆栈复位成envbuf中描述的状态进行操作,envbuf的设置是由预先调用setjmp()生成的。这样使程序的执行在 setjmp()调用后的下一个语句从新开始,使计算机认为从未离开调用setjmp()的函数。从效果上看,longjmp()函数似乎“绕”过了时间 和空间(内存)回到程序的原点,不必执行正常的函数返回过程。
缓冲区envbuf具有<setjmp.h>中定义的buf_jmp类型,它必须调用longjmp()前通过调用setjmp()来设置好。
值status变成setjmp()的返回值,由此确定长调转的来处。不允许的唯一值是0,0是程序直接调用函数setjmp()时由该函数返回的,不是间接通过执行函数longjmp()返回的。
longjmp()函数最常用于在一个错误发生时,从一组深层嵌套的实用程序中返回。
longjmp函数用于恢复先前程序中调用的setjmp函数时所保存的堆栈环境。setjmp和longjmp组合一起使用时,它们能提供一种在程序中实现“非本地局部跳转”(”non-local goto”)的机制。并且这种机制常常被用于来实现,把程序的控制流传递到错误处理模块,或者不采用正常的返回(return)语句,或函数的正常调用等方法,使程序能被恢复到先前的一个调用例程(也即函数)中。
对setjmp函数的调用时,会保存程序当前的堆栈环境到env参数中;接下来调用longjmp时,会根据这个曾经保存的变量来恢复先前的环境,并且 因此当前的程序控制流,会返回到先前调用setjmp时的执行点。此时,value参数值会被setjmp函数所返回,程序继续得以执行。并且,在接下来 的控制流的例程中,它所能够访问到的所有的变量(除寄存器类型的变量以外),包含了longjmp函数调用时,所拥有的变量;而寄存器类型的变量将不可预 料。setjmp函数返回的值必须是非零值,如果longjmp传送的value参数值为0,那么实际上被setjmp返回的值是1。
在调用setjmp的函数返回之前,调用longjmp,否则结果不可预料。
在使用longjmp时,请遵守以下规则或限制:
· 不要假象寄存器类型的变量将总会保持不变。在调用longjmp之后,通过setjmp所返回的控制流中,例程中寄存器类型的变量将不会被恢复。
· 不要使用longjmp函数,来实现把控制流,从一个中断处理例程中传出,除非被捕获的异常是一个浮点数异常。在后一种情况下,如果程序通过调用 _fpreset函数,来首先初始化浮点数包后,它是可以通过longjmp来实现从中断处理例程中返回。
如何实现异常处理
首先设置一个跳转点(setjmp() 函数可以实现这一功能),然后在其后的代码中任意地方调用 longjmp() 跳转回这个跳转点上,以此来实现当发生异常时,转到处理异常的程序上,在其后的介绍中将介绍如何实现。 setjmp() 为跳转返回保存现场并为异常提供处理程序,longjmp() 则进行跳转(抛出异常),setjmp() 与 longjmp() 可以在函数间进行跳转,这就像一个全局的 goto 语句,可以跨函数跳转。
jmp_buf 异常结构
使用 setjmp() 及 longjmp() 函数前,需要先认识一下 jmp_buf 异常结构。jmp_buf 将使用在 setjmp() 函数中,用于保存当前程序现场(保存当前需要用到的寄存器的值),jmp_buf 结构在 setjmp.h 文件内声明:
typedef struct
{
unsigned j_sp; // 堆栈指针寄存器
unsigned j_ss; // 堆栈段
unsigned j_flag; // 标志寄存器
unsigned j_cs; // 代码段
unsigned j_ip; // 指令指针寄存器
unsigned j_bp; // 基址指针
unsigned j_di; // 目的指针
unsigned j_es; // 附加段
unsigned j_si; // 源变址
unsigned j_ds; // 数据段
} jmp_buf;
jmp_buf 结构存放了程序当前寄存器的值,以确保使用 longjmp() 后可以跳回到该执行点上继续执行。
setjmp() 与 longjmp() 函数都使用了 jmp_buf 结构作为形参,它们的调用关系是这样的:
首先调用 setjmp() 函数来初始化 jmp_buf 结构变量 jmpb,将当前CPU中的大部分影响到程序执行的积存器存入 jmpb,为 longjmp() 函数提供跳转,setjmp() 函数是一个有趣的函数,它能返回两次,它应该是所有库函数中唯一一个能返回两次的函数,第一次是初始化时,返回零,第二次遇到 longjmp() 函数调用后,longjmp() 函数使 setjmp() 函数发生第二次返回,返回值由 longjmp() 的第二个参数给出(整型,这时不应该再返回零)。
在使用 setjmp() 初始化 jmpb 后,可以其后的程序中任意地方使用 longjmp() 函数跳转会 setjmp() 函数的位置,longjmp() 的第一个参数便是 setjmp() 初始化的 jmpb,若想跳转回刚才设置的 setjmp() 处,则 longjmp() 函数的第一个参数是 setjmp() 所初始化的 jmpb 这个异常,这也说明一件事,即 jmpb 这个异常,一般需要定义为全局变量,否则,若是局部变量,当跨函数调用时就几乎无法使用(除非每次遇到函数调用都将 jmpb 以参数传递,然而明显地,是不值得这样做的);longjmp() 函数的第二个参数是传给 setjmp() 的第二次返回值,这在介绍 setjmp() 函数时已经介绍过。
下面是 setjmp() 函数与 longjmp() 函数的一个示意图:

通过示意图可以看出 setjmp() 函数与 longjmp() 函数的关系,如何跳转。

呵呵!现在是否对程序的执行流程一目了然,其中最关键的就是setjjmp和longjmp函数的调用处理。我们分别来分析之。
当程序运行到第②步时,调用setjmp函数,这个函数会保存程序当前运行的一些状态信息,主要是一些系统寄存器的值,如ss,cs,eip, eax,ebx,ecx,edx,eflags等寄存器,其中尤其重要的是eip的值,因为它相当于保存了一个程序运行的执行点。这些信息被保存到 mark变量中,这是一个C标准库中所定义的特殊结构体类型的变量。
调用setjmp函数保存程序状态之后,该函数返回0值,于是接下来程序执行到第③步和第④步中。在第④步中语句执行时,如果变量n2为0值,于是便 引发了一个浮点数计算异常,,导致控制流转入fphandler函数中,也即进入到第⑤步。
然后运行到第⑥步,调用longjmp函数,这个函数内部会从先前的setjmp所保存的程序状态,也即mark变量中,来恢复到以前的系统寄存器的 值。于是便进入到了第⑦步,注意,这非常有点意思,实际上,通过longjmp函数的调用后,程序控制流(尤其是eip的值)再次戏剧性地进入到了 setjmp函数的处理内部中,但是这一次setjmp返回的值是longjmp函数调用时,所传入的第2个参数,也即-1,因此程序接下来进入到了第⑧ 步的执行之中。
因为 jmp_buf 全局只能存放一个 jmpb 结构,使得只有最后一组宏可以响应异常; 这是无法嵌套异常的原因,要实现多重嵌套可以建立一个全局堆栈来维护一组 jmpb 结构
实现机理
setjmp()保存其调用返回点的ebx, esi, edi, ebp, esp, eip,对于sigsetjmp(), 还保存当前的信号屏蔽字, longjmp恢复这些寄存器及信号屏蔽字,同时传递一个返回值。
ongjmp只是使CPU的状态和setjmp时的状态一致,相同的CPU初始状态执行相同的代码并不意味着产生相同的结果,setjmp, longjmp并不关心内存变量的变化,而只关心CPU的状态,
内存变量的确定性应该根据上下文来灵活处理.
如果将函数之间的调用关系看成一种树型结构, 将可执行文件的入口函数看成它的最内层节点(根节点), 那么setjmp提供了标记节点的方法, longjmp提供了从外层节点直接返回到更内层节点的方法,
在同一层节点之间或者从内层节点到外层节点的longjmp是没有意义的, 因为目标节点在此时根本不存在.
摘要:讨论一个利用标准C语言setjmp库函烽实现查询式协作多任务系统,给出完整的内核和样例程序并对源代码进行说明。该系统具有简单易用的特点,只需要编写存取堆栈指针的宏就可方便地移植到新的平台上。文章详述了系统的优缺点,讨论一些性能扩展的方法。该内核适用
于中小规模的嵌入式软件。
关键词:协作式多任务 C语言 setjmp
引言
本文介绍的是利用标准C语言setjmp库函数实现的具备此特点的协作式多任务系统。从本 质上讲,实时多任务操作系统应该具备按照优先级抢占调度的内核。然而,在实际应用中,抢中式的多任务某种程序上带来了用户程序设计时数据保护的困难,并 且,具备抢占功能的多任务内核设计时困难也比较多,这会增加操作系统自身的代码,也使它在小资源单片机系统中应用较少;而协作多任务系统的调度只在用户指 定的时机发生,这会大大简化内核和用户系统的设计,尤其本文实现的系统通过条件查询来放弃CPU,既符合传统单片机程序设计的思维,又带来了多任务、模块 化、可重入的编程便利。
Setjmp是标准C语言库函数的组成部分,它可以实现程序执行中的远程转操作。具体来 说,它可以在一个函数中使用setjmp来初始化一个全局标号,然后只要该函数未曾返回,那么在其它任何地方都可以通过longjmp调用来跳转到 setjmp的下一条语句执行。实际上,setjmp函数将发生调用处的局部环境保存在一个jmp_buf的结构当中,只要主调函数中对应的内存未曾释放 (函数返回时局部内存就失效了),那么在调用longjmp的时候就可以根据已保存的jmp_buf参数恢复到setjmp的地方执行。我们的系统中就是 分析了setjmp标准库函数的特点,以简单的方式实现了协作式多任务。
1 演示程序
为了便于理解,首先给出多任务演示程序的源代码。这个程序演示了协作式多任务切换、任务的 动态生成、多任务共用代码等功能,一共使用了init_coos初始化根任务(也就是C语言main函数)、creat_task创建新任务和 WAITFOR查询条件这3个基本的系统调用。由于面向嵌入式系统,因而程序不会中止并且运行中也没有进行任何输出,需要借助适合的调试工具来理解多任务 系统的运行。
example.c文件清单:
#include<stdlib.h>
#include“co-os.h”
void tskfunc1(int argc,void *argv);
void tskfunc2(int argc,void *argv);
void subfunc(void);
volatile int cnt,test;
int main(void){
int i;
init_coos(400);
creat_tsk(tskfunc1,12,NULL,400);
creat_tsk(tskfunc2,0,NULL,400);
i=0;
while(1){
WAITFOR(cnt= =8);
while(i++<cnt)test=i;
cnt++;
}
}
void tskfunc1(int argc,void *argv){
int i;
static int creat=0;
if(!creat){
creat_tsk(tskfunc1,9,NULL,400);
creat=1;
}
i=0;
while(1){
WAITFOR(cnt>argc);
test=0×55;
/*使用函数调用在子程序中测试WAITFOR*/
subfunc();
while(i++<cnt)test=i^0xAA;
}
}
void tskfunc2(int argc,void *argv){
while(1){
WAITFOR(++cnt>15);
cnt=0;
}
}
void subfunc(void){
int i;
WAITFOR(cnt<5);
for(i=0;i<++)test=0×10*i;
}
2 内核构成
内核包括一个供外部用户程序包含的头文件(co-os.h)和具体实现的源文件(co-os.c),它们提供了演示程序中用到的3个系统调用。
内核的实现代码假定了CPU堆栈是向下增长的,并且通过宏来直接操作堆栈指针。以下代码在 Microsoft VC6 for x86、Borland C++ Builder 5.5、SDS CrossCode7.0 for 68K和GCC3.2 for AVR四种平台中测试过,只需在co-os.h头文件中定义相应的平台类型即可顺利编译。
(1)co-os.h文件清单
#include<setjmp.h>
/*选择X86_VC6,X86_BC5,AVR_GCC或M68H_SDS.*/
#define X86_VC6
#define MAX_TSK 10
typedef struct {
void (*entry)(int argc,void *argv);
jmp_buf env;
int argc;
void *argv;
}TVB;
extern TCB tcb[MAX_TSK];
extern int task_num,tskid;
void init_coos(int mainstk);
int creat_tsk(void(*entry)(int argc,void *argv),int argc,void *argv,int stksize);
#define WAITFOR(condition)do{
setjmp(tcb[tskid].env);
if(!(condition)){
tskid++;
if(tskid>=task_num)tskid=0;
longijmp(tcb[tskid].env,1);
}
}while(0)
(2)co-os.c文件清单
#include “co-os.h”
#if defined(X86_VC6)||defined(X86_BC5)
#define SAVE_SP(p) _asm mov p,esp
#define RESTORE_SP(p) _asm mov esp,p
#elif defined(AVR_GCC)
#include<io.h>
#define SAVE_SP(p) p=(int*)SP
#define RESTORE_SP(p) SP=(int)p
#elif defined(M68K_SDS)
#define SAVE_SP(p) asm(“MOVE.L A7,{“#p”}”)
#define RESTORE_SP(p) asm(“MOVE.L {“#p”},A7″)
#endif
TCB tcb[MAX_TSK];
Int task_num=1;
Int tskid;
Static int stktop,oldsp;
Void init_coos(int mainstk){
SAVE_SP(stktop);
stktop=stktop+sizeof(void(*)(void))/sizeof(int)
-(mainstk+sizeof(int)-1)/sizeof(int);
}
int creat_tsk(void(*entry)(int argc,void *argv),
int argc,void *argv,int stksize){
if(task_num>=MAX_TSK)terurn-1;
SAVE_SP(oldsp);
RESTORE_SP(stktop);
If(!setjmp(tcb[task_num].env)){
RESTORE_SP(oldsp);
tcb[task_num].entry=entry;
tcb[task_num].argc=argc;
tcb[task_num].argv=argv;
task_num++;
stktop-=(stksize+sizeof(int)-1)/sizeof(int);
}
else tcb[tskid].entry(tcb[tskid].argc,tcb[tskid].argv);
return 0;
}
3 代码说明
任务代码通过执行setjmp设置本任务下次查询时的返回点,然后在等待条件放弃掉CPU 跳转到下一任务的返回点处执行。如此周而复始,让各任务都获得轮转运行的机会,也要求各任务都需要主动通过等待条件的方式放弃掉CPU。系统中除了中断服 务程序之外,所有任务都是平等的,都应该遵循同样的规则和其它任务一起协作运行。基本系统中没有设计杀死任务的调用,这要求各任务都应当设计成某种形式的 无限循环。
任务中等待的条件可以是任务复杂的表达式或都函数调用,也可以是中断服务程序设置的全局变 量(注意加volatile定义)。一般在任务执行时会让下次等待的条件不再满足,避免某个任务一直霸占CPU将系统饿死。在嵌入式软件中还经常会遇到任 务定时启动和超时等待在I/O操作上,在我们的系统中可以维护一个时间计数器,只需在适当的地方记录时刻,然后在任务查询条件中判断当前计数器和记录时刻 之间的差值就可以了。
内核实现的代码则相当简法。由于主要的保护和恢复任务现场的工作都由C语言标准库 setjmp实现了,我们就只需要操纵一下堆栈指针防止不同的任务使用了重叠的局部环境,这个工作在初始化和创建任务的时候通过预定义的两个宏来实现。在 init_coos函数中,记录了主任务(main函数)保留mainstk字节堆栈后的新栈顶位置(stktop),然后在每次creat_task时 都根据要求为每个任务保留stksize字节的堆栈并重新计算下一个stktop。在creat_task函数中利用了setjmp函数的返回值(直接返 回时为0,longjmp跳转返回时非0),使得一方面creat_task能正常回到调用者,又让下次轮转到新任务时能够找到创建时的入口。
co-os.h中定义的WAITFOR使用了一个do{…while(0)实现多语句宏的 C语言小技巧,这样能保证在任何情况下WAITFOR都可以如单条语句一样在源程序中使用,需要担心多了或者少了大括弧破坏if/else匹配之类的问 题,并且,所有的编译器都会优化掉这个假循环。
为了尽量使程序简单并说明问题,以上代码中没有考虑中断相关的数据保护问题。实际运行的系 统中,如果首先写堆栈指针不能一步完成(如AVR这样的8位机),那么,在写操作正在进行的时候绝对不能允许中断;另外,在任务中查询的条件如果和中断有 关,那么也必须考虑数据的完整性。
4 性能分析
所有的协作式多任务系统中任务切换时间都和用户代码(是否长期占用CPU)、就绪时刻有 关,比标准系统略差的是,我们的简单系统中不支持任务优先级,并且完成一轮查询调度的时间还和任务数目有关。这也是为了达到简单和可移植性目标而不得已作 出的牺牲。在各任务间切换查询条件通过C语言标准库函数longjmp实现,一般来讲longjmp函数要从内存中恢复大部分CPU寄存器,执行它也需要 若干条指令的时间。
为了面向嵌入式系统应用,任务控制块(TCB)采用静态数组来实现,这样要求预先确定系统 的最大任务数(co-os.h中的MAX_TSK)。如果需要,也可以通过环波链表来动态管理任务控制块(TCB),这时可以简单实现任务的动态创建和删 除,并且通过指针来访问TCB也要比通过下标(tskid)略快一点。
在某些情况下,如果在中断返回后需要执行某关键任务,可以考虑通过设置“高级中断”的方法 来实现。具体地讲,就是在中断返回前改变返回地址到某函数入口(“高级中断服务程序”),同时保留原返回地址到堆栈中,这样在“高级中断服务程序”完成后 执行return就又回到了正常的多任务查询流程。使用“高级中断”时要注意现场保护的衔接,并且这种技巧显然和CPU和体系结构有关。
5 结论
setjmp是标准C语言中用于远程跳转的库函数,利用它可方便实现一个简单易移植的协作式多任务系统。该系统功能完备、编程简单、易于学习,适合一些中小规模的嵌入式软件使用;并且,以此为基础,还可以用一些与平台相关的编程技巧提高其实时性和灵活性。
部分资料来源于希赛,单片机与嵌入式系统应用
很兴奋能参加这个会议,可惜公司这面早上只有我一个人去,大清早收拾好就在楼下的 984 车站等车,结果等了好久才来车,车上好几个人都是同去开会的,有两位先生还不错,下车后给我领了路,在开会过程中还见过几回,好像是 TechExcel 公司的(希望没有记错),先表示感谢一下吧。
还好没有迟到很多,蒋总(CSDN总裁 蒋涛)刚上台,我就进入主会场了。蒋总的开幕辞解释了为什么要办这次会议,以及这次会议的主题《揭示下一代软件开发趋势》。
查看 CSDN 报道 >> 【SD2.0大会】CSDN总裁蒋涛致大会开幕辞
第一场孟岩(CSDN & 《程序员》总编)和Jon Erickson(DDJ杂志主编)讨论了一下什么是软件开发2.0,很可惜,进去时太匆忙,忘了向工作MM要同声传译的耳机了,本来我的听力就巨烂无比,再加上做在我旁边和后台的几位仁兄肆无忌惮的聊天,让我感觉像在菜市场里看哑剧一样。我只注意到了一个词组,“Tipping Point”,关键点?顶点?突破点?
查看 CSDN 报道 >> 【SD2.0大会】DDJ总编与程序员总编孟岩对话SD2.0
第二场Ivar Jacobson(现代软件开发之父)的《软件开发大趋势》也不错,主要阐述了三个观点。
1、如何开发更优秀、高效和低成本的软件?
高效由多构件和积极主动的开发者来完成,低成本由大规模的构件重用实现,优秀的软件必然是实用性强,可扩展性高和稳定的产品。2、软件开发,实践为王
程序员需要更多的高级技术实践。重要的构件重用技术包括工程流,SOA,企业架构技术。实践是过程的基础,过程只是组成实践的一个元素。优秀的实践之所以成本低是由大规模的构件重用来实现。3、如何获得实践
传统的方法是通过书籍和网络,这样获得的数据相关性不够。先进的实践来源是没有限制的,包多基本和高级的方式,但只要是实用的就可以自由选择并合并这些实践组成一个新的过程。这种方法为开发人员提供了一种比较新的模式。
查看 CSDN 报道 >> 【SD2.0大会】Ivar:为什么我做的架构比你的年龄还长
第三场林斌(谷歌工程研究院副院长)介绍了 Google 的新手机平台 Android。之前我仅因为 Android 开源免费,并且出于对 Google 产品先量一贯的信任也装了一个 SDK 和 emulator 来玩一下,今天开会才了解到,Android 相对于其它平台的四个优势:及时响应;不会死机;通话切换;保存状态。不过同时公布的几项数据很有趣。“发布前两周,共250,000下载;下载量中国第一,超过美国1.5倍;”不知道 Google 用于奖励 Android 开发的一千万美元会有多少被中国人拿到?
查看 CSDN 报道 >> 【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 ,那么按照陈总的想法,手机可以和新组装的电脑一样,是裸机,通过我们安装服务来使用,这样大大的扩展了手机的功能。
查看 CSDN 报道 >> 【软件开发2.0大会】陈榕:让软件消失在用户面前
第五场Jim Reinders(Intel软件产品部首席宣传官居兼市场总监)讲的内容好像是关于并行计算这方面的,不过因为我在考虑其它事情,所以内容记得不是很清,也得明天找别人去“补课”了。
第六场Andrie Alexandrescu(C++天才作家、D语言领袖人物,华尔街咨询师)给我的感觉就是风趣……并且他那一长串长场介绍时的 title 也吸引了我,“某国伞兵”。
中午的午餐不过,就是同时就餐的人太多,要排好长的队,流量大,并发高,这也是我们这次会议要解决的问题。伙食不错,不过因为时间太紧,我也没有多吃,可能是因为菜有点咸,口味有点重(某些人看到这里不要误会,p囧q )。
下午第一场听的范路(Product Evangelist, China Mainland CodeGear)的《2.0时代软件开发新方法、新工具》,对 RAD STUDIO 2007 有了一些初步的了解。不过范路对软件体系结构、开发过程、语言以及开发工具的演变做了一些很有意思的分析和讲解。
查看 CSDN 报道 >> 【SD2.0大会】2.0开发时代的四大特性改变
在听下午第一场的中间,去洗手间的时候,顺路去博文视点的展台看了一下,看到一堆书上放了“请赐名片”和一位老兄把一张名片给了博文的工作人员,然后拿起一本书就走了,我以为是“以名片免费换书”,因为之前博文的传单上有写“免费赠书”。我兴致勃勃的回去找杨恺和老高要名牌,准备回来领书,结果回来一问,原来书是卖的,名片给不给都行……我被鄙视了……我看到的那个人之前给付钱了,不过我没看到。T_T
第二场幺宝刚讲解 Google Gear,之前有了解过 Gear 所以没有用太多的注意力来听,一直在紧紧的盯着“老钱”(钱宏武),期待着下一场他的演讲。
第三场,终于等到钱宏武演讲了,上回在悠视(悠视网 www.uusee.com)听他讲的时候,就感觉比较有内容,不像其它人讲的都是空泛的概念之类的,而他讲的是经验、问题和方法。其实,我这回自费来参加 SD2.0 大会,就是想来听他的演讲。钱宏武针对以前在 SOHU 做互动产品的经验介绍了如何开发和维护。其中他对于团队的构成和任务分配的特殊见解真是让我眼前豁然开朗,“给开发人员定一个稍高一点的目标”,“培养水平低的员工”等等……
查看 CSDN 报道 >> 【SD2.0大会】钱宏武谈做互联网产品就像娶老婆 贤惠又要好看

第四场听了前一半的董大伟的《ASP.NET AJAX 与 Silverlight 的完美结合》和冯彦文的《利用 Ajax/Java 技术建立高流量的即时双向沟通网站》。
终于等到我发挥特长的时候了,吃……晚宴时间。
晚上的沙龙算是这些大会给我的一个惊喜,原本订课时的沙龙是管理方面的,但是上午突然看到传单上有临时安排 Ben Wang(王文斌?当时离得太远,没看清,Taobao 首席架构师)、老钱(钱宏武)、雷鸣(前 Baidu 架构师)、汤道生(腾讯开发副总裁)四人合讲的《大型网站架构》收益良多啊……
总的来看 CSDN 这次举办的活动还是不错,真希望能坚持下去。
有几点让我感觉不太爽的地方:
1、每个人太早的发包,以至于,包比人多(有人来的时候自己本身就带包了,比如我),所以好多座位上都是放的包,让一些人没有地方座,吃饭、听课时都有这种情况。
2、经常在开会过程中听到手机响,真是搞不懂,开会前明明主持人已经让大家把手机都调成振动了。并且有人接到电话后还在原位置大声的煲电话粥,如果是工作就算了,竟然长时间打电话,还在闲聊!真是损人不利已。
3、原本晚上的沙龙是 VIP 才有的?但是看到好像没有什么限制,大家随便听。然后领东西时 VIP 也没有什么多的,就是一本增刊还是外面可以买到的,让我郁闷不已,VIP 和普通的没有什么区别嘛。
4、开会时,一直有人在下边聊天、拉关系,无比烦人!
转至 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
今天心情不错~ 分享一下小弟06年在某手机公司写的XML parser.
虽然当时脑子里还没有FSM的概念, 但代码逻辑还算清晰, 颇有成就感!
结构比较简单, 按DOM方式把指定文件解析成节点树, 另外提供几个简单的查找函数.
部分功能等完善, 过段时间再发一份功能比较完善的C++版本.
#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
#include <assert.h>
#include <fcntl.h>
#include <io.h>
#if defined(DEBUG) || 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( "[Xml Parser]: 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, “xml”, 3) )
{
// Here, dispose version and coding infomation in XML document header
}
else if ( nLenTag == 14 && !strncmp(lpszTag, “xml-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
汗一个…...
zhenyouchuangyi...
试图该怎么建立啊,,怎在程序中是吸纳...
看得人心旷神怡,好文,情不自禁的顶一下...
我也在处理这个问题,没有找到好的方法。我用了楼上兄弟的方法,还是可以的。不知道您找到好的方法了吗、我暂时楼上兄弟的方法。...
弱弱问一句:博主,你博客的模板这样设计pv高吗?...
博主,兔年快乐!...
great post!!I hope I can read more in your website....
好博文,支持分享...
博主的文章很不错,我是站长工具-站长精灵的作者,一款专业的SEO工具软件(可以帮您提高博客的流量),想跟您交换个链接,不知可否...