Skip to content

Commit 532ff87

Browse files
committed
decoder/psgplay: Fix file reading, max file size, tune prefix, seek
1 parent 3542419 commit 532ff87

1 file changed

Lines changed: 58 additions & 46 deletions

File tree

src/decoder/plugins/PsgplayDecoderPlugin.cxx

Lines changed: 58 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
#include "lib/fmt/PathFormatter.hxx"
1414
#include "lib/fmt/RuntimeError.hxx"
1515
#include "io/FileReader.hxx"
16+
#include "util/AllocatedArray.hxx"
1617
#include "util/Domain.hxx"
1718
#include "util/ScopeExit.hxx"
19+
#include "util/StringCompare.hxx"
1820

1921
extern "C" {
2022
#include <psgplay/psgplay.h>
@@ -24,13 +26,14 @@ extern "C" {
2426

2527
#include <fmt/format.h>
2628

27-
#include <fstream>
28-
#include <iterator>
29-
#include <string>
30-
#include <vector>
31-
3229
#define SUBTUNE_PREFIX "tune_"
3330

31+
/*
32+
* The Atari ST family of computers has a 24-bit bus,
33+
* so 16 MiB is more than enough for any SNDH file.
34+
*/
35+
#define MAX_SNDH_FILE_SIZE 0x1000000
36+
3437
static constexpr Domain psgplay_domain("psgplay");
3538

3639
struct PsgplayGlobal {
@@ -68,28 +71,34 @@ struct PsgplayContainerPath {
6871
unsigned track;
6972
};
7073

71-
static std::vector<uint8_t>
74+
static AllocatedArray<std::byte>
7275
psgplay_read_file(const Path &path_fs)
7376
{
74-
std::ifstream stream(NarrowPath(path_fs).c_str(),
75-
std::ios::in | std::ios::binary);
77+
FileReader file(path_fs);
78+
79+
const size_t size = file.GetSize();
80+
81+
if (size > MAX_SNDH_FILE_SIZE)
82+
throw FmtRuntimeError("File larger than {} bytes: {}",
83+
MAX_SNDH_FILE_SIZE, path_fs);
84+
85+
AllocatedArray<std::byte> data(size);
7686

77-
if (!stream)
78-
return { };
87+
if (file.Read(data) != size)
88+
throw FmtRuntimeError("Failed to read {} bytes: {}",
89+
size, path_fs);
7990

80-
return std::vector<uint8_t>((std::istreambuf_iterator<char>(stream)),
81-
std::istreambuf_iterator<char>());
91+
return data;
8292
}
8393

8494
[[gnu::pure]]
8595
static unsigned
8696
psgplay_subtune_track(const char *base) noexcept
8797
{
88-
if (memcmp(base, SUBTUNE_PREFIX, sizeof(SUBTUNE_PREFIX) - 1) != 0)
98+
base = StringAfterPrefix(base, SUBTUNE_PREFIX);
99+
if (base == nullptr)
89100
return 0;
90101

91-
base += sizeof(SUBTUNE_PREFIX) - 1;
92-
93102
char *endptr;
94103
auto track = strtoul(base, &endptr, 10);
95104
if (endptr == base || *endptr != '.')
@@ -114,7 +123,7 @@ psgplay_container_from_path(Path path_fs) noexcept
114123
}
115124

116125
static SongTime
117-
psgplay_subtune_duration(int subtune, const std::vector<uint8_t> &tune) noexcept
126+
psgplay_subtune_duration(int subtune, const AllocatedArray<std::byte> &tune) noexcept
118127
{
119128
float duration;
120129

@@ -127,12 +136,12 @@ psgplay_subtune_duration(int subtune, const std::vector<uint8_t> &tune) noexcept
127136
static void
128137
psgplay_file_decode(DecoderClient &client, Path path_fs)
129138
{
130-
const auto container = psgplay_container_from_path(path_fs);
131-
132-
const AudioFormat audio_format(44100, SampleFormat::S16, 2);
139+
static constexpr AudioFormat audio_format(44100, SampleFormat::S16, 2);
133140
assert(audio_format.IsValid());
134141

135-
const std::vector<uint8_t> tune = psgplay_read_file(container.path);
142+
const auto container = psgplay_container_from_path(path_fs);
143+
144+
const AllocatedArray<std::byte> tune = psgplay_read_file(container.path);
136145
if (tune.empty())
137146
return;
138147

@@ -151,27 +160,27 @@ psgplay_file_decode(DecoderClient &client, Path path_fs)
151160

152161
client.Ready(audio_format, true, duration);
153162

154-
size_t t_samples = 0;
163+
size_t t_frames = 0;
155164
DecoderCommand cmd;
156165

157166
do {
158167
enum { N = 4096 };
159168
struct psgplay_stereo buffer[N];
160169

161-
/* psgplay_read_stereo returns the number of samples */
162-
const ssize_t n_samples = psgplay_read_stereo(pp, buffer, N);
163-
if (n_samples <= 0)
170+
/* psgplay_read_stereo returns the number of (stereo) frames */
171+
const ssize_t n_frames = psgplay_read_stereo(pp, buffer, N);
172+
if (n_frames <= 0)
164173
break;
165174

166175
cmd = client.SubmitAudio(nullptr,
167-
std::span{buffer, (size_t)n_samples},
176+
std::span{buffer, (size_t)n_frames},
168177
0);
169-
t_samples += n_samples;
178+
t_frames += n_frames;
170179

171180
if (cmd == DecoderCommand::SEEK) {
172-
const uint64_t s_samples = client.GetSeekFrame();
181+
const uint64_t s_frames = client.GetSeekFrame();
173182

174-
if (s_samples < t_samples) {
183+
if (s_frames < t_frames) {
175184
psgplay_free(pp);
176185

177186
pp = psgplay_init(tune.data(), tune.size(),
@@ -181,17 +190,20 @@ psgplay_file_decode(DecoderClient &client, Path path_fs)
181190
return;
182191
psgplay_stop_at_time(pp, duration.ToDoubleS());
183192

184-
t_samples = 0;
193+
t_frames = 0;
185194
}
186195

187-
const ssize_t k_samples =
188-
psgplay_read_stereo(pp, nullptr,
189-
s_samples - t_samples);
190-
if (k_samples <= 0)
191-
break;
192-
t_samples += k_samples;
196+
if (s_frames > t_frames) {
197+
const ssize_t k_frames =
198+
psgplay_read_stereo(pp, nullptr,
199+
s_frames -
200+
t_frames);
201+
if (k_frames <= 0)
202+
break;
203+
t_frames += k_frames;
204+
}
193205

194-
if (t_samples != s_samples)
206+
if (t_frames != s_frames)
195207
client.SeekError();
196208

197209
client.CommandFinished();
@@ -203,7 +215,7 @@ static void
203215
psgplay_tag(enum TagType tag_type, TagHandler &th,
204216
bool (*tag)(char *text, size_t length,
205217
const void *data, const size_t size),
206-
const std::vector<uint8_t> &tune) noexcept
218+
const AllocatedArray<std::byte> &tune) noexcept
207219
{
208220
char text[256];
209221

@@ -212,14 +224,14 @@ psgplay_tag(enum TagType tag_type, TagHandler &th,
212224
}
213225

214226
static void
215-
psgplay_tag_subtune_title(unsigned track, unsigned n_tracks,
227+
psgplay_tag_subtune_name(unsigned track, unsigned n_tracks,
216228
TagHandler &th,
217-
const std::vector<uint8_t> &tune) noexcept
229+
const AllocatedArray<std::byte> &tune) noexcept
218230
{
219231
char text[256];
220232

221-
if (sndh_tag_subtune_title(text, sizeof(text), track,
222-
tune.data(), tune.size())) {
233+
if (sndh_tag_subtune_name(text, sizeof(text), track,
234+
tune.data(), tune.size())) {
223235
th.OnTag(TAG_TITLE, text);
224236
return;
225237
}
@@ -239,7 +251,7 @@ psgplay_tag_subtune_title(unsigned track, unsigned n_tracks,
239251
}
240252

241253
static int
242-
psgplay_tracks(const std::vector<uint8_t> &tune) noexcept
254+
psgplay_tracks(const AllocatedArray<std::byte> &tune) noexcept
243255
{
244256
int n_tracks;
245257

@@ -251,10 +263,10 @@ psgplay_tracks(const std::vector<uint8_t> &tune) noexcept
251263

252264
static void
253265
psgplay_on_tag(unsigned track, unsigned n_tracks, TagHandler &th,
254-
const std::vector<uint8_t> &tune) noexcept
266+
const AllocatedArray<std::byte> &tune) noexcept
255267
{
256268
psgplay_tag(TAG_ALBUM, th, sndh_tag_title, tune);
257-
psgplay_tag_subtune_title(track, n_tracks, th, tune);
269+
psgplay_tag_subtune_name(track, n_tracks, th, tune);
258270
psgplay_tag(TAG_ARTIST, th, sndh_tag_composer, tune);
259271
psgplay_tag(TAG_DATE, th, sndh_tag_year, tune);
260272

@@ -274,7 +286,7 @@ psgplay_scan_file(Path path_fs, TagHandler &th) noexcept
274286
{
275287
const auto container = psgplay_container_from_path(path_fs);
276288

277-
const std::vector<uint8_t> tune = psgplay_read_file(container.path);
289+
const AllocatedArray<std::byte> tune = psgplay_read_file(container.path);
278290
if (tune.empty())
279291
return false;
280292

@@ -288,7 +300,7 @@ psgplay_container_scan(Path path_fs)
288300
{
289301
std::forward_list<DetachedSong> list;
290302

291-
const std::vector<uint8_t> tune = psgplay_read_file(path_fs);
303+
const AllocatedArray<std::byte> tune = psgplay_read_file(path_fs);
292304

293305
const int n_tracks = psgplay_tracks(tune);
294306

0 commit comments

Comments
 (0)