CCFileUtils::getFileData疑惑
背景
这几天在使用cocos2d-x读取磁盘文件的时候,发现了CCFileUtils中一点不合理的地方,特此记录,以供研讨。
项目结构
①我使用的是cocos2d-x 2.1.3版本,CCFileUtils::getFileData的函数签名为:
但据观测,即使是最新版的cocos2d-x 3.2,这部分声明和实现仍没有变化。
②我们假设在项目Resources目录下,有data.txt,其中内容大致为下图:
③下面以win32和android两种平台做对比来分析其中出现的问题。
Win32
①读取文件的代码
②实际执行的读取代码
文件路径:cocos2dx\platform\CCFileUtils.cpp
③过程分析
在Windows中,行结尾符是”\r\n”,所以当程序执行完381行时,
*pSize = ( 5+2+6+2+6 , 21 );
当程序执行完384行时,
*pSize = ( 5+1+6+1+6 , 19 );
当程序返回时,
*pSize == 19; //没有问题
sizeof(pBuffer) == 21; //没有问题
pBuffer == “apple\norange\nbananba?????”; //问题很严重
④结果
当执行步骤①的代码时,我们使得data指向了这样一个字符串:
1.一段以”r”模式读取文件的代码,却在其中包含了’\n’;
2.这个字符串没有’\0’结尾。
这里的问题很好解决,只要我们添加下面一条语句,就可以避免悲剧:
data[pSize] = ‘\0’;
Windows平台上的问题很好解决,下面我们转向android.
Android
①读取文件的代码
②实际执行的读取代码
文件路径:cocos2dx\platform\android\CCFileUtilsAndroid.cpp
③过程分析
由于Android平台上行结尾符为\r,所以当执行完415行时,
*pSize = ( 5+1+6+1+6 , 19 );
sizeof(pBuffer) == 19
有问题吗?很严重。
④结果
下面回到步骤①,此时的data指向了一个字符串,这个字符串:
1.一段以”r”模式读取文件的代码,却在其中包含了’\n’;
2.这个字符串没有’\0’结尾。
但是,此时我们不能使用win32平台的解决方案。
data[size] = ‘\0’; //数组越界!
data[size-1] = ‘\0’;//banana中的最后一个a会被删除
此时,在语言层面上,只有把这段内存复制到一个更安全的地方,才可以解决这种冲突。如果你直接操纵data,几乎可以肯定会出问题。
错误解法:string str = (char*)data;
正确解法:string str( data, data+size );
结论
CCFileUtils::getFileData,一旦你以”r”模式来使用它,data就会变成一个没有’\0’结尾的字符串;一旦你在一个行结尾符是由单个字节组成的系统中使用它,你就不能给它加一个’\0’。如果不注意这两点,几乎可以肯定会误用这个函数。所以使用它的时候,请谨慎!
并且,请使用string str( data, data+size );的形式来复制这个易错字符串。
PS
话说这个函数的声明和实现相当容易被误用,不仔细分析几乎一定会被误用,因为其中的一些做法完全是和常识相违背的,不知道cocos2d-x的团队为什么不修改一下。
CCFileUtils::getFileData疑惑的更多相关文章
- cocos2d::CCFileUtils::sharedFileUtils()->getFileData(szFile, "r", &bufferSize) 不同平台返回值不一样
string pathKey = CCFileUtils::sharedFileUtils()->fullPathForFilename(fileName); unsigned char* pB ...
- 基于Quick-cocos2d-x的资源更新方案 二
写在前面 又是12点半了,对于一个程序员来说,这是一个黄金时间,精力旺盛,我想,是最适合整理和分享一些思路的时候了. 自从上次写了 基于Quick-cocos2d-x的资源更新方案 同样可见quick ...
- cocos2dx游戏资源加密之XXTEA
在手机游戏当中,游戏的资源加密保护是一件很重要的事情. 我花了两天的时间整理了自己在游戏当中的资源加密问题,实现了跨平台的资源流加密,这个都是巨人的肩膀之上的. 大概的思路是这样的,游戏资源通过XXT ...
- cocos2dx 不同平台上加载文件
原文转自:http://blog.sina.com.cn/s/blog_62b2318d0101eozt.html cocos2dx在不同平台上读取资源文件时的处理方式是不同的. 在ios下,程序调用 ...
- 如何学习 cocos2d-x ?
发表于 04/23/2014 作者 zrong — 24 条评论 ↓ 11,687 次查看 本站文章除注明转载外,均为本站原创或者翻译. 本站文章欢迎各种形式的转载,但请18岁以上的转载者注明文章出处 ...
- cocos2d-x lua 中使用protobuf并对http进行处理
cocos2d-x lua 中使用protobuf并对http进行处理 本文介绍 cocos2d-x lua 中使用http 和 基于cocos2d-x 对lua http的封装(部分ok) 本博客链 ...
- Atitit 图像处理的心得与疑惑 attilax总结
Atitit 图像处理的心得与疑惑 attilax总结 1.1. 使用类库好不好??还是自己实现算法1 1.2. 但是,如果遇到类库体积太大,后者没有合适的算法,那就只能自己开发算法了1 1.3. 如 ...
- 每日一记-mybatis碰到的疑惑:String类型可以传入多个参数吗
碰到一个觉得很疑惑的问题,Mybatis的parameterType为String类型的时候,能够接收多个参数的吗? 背景 初学Mybatis的时候,看的教程和书籍上都是在说基本的数据类型如:int. ...
- 解决上一篇jquery中on的疑惑
内容都是来自:http://www.365mini.com/page/jquery-on.htm.这里做一下收藏.文章的最后 疑问和解答可以解决所有的疑惑 看了之后能更好的整篇文章. on()函数 ...
随机推荐
- js判断是否微信浏览器打开
function is_weixn(){ var ua = navigator.userAgent.toLowerCase(); if(ua.match(/MicroMessenger/i)==&qu ...
- 本地windows下PHP连接远程oracle遇到的诸多问题
任务目的:本地windows下PHP连接远程服务器下的oracle. 必须必须 确定服务器的数据库版本,如果本地的驱动和对方服务器版本不一致,会导致许多报错. 已知的oracle版本 分为 32位的 ...
- 标准程序员系列-Github篇-初始化一个代码仓库
下面将一步步介绍怎样使用GitHub来初始化一个项目的版本控制仓库: 1. 到GitHub上注册自己的账号:https://github.com/ 2. 创建第一个代码仓库一个仓库相当于一个项目的代码 ...
- (转载)lib 和 dll 的区别、生成以及使用详解
简单地讲: 第一:.DLL是动态链接库,而.LIB是静态链接库dll是个编译好的程序,调用时可以直接调用其中的函数,不参加工程的编译. 而lib应该说是一个程序集, 只是把一些相应的函数总结在一起, ...
- tensorflow 使用
1.linux 安装tensorflow ubuntu中安装:link 用pip安装的过程中,可能出现网络链接的问题,尝试多次链接,直到成功!!! python -V sudo apt-get ins ...
- OCR中的倾斜矫正
电面中被问到了做的LPR,简单的介绍了下后又问到了关于如何矫正倾斜角的问题.答得比较含糊,所以今天来补充一下. 倾斜矫正的方法有很多种,包括基于Hough变换的矫正,基于字符投影的倾角矫正,常规线性角 ...
- jave script 经典排序 - -冒泡排序
有 5个数字,2:3:1:0:4,按大小顺序排列 <script type="text/javascript"> var arr =new Array(); arr . ...
- Android中写入读取XML
获取XML文件的基本思路是,通过getResources().getXml()获的XML原始文件,得到XmlResourceParser对象,通过该对象来判断是文档的开头还是结尾,是某个标签的开始还是 ...
- LeetCode_Scramble String
Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrin ...
- NOI2012 魔幻棋盘
http://www.lydsy.com/JudgeOnline/problem.php?id=2877 二维线段树. 好恶...... B类数据: 棋盘是一维的. 我们有一个结论: $gcd(a_{ ...