Godot 4 源码分析 - 文件读入编码处理

2023-10-29

今天需要读入xml文件进行处理,结果读入一个带中文的文件时,出错了。当然程序还能运行,但编译器一直报错,而且XML解析也不正确

单步调试发现读入的内容出现乱码,具体逻辑:

String FileAccess::get_as_text(bool p_skip_cr) const {
	uint64_t original_pos = get_position();
	const_cast<FileAccess *>(this)->seek(0);

	String text = get_as_utf8_string(p_skip_cr);

	const_cast<FileAccess *>(this)->seek(original_pos);

	return text;
}

String FileAccess::get_as_utf8_string(bool p_skip_cr, String encoding) const {
	encoding = encoding.to_lower();
	Vector<uint8_t> sourcef;
	uint64_t len = get_length();
	sourcef.resize(len + 1);

	uint8_t *w = sourcef.ptrw();
	uint64_t r = get_buffer(w, len);
	ERR_FAIL_COND_V(r != len, String());
	w[len] = 0;

	String s((const char *)w);
	s.parse_utf8((const char *)w, -1, p_skip_cr);
	return s;
}

Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) {
	if (!p_utf8) {
		return ERR_INVALID_DATA;
	}

	String aux;

	int cstr_size = 0;
	int str_size = 0;

	/* HANDLE BOM (Byte Order Mark) */
	if (p_len < 0 || p_len >= 3) {
		bool has_bom = uint8_t(p_utf8[0]) == 0xef && uint8_t(p_utf8[1]) == 0xbb && uint8_t(p_utf8[2]) == 0xbf;
		if (has_bom) {
			//8-bit encoding, byte order has no meaning in UTF-8, just skip it
			if (p_len >= 0) {
				p_len -= 3;
			}
			p_utf8 += 3;
		}
	}

	bool decode_error = false;
	bool decode_failed = false;
	{
		const char *ptrtmp = p_utf8;
		const char *ptrtmp_limit = &p_utf8[p_len];
		int skip = 0;
		uint8_t c_start = 0;
		while (ptrtmp != ptrtmp_limit && *ptrtmp) {
			uint8_t c = *ptrtmp >= 0 ? *ptrtmp : uint8_t(256 + *ptrtmp);

			if (skip == 0) {
				if (p_skip_cr && c == '\r') {
					ptrtmp++;
					continue;
				}
				/* Determine the number of characters in sequence */
				if ((c & 0x80) == 0) {
					skip = 0;
				} else if ((c & 0xe0) == 0xc0) {
					skip = 1;
				} else if ((c & 0xf0) == 0xe0) {
					skip = 2;
				} else if ((c & 0xf8) == 0xf0) {
					skip = 3;
				} else if ((c & 0xfc) == 0xf8) {
					skip = 4;
				} else if ((c & 0xfe) == 0xfc) {
					skip = 5;
				} else {
					skip = 0;
					print_unicode_error(vformat("Invalid UTF-8 leading byte (%x)", c), true);
					decode_failed = true;
				}
				c_start = c;

				if (skip == 1 && (c & 0x1e) == 0) {
					print_unicode_error(vformat("Overlong encoding (%x ...)", c));
					decode_error = true;
				}
				str_size++;
			} else {
				if ((c_start == 0xe0 && skip == 2 && c < 0xa0) || (c_start == 0xf0 && skip == 3 && c < 0x90) || (c_start == 0xf8 && skip == 4 && c < 0x88) || (c_start == 0xfc && skip == 5 && c < 0x84)) {
					print_unicode_error(vformat("Overlong encoding (%x %x ...)", c_start, c));
					decode_error = true;
				}
				if (c < 0x80 || c > 0xbf) {
					print_unicode_error(vformat("Invalid UTF-8 continuation byte (%x ... %x ...)", c_start, c), true);
					decode_failed = true;
					skip = 0;
				} else {
					--skip;
				}
			}

			cstr_size++;
			ptrtmp++;
		}

		if (skip) {
			print_unicode_error(vformat("Missing %d UTF-8 continuation byte(s)", skip), true);
			decode_failed = true;
		}
	}

	if (str_size == 0) {
		clear();
		return OK; // empty string
	}

	resize(str_size + 1);
	char32_t *dst = ptrw();
	dst[str_size] = 0;

	int skip = 0;
	uint32_t unichar = 0;
	while (cstr_size) {
		uint8_t c = *p_utf8 >= 0 ? *p_utf8 : uint8_t(256 + *p_utf8);

		if (skip == 0) {
			if (p_skip_cr && c == '\r') {
				p_utf8++;
				continue;
			}
			/* Determine the number of characters in sequence */
			if ((c & 0x80) == 0) {
				*(dst++) = c;
				unichar = 0;
				skip = 0;
			} else if ((c & 0xe0) == 0xc0) {
				unichar = (0xff >> 3) & c;
				skip = 1;
			} else if ((c & 0xf0) == 0xe0) {
				unichar = (0xff >> 4) & c;
				skip = 2;
			} else if ((c & 0xf8) == 0xf0) {
				unichar = (0xff >> 5) & c;
				skip = 3;
			} else if ((c & 0xfc) == 0xf8) {
				unichar = (0xff >> 6) & c;
				skip = 4;
			} else if ((c & 0xfe) == 0xfc) {
				unichar = (0xff >> 7) & c;
				skip = 5;
			} else {
				*(dst++) = 0x20;
				unichar = 0;
				skip = 0;
			}
		} else {
			if (c < 0x80 || c > 0xbf) {
				*(dst++) = 0x20;
				skip = 0;
			} else {
				unichar = (unichar << 6) | (c & 0x3f);
				--skip;
				if (skip == 0) {
					if (unichar == 0) {
						print_unicode_error("NUL character", true);
						decode_failed = true;
						unichar = 0x20;
					}
					if ((unichar & 0xfffff800) == 0xd800) {
						print_unicode_error(vformat("Unpaired surrogate (%x)", unichar));
						decode_error = true;
					}
					if (unichar > 0x10ffff) {
						print_unicode_error(vformat("Invalid unicode codepoint (%x)", unichar));
						decode_error = true;
					}
					*(dst++) = unichar;
				}
			}
		}

		cstr_size--;
		p_utf8++;
	}
	if (skip) {
		*(dst++) = 0x20;
	}

	if (decode_failed) {
		return ERR_INVALID_DATA;
	} else if (decode_error) {
		return ERR_PARSE_ERROR;
	} else {
		return OK;
	}
}

其实已经读入到w里,但String::parse_utf8出错。

回头看了一下,原目标文件为GB2312编码。而Godot的FileAccess不支持别的编码。

那就加上,在不影响原有逻辑的基础上,小动一下:

ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr", "encoding"), &FileAccess::get_as_text, DEFVAL(false), DEFVAL("utf-8"));

String FileAccess::get_as_text(bool p_skip_cr, String encoding) const {
	uint64_t original_pos = get_position();
	const_cast<FileAccess *>(this)->seek(0);

	String text = get_as_utf8_string(p_skip_cr, encoding);

	const_cast<FileAccess *>(this)->seek(original_pos);

	return text;
}

String FileAccess::get_as_utf8_string(bool p_skip_cr, String encoding) const {
	encoding = encoding.to_lower();
	Vector<uint8_t> sourcef;
	uint64_t len = get_length();
	sourcef.resize(len + 1);

	uint8_t *w = sourcef.ptrw();
	uint64_t r = get_buffer(w, len);
	ERR_FAIL_COND_V(r != len, String());
	w[len] = 0;

	if (encoding == "gb2312") {
		std::string str((const char *)w);
		String s(str);
		return s;
	}
	
	String s((const char *)w);
	s.parse_utf8((const char *)w, -1, p_skip_cr);
	return s;
}

GDScript中调用:

	var xml : Xml = Xml.new("D:\\ExenObj\\Exe\\DrGraph\\Files\\Demo.sch")
	xml.Read("gb2312");

class Xml:
	var RootNode: XmlNode = null
	var FileName: String = ""
	func _init(fileName: String) -> void:
		FileName = fileName
	
	func Read(encoding: String = "utf-8") -> void:
		if FileAccess.file_exists(FileName):			
			var fs = FileAccess.open(FileName, FileAccess.READ)
			var text = fs.get_as_text(false, encoding)
			var textStart = Helper.RegMatchAt(text, "<[^!?]")
			var pos = 0;
			if textStart.length() > 0:
				pos = text.find(textStart)
			if pos > 0:
				var header = text.substr(0, pos - 1)			
				text = text.substr(pos)
				var from = 0
				while pos > 0:
					pos = header.find("<!", from)
					if pos == -1:
						break
					from = pos + 1
					pos = header.find("\n", from)
					var str = header.substr(from, pos - from)
					var entityName = Helper.RegMatchAt(str, "Cbw.*?(?= )")
					var value = Helper.RegMatchAt(str, "(?<=').*?(?=')")
					if entityName.length() > 0 and value.length() > 0:
						print(entityName, " = ", value)
			RootNode = XmlNode.new("root");
			RootNode.xml = self;
			RootNode.from_string(text)
			fs.close()

如此,恢复正常。XML文本内容解析为图形效果

<CbwObjects>
	<TLine name="Line967">
		<Points>
			<Point x="258" y="868"/>
			<Point x="606" y="1043"/>
		</Points>
	</TLine>
	<TLine name="Line968">
		<Points>
			<Point x="329" y="698"/>
			<Point x="142" y="864"/>
		</Points>
	</TLine>
	<TRectangle name="Rect147">
		<Points>
			<Point x="433" y="804"/>
			<Point x="712" y="917"/>
		</Points>
	</TRectangle>
	<TRectangle name="Rect148">
		<Points>
			<Point x="378" y="638"/>
			<Point x="461" y="764"/>
		</Points>
	</TRectangle>
	<TRectangle name="Rect149">
		<Points>
			<Point x="105" y="651"/>
			<Point x="201" y="826"/>
		</Points>
	</TRectangle>
	<TRectangle name="Rect150">
		<Points>
			<Point x="139" y="1011"/>
			<Point x="341" y="866"/>
		</Points>
	</TRectangle>
	<TRectangle name="Rect151">
		<Points>
			<Point x="847" y="832"/>
			<Point x="939" y="1043"/>
		</Points>
	</TRectangle>
	<TRectangle name="Rect152">
		<Points>
			<Point x="850" y="635"/>
			<Point x="985" y="710"/>
		</Points>
	</TRectangle>
	<TEllipse name="Ellipse74">
		<Points>
			<Point x="551.451219512195" y="644.367464840815"/>
			<Point x="788" y="762"/>
		</Points>
	</TEllipse>
	<TLine name="Line799" pen="&CbwPen0;">
		<Points>
			<Point x="230" y="46"/>
			<Point x="417" y="284"/>
		</Points>
	</TLine>
</CbwObjects>

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Godot 4 源码分析 - 文件读入编码处理 的相关文章

  • unity 停止调用InvokeRepeating()的方法

    可以使用CancelInvoke 函数来停止InvokeRepeating 的调用 示例如下 声明一个float类型的变量用来存储调用Invokerepeating 的时间间隔 public float repeatTime 2 0f vo
  • HLSL 偏导数 ddx / ddy

    HLSL ddx ddy 在光栅化的时刻 GPUs会在同一时刻并行运行很多Fragment Shader 但是并不是一个pixel一个pixel去执行的 而是将其组织在2x2的一组pixels分块中 去并行执行 偏导数就正好是计算的这一块像
  • 用虚幻4开发搭积木的VR游戏

    2016 年 9 月 23 24 日 由 CSDN 和创新工场联合主办的 MDCC 2016 移动开发者大会 中国 Mobile Developer Conference China 将在北京 国家会议中心召开 来自iOS Android
  • Unity笔记:修改代码执行的默认打开方式

    使用 External Tools 偏好设置可设置用于编写脚本 处理图像和进行源代码控制的外部应用程序 External Script Editor 选择 Unity 应使用哪个应用程序来打开脚本文件 Unity 会自动将正确的参数传递给内
  • 【unity3D】创建TextMeshPro(TMP)中文字体(解决输入中文乱码问题)

    未来的游戏开发程序媛 现在的努力学习菜鸡 本专栏是我关于游戏开发的学习笔记 本篇是unity的TMP中文输入显示乱码的解决方式 创建 TextMeshPro 中文字体 遇到的问题描述 解决方式 Font Asset Creator 面板扩展
  • unity期末作业-插针游戏

    unity期末作业 插针游戏 附下载链接 鼠标控制针的发射 圆盘可以显示接住的针数目 若两根针碰到则界面变红 游戏结束 详细情况如下动态图 点我下载 https download csdn net download weixin 43474
  • Unity小游戏-勇闯小岛(PC) 项目展示+完整项目源码

    游戏录像 游戏玩法 主角可以变换四种状态 玩家通过四种状态特有的技能来击败眼前的怪物闯关 切换到棕色 有一个一直围绕自己旋转的大摆斧攻击敌人 切换到绿色 可以抵挡一切的投掷物 但是无法攻击敌人 切换到粉色 切换瞬间可以发出飞镖 切换到蓝色
  • Unity --- 触摸方法,以及灯光与烘培的使用

    触摸方法 1 首先触摸分为两大类 多点触摸和单点触摸 这两种方式的触摸通过下面这个触摸数来进行判断 当其等于1的时候 为单点触摸 当其大于1的时候为多点触摸 2 当我们在调用触摸方法的时候我们首先需要打开对应的多点 单点触摸 上面这个是开启
  • 跨平台游戏引擎 Axmol-2.0.0 正式发布

    下载 https github com axmolengine axmol releases tag v2 0 0 更新日志 添加实验性的 WebAssembly 构建支持 WebGL 2 0 由 nowasm 贡献 已知问题 WebGL
  • Unity 用脚本操作常用UI控件(上)

    控件介绍 在界面系统的术语中 将一个具有独立状态 外观和操作的对象称为控件 例如 常用的交互控件有按钮 输入框 滑动条等 常见的非交互式控件有文本标签 图片等 Unity采用了父子物体和组件的设计思想 其每个界面控件 往往也是由游戏物体挂载
  • Unity MRTK使用详解(Htc vive+LeapMotion)

    MRTK Unity是一个由Microsoft驱动的开源项目 提供了多种组件和功能 用于加速Unity中的跨平台MR应用程序开发 以下是其一些功能 提供跨平台输入系统和用于空间交互和UI组件 启用快速原型通过在编辑器中的模拟 让你马上看到变
  • 游戏引擎:打造梦幻游戏世界的秘密武器

    介绍 游戏引擎是游戏开发中不可或缺的工具 它为开发者提供了构建游戏世界所需的各种功能和工具 本文将介绍游戏引擎的概念 使用方法以及一个完整的游戏项目示例 游戏引擎的概念 游戏引擎是一种软件框架 它提供了游戏开发所需的各种功能和工具 包括图形
  • 蒙特卡洛积分、重要性采样、低差异序列

    渲染公式 渲染的目标在于计算周围环境的光线有多少从表面像素点反射到相机视口中 要计算总的反射光 每个入射方向的贡献 必须将他们在半球上相加 为入射光线 与法线 的夹角 为方便计算可以使用法线向量和入射向量 单位化 的乘积表示 对于基于图像的
  • Unity 安卓打包

    Unity打包的方式有很多种 自动打包和手动打包 今天小弟就鼓捣鼓捣unity手动打包 如果想动态打包的话 可以去看其他大佬的帖帖哈 unity打包先配置环境 下载unity的时候可以顺道把unity的安卓包下载下来 如果忘了也没事 可以从
  • 1.17 从0开始学习Unity游戏开发--场景切换

    前面的所有文章我们都在一个固定的游戏场景内进行开发 在最开始介绍场景这个概念的时候就已经提及 这个场景可以是一张地图 或者是一个对战房间等等 所以显然这个场景可以有多个 并且可以从一个场景切换到另外一个场景 那么在Unity中如何进行场景切
  • Unity中UI框架的使用1-添加面板、显示Loading页面

    其中BasePanel和Canvas都是挂在面板的预制物上的 1 导入我们的UI框架 本篇文章中有用的是两个UIPanelType NUIManager和NBasePanel 会放在文章最后供大家使用 2 先将我们做好的Panel设置成预制
  • 如何创建没有 setter 函数的 getter 函数?

    我的脚本中有多个导出的变量 每当更改一个变量时 我想调用一个通用的 getter 并让值自动设置 tool export float var sample1 setget smthn changed export float var sam
  • 【Unity】运行时创建曲线(贝塞尔的运用)

    Unity 运行时创建线 贝塞尔的运用 1 实现的目标 在运行状态下创建一条可以使用贝塞尔方法实时编辑的网格曲线 2 原理介绍 2 1 曲线的创建 unity建立网格曲线可以参考 Unity程序化网格体 的实现方法 主要分为顶点 三角面 U
  • Godot:调用外部方法

    经过大量谷歌搜索 我仍然不明白什么可能是一个简单的解决方案 场景 主要 包含一个 TileMap Grid 并附有一个脚本 Grid gd 场景 玩家 包含一个 KinematicBody2D Player 及其附加脚本 Player gd
  • 同一节点的碰撞检测和重叠检测? [第2部分]

    的延续上一个问题 https stackoverflow com questions 71608423 collision detection and overlapping detection in same node 71622366

随机推荐

  • shc gzexe 将shell脚本转换为二进制的可执行文件

    第一种方法 gzexe 这种加密方式不是非常保险的方法 但是能够满足一般的加密用途 可以隐蔽脚本中的密码等信息 它是使用系统自带的gzexe程序 它不但加密 同时压缩文件 使用方法 gzexe file sh它会把原来没有加密的文件备份为
  • Netty源码解析系列三:Netty与Tomcat的区别

    Netty与Tomcat的区别 作用不同 Tomcat 是 Servlet 容器 可以视为 Web 服务器 而 Netty 是异步事件驱动的网络应用程序框架和工具用于简化网络编程 例如TCP和UDP套接字服务器 协议不同 Tomcat 是基
  • Random.Range 范围

    第一 Random Range随机数问题 时间20141212 今天在开发中用到随机数 差点就错过了 没注意这个问题 for int ooi 0 ooi lt 5000 ooi int hhh Random Range 0 3 if hhh
  • latex 参考文献没有显示_LaTeX 中的参考文献

    LaTeX 的对参考文献的处理实在是非常的方便 我用过几次 有些体会 写出来供大家 参考 当然 自己的功力还不够深 有些地方问题一解决就罢手了 没有细究 LaTeX 对参考文献的处理有这么一些优点 1 可以维护一个 bib 文件 在你的整个
  • 系统架构技能之设计模式-组合模式

    一 上篇回顾 我们上篇主要讲述了结构型模式中的外观模式 外观模式作为结构型模式中的一个简单又实用的模式 外观模式通过封装细节来提供大粒度的调用 直接的好处就是 封装细节 提供了应用写程序的可维护性和易用性 外观模式一般应用在系统架构的服务层
  • 【转】Vector与ArrayList区别

    the following is from http blessed24 javaeye com blog 751336 1 Vector ArrayList 1 Vector的方法都是同步的 Synchronized 是线程安全的 thr
  • 以太坊DAO之时间锁定Multisig

    Decentralized Autonomous Organization 简称DAO 以太坊中重要的概念 一般翻译为去中心化的自治组织 有时候 时间也可以用作一种很好的安全机制 以下代码基于DAO区块链大会 但有不同的变化 不是每个操作需
  • IdWorker---分布式ID工具类

    IdWorker 分布式ID工具类 import java lang management ManagementFactory import java net InetAddress import java net NetworkInter
  • ip地址的转换与递增

    void a void unsigned long addr inet addr 192 168 0 1 addr ntohl addr addr addr htonl addr char a 0x20 in addr in in S un
  • jenkins 发送邮件失败

    jenkins 配置发送邮件 发送测试邮件 邮件发送失败 Failed to send out e mail javax mail MessagingException Could not connect to SMTP host loca
  • C语言中的弱符号与强符号介绍

    弱符号 Weak symbol 是链接器 ld 在生成ELF Executable and Linkable Format 缩写为ELF 可执行和可链接格式 是一种用于可执行文件 目标文件 共享库和核心转储的标准文件格式 ELF文件有两种索
  • Git如何拉项目

    summary 放置 pub文件后 直接clone即可 Git设置SSH命令 ssh keygen t rsa C dong dong是用户名 passphrase是在私钥上又加了一层加码 一般直接回车不用设置 Git拉项目需要在项目服务器
  • JVM优化(OOM,内存溢出),查看线程快照,堆内存情况等问题

    1 堆大小 新生代 老年代 新生代 Young 与老年代 Old 的比例的值为 1 2 该值可以通过参数 XX NewRatio 来指定 2 Xmn参数总是应当小于 Xmx参数 否则就会触发OOM错误 3 jvm优化与查看gc回收情况 gc
  • WDK李宏毅学习笔记第二十周01_Deep Reinforcemen Learning

    Deep Reinforcemen Learning 文章目录 Deep Reinforcemen Learning 摘要 1 Reinforcemen Learning RL 是什么 1 1 RL的做法 1 1 1 Function wi
  • 6.4 PyTorch实现Skipgram模型

    欢迎订阅本专栏 PyTorch深度学习实践 订阅地址 https blog csdn net sinat 33761963 category 9720080 html 第二章 认识Tensor的类型 创建 存储 api等 打好Tensor的
  • [游戏更新]游戏更新框架的设计

    主要是通过文章来记录一下游戏更新流程的框架设计 资源打包 资源下载等 热更新的功能框架使用的是XLua 这里不做详细介绍 流程图 因为是海外游戏 考虑到GooglePlay对包体大小的限制 因此 会有一些资源做成压缩包 在特定时间进行下载
  • 学习grep(参数)选项

    grep一般格式为 grep 选项 基本正则表达式 文件 这里基本正则表达式可为字符串 1 1 双引号引用 在grep命令中输入字符串参数时 最好将其用双引号括起来 例如 m y s t r i n g 这样做有两个原因 一是以防被误解为s
  • 使用python时,ModuleNotFoundError: No module named ‘win32api‘处理方法

    方法一 亲测有效 直接 pip install pywin32 就行了 方法二 转载自https blog csdn net qq 41676500 article details 89282872 1 环境 win10 python3 7
  • Golang面试题(51-75)

    51 读写锁RWMutex的实现原理 概念 读写互斥锁是对Mutex的一个扩展 当一个Goroutine获得读锁后 其他Goroutine仍然可以获取读锁 当一个Goroutine获取写锁后 其他Goroutine不能获取读锁和写锁 使用场
  • Godot 4 源码分析 - 文件读入编码处理

    今天需要读入xml文件进行处理 结果读入一个带中文的文件时 出错了 当然程序还能运行 但编译器一直报错 而且XML解析也不正确 单步调试发现读入的内容出现乱码 具体逻辑 String FileAccess get as text bool