mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
FModel 3.0.4
This commit is contained in:
parent
584d5e4c2e
commit
791fcd4008
|
|
@ -7,7 +7,7 @@
|
|||
mc:Ignorable="d"
|
||||
Title="About"
|
||||
Height="180"
|
||||
Width="510"
|
||||
Width="550"
|
||||
Style="{StaticResource {x:Type Window}}"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
<Label x:Name="AboutTitle_Lbl" Content="FModel" HorizontalAlignment="Center" VerticalAlignment="Top" FontSize="24" FontWeight="Bold" Margin="0,5,0,0"/>
|
||||
<Label Content="A powerful .PAK file explorer fully dedicated to Fortnite." HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,33,0,0"/>
|
||||
<Label Content="Big thanks to:" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,60,0,0"/>
|
||||
<Label Content="• Waddlesworth • Maiky • FunGames • PsychoPast • TSG • FireMonkey" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,75,0,0" FontSize="11"/>
|
||||
<Label Content="• Waddlesworth • Maiky • FunGames • Not Officer • PsychoPast • TSG • FireMonkey" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,75,0,0" FontSize="11"/>
|
||||
|
||||
<Label HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Padding="0" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Cursor="Hand">
|
||||
<TextBlock>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using FModel.Methods.Auth;
|
||||
using FModel.Methods.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using PakReader;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -226,7 +225,7 @@ namespace FModel.Methods.Assets
|
|||
string txtNativeString = GetValueFromParam(line, "NativeString=\"", "\",");
|
||||
|
||||
string translations = GetValueFromParam(line, "LocalizedStrings=(", "))");
|
||||
if (!translations.EndsWith(")")) { translations = translations + ")"; }
|
||||
if (!translations.EndsWith(")")) { translations += ")"; }
|
||||
|
||||
if (!HotfixLocResDict.ContainsKey(txtNamespace))
|
||||
HotfixLocResDict[txtNamespace] = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
|
||||
|
|
@ -248,7 +247,9 @@ namespace FModel.Methods.Assets
|
|||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
string[] langParts = match.Value.Substring(1, match.Value.Length - 2).Split(new string[] { "\", \"" }, StringSplitOptions.None);
|
||||
HotfixLocResDict[txtNamespace][txtKey][txtNativeString][langParts[0]] = langParts[1];
|
||||
if (langParts.Length > 1)
|
||||
// 02/22/2020 legendary trad in spanish is miss-typed and cause crash ("es",Legendario""),
|
||||
HotfixLocResDict[txtNamespace][txtKey][txtNativeString][langParts[0]] = langParts[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,12 +274,17 @@ namespace FModel.Methods.PAKs
|
|||
List<FPakEntry> entries = new List<FPakEntry>();
|
||||
while (reader.BaseStream.Position < reader.BaseStream.Length)
|
||||
{
|
||||
FPakEntry entry = new FPakEntry(
|
||||
reader.ReadString(),
|
||||
reader.ReadInt64(),
|
||||
reader.ReadInt64(),
|
||||
reader.ReadInt64(),
|
||||
reader.ReadBytes(20), null, 0, 0, 0);
|
||||
// we must follow this order
|
||||
long offset = reader.ReadInt64();
|
||||
long size = reader.ReadInt64();
|
||||
long uncompressedSize = reader.ReadInt64();
|
||||
bool encrypted = reader.ReadBoolean();
|
||||
long structSize = reader.ReadInt32();
|
||||
string name = reader.ReadString();
|
||||
long compressionMethodIndex = reader.ReadInt32();
|
||||
|
||||
// we actually only need name and uncompressedSize to compare
|
||||
FPakEntry entry = new FPakEntry(name, offset, size, uncompressedSize, new byte[20], null, 0, 0, 0);
|
||||
entries.Add(entry);
|
||||
}
|
||||
BackupEntries = entries.ToArray();
|
||||
|
|
|
|||
|
|
@ -245,19 +245,8 @@ namespace PakReader
|
|||
}
|
||||
}
|
||||
|
||||
public abstract class BasePakEntry
|
||||
{
|
||||
public long Pos;
|
||||
public long Size;
|
||||
public long UncompressedSize;
|
||||
public bool Encrypted;
|
||||
|
||||
public int StructSize;
|
||||
}
|
||||
|
||||
public struct FPakEntry : IEquatable<FPakEntry>
|
||||
{
|
||||
const byte Flag_None = 0x00;
|
||||
const byte Flag_Encrypted = 0x01;
|
||||
const byte Flag_Deleted = 0x02;
|
||||
|
||||
|
|
@ -338,32 +327,6 @@ namespace PakReader
|
|||
StructSize = (int)(reader.BaseStream.Position - StartOffset);
|
||||
}
|
||||
|
||||
internal FPakEntry(BinaryReader reader, string mountPoint)
|
||||
{
|
||||
CompressionBlocks = null;
|
||||
CompressionBlockSize = 0;
|
||||
Flags = 0;
|
||||
|
||||
Name = mountPoint + reader.ReadFString(FPakInfo.MAX_PACKAGE_PATH).Replace(".umap", ".uasset");
|
||||
|
||||
var StartOffset = reader.BaseStream.Position;
|
||||
|
||||
Offset = reader.ReadInt64();
|
||||
Size = reader.ReadInt64();
|
||||
UncompressedSize = reader.ReadInt64();
|
||||
CompressionMethodIndex = reader.ReadUInt32();
|
||||
Hash = reader.ReadBytes(20);
|
||||
if (CompressionMethodIndex != 0)
|
||||
{
|
||||
CompressionBlocks = reader.ReadTArray(() => new FPakCompressedBlock(reader));
|
||||
}
|
||||
Flags = reader.ReadByte();
|
||||
CompressionBlockSize = reader.ReadUInt32();
|
||||
|
||||
// Used to seek ahead to the file data instead of parsing the entry again
|
||||
StructSize = (int)(reader.BaseStream.Position - StartOffset);
|
||||
}
|
||||
|
||||
internal FPakEntry(string name, long offset, long size, long uncompressedSize, byte[] hash, FPakCompressedBlock[] compressionBlocks, uint compressionBlockSize, uint compressionMethodIndex, byte flags)
|
||||
{
|
||||
Name = name;
|
||||
|
|
@ -375,7 +338,7 @@ namespace PakReader
|
|||
CompressionBlockSize = compressionBlockSize;
|
||||
CompressionMethodIndex = compressionMethodIndex;
|
||||
Flags = flags;
|
||||
StructSize = (int)GetSize(PAK_VERSION.PAK_LATEST, compressionMethodIndex, (uint)compressionBlocks.Length);
|
||||
StructSize = compressionBlocks != null ? (int)GetSize(PAK_VERSION.PAK_LATEST, compressionMethodIndex, (uint)compressionBlocks.Length) : 0;
|
||||
}
|
||||
|
||||
public static long GetSize(PAK_VERSION version, uint CompressionMethodIndex = 0, uint CompressionBlocksCount = 0)
|
||||
|
|
@ -419,6 +382,32 @@ namespace PakReader
|
|||
public override int GetHashCode() => FProp.Default.FDiffFileSize ? (Name, UncompressedSize).GetHashCode() : (Name).GetHashCode();
|
||||
}
|
||||
|
||||
public struct FPathHashIndexEntry
|
||||
{
|
||||
public string Filename { get; }
|
||||
|
||||
public int Location { get; }
|
||||
|
||||
public FPathHashIndexEntry(BinaryReader reader)
|
||||
{
|
||||
Filename = reader.ReadFString();
|
||||
Location = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public struct FPakDirectoryEntry
|
||||
{
|
||||
public string Directory { get; }
|
||||
|
||||
public FPathHashIndexEntry[] Entries { get; }
|
||||
|
||||
public FPakDirectoryEntry(BinaryReader reader)
|
||||
{
|
||||
Directory = reader.ReadFString();
|
||||
Entries = reader.ReadTArray(() => new FPathHashIndexEntry(reader));
|
||||
}
|
||||
}
|
||||
|
||||
public struct FPakCompressedBlock
|
||||
{
|
||||
public long CompressedStart;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace PakReader
|
|||
readonly Stream Stream;
|
||||
readonly BinaryReader Reader;
|
||||
readonly byte[] Aes;
|
||||
public readonly string MountPoint;
|
||||
public string MountPoint;
|
||||
public FPakEntry[] FileInfos;
|
||||
public readonly string Name;
|
||||
|
||||
|
|
@ -85,39 +85,28 @@ namespace PakReader
|
|||
throw new FileLoadException("The AES key is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
infoReader.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
if (!ParseFiles) return;
|
||||
|
||||
// Pak index reading time :)
|
||||
infoReader.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||
MountPoint = infoReader.ReadFString(FPakInfo.MAX_PACKAGE_PATH);
|
||||
bool badMountPoint = false;
|
||||
if (!MountPoint.StartsWith("../../.."))
|
||||
{
|
||||
badMountPoint = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MountPoint = MountPoint.Substring(8);
|
||||
}
|
||||
if (MountPoint[0] != '/' || ((MountPoint.Length > 1) && (MountPoint[1] == '.')))
|
||||
{
|
||||
badMountPoint = true;
|
||||
}
|
||||
|
||||
if (badMountPoint)
|
||||
{
|
||||
DebugHelper.WriteLine($".PAKs: WARNING: Pak \"{Name}\" has strange mount point \"{MountPoint}\", mounting to root");
|
||||
MountPoint = "/";
|
||||
}
|
||||
|
||||
if (info.Version >= (int)PAK_VERSION.PAK_PATH_HASH_INDEX)
|
||||
{
|
||||
ReadIndexUpdated(infoReader, MountPoint, info, Aes, Stream.Length);
|
||||
ReadIndexUpdated(infoReader, info, Aes);
|
||||
}
|
||||
else
|
||||
{
|
||||
MountPoint = infoReader.ReadFString();
|
||||
if (MountPoint.StartsWith("../../.."))
|
||||
{
|
||||
MountPoint = MountPoint.Substring(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
MountPoint = "/";
|
||||
}
|
||||
|
||||
FileInfos = new FPakEntry[infoReader.ReadInt32()];
|
||||
for (int i = 0; i < FileInfos.Length; i++)
|
||||
{
|
||||
|
|
@ -126,127 +115,64 @@ namespace PakReader
|
|||
}
|
||||
}
|
||||
|
||||
void ReadIndexUpdated(BinaryReader reader, string mountPoint, FPakInfo info, byte[] key, long totalSize)
|
||||
private void ReadIndexUpdated(BinaryReader reader, FPakInfo info, byte[] aesKey)
|
||||
{
|
||||
int NumEntries = reader.ReadInt32();
|
||||
ulong PathHashSeed = reader.ReadUInt64();
|
||||
|
||||
bool bReaderHasPathHashIndex = false;
|
||||
long PathHashIndexOffset = -1; // INDEX_NONE
|
||||
long PathHashIndexSize = 0;
|
||||
FSHAHash PathHashIndexHash = default;
|
||||
bReaderHasPathHashIndex = reader.ReadInt32() != 0;
|
||||
if (bReaderHasPathHashIndex)
|
||||
MountPoint = reader.ReadFString();
|
||||
if (MountPoint.StartsWith("../../.."))
|
||||
{
|
||||
PathHashIndexOffset = reader.ReadInt64();
|
||||
PathHashIndexSize = reader.ReadInt64();
|
||||
PathHashIndexHash = new FSHAHash(reader);
|
||||
bReaderHasPathHashIndex = bReaderHasPathHashIndex && PathHashIndexOffset != -1;
|
||||
}
|
||||
|
||||
bool bReaderHasFullDirectoryIndex = false;
|
||||
long FullDirectoryIndexOffset = -1; // INDEX_NONE
|
||||
long FullDirectoryIndexSize = 0;
|
||||
FSHAHash FullDirectoryIndexHash = default;
|
||||
bReaderHasFullDirectoryIndex = reader.ReadInt32() != 0;
|
||||
if (bReaderHasFullDirectoryIndex)
|
||||
{
|
||||
FullDirectoryIndexOffset = reader.ReadInt64();
|
||||
FullDirectoryIndexSize = reader.ReadInt64();
|
||||
FullDirectoryIndexHash = new FSHAHash(reader);
|
||||
bReaderHasFullDirectoryIndex = bReaderHasFullDirectoryIndex && FullDirectoryIndexOffset != -1;
|
||||
}
|
||||
|
||||
byte[] EncodedPakEntries = reader.ReadTArray(() => reader.ReadByte());
|
||||
|
||||
int FilesNum = reader.ReadInt32();
|
||||
if (FilesNum < 0)
|
||||
// Should not be possible for any values in the PrimaryIndex to be invalid, since we verified the index hash
|
||||
throw new FileLoadException("Corrupt pak PrimaryIndex detected!");
|
||||
|
||||
FPakEntry[] Files = new FPakEntry[FilesNum]; // from what i can see, there aren't any???
|
||||
if (FilesNum > 0)
|
||||
for (int FileIndex = 0; FileIndex < FilesNum; ++FileIndex)
|
||||
Files[FileIndex] = new FPakEntry(reader, mountPoint, (PAK_VERSION)info.Version);
|
||||
|
||||
// Decide which SecondaryIndex(es) to load
|
||||
bool bWillUseFullDirectoryIndex;
|
||||
bool bWillUsePathHashIndex;
|
||||
bool bReadFullDirectoryIndex;
|
||||
if (bReaderHasPathHashIndex && bReaderHasFullDirectoryIndex)
|
||||
{
|
||||
bWillUseFullDirectoryIndex = false;
|
||||
bWillUsePathHashIndex = !bWillUseFullDirectoryIndex;
|
||||
bool bWantToReadFullDirectoryIndex = false;
|
||||
bReadFullDirectoryIndex = bReaderHasFullDirectoryIndex && bWantToReadFullDirectoryIndex;
|
||||
}
|
||||
else if (bReaderHasPathHashIndex)
|
||||
{
|
||||
bWillUsePathHashIndex = true;
|
||||
bWillUseFullDirectoryIndex = false;
|
||||
bReadFullDirectoryIndex = false;
|
||||
}
|
||||
else if (bReaderHasFullDirectoryIndex)
|
||||
{
|
||||
// We don't support creating the PathHash Index at runtime; we want to move to having only the PathHashIndex, so supporting not having it at all is not useful enough to write
|
||||
bWillUsePathHashIndex = false;
|
||||
bWillUseFullDirectoryIndex = true;
|
||||
bReadFullDirectoryIndex = true;
|
||||
MountPoint = MountPoint.Substring(8);
|
||||
}
|
||||
else
|
||||
// It should not be possible for PrimaryIndexes to be built without a PathHashIndex AND without a FullDirectoryIndex; CreatePakFile in UnrealPak.exe has a check statement for it.
|
||||
{
|
||||
MountPoint = "/";
|
||||
}
|
||||
|
||||
var filesNum = reader.ReadInt32();
|
||||
reader.ReadUInt64();
|
||||
|
||||
if (reader.ReadInt32() == 0)
|
||||
{
|
||||
throw new FileLoadException("No path hash index");
|
||||
}
|
||||
|
||||
//reader.ReadInt64();
|
||||
//reader.ReadInt64();
|
||||
reader.BaseStream.Position += 20L + 8L + 8L;
|
||||
|
||||
if (reader.ReadInt32() == 0)
|
||||
{
|
||||
throw new FileLoadException("No directory index");
|
||||
}
|
||||
|
||||
var position = reader.ReadInt64();
|
||||
var directoryIndexSize = reader.ReadInt64();
|
||||
reader.BaseStream.Position += 20L;
|
||||
var encodedPakEntries = reader.ReadTArray(reader.ReadByte);
|
||||
var files = reader.ReadInt32();
|
||||
|
||||
if (files < 0)
|
||||
{
|
||||
throw new FileLoadException("Corrupt pak PrimaryIndex detected!");
|
||||
|
||||
// Load the Secondary Index(es)
|
||||
byte[] PathHashIndexData;
|
||||
Dictionary<ulong, int> PathHashIndex;
|
||||
BinaryReader PathHashIndexReader = default;
|
||||
if (bWillUsePathHashIndex)
|
||||
{
|
||||
if (PathHashIndexOffset < 0 || totalSize < (PathHashIndexOffset + PathHashIndexSize))
|
||||
// Should not be possible for these values (which came from the PrimaryIndex) to be invalid, since we verified the index hash of the PrimaryIndex
|
||||
throw new FileLoadException("Corrupt pak PrimaryIndex detected!");
|
||||
|
||||
Reader.BaseStream.Position = PathHashIndexOffset;
|
||||
PathHashIndexData = Reader.ReadBytes((int)PathHashIndexSize);
|
||||
{
|
||||
if (!DecryptAndValidateIndex(info.bEncryptedIndex != 0, ref PathHashIndexData, key, PathHashIndexHash, out var ComputedHash))
|
||||
throw new FileLoadException("Corrupt pak PrimaryIndex detected!");
|
||||
}
|
||||
|
||||
PathHashIndexReader = new BinaryReader(new MemoryStream(PathHashIndexData));
|
||||
PathHashIndex = ReadPathHashIndex(PathHashIndexReader);
|
||||
}
|
||||
|
||||
var DirectoryIndex = new Dictionary<string, Dictionary<string, int>>();
|
||||
if (!bReadFullDirectoryIndex)
|
||||
{
|
||||
DirectoryIndex = ReadDirectoryIndex(PathHashIndexReader);
|
||||
}
|
||||
if (DirectoryIndex.Count == 0)
|
||||
{
|
||||
if (totalSize < (FullDirectoryIndexOffset + FullDirectoryIndexSize) || FullDirectoryIndexOffset < 0)
|
||||
throw new FileLoadException("Corrupt pak PrimaryIndex detected!");
|
||||
Reader.BaseStream.Position = FullDirectoryIndexOffset;
|
||||
byte[] FullDirectoryIndexData = Reader.ReadBytes((int)FullDirectoryIndexSize);
|
||||
Reader.BaseStream.Position = position;
|
||||
var directoryIndexData = Reader.ReadBytes((int)directoryIndexSize);
|
||||
|
||||
{
|
||||
if (!DecryptAndValidateIndex(info.bEncryptedIndex != 0, ref FullDirectoryIndexData, key, FullDirectoryIndexHash, out var ComputedHash))
|
||||
throw new FileLoadException("Corrupt pak PrimaryIndex detected!");
|
||||
}
|
||||
|
||||
var SecondaryIndexReader = new BinaryReader(new MemoryStream(FullDirectoryIndexData));
|
||||
DirectoryIndex = ReadDirectoryIndex(SecondaryIndexReader);
|
||||
if (info.bEncryptedIndex != 0)
|
||||
{
|
||||
directoryIndexData = AESDecryptor.DecryptAES(directoryIndexData, aesKey);
|
||||
}
|
||||
|
||||
var entries = new List<FPakEntry>(NumEntries);
|
||||
foreach (var stringDict in DirectoryIndex)
|
||||
var directoryIndexReader = new BinaryReader(new MemoryStream(directoryIndexData));
|
||||
var directoryEntries = directoryIndexReader.ReadTArray(() => new FPakDirectoryEntry(directoryIndexReader));
|
||||
|
||||
var entries = new List<FPakEntry>(filesNum);
|
||||
foreach (var directoryEntry in directoryEntries)
|
||||
{
|
||||
foreach (var stringInt in stringDict.Value)
|
||||
foreach (var hashIndexEntry in directoryEntry.Entries)
|
||||
{
|
||||
string path = stringDict.Key + stringInt.Key;
|
||||
FPakEntry entry = GetEntry(mountPoint + path, stringInt.Value, EncodedPakEntries);
|
||||
entries.Add(entry);
|
||||
string path = MountPoint + directoryEntry.Directory + hashIndexEntry.Filename;
|
||||
entries.Add(GetEntry(path, hashIndexEntry.Location, encodedPakEntries));
|
||||
}
|
||||
}
|
||||
this.FileInfos = entries.ToArray();
|
||||
|
|
@ -380,53 +306,8 @@ namespace PakReader
|
|||
return new FPakEntry(name, Offset, Size, UncompressedSize, new byte[20], CompressionBlocks, CompressionBlockSize, CompressionMethodIndex, (byte)((Encrypted ? 0x01 : 0x00) | (Deleted ? 0x02 : 0x00)));
|
||||
}
|
||||
else
|
||||
{
|
||||
pakLocation = -(pakLocation + 1);
|
||||
//pakLocation = -(pakLocation + 1);
|
||||
throw new FileLoadException("list indexes aren't supported");
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<ulong, int> ReadPathHashIndex(BinaryReader reader)
|
||||
{
|
||||
var ret = new Dictionary<ulong, int>();
|
||||
var keys = reader.ReadTArray(() => (reader.ReadUInt64(), reader.ReadInt32()));
|
||||
foreach (var (k, v) in keys)
|
||||
{
|
||||
ret[k] = v;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Dictionary<string, Dictionary<string, int>> ReadDirectoryIndex(BinaryReader reader)
|
||||
{
|
||||
var ret = new Dictionary<string, Dictionary<string, int>>();
|
||||
var keys = reader.ReadTArray(() => (reader.ReadFString(), ReadFPakDirectory(reader)));
|
||||
foreach (var (k, v) in keys)
|
||||
{
|
||||
ret[k] = v;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Dictionary<string, int> ReadFPakDirectory(BinaryReader reader)
|
||||
{
|
||||
var ret = new Dictionary<string, int>();
|
||||
var keys = reader.ReadTArray(() => (reader.ReadFString(), reader.ReadInt32()));
|
||||
foreach (var (k, v) in keys)
|
||||
{
|
||||
ret[k] = v;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DecryptAndValidateIndex(bool bEncryptedIndex, ref byte[] IndexData, byte[] aesKey, FSHAHash ExpectedHash, out FSHAHash OutHash)
|
||||
{
|
||||
if (bEncryptedIndex)
|
||||
{
|
||||
IndexData = AESDecryptor.DecryptAES(IndexData, aesKey);
|
||||
}
|
||||
OutHash = ExpectedHash;
|
||||
return true;
|
||||
}
|
||||
|
||||
public Stream GetPackageStream(FPakEntry entry)
|
||||
|
|
|
|||
|
|
@ -1,64 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<SyntaxDefinition name="Ini" extensions=".cfg;.conf;.ini;.iss;"
|
||||
xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
|
||||
|
||||
<!--
|
||||
INI/INF syntax highlighting
|
||||
Written by Ezra Altahan
|
||||
Created 18/07/2009 | Updated 16/10/2016
|
||||
Version 1.0
|
||||
<Color name="Bool" foreground="#61AFEF"/>
|
||||
<Color name="Digits" foreground="#D19A66"/>
|
||||
<Color name="Comment" foreground="SeaGreen"/>
|
||||
<Color name="Punctuation" foreground="#BBBBBB"/>
|
||||
<Color name="String" foreground="#98C379"/>
|
||||
<Color name="String2" foreground="#98C379"/>
|
||||
|
||||
hello@exr.be
|
||||
https://github.com/ei
|
||||
-->
|
||||
<Color name="Section" foreground="#7F848E"/>
|
||||
|
||||
<SyntaxDefinition name="INI" extensions=".ini;.inf;.wer;.dof">
|
||||
<Color name="PropertyName" foreground="#E06C6C"/>
|
||||
|
||||
<Environment>
|
||||
<Default color="Black" bgcolor="#FFFFFF"/>
|
||||
<Selection color="Black" bgcolor="#C3C3FF"/>
|
||||
<LineNumbers color="Gray" bgcolor="#FFFFFF"/>
|
||||
<CaretMarker color="#F0F0F1"/>
|
||||
<VRuler color="#E0E0E5"/>
|
||||
<RuleSet ignoreCase="true">
|
||||
|
||||
<FoldLine color="#A0A0A0" bgcolor="#FFFFFF"/>
|
||||
<FoldMarker color="Black" bgcolor="#FFFFFF"/>
|
||||
<SelectedFoldLine color="Black" bgcolor="#FFFFFF"/>
|
||||
<Span color="String" multiline="false" >
|
||||
<Begin>'</Begin>
|
||||
<End>'</End>
|
||||
</Span>
|
||||
|
||||
<EOLMarkers color="#CACAD2"/>
|
||||
<SpaceMarkers color="#B6B6C0"/>
|
||||
<TabMarkers color="#B6B6C0"/>
|
||||
<InvalidLines color="#B6B6C0"/>
|
||||
</Environment>
|
||||
<Keywords color="Bool" >
|
||||
<Word>true</Word>
|
||||
<Word>false</Word>
|
||||
</Keywords>
|
||||
|
||||
<Properties>
|
||||
<Property name="LineComment" value=";"/>
|
||||
</Properties>
|
||||
<Span color="String2" multiline="false" >
|
||||
<Begin>"</Begin>
|
||||
<End>"</End>
|
||||
</Span>
|
||||
|
||||
<Digits name="Digits" color="#ED6464"/>
|
||||
<!-- span for escape sequences -->
|
||||
<Span color="Comment" multiline="false">
|
||||
<Begin>;</Begin>
|
||||
</Span>
|
||||
<Span color="Comment" multiline="false">
|
||||
<Begin>\#</Begin>
|
||||
</Span>
|
||||
|
||||
<RuleSets>
|
||||
<RuleSet ignorecase="false">
|
||||
<Span color="Section" multiline="false">
|
||||
<Begin>\[</Begin>
|
||||
<End>\]</End>
|
||||
</Span>
|
||||
|
||||
<Delimiters>&|\/"',;=:-</Delimiters>
|
||||
<Rule color="PropertyName">
|
||||
[a-zA-Z]
|
||||
</Rule>
|
||||
|
||||
<Span name="LineComment1" stopateol="true" color="Green" bold="false" italic="false">
|
||||
<Begin>;</Begin>
|
||||
</Span>
|
||||
<Rule color="Punctuation">
|
||||
[?,.;()\[\]{}+=_\-/%*<>^+~!|&]+
|
||||
</Rule>
|
||||
|
||||
<Span name="LineComment2" stopateol="true" color="Green" bold="false" italic="false">
|
||||
<Begin>#</Begin>
|
||||
</Span>
|
||||
<Rule color="Digits">
|
||||
\b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)?
|
||||
</Rule>
|
||||
|
||||
<Span name="String" stopateol="true" color="#6495ED" bold="false" italic="false" escapecharacter="\">
|
||||
<Begin>"</Begin>
|
||||
<End>"</End>
|
||||
</Span>
|
||||
</RuleSet>
|
||||
|
||||
<Span name="Variable" stopateol="true" color="Goldenrod" bold="true" italic="false">
|
||||
<Begin startofline="true">[</Begin>
|
||||
<End>]</End>
|
||||
</Span>
|
||||
|
||||
<MarkPrevious color="Crimson" bold="false" italic="false">=</MarkPrevious>
|
||||
</RuleSet>
|
||||
</RuleSets>
|
||||
</SyntaxDefinition>
|
||||
</SyntaxDefinition>
|
||||
|
|
@ -1,24 +1,76 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<!--
|
||||
Syntaxdefinition for Json by alek kowalczyk
|
||||
Update by zuijin in 2019.12.20
|
||||
-->
|
||||
|
||||
<SyntaxDefinition name="Json" extensions=".json" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
|
||||
<Color name="Digits" foreground="#ED6464"/>
|
||||
<Color name="Value" foreground="#6495ED"/>
|
||||
<Color name="ParamName" foreground="Goldenrod"/>
|
||||
<RuleSet ignoreCase="false">
|
||||
<Keywords color="Digits" >
|
||||
<Word>true</Word>
|
||||
<Word>false</Word>
|
||||
<Word>null</Word>
|
||||
</Keywords>
|
||||
<Span color="ParamName">
|
||||
<Color name="Bool" foreground="#61AFEF" exampleText="true | false" />
|
||||
<Color name="Number" foreground="#D19A66" exampleText="3.14" />
|
||||
<Color name="String" foreground="#98C379" exampleText="" />
|
||||
<Color name="Null" foreground="#7F848E" exampleText="" />
|
||||
<Color name="FieldName" foreground="#E06C6C" />
|
||||
<Color name="Punctuation" foreground="#BBBBBB" />
|
||||
|
||||
<RuleSet name="String">
|
||||
<Span begin="\\" end="."/>
|
||||
</RuleSet>
|
||||
|
||||
<RuleSet name="Object">
|
||||
<Span color="FieldName" ruleSet="String">
|
||||
<Begin>"</Begin>
|
||||
<End>(?=:)</End>
|
||||
</Span>
|
||||
<Span color="Value" multiline="true">
|
||||
<Begin>
|
||||
(?<=:)\040"[^"]*
|
||||
</Begin>
|
||||
<End>"</End>
|
||||
</Span>
|
||||
<Rule color="Digits">\b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)?</Rule>
|
||||
<Span color="FieldName" ruleSet="String">
|
||||
<Begin>'</Begin>
|
||||
<End>'</End>
|
||||
</Span>
|
||||
<Span color="Punctuation" ruleSet="Expression">
|
||||
<Begin>:</Begin>
|
||||
</Span>
|
||||
<Span color="Punctuation">
|
||||
<Begin>,</Begin>
|
||||
</Span>
|
||||
</RuleSet>
|
||||
|
||||
<RuleSet name="Array">
|
||||
<Import ruleSet="Expression"/>
|
||||
<Span color="Punctuation">
|
||||
<Begin>,</Begin>
|
||||
</Span>
|
||||
</RuleSet>
|
||||
|
||||
<RuleSet name="Expression">
|
||||
<Keywords color="Bool" >
|
||||
<Word>true</Word>
|
||||
<Word>false</Word>
|
||||
</Keywords>
|
||||
<Keywords color="Null" >
|
||||
<Word>null</Word>
|
||||
</Keywords>
|
||||
<Span color="String" ruleSet="String">
|
||||
<Begin>"</Begin>
|
||||
<End>"</End>
|
||||
</Span>
|
||||
<Span color="String" ruleSet="String">
|
||||
<Begin>'</Begin>
|
||||
<End>'</End>
|
||||
</Span>
|
||||
<Span color="Punctuation" ruleSet="Object" multiline="true">
|
||||
<Begin>\{</Begin>
|
||||
<End>\}</End>
|
||||
</Span>
|
||||
<Span color="Punctuation" ruleSet="Array" multiline="true">
|
||||
<Begin>\[</Begin>
|
||||
<End>\]</End>
|
||||
</Span>
|
||||
<Rule color="Number">
|
||||
\b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)?
|
||||
</Rule>
|
||||
</RuleSet>
|
||||
|
||||
<RuleSet>
|
||||
<Import ruleSet="Expression"/>
|
||||
</RuleSet>
|
||||
</SyntaxDefinition>
|
||||
|
|
@ -51,5 +51,5 @@ using System.Windows;
|
|||
// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
|
||||
// en utilisant '*', comme indiqué ci-dessous :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("3.0.3.0")]
|
||||
[assembly: AssemblyFileVersion("3.0.3.0")]
|
||||
[assembly: AssemblyVersion("3.0.4.0")]
|
||||
[assembly: AssemblyFileVersion("3.0.4.0")]
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -14,7 +14,7 @@
|
|||
alt="Releases">
|
||||
</a>
|
||||
<a href="https://github.com/iAmAsval/FModel/releases/latest">
|
||||
<img src="https://img.shields.io/github/downloads/iAmAsval/FModel/latest/total.svg?label=v3.0.3%20Downloads"
|
||||
<img src="https://img.shields.io/github/downloads/iAmAsval/FModel/latest/total.svg?label=v3.0.4%20Downloads"
|
||||
alt="Downloads">
|
||||
</a>
|
||||
<a href="https://twitter.com/AsvalFN"><img src="https://img.shields.io/badge/Twitter-@AsvalFN-1da1f2.svg?logo=twitter"></a>
|
||||
|
|
@ -139,6 +139,14 @@ For x32 users, you just have to clone or download the repository and build FMode
|
|||
<a href="https://github.com/FunGamesLeaks" title="Github">🔧</a>
|
||||
<a href="https://twitter.com/FunGamesLeaks" title="Twitter">🐦</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/NotOfficer">
|
||||
<img src="https://avatars1.githubusercontent.com/u/29897990?s=200&v=4" width="100px;" alt="Not Officer"/><br>
|
||||
<sub><b>Not Officer</b></sub>
|
||||
</a><br>
|
||||
<a href="https://github.com/NotOfficer" title="Github">🔧</a>
|
||||
<a href="https://twitter.com/Not0fficer" title="Twitter">🐦</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/PsychoPast">
|
||||
<img src="https://avatars0.githubusercontent.com/u/33565739?s=200&v=4" width="100px;" alt="PsychoPast"/><br>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user