<commit_before>﻿// Copyright (c) ppy Pty Ltd <<EMAIL>>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.IO;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.Legacy;
using osu.Game.IO.Legacy;
using osu.Game.Replays;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using SharpCompress.Compressors.LZMA;

namespace osu.Game.Scoring.Legacy
{
    public abstract class LegacyScoreParser
    {
        private IBeatmap currentBeatmap;
        private Ruleset currentRuleset;

        public Score Parse(Stream stream)
        {
            var score = new Score
            {
                ScoreInfo = new ScoreInfo(),
                Replay = new Replay()
            };

            using (SerializationReader sr = new SerializationReader(stream))
            {
                currentRuleset = GetRuleset(sr.ReadByte());
                var scoreInfo = new LegacyScoreInfo { Ruleset = currentRuleset.RulesetInfo };

                score.ScoreInfo = scoreInfo;

                var version = sr.ReadInt32();

                var workingBeatmap = GetBeatmap(sr.ReadString());
                if (workingBeatmap is DummyWorkingBeatmap)
                    throw new BeatmapNotFoundException();

                currentBeatmap = workingBeatmap.Beatmap;
                scoreInfo.Beatmap = currentBeatmap.BeatmapInfo;

                scoreInfo.User = new User { Username = sr.ReadString() };

                // MD5Hash
                sr.ReadString();

                scoreInfo.Count300 = sr.ReadUInt16();
                scoreInfo.Count100 = sr.ReadUInt16();
                scoreInfo.Count50 = sr.ReadUInt16();
                scoreInfo.CountGeki = sr.ReadUInt16();
                scoreInfo.CountKatu = sr.ReadUInt16();
                scoreInfo.CountMiss = sr.ReadUInt16();

                scoreInfo.TotalScore = sr.ReadInt32();
                scoreInfo.MaxCombo = sr.ReadUInt16();

                /* score.Perfect = */
                sr.ReadBoolean();

                scoreInfo.Mods = currentRuleset.ConvertLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();

                /* score.HpGraphString = */
                sr.ReadString();

                scoreInfo.Date = sr.ReadDateTime();

                var compressedReplay = sr.ReadByteArray();

                if (version >= 20140721)
                    scoreInfo.OnlineScoreID = sr.ReadInt64();
                else if (version >= 20121008)
                    scoreInfo.OnlineScoreID = sr.ReadInt32();

                if (compressedReplay?.Length > 0)
                {
                    using (var replayInStream = new MemoryStream(compressedReplay))
                    {
                        byte[] properties = new byte[5];
                        if (replayInStream.Read(properties, 0, 5) != 5)
                            throw new IOException("input .lzma is too short");

                        long outSize = 0;

                        for (int i = 0; i < 8; i++)
                        {
                            int v = replayInStream.ReadByte();
                            if (v < 0)
                                throw new IOException("Can't Read 1");

                            outSize |= (long)(byte)v << (8 * i);
                        }

                        long compressedSize = replayInStream.Length - replayInStream.Position;

                        using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize))
                        using (var reader = new StreamReader(lzma))
                            readLegacyReplay(score.Replay, reader);
                    }
                }
            }

            CalculateAccuracy(score.ScoreInfo);<commit_msg>Fix legacy scores with no online ID being imported with a non-null ID<commit_after>﻿// Copyright (c) ppy Pty Ltd <<EMAIL>>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.IO;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.Legacy;
using osu.Game.IO.Legacy;
using osu.Game.Replays;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using SharpCompress.Compressors.LZMA;

namespace osu.Game.Scoring.Legacy
{
    public abstract class LegacyScoreParser
    {
        private IBeatmap currentBeatmap;
        private Ruleset currentRuleset;

        public Score Parse(Stream stream)
        {
            var score = new Score
            {
                ScoreInfo = new ScoreInfo(),
                Replay = new Replay()
            };

            using (SerializationReader sr = new SerializationReader(stream))
            {
                currentRuleset = GetRuleset(sr.ReadByte());
                var scoreInfo = new LegacyScoreInfo { Ruleset = currentRuleset.RulesetInfo };

                score.ScoreInfo = scoreInfo;

                var version = sr.ReadInt32();

                var workingBeatmap = GetBeatmap(sr.ReadString());
                if (workingBeatmap is DummyWorkingBeatmap)
                    throw new BeatmapNotFoundException();

                currentBeatmap = workingBeatmap.Beatmap;
                scoreInfo.Beatmap = currentBeatmap.BeatmapInfo;

                scoreInfo.User = new User { Username = sr.ReadString() };

                // MD5Hash
                sr.ReadString();

                scoreInfo.Count300 = sr.ReadUInt16();
                scoreInfo.Count100 = sr.ReadUInt16();
                scoreInfo.Count50 = sr.ReadUInt16();
                scoreInfo.CountGeki = sr.ReadUInt16();
                scoreInfo.CountKatu = sr.ReadUInt16();
                scoreInfo.CountMiss = sr.ReadUInt16();

                scoreInfo.TotalScore = sr.ReadInt32();
                scoreInfo.MaxCombo = sr.ReadUInt16();

                /* score.Perfect = */
                sr.ReadBoolean();

                scoreInfo.Mods = currentRuleset.ConvertLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();

                /* score.HpGraphString = */
                sr.ReadString();

                scoreInfo.Date = sr.ReadDateTime();

                var compressedReplay = sr.ReadByteArray();

                if (version >= 20140721)
                    scoreInfo.OnlineScoreID = sr.ReadInt64();
                else if (version >= 20121008)
                    scoreInfo.OnlineScoreID = sr.ReadInt32();

                if (scoreInfo.OnlineScoreID <= 0)
                    scoreInfo.OnlineScoreID = null;

                if (compressedReplay?.Length > 0)
                {
                    using (var replayInStream = new MemoryStream(compressedReplay))
                    {
                        byte[] properties = new byte[5];
                        if (replayInStream.Read(properties, 0, 5) != 5)
                            throw new IOException("input .lzma is too short");

                        long outSize = 0;

                        for (int i = 0; i < 8; i++)
                        {
                            int v = replayInStream.ReadByte();
                            if (v < 0)
                                throw new IOException("Can't Read 1");

                            outSize |= (long)(byte)v << (8 * i);
                        }

                        long compressedSize = replayInStream.Length - replayInStream.Position;

                        using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize))
                        using (var reader = new StreamReader(lzma))
                            readLegacyReplay(score.Replay, reader);
                    }
                }
            }

            CalculateAccuracy(score.ScoreInfo);
{'fraction_non_alphanumeric': 0.09057118077066038, 'fraction_numerical': 0.014991946475034072, 'mean_word_length': 1.506832298136646, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4431144', 'n_tokens_mistral': 2353, 'n_tokens_neox': 2022, 'n_words': 468}