﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-lihuiba</title><link>http://www.cppblog.com/lihuiba/</link><description /><language>zh-cn</language><lastBuildDate>Sun, 05 Apr 2026 18:41:48 GMT</lastBuildDate><pubDate>Sun, 05 Apr 2026 18:41:48 GMT</pubDate><ttl>60</ttl><item><title>解决kvm中XP虚拟机鼠标漂移/不同步的问题（转载）</title><link>http://www.cppblog.com/lihuiba/archive/2012/07/26/185156.html</link><dc:creator>lihuiba</dc:creator><author>lihuiba</author><pubDate>Thu, 26 Jul 2012 03:42:00 GMT</pubDate><guid>http://www.cppblog.com/lihuiba/archive/2012/07/26/185156.html</guid><wfw:comment>http://www.cppblog.com/lihuiba/comments/185156.html</wfw:comment><comments>http://www.cppblog.com/lihuiba/archive/2012/07/26/185156.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lihuiba/comments/commentRss/185156.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lihuiba/services/trackbacks/185156.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="font-family: Tahoma, Verdana, 'BitStream vera Sans', Arial, Helvetica, sans-serif; font-size: 12px; line-height: 19px; background-color: #f9f9f9; "><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">前几天重操旧业，为了做测试又装了个windows xp的kvm虚拟机。一年没碰过这东西了，明显忘记了一些细节，比如安装完系统后，发现VNC中的鼠标走得总是比本地系统中的鼠标要慢，不同步，往往实体机中的鼠标都移出vnc窗口外边了，虚拟机中的鼠标指针还没移到需要点击的位置。</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span id="more-159"></span></p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">为此在网上找了半天，也没只找到一种法子：</p><blockquote style="margin-top: 5px; margin-right: 0px; margin-bottom: 5px; margin-left: 0px; padding-top: 8px; padding-bottom: 7px; padding-left: 36px; border-bottom-width: 1px; border-bottom-color: #fafafa; border-left-width: 3px; border-left-color: #e5e5e5; background-image: url(http://www.knktc.com/wordpress/wp-content/themes/ineo/img/sprite.png); background-color: #fafafa; background-position: -197px -321px; background-repeat: no-repeat no-repeat; "><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">在控制面板中选择鼠标设置，在指针设置中去掉&#8220;提高鼠标灵敏度&#8221;的选择。</p></blockquote><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">试用了下，只解决一般的问题：此时，虚拟机中的鼠标和实体机中的鼠标运动速度同步了，但是默认在打开VNC之后，虚拟机中的鼠标指针和实体机鼠标指针不重合。每次都必须努力移动鼠标指针到VNC边上，把实体机和虚拟机的鼠标指针弄得重合了，才能正常使用。</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">我突然想到，我们的业务系统中用的kvm虚拟机怎么就没有这问题呢？马上在virsh下查看了下业务系统中虚拟机的配置，才发现，这些虚拟机在输入设备中加了这么一句：</p><blockquote style="margin-top: 5px; margin-right: 0px; margin-bottom: 5px; margin-left: 0px; padding-top: 8px; padding-bottom: 7px; padding-left: 36px; border-bottom-width: 1px; border-bottom-color: #fafafa; border-left-width: 3px; border-left-color: #e5e5e5; background-image: url(http://www.knktc.com/wordpress/wp-content/themes/ineo/img/sprite.png); background-color: #fafafa; background-position: -197px -321px; background-repeat: no-repeat no-repeat; "><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">&nbsp;&nbsp; &lt;input type=&#8217;tablet&#8217; bus=&#8217;usb&#8217;/&gt;</p></blockquote><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">（该句位于&lt;devices&gt;配置中）</p></span><font class="Apple-style-span" face="Tahoma, Verdana, 'BitStream vera Sans', Arial, Helvetica, sans-serif"><span class="Apple-style-span" style="font-size: 12px; line-height: 19px;"><br /></span></font><span class="Apple-style-span" style="font-family: Tahoma, Verdana, 'BitStream vera Sans', Arial, Helvetica, sans-serif; font-size: 12px; line-height: 19px; background-color: #f9f9f9; "><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">我马上在我的虚拟机配置文件中也输入了这一句，加上这个输入设备，重启虚拟机后发现果然好使，打开VNC查看虚拟机界面后默认情况下虚拟机中的鼠标指针和实体机的鼠标指针就是重合的，且两者运动速度也是同步的，终于算是彻底解决了鼠标指针漂移/不同步的情况了。<br /><br /><br />lihuiba注：如果用kvm命令行，可增加参数<div style="display: inline-block; "></div></p></span><span class="Apple-style-span" style="font-family: Tahoma, Verdana, 'BitStream vera Sans', Arial, Helvetica, sans-serif; font-size: 12px; line-height: 19px; background-color: #f9f9f9; ">-device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -device usb-tablet,id=input0</span><span class="Apple-style-span" style="font-family: Tahoma, Verdana, 'BitStream vera Sans', Arial, Helvetica, sans-serif; font-size: 12px; line-height: 19px; background-color: #f9f9f9; "><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><br /><br /><br /><br /><br /></p></span><img src ="http://www.cppblog.com/lihuiba/aggbug/185156.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lihuiba/" target="_blank">lihuiba</a> 2012-07-26 11:42 <a href="http://www.cppblog.com/lihuiba/archive/2012/07/26/185156.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OpenStack安装过程中的KeyStone初始化</title><link>http://www.cppblog.com/lihuiba/archive/2012/07/26/185155.html</link><dc:creator>lihuiba</dc:creator><author>lihuiba</author><pubDate>Thu, 26 Jul 2012 03:38:00 GMT</pubDate><guid>http://www.cppblog.com/lihuiba/archive/2012/07/26/185155.html</guid><wfw:comment>http://www.cppblog.com/lihuiba/comments/185155.html</wfw:comment><comments>http://www.cppblog.com/lihuiba/archive/2012/07/26/185155.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lihuiba/comments/commentRss/185155.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lihuiba/services/trackbacks/185155.html</trackback:ping><description><![CDATA[<div><div>openstack essex版在装完keystone之后需要建立租户、用户和角色，官方手册提供了https://github.com/openstack/keystone/blob/master/tools/sample_data.sh脚本来做这件事情，然而这个脚本有bug，直接运行会产生大量错误信息（访问时间：2012.7.24）。</div><div></div><div>经过分析后发现，问题主要有以下几点：</div><div>0. 应在环境参数中设置用户的初始密码，分别存于变量ADMIN_PASSWORD和SERVICE_PASSWORD中。</div><div>1. 此外还应设定ENABLE_ENDPOINTS变量，以允许创建endpoints。ENABLE_ENDPOINTS和ENABLE_QUANTUM可根据情况选择。这些参数在脚本内注释里有提及。</div><div>2. 修改&#8220;keystone --endpoint-create ...&#8221;相关语句中的各种url的IP地址和语句格式，使之正确（NOVA_SERVICE的版本、格式有误）。</div><div>3. 脚本内的所有&#8220;keystone user-role-add&#8221;命令参数有误，应将所有的&#8220;--user_id&#8221;和&#8220;--role_id&#8221;中的&#8220;_id&#8221;删除，&#8220;--tenant_id&#8221;不变</div><div>4. 脚本内的所有&#8220;keystone ec2-credentials-create&#8221;命令参数有误，应将所有的&#8220;--user_id&#8221;中的&#8220;_id&#8221;删除，&#8220;--tenant_id&#8221;不变</div><div></div><div>done</div></div><div></div><img src ="http://www.cppblog.com/lihuiba/aggbug/185155.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lihuiba/" target="_blank">lihuiba</a> 2012-07-26 11:38 <a href="http://www.cppblog.com/lihuiba/archive/2012/07/26/185155.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>该如何应对危机？</title><link>http://www.cppblog.com/lihuiba/archive/2009/10/12/98419.html</link><dc:creator>lihuiba</dc:creator><author>lihuiba</author><pubDate>Mon, 12 Oct 2009 12:43:00 GMT</pubDate><guid>http://www.cppblog.com/lihuiba/archive/2009/10/12/98419.html</guid><wfw:comment>http://www.cppblog.com/lihuiba/comments/98419.html</wfw:comment><comments>http://www.cppblog.com/lihuiba/archive/2009/10/12/98419.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lihuiba/comments/commentRss/98419.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lihuiba/services/trackbacks/98419.html</trackback:ping><description><![CDATA[<p>自从08年9月份金融危机全面爆发以来，世界各国都采取了许多措施来应对挑战。我国的应对方法可以粗略概括为政府投资、银行放贷和政策扶持等几大方面。这一套应对方法受到了许多人的评判，认为没有对症下药，治标不治本等等。然而许多人在批评之余，并没有提出任何建设性的意见和建议。例如，今天看到郎咸平先生的一篇讲稿，里面谈到政府几年前的宏观调控一直就是错误的，直到去年9月才明白过来，于是180度转身，但是已经晚了。他还谈到现在政府实施的修路架桥、10大产业振兴、过量放贷等措施根本不能解决当下危机，反而会加重日后的产能过剩。然而我却认为，这些措施虽然不是应对危机的根本方法，但也有其可取之处。 <p>我不想讨论前几年的宏观调控措施是否正确，因为过去的事情已经过去，再论也于事无补。我想要讨论的是当下应对危机的实用手段，这要讲求可行性、可操作性，不能过于理论化、理想化。我的观点以及推理逻辑基于如下两条“公理”（我的世界观中的公理，呵呵），如果这两条公理您不认可，那就不需要继续往下看了。 <p>1. 任何国家、政府都会追求社会稳定，即使奥玛·美帝也是这样。因此当自身或者外部环境发生大变动的时候，政府应该出台补偿政策，使得变化趋于缓和。这就跟生病了就要打针吃药，天冷了就要加衣服是一个道理。 <p>2. 小时候在教课书里看到万恶的资本家宁可把牛奶倒入河里，也不肯分给穷人，感到十分气愤。长大了，学会从资本家的角度去考虑，觉得这么作对于他们来说或许利益是最大化的。现在我认为，从社会财富角度去讲，这无疑是一种巨大浪费，应该尽力避免。 <p>一、讨论方法。经济学、金融学通常以货币——就是钱——作为研究对象，然而我认为有时候从很宏观的角度去思考问题时，绕过货币，直接考虑财富可能更容易看清本质。这里的“财富”是指人所需要的各种物品如粮食、衣服、房子、计算机、各种服务等等，不特指金银珠宝。货币只是社会财富分配的辅助工具，是表面现象，而财富才是人所需的本质东西。因而在考虑宏观问题，特别是国与国之间的问题时（不同货币），直接考虑财富有时是一条捷径。 <p>二、中美财富关系。中国在这两年俨然已成为世界工厂，中国生产物质财富，出口到美国并赚取外汇；美国向中国借美元，然后购买财富并消费。中美之间的财富关系就是财富从中国净流出到美国，累积价值已超过2万亿美元。这个关系可以比喻为：A(merica)先生很能干，但是生活奢侈，一直靠C(hina)先生救济过日子；C先生勤劳朴实，宁可自己缺衣少食，也笑着把最好的东西借给A先生以维持他的生活标准。直到有一天，A先生决定要改变一下生活方式。 <p>三、双方危机的实质。如今借钱的是孙子，欠债的是爷。美国危机的本质（主要矛盾）是债务太多，那么接下来自然的处理办法之一就是勒紧裤腰带，勤奋工作，自食其力，增加储蓄。美国自食其力，必要要显著减少进口。中国危机的本质（主要矛盾）是出口受阻，外贸企业面临倒闭。简单地说就是人家不要我们给他打工了，我们被炒鱿鱼了。最理想的办法是出口转内销，给自己人以“最惠国民”待遇。然而这个转变需要时间，甚至个别产业可能无法转变。这个过程是个大课题，在此就不深入讨论了。 <p>四、中国应对危机。由于出口锐减，是外部环境的突变，根据公理1，政府应该出台补偿性措施，以缓和冲击，避免相关产业出现工人大量失业。于是提高出口退税、结构性减税、XX下乡等措施相继出台。但是这些还不够，因为再怎么补贴也只能救急，出口量最终一定会减少的。为了进一步补偿出口下降的影响，同时也尽量避免让产品、产能闲置浪费，国家应该大力投资，以消费这些产品。 <p>为了避免大量失业，工厂就要开工，产品就要有销路。当前只有政府来充当这个“冤大头”买入这些产品，比如钢铁、水泥。那么买入之后呢？根据公理2，闲置浪费当然不如修路架桥，即便这些路在10年之内都没有多少人走，也比水泥闲置结块，钢铁闲置生锈强！ <p>许多人担心这些投资的收益问题，担心投资几万亿成为坏账。其实这些观点都是从基于货币的资源、财富分配角度考虑的，而如前所述，货币只是表象。在浪费货币（坏账核销）和浪费财富（产品废弃）之间，我们当然毫不犹豫地选择浪费货币。 <p>货币是什么？就是一张小纸片，甚至连纸片都不是，就是数据库中的一条记录而已。这样的投资并不会带来通胀，因为整个外贸业并没有得到更多的货币，相反还在不断萎缩；国内的物质财富也没有减少，而且增加得更快（出口转内销）。通胀是什么？就是货币相对财富变多，或者财富相对货币变少。 <p>（上半年的天量信贷目的为何我并没有太清楚，财政不够？转移支付？烘托股市楼市？支持国进？避免大量企业被国外收购？或许都有吧。） <p>五、未来之路。当出口产能过剩的问题基本解决，推动国民最终消费增长才能成为主要矛盾。投资、出口、消费三架马车现在坏了一辆，现在只能指望投资和消费。政府在危机爆发的瞬态响应是增加投资弥补出口量跌以及提高退税补贴出口盈利，但长久之计还是要增加消费，因为各国危机之下，贸易保护主义必将抬头，补贴出口不可持久，而且政府主导的投资效率较低。提高国民最终消费，就牵扯到两个问题：1要让群众有更多的钱来消费，2要让群众无后顾之忧地消费。这是两块硬骨头，前者要减少政府和企业所得的蛋糕份额，后者要解决教育、医疗、住房三座大山，不知道D要如何作为，但可以肯定这是一个长期的过程。中国政府是一个中央集权的强势政府，估计即使到达了稳态，政府投资的比例也仍然会较高，因为政府有钱有意愿。 <p>本来写完了，突然又想起一个“妙招”：把居民消费作为官员考核指标即可，呵呵，GDP指标取消还不能取消，要稳定，稳定。</p><img src ="http://www.cppblog.com/lihuiba/aggbug/98419.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lihuiba/" target="_blank">lihuiba</a> 2009-10-12 20:43 <a href="http://www.cppblog.com/lihuiba/archive/2009/10/12/98419.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ogre3D中的MPQ档案读取</title><link>http://www.cppblog.com/lihuiba/archive/2009/09/29/97572.html</link><dc:creator>lihuiba</dc:creator><author>lihuiba</author><pubDate>Tue, 29 Sep 2009 12:34:00 GMT</pubDate><guid>http://www.cppblog.com/lihuiba/archive/2009/09/29/97572.html</guid><wfw:comment>http://www.cppblog.com/lihuiba/comments/97572.html</wfw:comment><comments>http://www.cppblog.com/lihuiba/archive/2009/09/29/97572.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/lihuiba/comments/commentRss/97572.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lihuiba/services/trackbacks/97572.html</trackback:ping><description><![CDATA[<p></p> <p><font size="4" face="宋体">Ogre的全称是面向对象的图形渲染引擎（Object-oriented Graphics Rendering Engine），它直接支持从文件系统或者zip档案中加载资源，同时也支持用户自定义档案格式。我基于StormLib为Ogre添加了MPQ格式支持。如图1所示，在Ogre中新增档案格式需要扩展ArchiveFactory、Archive和DataStream等几个类，具体来说，我新增了MpqArchiveFactory、MpqArchive和MpqDataStream三个类，其中工厂类（MpqArchiveFactory）用于向档案管理器注册（未画出），同时告诉管理器新增档案的类型（"Mpq"），并提供相应档案类的创建、销毁函数；档案类（MpqArchive）代表实际的MPQ档案，它提供了档案内的文件查找、元信息查询以及文件打开的功能；文件打开后得到的是DataStream的派生对象（MpqDataStream），负责文件内的数据读取工作。 这三个新增类的具体定义如图2所示。</font>  <p>&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/Archive%20Overview_6.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Archive Overview" border="0" alt="Archive Overview" src="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/Archive%20Overview_thumb_2.png" width="712" height="881"></a>&nbsp;&nbsp; <p align="left">图1 Ogre中的档案模块理结构  <p>&nbsp; <p><a href="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/MpqArchiveFactory_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="MpqArchiveFactory" border="0" alt="MpqArchiveFactory" src="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/MpqArchiveFactory_thumb.png" width="220" height="167"></a>&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/MpqArchive_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="MpqArchive" border="0" alt="MpqArchive" src="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/MpqArchive_thumb.png" width="221" height="373"></a>&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/MpqDataStream_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="MpqDataStream" border="0" alt="MpqDataStream" src="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/MpqDataStream_thumb.png" width="199" height="244"></a>  <p>图2 Mpq档案相关类的类图  <p><font size="4" face="宋体">由于MPQ档案内不包含文件名和路径名，我目前的实现要求所打开的档案内必须包含"(listfile)"文件，并从中读取文件名全集，并排序以便于后续检索。由于Archive中的find(), findFileInfo(), list()以及listFileInfo()函数的功能较为相似，我实现了一个filter()函数，用于从文件名全集中按需过滤出指定子集，同时还实现了一个details()函数，用于添加文件详细信息。这两个函数的适当组合便能实现上述四个函数的功能。</font><font size="4" face="宋体">由于<font size="4" face="宋体">MpqDataStream类</font>功能较为简单，基本上是直接调用StormLib中的相应功能，完全实现只用了20余行代码。</font>  <p><font size="4" face="宋体">Ogre自带了一个读取Quake3地图(zip档案)的例子。我用现成工具将pk3档案转换为MPQ格式，并修改该例配置文件，读取MPQ文档成功。有截图为证（其加载过程和地图漫游）：</font>  <p><a href="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/loading_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="loading" border="0" alt="loading" src="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/loading_thumb.png" width="612" height="484"></a></p> <p><a href="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/scene_2.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="scene" border="0" alt="scene" src="http://www.cppblog.com/images/cppblog_com/lihuiba/WindowsLiveWriter/Ogre3DMPQ_12453/scene_thumb.jpg" width="644" height="364"></a></p> <p><font size="4" face="宋体"></font>&nbsp; <p><font face="宋体"></font><font size="4" face="微软雅黑">小花絮：Stream中的陷阱</font>&nbsp; <p><font size="4" face="宋体"><font size="4" face="宋体">MpqDataStream的实现过程让我走了许多冤枉路。当我快速实现这个类之后，</font></font><font size="4" face="宋体">实际运行却会导致一个访问异常的错误。这个错误发生在Ogre内部，我没有装Ogre源代码，无法精确定位错误，只能猜测可能的原因。由于Stream类、Factory类都很简单，所有函数都不超过3行，在目测“无误”后我就紧盯MpqArchive类的实现。由于MPQ文件是平板模式，在物理上没有目录树的结构，而Archive类假定档案是有结构的，我起初怀疑问题出在文件名和路径名的处理上，然而经过仔细编写并多次重构之后问题依旧，一筹莫展。尝试了debug、release两套配置，都报告错误。</font>  <p><font size="4" face="宋体">在无奈之际，我又尝试自己编写一个针对文件系统的档案读取套装，实际上就是重新实现了FileSystemArchive系列类。由于这个套装十分简单并且与MPQ档案无关，这个尝试可以快速验证我对Ogre档案格式扩展机制的理解是否正确、全面。结果证明问题果然在这里——我的文件系统档案套装引发了完全一样的错误。</font>  <p><font size="4"><font face="宋体">虽然明白错误在这个区域，但仍然无法知道究竟是那里疏忽了。我明白我需要查看故障处的源代码，然而SDK不但没有源代码，而且没有提供PDB（程序的debug数据库），只能重新编译，自己生成。在一通下载、编译、调试和分析之后，终于发现了原因：BSP场景管理器打开了BSP地图，然而却没有从我的MpqDataStream中读出数据，并在没有检查是否读出的情况就使用了“数据”，最终导致访问违例。<font color="#800000">而之所以未能从MpqDataStream读出数据，是因为DataStream父类中的保护成员mSize没有赋值（默认为0），导致DataStream误认为数据流的长度为0。</font><font color="#000000">最终，在MpqDataStream类的构造函数中设值正确的mSize值，解决问题。</font></font></font> <p><font size="4" face="宋体">一般来说，我在继承类的时候，会比较注意其中的虚函数，尤其是纯虚函数，认为这些是留给我用的钩子。但我以为保护型（<font color="#008000">proected</font>）成员（尤其是保护型数据成员）一般是可选钩子，或者是留给我的福利，而不应为强加给我的责任。这种角色最好以纯虚函数的方式表达（模板方法模式），这样我一眼就看出我必须做这件事。更为要命的是，我再次查阅Ogre API Reference的时候，发现它并没有说这个mSize必须要设值，只说默认为0。</font></p><img src ="http://www.cppblog.com/lihuiba/aggbug/97572.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lihuiba/" target="_blank">lihuiba</a> 2009-09-29 20:34 <a href="http://www.cppblog.com/lihuiba/archive/2009/09/29/97572.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MPQ文件读取</title><link>http://www.cppblog.com/lihuiba/archive/2009/09/23/97059.html</link><dc:creator>lihuiba</dc:creator><author>lihuiba</author><pubDate>Wed, 23 Sep 2009 14:49:00 GMT</pubDate><guid>http://www.cppblog.com/lihuiba/archive/2009/09/23/97059.html</guid><wfw:comment>http://www.cppblog.com/lihuiba/comments/97059.html</wfw:comment><comments>http://www.cppblog.com/lihuiba/archive/2009/09/23/97059.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lihuiba/comments/commentRss/97059.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lihuiba/services/trackbacks/97059.html</trackback:ping><description><![CDATA[<pre><div align="left" border="1">MPQ文件是暴雪公司的一种私有文档打包格式，广泛应用在其游戏产品中，如魔兽争霸系列、星际争霸系列等、暗黑破坏神系列以及魔兽世界等。MPQ包内保存了几乎全部的游戏资源，包括模型、纹理、材质、动画、音频、视频、单位属性等等。除了游戏资源之外，这些游戏的地图、战役以及一些游戏的进度存档也是都MPQ格式，只是扩展名用了其他的标识。MPQ文档兼具打包和压缩的功能，并且其压缩算法可以根据具体文件格式而有所不同。例如，根据StormLib源代码结构信息，MPQ包至少支持bzip2、huffman、pklib以及一种专门针对wav格式的压缩算法。 
</div></pre>
<p>MPQ是一种针对读取优化的文档，与其他格式（如zip）相比，它最大的特点是没有树形结构，甚至连文件名都不保存。在存取时，它将文件的全路径名称做两次不同的哈希：h1 = hash1(pathname)、h2 = hash2(pathname)，并将这两个哈希值作为索引信息。由于将路径文件名整体作为字符串计算哈希值，整个MPQ包构成平板模式，在物理上没有目录结构。在检索文件时，由于不需要逐级深入目录，MPQ包的读取较为简洁高效。 
<p>MPQ是一种古老的包格式，现有许多第三方工具可以读写这种格式，其中很多都公布了源代码，甚至形成了专门的读写库。我找到的各个MPQ相关库总结如下： 
<table border="1" cellspacing="0" cellpadding="0" width="633">
<tbody>
<tr>
<td valign="top" width="183">
<p align="center">名称（标配工具）</p></td>
<td valign="top" width="101">
<p align="center">作者</p></td>
<td valign="top" width="347">
<p align="center">备注</p></td></tr>
<tr>
<td valign="top" width="183">
<p align="center">Storm.dll</p></td>
<td width="101">
<p align="center">Blizzard</p></td>
<td width="347">
<p>Diablo I附带的Storm.dll可被其他工具调用。</p></td></tr>
<tr>
<td valign="top" width="183">
<p align="center">StormLess MPQ Editor</p></td>
<td width="101">
<p align="center">Tom Amigo</p></td>
<td width="347">
<p>提供VC6源代码。最新版本发布与2000年。</p></td></tr>
<tr>
<td valign="top" width="183">
<p align="center">StormLib 
<p align="center">(MPQEditor)</p></td>
<td width="101">
<p align="center">Ladislav Zezula</p></td>
<td width="347">
<p>由Marko Friedemann将其移植到Linux平台。</p></td></tr>
<tr>
<td valign="top" width="183">
<p align="center">Libmpq 
<p align="center">(MPQ-tools)</p></td>
<td width="101">
<p align="center">Maik Broemme</p></td>
<td width="347">
<p>似乎只支持Linux。</p></td></tr>
<tr>
<td valign="top" width="183">
<p align="center">SFmpq.dll 
<p align="center">(WinMPQ)</p></td>
<td width="101">
<p align="center">ShadowFlare Software</p></td>
<td width="347">
<p>SFmpq.dll由VC++编写，WinMPQ应用由VB4编写。</p></td></tr>
<tr>
<td valign="top" width="183">
<p align="center">MPQlib 
<p align="center">(MPQMaster)</p></td>
<td width="101">
<p align="center">Quixotic Yawl Studio</p></td>
<td width="347">
<p>没有找到源代码，不过从它暴露的语言扩展接口来看，似乎是Delphi写的。</p></td></tr></tbody></table>
<p>Ladislav Zezula同志的StormLib成为使用毫无疑问是Windows平台下C++程序访问MPQ包的最佳选择。我将StormLib的使用心得以要点形式总结如下： 
<p>1. 所有的API函数、常量定义、结构体定义都可以在StormLib.h中查到，Zezula的主页上也有大部分函数的介绍，在此就不copy &amp; paste了。 
<p>2. 读取文件所需函数：SFileOpenArchive()、SFileCloseArchive()分别为打开、关闭MPQ文件；SFileOpenFileEx()、SFileCloseFile()分别为打开、关闭MPQ包中的文件；SFileReadFile()读取实际数据，隐含解压缩过程。 
<p>3. 一个关于FilePointer的小陷阱：SFileSetFilePointer()函数用于设置文件指针，类似于C标准库中的fseek()函数，然而SFileGetFilePos()并不是返回文件指针，而是返回该文件在MPQ包中的物理位置。要得到当前文件指针位置，仍然需要SFileSetFilePointer()函数，将文件指针相对当前位置移动0，其返回值则为当前指针位置，如： </p>
<table border="1">
<tbody>
<tr>
<td><pre><span style="color: #0000ff">virtual</span> size_t tell() <span style="color: #0000ff">const</span>
{
	<span style="color: #0000ff">return</span> (size_t)SFileSetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
}</pre></td></tr></tbody></table>4. StormLib没有提供feof()之类的调用，可以用当前文件指针与文件大小进行比较得到，如<br>
<table border="1">
<tbody>
<tr>
<td><pre><span style="color: #0000ff">virtual</span> <span style="color: #0000ff">bool</span> eof() <span style="color: #0000ff">const</span> 
{
	DWORD pos = SFileSetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
	DWORD size = SFileGetFileSize(m_hFile);
	<span style="color: #0000ff">return</span> pos&gt;=size;
}</pre></td></tr></tbody></table>
<p>5. StormLib还提供了创建MPQ包、写入文件、包内搜索文件等功能，本文从略。</p><img src ="http://www.cppblog.com/lihuiba/aggbug/97059.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lihuiba/" target="_blank">lihuiba</a> 2009-09-23 22:49 <a href="http://www.cppblog.com/lihuiba/archive/2009/09/23/97059.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>