fix: Wrong keyword encoding, bad buffer, update cache fix

Was using ASCII for keyword and was generating inconsistent CRC whoops
This commit is contained in:
Teacup
2025-08-08 17:57:55 -07:00
committed by Natsumi
parent 06e06a7164
commit 7fe8f4e079
4 changed files with 23 additions and 17 deletions

View File

@@ -7,7 +7,7 @@ using System.Text;
namespace VRCX; namespace VRCX;
public struct PNGChunk public class PNGChunk
{ {
public int Index; public int Index;
public int Length; public int Length;
@@ -58,7 +58,7 @@ public struct PNGChunk
*/ */
// Parse keyword as null-terminated string // Parse keyword as null-terminated string
var keywordEncoding = Encoding.GetEncoding("ISO-8859-1"); var keywordEncoding = Encoding.UTF8;
int keywordLength = 0; int keywordLength = 0;
for (int i = 0; i < chunkLength; i++) for (int i = 0; i < chunkLength; i++)
{ {
@@ -126,8 +126,9 @@ public struct PNGChunk
public bool ExistsInFile(FileStream fileStream) public bool ExistsInFile(FileStream fileStream)
{ {
fileStream.Seek(Index, SeekOrigin.Begin); fileStream.Seek(Index, SeekOrigin.Begin);
byte[] buffer = new byte[Length];
fileStream.ReadExactly(buffer, 0, Length); byte[] buffer = new byte[4];
fileStream.ReadExactly(buffer, 0, 4);
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 4); Array.Reverse(buffer, 0, 4);
@@ -137,14 +138,15 @@ public struct PNGChunk
return false; return false;
fileStream.Seek(4 + chunkLength, SeekOrigin.Current); fileStream.Seek(4 + chunkLength, SeekOrigin.Current);
fileStream.ReadExactly(buffer, 0, Length); fileStream.ReadExactly(buffer, 0, 4);
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
Array.Reverse(buffer, 0, 4); Array.Reverse(buffer, 0, 4);
uint crc = BitConverter.ToUInt32(buffer, 0); uint crc = BitConverter.ToUInt32(buffer, 0);
uint calculatedCRC = CalculateCRC();
return crc == CalculateCRC(); return crc == calculatedCRC;
} }
/// <summary> /// <summary>
@@ -186,7 +188,7 @@ public struct PNGChunk
public uint CalculateCRC() public uint CalculateCRC()
{ {
var chunkTypeBytes = Encoding.ASCII.GetBytes(ChunkType); var chunkTypeBytes = Encoding.UTF8.GetBytes(ChunkType);
return Crc32(Data, 0, Data.Length, Crc32(chunkTypeBytes, 0, chunkTypeBytes.Length, 0)); return Crc32(Data, 0, Data.Length, Crc32(chunkTypeBytes, 0, chunkTypeBytes.Length, 0));
} }

View File

@@ -60,7 +60,7 @@ public class PNGFile : IDisposable
public PNGChunk? GetChunkReverse(PNGChunkTypeFilter chunkTypeFilter) public PNGChunk? GetChunkReverse(PNGChunkTypeFilter chunkTypeFilter)
{ {
var chunk = ReadChunkReverse(chunkTypeFilter); var chunk = ReadChunkReverse(chunkTypeFilter);
if (chunk.HasValue &&chunk.Value.IsZero()) if (chunk != null && chunk.IsZero())
return null; return null;
return chunk; return chunk;
@@ -147,10 +147,10 @@ public class PNGFile : IDisposable
} }
fileStream.SetLength(fileStream.Length - deleteLength); fileStream.SetLength(fileStream.Length - deleteLength);
metadataChunkCache.Remove(chunk); metadataChunkCache.Remove(chunk);
// update the index of all cached chunks // Update the index of cached chunks
for (int i = 0; i < metadataChunkCache.Count; i++) for (int i = 0; i < metadataChunkCache.Count; i++)
{ {
var cachedChunk = metadataChunkCache[i]; var cachedChunk = metadataChunkCache[i];

View File

@@ -16,9 +16,9 @@ namespace VRCX
public static string ReadResolution(PNGFile pngFile) public static string ReadResolution(PNGFile pngFile)
{ {
var ihdrChunk = pngFile.GetChunk(PNGChunkTypeFilter.IHDR); var ihdrChunk = pngFile.GetChunk(PNGChunkTypeFilter.IHDR);
if (ihdrChunk.HasValue) if (ihdrChunk != null)
{ {
var resolution = ihdrChunk.Value.ReadIHDRChunkResolution(); var resolution = ihdrChunk.ReadIHDRChunkResolution();
return resolution.Item1 + "x" + resolution.Item2; return resolution.Item1 + "x" + resolution.Item2;
} }
@@ -42,9 +42,9 @@ namespace VRCX
if (legacySearch) if (legacySearch)
{ {
var legacyTextChunk = pngFile.GetChunkReverse(PNGChunkTypeFilter.iTXt); var legacyTextChunk = pngFile.GetChunkReverse(PNGChunkTypeFilter.iTXt);
if (legacyTextChunk.HasValue) if (legacyTextChunk != null)
{ {
var data = legacyTextChunk.Value.ReadITXtChunk(); var data = legacyTextChunk.ReadITXtChunk();
if (data.Item1 == keyword) if (data.Item1 == keyword)
return data.Item2; return data.Item2;
} }
@@ -91,7 +91,7 @@ namespace VRCX
public static PNGChunk GenerateTextChunk(string keyword, string text) public static PNGChunk GenerateTextChunk(string keyword, string text)
{ {
byte[] textBytes = Encoding.UTF8.GetBytes(text); byte[] textBytes = Encoding.UTF8.GetBytes(text);
byte[] keywordBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(keyword); byte[] keywordBytes = Encoding.UTF8.GetBytes(keyword);
List<byte> constructedTextChunk = new List<byte>(); List<byte> constructedTextChunk = new List<byte>();
constructedTextChunk.AddRange(keywordBytes); constructedTextChunk.AddRange(keywordBytes);

View File

@@ -209,7 +209,7 @@ namespace VRCX
// Check for chunk only present in files created by older modded versions of vrchat. (LFS, screenshotmanager), which put their metadata at the end of the file (which is not in spec bro). // Check for chunk only present in files created by older modded versions of vrchat. (LFS, screenshotmanager), which put their metadata at the end of the file (which is not in spec bro).
// Searching from the end of the file is a slower bruteforce operation so only do it if we have to. // Searching from the end of the file is a slower bruteforce operation so only do it if we have to.
if (result.Count == 0 && pngFile.GetChunk(PNGChunkTypeFilter.sRGB).HasValue) if (result.Count == 0 && pngFile.GetChunk(PNGChunkTypeFilter.sRGB) != null)
{ {
var lfsMetadata = PNGHelper.ReadTextChunk("Description", pngFile, true); var lfsMetadata = PNGHelper.ReadTextChunk("Description", pngFile, true);
@@ -233,7 +233,11 @@ namespace VRCX
{ {
using var pngFile = new PNGFile(path); using var pngFile = new PNGFile(path);
var chunk = PNGHelper.GenerateTextChunk("Description", text); var chunk = PNGHelper.GenerateTextChunk("Description", text);
return pngFile.WriteChunk(chunk); pngFile.WriteChunk(chunk);
DeleteTextMetadata(path, true);
return true;
} }
public static ScreenshotMetadata ParseVRCImage(string xmlString) public static ScreenshotMetadata ParseVRCImage(string xmlString)