#if UNITY_6000_0_OR_NEWER
using System;
using System.Diagnostics;
using System.IO;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace UnityEditor.AddressableAssets.Build
{
///
/// Handles conversion of legacy BinaryFormatter files to the new DataContractSerializer format.
/// This class provides utilities for detecting legacy formats and running the converter tool.
///
internal static class LegacyFormatConverter
{
///
/// Version marker for content state files (.bin): "ACS" + version 1
///
public static readonly byte[] ContentStateVersionMarker = { 0x41, 0x43, 0x53, 0x01 };
///
/// Version marker for config data files (.dat): "ACD" + version 1
///
public static readonly byte[] ConfigDataVersionMarker = { 0x41, 0x43, 0x44, 0x01 };
///
/// Checks if a file is in the legacy BinaryFormatter format by comparing against the expected version marker.
///
/// Path to the file to check.
/// The version marker bytes expected for the new format.
/// True if the file is in legacy format (doesn't have the version marker), false otherwise.
public static bool IsLegacyFormat(string path, byte[] versionMarker)
{
if (!File.Exists(path))
return false;
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
return IsLegacyFormat(stream, versionMarker);
}
}
///
/// Checks if a stream contains legacy BinaryFormatter format data.
///
/// The stream to check. Position will be reset after checking.
/// The version marker bytes expected for the new format.
/// True if the stream contains legacy format data.
public static bool IsLegacyFormat(Stream stream, byte[] versionMarker)
{
if (stream.Length < versionMarker.Length)
return true; // Too short, assume legacy
var originalPosition = stream.Position;
var header = new byte[versionMarker.Length];
stream.Read(header, 0, versionMarker.Length);
stream.Position = originalPosition;
for (int i = 0; i < versionMarker.Length; i++)
{
if (header[i] != versionMarker[i])
return true; // Doesn't match new format marker, assume legacy
}
return false;
}
///
/// Gets the path to the converter tool for the current platform.
/// The tool is located in the package's Editor/Tools~ directory.
///
/// Path to the converter tool executable.
public static string GetConverterToolPath()
{
var packagePath = Path.GetFullPath("Packages/com.unity.addressables");
var toolsPath = Path.Combine(packagePath, "Editor", "Tools~");
#if UNITY_EDITOR_WIN
return Path.Combine(toolsPath, "win/AddressablesFormatConverter.exe");
#elif UNITY_EDITOR_OSX
#if UNITY_EDITOR_ARM64
return Path.Combine(toolsPath, "osx-arm64/AddressablesFormatConverter");
#else
return Path.Combine(toolsPath, "osx-x64/AddressablesFormatConverter");
#endif
#elif UNITY_EDITOR_LINUX
return Path.Combine(toolsPath, "linux/AddressablesFormatConverter");
#else
return Path.Combine(toolsPath, "win/AddressablesFormatConverter.exe");
#endif
}
///
/// Converts a legacy BinaryFormatter file to the new format using the converter tool.
///
/// Path to the legacy file.
/// If true, logs failures as warnings instead of errors.
/// Path to the converted file (same as input, replaced in-place), or null if conversion failed.
public static string ConvertLegacyFile(string legacyPath, bool logAsWarning = false)
{
var converterPath = GetConverterToolPath();
if (string.IsNullOrEmpty(converterPath) || !File.Exists(converterPath))
{
var message = $"Format converter tool not found at: {converterPath}";
if (logAsWarning)
Debug.LogWarning(message);
else
Debug.LogError(message);
return null;
}
var convertedPath = legacyPath + ".converted";
try
{
var startInfo = new ProcessStartInfo
{
FileName = converterPath,
Arguments = $"\"{legacyPath}\" \"{convertedPath}\"",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
using (var process = Process.Start(startInfo))
{
process.WaitForExit(60000); // 60 second timeout
if (process.ExitCode != 0)
{
var error = process.StandardError.ReadToEnd();
var message = $"Format converter failed with exit code {process.ExitCode}: {error}";
if (logAsWarning)
Debug.LogWarning(message);
else
Debug.LogError(message);
return null;
}
}
if (!File.Exists(convertedPath))
{
var message = "Format converter did not produce output file.";
if (logAsWarning)
Debug.LogWarning(message);
else
Debug.LogError(message);
return null;
}
// Replace the original file with the converted one
File.Delete(legacyPath);
File.Move(convertedPath, legacyPath);
Debug.Log($"Successfully converted legacy file: {legacyPath}");
return legacyPath;
}
catch (Exception e)
{
if (logAsWarning)
Debug.LogWarning($"Failed to convert legacy file: {e.Message}");
else
Debug.LogException(e);
return null;
}
}
}
}
#endif