1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-15 23:47:25 +08:00
osu-lazer/osu.Game/Database/LegacyArchiveExporter.cs

84 lines
3.0 KiB
C#
Raw Normal View History

2023-02-19 00:18:27 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.IO;
using System.Linq;
2024-04-30 21:40:04 +08:00
using System.Text;
2023-02-19 00:18:27 +08:00
using System.Threading;
2023-02-23 19:20:54 +08:00
using osu.Framework.Logging;
2023-02-19 00:18:27 +08:00
using osu.Framework.Platform;
using osu.Game.Extensions;
Force encoding to Shift-JIS for archive filenames After way too much time investigating this, the encoding situation is not great right now. - Stable sets the "default code page" to be used for encoding filenames to Shift-JIS (932): https://github.com/peppy/osu-stable-reference/blob/c29ebd7fc52113013fb4ac2db230699d81e1fe2c/osu!/GameBase.cs#L3099 - Lazer does nothing (therefore using UTF-8). When importing to lazer, stable files are assumed to be UTF-8. This means that the linked beatmaps don't work correctly. Forcing lazer to decompress *and* compress using Shift-JIS will fix this. Here's a rough idea of how things look for japanese character filenames in current `master`: | | stable | lazer | |--------|--------|--------| | export encoding | shift-jis | utf8 | | utf8 [bit flag](https://superuser.com/a/1507988) set | ❌ | ❌ | | import stable export osz | ✅ | ❌ | | import lazer export osz | ❌ | ✅ | | windows unzip | ❌ | ❌ | | macos unzip | ✅ | ✅ | and after this change | | stable | lazer | |--------|--------|--------| | export encoding | shift-jis | shift-jis | | utf8 [bit flag](https://superuser.com/a/1507988) set | ❌ | ❌ | | import stable export osz | ✅ | ✅ | | import lazer export osz | ✅ | ✅ | | windows unzip | ❌ | ❌ | | macos unzip | ✅ | ✅ | A future endeavour to improve compatibility would be to look at setting the utf8 flag in lazer, switching the default to utf8, and ensuring the stable supports this flag (I don't believe it does right now).
2024-04-29 18:49:17 +08:00
using osu.Game.IO.Archives;
2023-02-19 00:18:27 +08:00
using osu.Game.Overlays.Notifications;
using Realms;
using SharpCompress.Common;
using SharpCompress.Writers;
using SharpCompress.Writers.Zip;
2023-02-23 19:20:54 +08:00
using Logger = osu.Framework.Logging.Logger;
2023-02-19 00:18:27 +08:00
namespace osu.Game.Database
{
/// <summary>
2023-05-06 22:53:35 +08:00
/// Handles the common scenario of exporting a model to a zip-based archive, usually with a custom file extension.
/// </summary>
public abstract class LegacyArchiveExporter<TModel> : LegacyExporter<TModel>
2023-02-19 00:18:27 +08:00
where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey
{
2024-04-30 21:40:04 +08:00
/// <summary>
/// Whether to always use Shift-JIS encoding for archive filenames (like osu!stable did).
/// </summary>
protected virtual bool UseFixedEncoding => true;
protected LegacyArchiveExporter(Storage storage)
: base(storage)
2023-02-19 00:18:27 +08:00
{
}
2023-05-05 20:28:43 +08:00
public override void ExportToStream(TModel model, Stream outputStream, ProgressNotification? notification, CancellationToken cancellationToken = default)
2023-02-19 00:18:27 +08:00
{
2024-04-30 21:47:03 +08:00
var zipWriterOptions = new ZipWriterOptions(CompressionType.Deflate)
{
ArchiveEncoding = UseFixedEncoding ? ZipArchiveReader.DEFAULT_ENCODING : new ArchiveEncoding(Encoding.UTF8, Encoding.UTF8)
};
using (var writer = new ZipWriter(outputStream, zipWriterOptions))
2023-02-19 00:18:27 +08:00
{
int i = 0;
int fileCount = model.Files.Count();
2023-05-07 01:38:41 +08:00
bool anyFileMissing = false;
2023-02-19 01:06:07 +08:00
foreach (var file in model.Files)
2023-02-19 00:18:27 +08:00
{
2023-02-19 01:06:07 +08:00
cancellationToken.ThrowIfCancellationRequested();
using (var stream = GetFileContents(model, file))
2023-02-19 00:18:27 +08:00
{
2023-02-19 01:06:07 +08:00
if (stream == null)
2023-02-19 00:18:27 +08:00
{
Logger.Log($"File {file.Filename} is missing in local storage and will not be included in the export", LoggingTarget.Database);
2023-05-07 01:38:41 +08:00
anyFileMissing = true;
continue;
2023-02-19 00:18:27 +08:00
}
writer.Write(file.Filename, stream);
2023-02-19 00:18:27 +08:00
}
2023-02-19 01:06:07 +08:00
i++;
2023-04-09 21:11:52 +08:00
if (notification != null)
{
notification.Progress = (float)i / fileCount;
2023-04-09 21:11:52 +08:00
}
2023-02-19 00:18:27 +08:00
}
2023-05-07 01:38:41 +08:00
if (anyFileMissing)
{
2023-05-07 01:38:05 +08:00
Logger.Log("Some files are missing in local storage and will not be included in the export", LoggingTarget.Database, LogLevel.Error);
}
2023-02-19 01:06:07 +08:00
}
2023-02-19 00:18:27 +08:00
}
protected virtual Stream? GetFileContents(TModel model, INamedFileUsage file) => UserFileStorage.GetStream(file.File.GetStoragePath());
2023-02-19 00:18:27 +08:00
}
}