1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Models;
7
8class BeatmapFile
9{
10 private $parsed = false;
11 private $backgroundImage;
12
13 public static function parse(string $content)
14 {
15 // strip utf8 bom
16 $content = strip_utf8_bom($content);
17
18 // check file 'header'
19 if (!starts_with($content, 'osu file format v')) {
20 return false;
21 }
22
23 // TODO: parse more stuff? ^_^b
24 $matching = false;
25 $lines = explode("\n", $content);
26 foreach ($lines as $line) {
27 $line = trim($line);
28
29 if ($matching) {
30 $parts = explode(',', $line);
31 // Background Image, e.g.:
32 // 0,0,"bg.jpg",0,0
33 if (count($parts) > 2 && $parts[0] === '0') {
34 $imageFilename = str_replace('"', '', $parts[2]);
35 break;
36 }
37 // Storyboard Layer (for when BG isn't defined, e.g. old beatmap)
38 // This *should* appear after the above BG in a valid .osu file, e.g.:
39 // 4,0,0,"evangelion_20_640.jpg",0,0
40 if (count($parts) > 2 && ($parts[0] === '4' || $parts[0] === 'Sprite')) {
41 $imageFilename = str_replace('"', '', $parts[3]);
42 break;
43 }
44 }
45
46 if ($line === '[Events]') {
47 $matching = true;
48 }
49
50 if ($line === '[HitObjects]') {
51 // Too far, give up
52 break;
53 }
54 }
55
56 $file = new static();
57 $file->parsed = true;
58
59 if (isset($imageFilename)) {
60 // older beatmaps may not have sanitized paths
61 $file->backgroundImage = str_replace('\\', '/', $imageFilename);
62 } else {
63 $file->backgroundImage = false;
64 }
65
66 return $file;
67 }
68
69 public function backgroundImage()
70 {
71 if (!$this->parsed) {
72 return false;
73 }
74
75 return $this->backgroundImage;
76 }
77}