我有一个C++/UnrealEngine客户端,可以与现有的C#服务器和现有的JavaScript服务器(全部在Windows上)进行对话.

我的问题是当我用C++对Guid进行Base 64编码时,我从C#和JS得到不同的结果.据我所知,这与this SO answer中提到的Guid字符串的编码方式直接相关.

我无法真正更改C#和JS服务器,因为它们有其他依赖系统,那么我需要在C++(或Unreal)中做什么才能确保得到相同的输出?

//The Guid as a literal string
"3F73B3E6-7351-416F-ACA3-AE639A3F587F"

//C# & JSEncoded
"5rNzP1Fzb0Gso65jmj9Yfw"

//C++ Encoded
"P3Oz5nNRQW+sowAArmOaPw"

此外,使用在线转换器(判断自己的健康状况)我会得到相同的两个不同的结果,所以似乎没有真正标准化的方式.

//https://rcfed.com/Utilities/Base64GUID
//https://toolslick.com/conversion/data/guid
"5rNzP1Fzb0Gso65jmj9Yfw"

//https://www.fileformat.info/tool/guid-base64.htm
"P3Oz5nNRQW+sowAArmOaPw"

用于转换的代码如下:

//In C#
Guid myGuid = new Guid("3F73B3E6-7351-416F-ACA3-AE639A3F587F");

//Encodes / & + for URL & truncates the trailing "==" padding
string strBase64Guid = Convert.ToBase64String(myGuid.ToByteArray()).Substring(0, 22).Replace("/", "_").Replace("+", "-");
//In JavaScript
//https://stackoverflow.com/questions/55356285/how-to-convert-a-string-to-base64-encoding-using-byte-array-in-javascript
var strGuid = GuidToBase64("3F73B3E6-7351-416F-ACA3-AE639A3F587F");

function GuidToBase64(guid){
    //Guid to ByteArray
    var buffer = [];
    guid.split('-').map((number, index) => {
        var bytesInChar = index < 3 ? number.match(/.{1,2}/g).reverse() : number.match(/.{1,2}/g);
        bytesInChar.map((byte) => { buffer.push(parseInt(byte, 16)); })
    });
    
    var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)));
    //Encodes / & + for URL & truncates the trailing "==" padding
    return base64String.slice(0, 22).replace("/", "_").replace("+", "-");
}
//In C++ (Unreal Engine)
FGuid& myGuid = FGuid("3F73B3E6-7351-416F-ACA3-AE639A3F587F");
FString& strGuid = myGuid.ToString(EGuidFormats::Short);


//Copyright Epic Games, Inc. (AFAIK I'm allowed to paste snippets from the sources, just not the whole thing. UE's source it's all on GitHub anyway.)

//Truncated [Function overloads, & Guid format handling]

uint32 Bytes[4] = { NETWORK_ORDER32(A), NETWORK_ORDER32(B), NETWORK_ORDER32(C), NETWORK_ORDER32(D) };
TCHAR Buffer[25];
int32 Len = FBase64::Encode(reinterpret_cast<const uint8*>(Bytes), sizeof(Bytes), Buffer);
TArrayView<TCHAR> Result(Buffer, Len);
    
//Truncated [Sanitizes '+' & '/' and cuts the '==' padding]
}

推荐答案

所讨论的base64是以二进制格式(而不是原始字符串格式)编码Guid的结果.

二进制格式的Guid包括:

  • 4-字节整数
  • 2-字节整数
  • 2-字节整数
  • 8字节[13]

它不包括:

  • 4-字节整数
  • 2-字节整数
  • 2-字节整数
  • 2-字节整数
  • 6字节[13]

如字符串格式所示.

您的C++代码是base64-对四个4字节的整组进行编码(因为这是FGuid存储它们的方式-我不知道为什么),这与C#和JavaScript使用的Guid格式不同.您需要确保使用正确的整数数量以及正确的字节大小和字节序,以匹配C#和JavaScript正在使用的内容.

IIRC、JavaScript使用大端(Big-Endian)的integer,C#使用大端(Big-Endian)或小端(Little-Endian)的integer,具体取决于系统(参见BitConverter.IsLittleEndian).

5rNzP1Fzb0Gso65jmj9Yfw解码为字节:

e6 b3 73 3f 51 73 6f 41 ac a3 ae 63 9a 3f 58 7f

这是以下二进制格式的Guid值:

e6 b3 73 3f = 0x3F73B3E6
51 73 = 0x7351
6f 41 = 0x416F
ac a3 ae 63 9a 3f 58 7f

因此,您的C++代码需要达到以下equivalent倍:

uint8 Bytes[16];
memcpy(Bytes+0,  &myGuid.A, 4);
memcpy(Bytes+4,  &myGuid.B, 4);
memcpy(Bytes+8,  &myGuid.C, 4);
memcpy(Bytes+12, &myGuid.D, 4);

uint32 *ptr1 = reinterpret_cast<uint32*>(Bytes+0);
uint16 *ptr2 = reinterpret_cast<uint16*>(Bytes+4);
uint16 *ptr3 = reinterpret_cast<uint16*>(Bytes+2);

*ptr1 = NETWORK_ORDER32(*ptr1);
*ptr2 = NETWORK_ORDER16(*ptr2);
*ptr3 = NETWORK_ORDER16(*ptr3);
// not sure if FGuid stores the remaining
// 8 bytes in the correct order or not. If
// not, swap them around here as needed...

TCHAR Buffer[25];
int32 Len = FBase64::Encode(Bytes, sizeof(Bytes), Buffer);
...

Javascript相关问答推荐

JavaScript Date对象在UTC中设置为午夜时显示不正确的日期

如何在加载的元数据上使用juserc和await中获得同步负载?

对象和数字减法会抵消浏览器js中的数字

如何判断属于多个元素的属性是否具有多个值之一

我开始使用/url?q=使用Cheerio

如何解决chrome—extension代码中的错误,它会实时覆盖google—meet的面部图像?'

判断表格单元格中是否存在文本框

TypeScript索引签名模板限制

如何修复(或忽略)HTML模板中的TypeScript错误?'

如何粗体匹配的字母时输入搜索框使用javascript?

JS:XML insertBefore插入元素

对路由DOM嵌套路由作出react

用于在路径之间移动图像的查询

查询参数未在我的Next.js应用路由接口中定义

检索相加到点的子项

不同表的条件API端点Reaction-redux

postman 预请求中的hmac/sha256内标识-从js示例转换

在没有任何悬停或其他触发的情况下连续交换图像

将延迟加载的模块转换为Eager 加载的模块

计算对象数组中属性的滚动增量