• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MeltyPlayer / MeltyTool / 17993985084

25 Sep 2025 01:17AM UTC coverage: 39.931%. Remained the same
17993985084

push

github

MeltyPlayer
Used concrete types throughout solution.

5826 of 16491 branches covered (35.33%)

Branch coverage included in aggregate %.

44 of 85 new or added lines in 38 files covered. (51.76%)

1 existing line in 1 file now uncovered.

24549 of 59577 relevant lines covered (41.21%)

71883.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

41.45
/FinModelUtility/Fin/Fin.Compression/src/Lz77Decompressor.cs
1
using fin.math;
2
using fin.util.asserts;
3

4
using schema.binary;
5

6
namespace fin.compression;
7

8
/// <summary>
9
///   Shamelessly stolen from:
10
///   https://github.com/scurest/apicula/blob/3d4e91e14045392a49c89e86dab8cb936225588c/src/decompress/mod.rs
11
/// </summary>
12
public class Lz77Decompressor : BBinaryReaderToArrayDecompressor {
13
  public override bool TryDecompress(IBinaryReader br, out byte[] data) {
63✔
14
    br.PushContainerEndianness(Endianness.LittleEndian);
63✔
15
    br.AssertString("LZ77");
63✔
16
    var compressionType = br.ReadByte();
63✔
17
    var decompressedSize = ReadDecompressedSize_(br);
63✔
18
    br.PopEndianness();
63✔
19

20
    br.PushContainerEndianness(Endianness.BigEndian);
63✔
21
    switch (compressionType) {
63!
22
      case 0x10: {
63✔
23
        data = Decompress10_(br, decompressedSize);
63✔
24
        return true;
63✔
25
      }
26
      case 0x11: {
×
27
        data = Decompress11_(br, decompressedSize);
×
28
        return true;
×
29
      }
30
    }
31
    br.PopEndianness();
×
32

NEW
33
    data = null;
×
34
    return false;
×
35
  }
63✔
36

37
  private static uint ReadDecompressedSize_(IBinaryReader br) {
63✔
38
    var decompressedSize = br.ReadUInt24();
63✔
39
    if (decompressedSize == 0) {
63!
40
      decompressedSize = br.ReadUInt32();
×
41
    }
×
42

43
    if (decompressedSize < 40) {
63!
44
      Asserts.Fail($"LZ77 decompressed size is too small: {decompressedSize}");
×
45
    }
×
46

47
    if (decompressedSize > (1 << 19) * 4) {
63!
48
      Asserts.Fail($"LZ77 decompressed size is too big: {decompressedSize}");
×
49
    }
×
50

51
    return decompressedSize;
63✔
52
  }
63✔
53

54
  private static byte[] Decompress10_(IBinaryReader br, uint decompressedSize) {
63✔
55
    var data = new List<byte>((int) decompressedSize);
63✔
56
    while (data.Count < decompressedSize) {
71,581✔
57
      var flags = br.ReadByte();
35,759✔
58

59
      for (var i = 0; i < 8; ++i) {
928,843✔
60
        var compressed = (flags & 0x80) != 0;
285,817✔
61
        flags <<= 1;
285,817✔
62

63
        if (!compressed) {
502,656✔
64
          // Uncompressed byte
65
          data.Add(br.ReadByte());
216,839✔
66
        } else {
285,817✔
67
          // LZ backreference
68
          var ofsSub1And3 = br.ReadUInt16();
68,978✔
69
          var ofsSub1 = ofsSub1And3.ExtractFromRight(0, 12);
68,978✔
70
          var ofsSub3 = ofsSub1And3.ExtractFromRight(12, 4);
68,978✔
71

72
          var ofs = ofsSub1 + 1;
68,978✔
73
          var n = ofsSub3 + 3;
68,978✔
74

75
          if (data.Count + n > decompressedSize) {
68,978!
76
            Asserts.Fail("Too much data!");
×
77
          }
×
78

79
          if (data.Count < ofs) {
68,978!
80
            Asserts.Fail("Not enough data!");
×
81
          }
×
82

83
          for (var ii = 0; ii < n; ++ii) {
1,291,855✔
84
            var x = data[data.Count - ofs];
384,633✔
85
            data.Add(x);
384,633✔
86
          }
384,633✔
87
        }
68,978✔
88

89
        if (data.Count >= decompressedSize) {
285,880✔
90
          break;
63✔
91
        }
92
      }
285,754✔
93
    }
35,759✔
94

95
    return data.ToArray();
63✔
96
  }
63✔
97

98
  private static byte[] Decompress11_(IBinaryReader br, uint decompressedSize) {
×
99
    var data = new List<byte>((int) decompressedSize);
×
100
    while (data.Count < decompressedSize) {
×
101
      var flags = br.ReadByte();
×
102
      for (var i = 0; i < 8; ++i) {
×
103
        var compressed = (flags & 0x80) != 0;
×
104
        flags <<= 1;
×
105

106
        if (!compressed) {
×
107
          // Uncompressed byte
108
          data.Add(br.ReadByte());
×
109
        } else {
×
110
          br.ReadByte().SplitNibbles(out var a, out var b);
×
111
          var cd = br.ReadByte();
×
112

113
          int n, ofs;
114
          switch (a) {
×
115
            case 0: {
×
116
              // ab cd ef
117
              // =>
118
              // n = abc + 0x11 = bc + 0x11
119
              // ofs = def + 1
120
              cd.SplitNibbles(out var c, out var d);
×
121
              var ef = br.ReadByte();
×
122

123
              n = ((b << 4) | c) + 0x11;
×
124
              ofs = ((d << 8) | ef) + 1;
×
125
              break;
×
126
            }
127
            case 1: {
×
128
              // ab cd ef gh
129
              // =>
130
              // n = bcde + 0x111
131
              // ofs = fgh + 1
132
              br.ReadByte().SplitNibbles(out var e, out var f);
×
133
              var gh = br.ReadByte();
×
134

135
              n = ((b << 12) | (cd << 4) | e) +
×
136
                  0x111;
×
137
              ofs = ((f << 8) | gh) + 1;
×
138
              break;
×
139
            }
140
            default: {
×
141
              // ab cd
142
              // =>
143
              // n = a + 1
144
              // ofs = bcd + 1
145
              n = a + 1;
×
146
              ofs = ((b << 8) | cd) + 1;
×
147
              break;
×
148
            }
149
          }
150

151
          if (data.Count + n > decompressedSize) {
×
152
            Asserts.Fail("Too much data!");
×
153
          }
×
154

155
          if (data.Count < ofs) {
×
156
            Asserts.Fail("Not enough data!");
×
157
          }
×
158

159
          for (var ii = 0; ii < n; ii++) {
×
160
            var x = data[data.Count - ofs];
×
161
            data.Add(x);
×
162
          }
×
163
        }
×
164

165
        if (data.Count >= decompressedSize) {
×
166
          break;
×
167
        }
168
      }
×
169
    }
×
170

171
    return data.ToArray();
×
172
  }
×
173
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc