mirror of
https://github.com/Perfare/Il2CppDumper.git
synced 2025-01-24 17:57:56 -03:00
重构
This commit is contained in:
parent
6b4a33d115
commit
a357705e15
3 changed files with 217 additions and 114 deletions
|
@ -13,23 +13,6 @@ namespace Il2CppDumper
|
|||
private Il2Cpp il2Cpp;
|
||||
private Dictionary<Il2CppMethodDefinition, string> methodModifiers = new Dictionary<Il2CppMethodDefinition, string>();
|
||||
|
||||
public float Version => il2Cpp.version;
|
||||
public Il2CppImageDefinition[] Images => metadata.imageDefs;
|
||||
public Il2CppTypeDefinition[] Types => metadata.typeDefs;
|
||||
public Il2CppMethodDefinition[] Methods => metadata.methodDefs;
|
||||
public Il2CppParameterDefinition[] Parameters => metadata.parameterDefs;
|
||||
public Il2CppFieldDefinition[] Fields => metadata.fieldDefs;
|
||||
public Il2CppPropertyDefinition[] Properties => metadata.propertyDefs;
|
||||
public Il2CppEventDefinition[] Events => metadata.eventDefs;
|
||||
public Il2CppGenericContainer[] GenericContainers => metadata.genericContainers;
|
||||
public Il2CppGenericParameter[] GenericParameters => metadata.genericParameters;
|
||||
public Il2CppFieldRef[] FieldRefs => metadata.fieldRefs;
|
||||
public Dictionary<uint, SortedDictionary<uint, uint>> MetadataUsageDic => metadata.metadataUsageDic;
|
||||
public Il2CppType[] il2CppTypes => il2Cpp.types;
|
||||
public ulong[] MetadataUsages => il2Cpp.metadataUsages;
|
||||
public Il2CppGenericInst[] GenericInsts => il2Cpp.genericInsts;
|
||||
public Il2CppMethodSpec[] MethodSpecs => il2Cpp.methodSpecs;
|
||||
|
||||
public Il2CppDecompiler(Metadata metadata, Il2Cpp il2Cpp)
|
||||
{
|
||||
this.metadata = metadata;
|
||||
|
@ -636,42 +619,5 @@ namespace Il2CppDumper
|
|||
}
|
||||
return re.ToString();
|
||||
}
|
||||
|
||||
public List<ulong> GenerateOrderedPointers()
|
||||
{
|
||||
List<ulong> orderedPointers;
|
||||
if (il2Cpp.version >= 24.2f)
|
||||
{
|
||||
orderedPointers = new List<ulong>();
|
||||
foreach (var methodPointers in il2Cpp.codeGenModuleMethodPointers)
|
||||
{
|
||||
orderedPointers.AddRange(methodPointers);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
orderedPointers = il2Cpp.methodPointers.ToList();
|
||||
}
|
||||
orderedPointers.AddRange(il2Cpp.genericMethodPointers);
|
||||
orderedPointers.AddRange(il2Cpp.invokerPointers);
|
||||
orderedPointers.AddRange(il2Cpp.customAttributeGenerators);
|
||||
if (il2Cpp.version >= 22)
|
||||
{
|
||||
orderedPointers.AddRange(il2Cpp.reversePInvokeWrappers);
|
||||
orderedPointers.AddRange(il2Cpp.unresolvedVirtualCallPointers);
|
||||
}
|
||||
//TODO interopData内也包含函数
|
||||
orderedPointers = orderedPointers.Distinct().OrderBy(x => x).ToList();
|
||||
orderedPointers.Remove(0);
|
||||
return orderedPointers;
|
||||
}
|
||||
|
||||
//TODO
|
||||
public string GetStringFromIndex(uint index) => metadata.GetStringFromIndex(index);
|
||||
public string GetStringLiteralFromIndex(uint index) => metadata.GetStringLiteralFromIndex(index);
|
||||
public bool IsPE => il2Cpp is PE;
|
||||
public ulong GetMethodPointer(int methodIndex, int methodDefinitionIndex, int imageIndex, uint methodToken)
|
||||
=> il2Cpp.GetMethodPointer(methodIndex, methodDefinitionIndex, imageIndex, methodToken);
|
||||
public ulong FixPointer(ulong pointer) => il2Cpp.FixPointer(pointer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -272,7 +272,7 @@ namespace Il2CppDumper
|
|||
Console.WriteLine("Done!");
|
||||
Console.WriteLine("Generate script...");
|
||||
var scriptwriter = new StreamWriter(new FileStream("script.py", FileMode.Create), new UTF8Encoding(false));
|
||||
var scriptGenerator = new ScriptGenerator(decompiler);
|
||||
var scriptGenerator = new ScriptGenerator(metadata, il2Cpp);
|
||||
scriptGenerator.WriteScript(scriptwriter, config);
|
||||
Console.WriteLine("Done!");
|
||||
if (config.DummyDll)
|
||||
|
|
|
@ -3,17 +3,20 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static Il2CppDumper.DefineConstants;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
public class ScriptGenerator
|
||||
{
|
||||
private Il2CppDecompiler decompiler;
|
||||
private Metadata metadata;
|
||||
private Il2Cpp il2Cpp;
|
||||
private Dictionary<Il2CppTypeDefinition, int> typeDefImageIndices = new Dictionary<Il2CppTypeDefinition, int>();
|
||||
|
||||
public ScriptGenerator(Il2CppDecompiler decompiler)
|
||||
public ScriptGenerator(Metadata metadata, Il2Cpp il2Cpp)
|
||||
{
|
||||
this.decompiler = decompiler;
|
||||
this.metadata = metadata;
|
||||
this.il2Cpp = il2Cpp;
|
||||
}
|
||||
|
||||
public void WriteScript(StreamWriter writer, Config config)
|
||||
|
@ -44,25 +47,25 @@ namespace Il2CppDumper
|
|||
writer.WriteLine();
|
||||
writer.WriteLine("index = 1");
|
||||
writer.WriteLine("print('Making method name...')");
|
||||
for (var imageIndex = 0; imageIndex < decompiler.Images.Length; imageIndex++)
|
||||
for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++)
|
||||
{
|
||||
var imageDef = decompiler.Images[imageIndex];
|
||||
var imageDef = metadata.imageDefs[imageIndex];
|
||||
var typeEnd = imageDef.typeStart + imageDef.typeCount;
|
||||
for (int typeIndex = imageDef.typeStart; typeIndex < typeEnd; typeIndex++)
|
||||
{
|
||||
var typeDef = decompiler.Types[typeIndex];
|
||||
var typeName = decompiler.GetTypeName(typeDef);
|
||||
var typeDef = metadata.typeDefs[typeIndex];
|
||||
var typeName = GetTypeName(typeDef);
|
||||
typeDefImageIndices.Add(typeDef, imageIndex);
|
||||
var methodEnd = typeDef.methodStart + typeDef.method_count;
|
||||
for (var i = typeDef.methodStart; i < methodEnd; ++i)
|
||||
{
|
||||
var methodDef = decompiler.Methods[i];
|
||||
var methodName = decompiler.GetStringFromIndex(methodDef.nameIndex);
|
||||
var methodPointer = decompiler.GetMethodPointer(methodDef.methodIndex, i, imageIndex, methodDef.token);
|
||||
var methodDef = metadata.methodDefs[i];
|
||||
var methodName = metadata.GetStringFromIndex(methodDef.nameIndex);
|
||||
var methodPointer = il2Cpp.GetMethodPointer(methodDef.methodIndex, i, imageIndex, methodDef.token);
|
||||
if (methodPointer > 0)
|
||||
{
|
||||
var fixedMethodPointer = decompiler.FixPointer(methodPointer);
|
||||
if (decompiler.IsPE)
|
||||
var fixedMethodPointer = il2Cpp.FixPointer(methodPointer);
|
||||
if (il2Cpp is PE)
|
||||
{
|
||||
writer.WriteLine($"SetName(0x{methodPointer:X}, '{typeName + "$$" + methodName}')");
|
||||
}
|
||||
|
@ -75,83 +78,106 @@ namespace Il2CppDumper
|
|||
}
|
||||
}
|
||||
writer.WriteLine("print('Make method name done')");
|
||||
if (decompiler.Version > 16)
|
||||
if (il2Cpp.version > 16)
|
||||
{
|
||||
writer.WriteLine("print('Setting MetadataUsage...')");
|
||||
foreach (var i in decompiler.MetadataUsageDic[1]) //kIl2CppMetadataUsageTypeInfo
|
||||
foreach (var i in metadata.metadataUsageDic[1]) //kIl2CppMetadataUsageTypeInfo
|
||||
{
|
||||
var type = decompiler.il2CppTypes[i.Value];
|
||||
var typeName = decompiler.GetTypeName(type, true);
|
||||
writer.WriteLine($"SetName(0x{decompiler.MetadataUsages[i.Key]:X}, '{"Class$" + typeName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{decompiler.MetadataUsages[i.Key]:X}, r'{typeName}', 1)");
|
||||
var type = il2Cpp.types[i.Value];
|
||||
var typeName = GetTypeName(type, true);
|
||||
writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Class$" + typeName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{il2Cpp.metadataUsages[i.Key]:X}, r'{typeName}', 1)");
|
||||
}
|
||||
foreach (var i in decompiler.MetadataUsageDic[2]) //kIl2CppMetadataUsageIl2CppType
|
||||
foreach (var i in metadata.metadataUsageDic[2]) //kIl2CppMetadataUsageIl2CppType
|
||||
{
|
||||
var type = decompiler.il2CppTypes[i.Value];
|
||||
var typeName = decompiler.GetTypeName(type, true);
|
||||
writer.WriteLine($"SetName(0x{decompiler.MetadataUsages[i.Key]:X}, '{"Class$" + typeName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{decompiler.MetadataUsages[i.Key]:X}, r'{typeName}', 1)");
|
||||
var type = il2Cpp.types[i.Value];
|
||||
var typeName = GetTypeName(type, true);
|
||||
writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Class$" + typeName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{il2Cpp.metadataUsages[i.Key]:X}, r'{typeName}', 1)");
|
||||
}
|
||||
foreach (var i in decompiler.MetadataUsageDic[3]) //kIl2CppMetadataUsageMethodDef
|
||||
foreach (var i in metadata.metadataUsageDic[3]) //kIl2CppMetadataUsageMethodDef
|
||||
{
|
||||
var methodDef = decompiler.Methods[i.Value];
|
||||
var typeDef = decompiler.Types[methodDef.declaringType];
|
||||
var typeName = decompiler.GetTypeName(typeDef);
|
||||
var methodName = typeName + "." + decompiler.GetStringFromIndex(methodDef.nameIndex) + "()";
|
||||
writer.WriteLine($"SetName(0x{decompiler.MetadataUsages[i.Key]:X}, '{"Method$" + methodName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{decompiler.MetadataUsages[i.Key]:X}, '{"Method$" + methodName}', 1)");
|
||||
var methodDef = metadata.methodDefs[i.Value];
|
||||
var typeDef = metadata.typeDefs[methodDef.declaringType];
|
||||
var typeName = GetTypeName(typeDef);
|
||||
var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()";
|
||||
writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}', 1)");
|
||||
var imageIndex = typeDefImageIndices[typeDef];
|
||||
var methodPointer = decompiler.GetMethodPointer(methodDef.methodIndex, (int)i.Value, imageIndex, methodDef.token);
|
||||
writer.WriteLine($"idc.set_cmt(0x{decompiler.MetadataUsages[i.Key]:X}, '0x{methodPointer:X}', 0)");
|
||||
var methodPointer = il2Cpp.GetMethodPointer(methodDef.methodIndex, (int)i.Value, imageIndex, methodDef.token);
|
||||
writer.WriteLine($"idc.set_cmt(0x{il2Cpp.metadataUsages[i.Key]:X}, '0x{methodPointer:X}', 0)");
|
||||
}
|
||||
foreach (var i in decompiler.MetadataUsageDic[4]) //kIl2CppMetadataUsageFieldInfo
|
||||
foreach (var i in metadata.metadataUsageDic[4]) //kIl2CppMetadataUsageFieldInfo
|
||||
{
|
||||
var fieldRef = decompiler.FieldRefs[i.Value];
|
||||
var type = decompiler.il2CppTypes[fieldRef.typeIndex];
|
||||
var typeDef = decompiler.Types[type.data.klassIndex];
|
||||
var fieldDef = decompiler.Fields[typeDef.fieldStart + fieldRef.fieldIndex];
|
||||
var fieldName = decompiler.GetTypeName(type, true) + "." + decompiler.GetStringFromIndex(fieldDef.nameIndex);
|
||||
writer.WriteLine($"SetName(0x{decompiler.MetadataUsages[i.Key]:X}, '{"Field$" + fieldName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{decompiler.MetadataUsages[i.Key]:X}, r'{fieldName}', 1)");
|
||||
var fieldRef = metadata.fieldRefs[i.Value];
|
||||
var type = il2Cpp.types[fieldRef.typeIndex];
|
||||
var typeDef = metadata.typeDefs[type.data.klassIndex];
|
||||
var fieldDef = metadata.fieldDefs[typeDef.fieldStart + fieldRef.fieldIndex];
|
||||
var fieldName = GetTypeName(type, true) + "." + metadata.GetStringFromIndex(fieldDef.nameIndex);
|
||||
writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Field$" + fieldName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{il2Cpp.metadataUsages[i.Key]:X}, r'{fieldName}', 1)");
|
||||
}
|
||||
var stringLiterals = decompiler.MetadataUsageDic[5].Select(x => new //kIl2CppMetadataUsageStringLiteral
|
||||
var stringLiterals = metadata.metadataUsageDic[5].Select(x => new //kIl2CppMetadataUsageStringLiteral
|
||||
{
|
||||
value = decompiler.GetStringLiteralFromIndex(x.Value),
|
||||
address = $"0x{decompiler.MetadataUsages[x.Key]:X}"
|
||||
value = metadata.GetStringLiteralFromIndex(x.Value),
|
||||
address = $"0x{il2Cpp.metadataUsages[x.Key]:X}"
|
||||
}).ToArray();
|
||||
File.WriteAllText("stringliteral.json", JsonConvert.SerializeObject(stringLiterals, Formatting.Indented), new UTF8Encoding(false)); //TODO
|
||||
foreach (var stringLiteral in stringLiterals)
|
||||
{
|
||||
writer.WriteLine($"SetString({stringLiteral.address}, r'{decompiler.ToEscapedString(stringLiteral.value)}')");
|
||||
writer.WriteLine($"SetString({stringLiteral.address}, r'{ToEscapedString(stringLiteral.value)}')");
|
||||
}
|
||||
foreach (var i in decompiler.MetadataUsageDic[6]) //kIl2CppMetadataUsageMethodRef
|
||||
foreach (var i in metadata.metadataUsageDic[6]) //kIl2CppMetadataUsageMethodRef
|
||||
{
|
||||
var methodSpec = decompiler.MethodSpecs[i.Value];
|
||||
var methodDef = decompiler.Methods[methodSpec.methodDefinitionIndex];
|
||||
var typeDef = decompiler.Types[methodDef.declaringType];
|
||||
var typeName = decompiler.GetTypeName(typeDef);
|
||||
var methodSpec = il2Cpp.methodSpecs[i.Value];
|
||||
var methodDef = metadata.methodDefs[methodSpec.methodDefinitionIndex];
|
||||
var typeDef = metadata.typeDefs[methodDef.declaringType];
|
||||
var typeName = GetTypeName(typeDef);
|
||||
if (methodSpec.classIndexIndex != -1)
|
||||
{
|
||||
var classInst = decompiler.GenericInsts[methodSpec.classIndexIndex];
|
||||
typeName += decompiler.GetGenericTypeParams(classInst);
|
||||
var classInst = il2Cpp.genericInsts[methodSpec.classIndexIndex];
|
||||
typeName += GetGenericTypeParams(classInst);
|
||||
}
|
||||
var methodName = typeName + "." + decompiler.GetStringFromIndex(methodDef.nameIndex) + "()";
|
||||
var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()";
|
||||
if (methodSpec.methodIndexIndex != -1)
|
||||
{
|
||||
var methodInst = decompiler.GenericInsts[methodSpec.methodIndexIndex];
|
||||
methodName += decompiler.GetGenericTypeParams(methodInst);
|
||||
var methodInst = il2Cpp.genericInsts[methodSpec.methodIndexIndex];
|
||||
methodName += GetGenericTypeParams(methodInst);
|
||||
}
|
||||
writer.WriteLine($"SetName(0x{decompiler.MetadataUsages[i.Key]:X}, '{"Method$" + methodName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{decompiler.MetadataUsages[i.Key]:X}, '{"Method$" + methodName}', 1)");
|
||||
writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}')");
|
||||
writer.WriteLine($"idc.set_cmt(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}', 1)");
|
||||
var imageIndex = typeDefImageIndices[typeDef];
|
||||
var methodPointer = decompiler.GetMethodPointer(methodDef.methodIndex, methodSpec.methodDefinitionIndex, imageIndex, methodDef.token);
|
||||
writer.WriteLine($"idc.set_cmt(0x{decompiler.MetadataUsages[i.Key]:X}, '0x{methodPointer:X}', 0)");
|
||||
var methodPointer = il2Cpp.GetMethodPointer(methodDef.methodIndex, methodSpec.methodDefinitionIndex, imageIndex, methodDef.token);
|
||||
writer.WriteLine($"idc.set_cmt(0x{il2Cpp.metadataUsages[i.Key]:X}, '0x{methodPointer:X}', 0)");
|
||||
}
|
||||
writer.WriteLine("print('Set MetadataUsage done')");
|
||||
}
|
||||
if (config.MakeFunction)
|
||||
{
|
||||
var orderedPointers = decompiler.GenerateOrderedPointers();
|
||||
List<ulong> orderedPointers;
|
||||
if (il2Cpp.version >= 24.2f)
|
||||
{
|
||||
orderedPointers = new List<ulong>();
|
||||
foreach (var methodPointers in il2Cpp.codeGenModuleMethodPointers)
|
||||
{
|
||||
orderedPointers.AddRange(methodPointers);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
orderedPointers = il2Cpp.methodPointers.ToList();
|
||||
}
|
||||
orderedPointers.AddRange(il2Cpp.genericMethodPointers);
|
||||
orderedPointers.AddRange(il2Cpp.invokerPointers);
|
||||
orderedPointers.AddRange(il2Cpp.customAttributeGenerators);
|
||||
if (il2Cpp.version >= 22)
|
||||
{
|
||||
orderedPointers.AddRange(il2Cpp.reversePInvokeWrappers);
|
||||
orderedPointers.AddRange(il2Cpp.unresolvedVirtualCallPointers);
|
||||
}
|
||||
//TODO interopData内也包含函数
|
||||
orderedPointers = orderedPointers.Distinct().OrderBy(x => x).ToList();
|
||||
orderedPointers.Remove(0);
|
||||
writer.WriteLine("print('Making function...')");
|
||||
for (int i = 0; i < orderedPointers.Count - 1; i++)
|
||||
{
|
||||
|
@ -162,5 +188,136 @@ namespace Il2CppDumper
|
|||
writer.WriteLine("print('Script finished!')");
|
||||
writer.Close();
|
||||
}
|
||||
|
||||
public string GetTypeName(Il2CppType type, bool fullName = false)
|
||||
{
|
||||
string ret;
|
||||
switch (type.type)
|
||||
{
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
|
||||
{
|
||||
var typeDef = metadata.typeDefs[type.data.klassIndex];
|
||||
ret = string.Empty;
|
||||
if (fullName)
|
||||
{
|
||||
ret = metadata.GetStringFromIndex(typeDef.namespaceIndex);
|
||||
if (ret != string.Empty)
|
||||
{
|
||||
ret += ".";
|
||||
}
|
||||
}
|
||||
ret += GetTypeName(typeDef);
|
||||
break;
|
||||
}
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
|
||||
{
|
||||
var genericClass = il2Cpp.MapVATR<Il2CppGenericClass>(type.data.generic_class);
|
||||
var typeDef = metadata.typeDefs[genericClass.typeDefinitionIndex];
|
||||
ret = metadata.GetStringFromIndex(typeDef.nameIndex);
|
||||
var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(genericClass.context.class_inst);
|
||||
ret += GetGenericTypeParams(genericInst);
|
||||
break;
|
||||
}
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
||||
{
|
||||
var arrayType = il2Cpp.MapVATR<Il2CppArrayType>(type.data.array);
|
||||
var oriType = il2Cpp.GetIl2CppType(arrayType.etype);
|
||||
ret = $"{GetTypeName(oriType)}[{new string(',', arrayType.rank - 1)}]";
|
||||
break;
|
||||
}
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
|
||||
{
|
||||
var oriType = il2Cpp.GetIl2CppType(type.data.type);
|
||||
ret = $"{GetTypeName(oriType)}[]";
|
||||
break;
|
||||
}
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
|
||||
{
|
||||
var oriType = il2Cpp.GetIl2CppType(type.data.type);
|
||||
ret = $"{GetTypeName(oriType)}*";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = TypeString[(int)type.type];
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public string GetTypeName(Il2CppTypeDefinition typeDef)
|
||||
{
|
||||
var ret = string.Empty;
|
||||
if (typeDef.declaringTypeIndex != -1)
|
||||
{
|
||||
ret += GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex]) + ".";
|
||||
}
|
||||
ret += metadata.GetStringFromIndex(typeDef.nameIndex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public string GetGenericTypeParams(Il2CppGenericInst genericInst)
|
||||
{
|
||||
var typeNames = new List<string>();
|
||||
var pointers = il2Cpp.ReadPointers(genericInst.type_argv, genericInst.type_argc);
|
||||
for (uint i = 0; i < genericInst.type_argc; ++i)
|
||||
{
|
||||
var oriType = il2Cpp.GetIl2CppType(pointers[i]);
|
||||
typeNames.Add(GetTypeName(oriType));
|
||||
}
|
||||
return $"<{string.Join(", ", typeNames)}>";
|
||||
}
|
||||
|
||||
public string ToEscapedString(string s)
|
||||
{
|
||||
var re = new StringBuilder(s.Length);
|
||||
foreach (var c in s)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\'':
|
||||
re.Append(@"\'");
|
||||
break;
|
||||
case '"':
|
||||
re.Append(@"\""");
|
||||
break;
|
||||
case '\t':
|
||||
re.Append(@"\t");
|
||||
break;
|
||||
case '\n':
|
||||
re.Append(@"\n");
|
||||
break;
|
||||
case '\r':
|
||||
re.Append(@"\r");
|
||||
break;
|
||||
case '\f':
|
||||
re.Append(@"\f");
|
||||
break;
|
||||
case '\b':
|
||||
re.Append(@"\b");
|
||||
break;
|
||||
case '\\':
|
||||
re.Append(@"\\");
|
||||
break;
|
||||
case '\0':
|
||||
re.Append(@"\0");
|
||||
break;
|
||||
case '\u0085':
|
||||
re.Append(@"\u0085");
|
||||
break;
|
||||
case '\u2028':
|
||||
re.Append(@"\u2028");
|
||||
break;
|
||||
case '\u2029':
|
||||
re.Append(@"\u2029");
|
||||
break;
|
||||
default:
|
||||
re.Append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return re.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue