@coderline/alphatab 1.9.0-alpha.1804 → 1.9.0-alpha.1806
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/alphaTab.core.min.mjs +2 -2
- package/dist/alphaTab.core.mjs +176 -65
- package/dist/alphaTab.d.ts +40 -0
- package/dist/alphaTab.js +176 -65
- package/dist/alphaTab.min.js +2 -2
- package/dist/alphaTab.min.mjs +1 -1
- package/dist/alphaTab.mjs +1 -1
- package/dist/alphaTab.worker.min.mjs +1 -1
- package/dist/alphaTab.worker.mjs +1 -1
- package/dist/alphaTab.worklet.min.mjs +1 -1
- package/dist/alphaTab.worklet.mjs +1 -1
- package/package.json +1 -1
package/dist/alphaTab.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* alphaTab v1.9.0-alpha.
|
|
2
|
+
* alphaTab v1.9.0-alpha.1806 (develop, build 1806)
|
|
3
3
|
*
|
|
4
4
|
* Copyright © 2026, Daniel Kuschny and Contributors, All rights reserved.
|
|
5
5
|
*
|
|
@@ -209,9 +209,9 @@
|
|
|
209
209
|
* @internal
|
|
210
210
|
*/
|
|
211
211
|
class VersionInfo {
|
|
212
|
-
static version = '1.9.0-alpha.
|
|
213
|
-
static date = '2026-05-
|
|
214
|
-
static commit = '
|
|
212
|
+
static version = '1.9.0-alpha.1806';
|
|
213
|
+
static date = '2026-05-18T04:36:35.809Z';
|
|
214
|
+
static commit = 'e926f2b6bcfbaa219a04140bf34fdd9431a6ca17';
|
|
215
215
|
static print(print) {
|
|
216
216
|
print(`alphaTab ${VersionInfo.version}`);
|
|
217
217
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -16007,6 +16007,68 @@
|
|
|
16007
16007
|
}
|
|
16008
16008
|
}
|
|
16009
16009
|
|
|
16010
|
+
/**
|
|
16011
|
+
* Thrown whenever we hit the end of input data unexpectedly.
|
|
16012
|
+
* @public
|
|
16013
|
+
*/
|
|
16014
|
+
class EndOfReaderError extends AlphaTabError {
|
|
16015
|
+
constructor() {
|
|
16016
|
+
super(exports.AlphaTabErrorType.Format, 'Unexpected end of data within reader');
|
|
16017
|
+
}
|
|
16018
|
+
}
|
|
16019
|
+
/**
|
|
16020
|
+
* Thrown whenever an overflow in data or buffer sizes is detected.
|
|
16021
|
+
* @public
|
|
16022
|
+
*/
|
|
16023
|
+
class OverflowError extends AlphaTabError {
|
|
16024
|
+
constructor(message) {
|
|
16025
|
+
super(exports.AlphaTabErrorType.Format, message);
|
|
16026
|
+
}
|
|
16027
|
+
}
|
|
16028
|
+
/**
|
|
16029
|
+
* An {@see IReadable} implementation throwing when the end of stream is reached guarding against
|
|
16030
|
+
* corrupted or maliciously crafted files leading to endless reading
|
|
16031
|
+
* @internal
|
|
16032
|
+
*/
|
|
16033
|
+
class ThrowingReadable {
|
|
16034
|
+
_readable;
|
|
16035
|
+
constructor(readable) {
|
|
16036
|
+
this._readable = readable;
|
|
16037
|
+
}
|
|
16038
|
+
get position() {
|
|
16039
|
+
return this._readable.position;
|
|
16040
|
+
}
|
|
16041
|
+
set position(value) {
|
|
16042
|
+
this._readable.position = value;
|
|
16043
|
+
}
|
|
16044
|
+
get length() {
|
|
16045
|
+
return this._readable.length;
|
|
16046
|
+
}
|
|
16047
|
+
reset() {
|
|
16048
|
+
this._readable.reset();
|
|
16049
|
+
}
|
|
16050
|
+
skip(offset) {
|
|
16051
|
+
this._readable.skip(offset);
|
|
16052
|
+
}
|
|
16053
|
+
_requireBytes(bytes) {
|
|
16054
|
+
const remaining = this.length - this.position;
|
|
16055
|
+
if (remaining < bytes) {
|
|
16056
|
+
throw new EndOfReaderError();
|
|
16057
|
+
}
|
|
16058
|
+
}
|
|
16059
|
+
readByte() {
|
|
16060
|
+
this._requireBytes(1);
|
|
16061
|
+
return this._readable.readByte();
|
|
16062
|
+
}
|
|
16063
|
+
read(buffer, offset, count) {
|
|
16064
|
+
this._requireBytes(count);
|
|
16065
|
+
return this._readable.read(buffer, offset, count);
|
|
16066
|
+
}
|
|
16067
|
+
readAll() {
|
|
16068
|
+
return this._readable.readAll();
|
|
16069
|
+
}
|
|
16070
|
+
}
|
|
16071
|
+
|
|
16010
16072
|
/**
|
|
16011
16073
|
* This is the base public class for creating new song importers which
|
|
16012
16074
|
* enable reading scores from any binary datasource
|
|
@@ -16019,7 +16081,12 @@
|
|
|
16019
16081
|
* Initializes the importer with the given data and settings.
|
|
16020
16082
|
*/
|
|
16021
16083
|
init(data, settings) {
|
|
16022
|
-
|
|
16084
|
+
if (data instanceof ThrowingReadable) {
|
|
16085
|
+
this.data = data;
|
|
16086
|
+
}
|
|
16087
|
+
else {
|
|
16088
|
+
this.data = new ThrowingReadable(data);
|
|
16089
|
+
}
|
|
16023
16090
|
this.settings = settings;
|
|
16024
16091
|
// when beginning reading a new score we reset the IDs.
|
|
16025
16092
|
Score.resetIds();
|
|
@@ -17688,8 +17755,10 @@
|
|
|
17688
17755
|
*/
|
|
17689
17756
|
class ZipReader {
|
|
17690
17757
|
_readable;
|
|
17691
|
-
|
|
17758
|
+
_maxDecodingBufferSize;
|
|
17759
|
+
constructor(readable, maxDecodingBufferSize) {
|
|
17692
17760
|
this._readable = readable;
|
|
17761
|
+
this._maxDecodingBufferSize = maxDecodingBufferSize;
|
|
17693
17762
|
}
|
|
17694
17763
|
read() {
|
|
17695
17764
|
const entries = [];
|
|
@@ -17721,7 +17790,13 @@
|
|
|
17721
17790
|
IOHelper.readInt32LE(readable); // crc-32
|
|
17722
17791
|
IOHelper.readInt32LE(readable); // compressed size
|
|
17723
17792
|
const uncompressedSize = IOHelper.readInt32LE(readable);
|
|
17793
|
+
if (uncompressedSize > this._maxDecodingBufferSize) {
|
|
17794
|
+
throw new OverflowError(`Zip contains files exceeding the configured maxDecodingBufferSize`);
|
|
17795
|
+
}
|
|
17724
17796
|
const fileNameLength = IOHelper.readInt16LE(readable);
|
|
17797
|
+
if (fileNameLength > this._maxDecodingBufferSize) {
|
|
17798
|
+
throw new OverflowError(`Zip contains file names exceeding the configured maxDecodingBufferSize`);
|
|
17799
|
+
}
|
|
17725
17800
|
const extraFieldLength = IOHelper.readInt16LE(readable);
|
|
17726
17801
|
const fname = IOHelper.toString(IOHelper.readByteArray(readable, fileNameLength), 'utf-8');
|
|
17727
17802
|
readable.skip(extraFieldLength);
|
|
@@ -17734,6 +17809,9 @@
|
|
|
17734
17809
|
while (true) {
|
|
17735
17810
|
const bytes = z.readBytes(buffer, 0, buffer.length);
|
|
17736
17811
|
target.write(buffer, 0, bytes);
|
|
17812
|
+
if (target.length > this._maxDecodingBufferSize) {
|
|
17813
|
+
throw new OverflowError(`Zip entry "${fname}" contains data exceeding the configured maxDecodingBufferSize`);
|
|
17814
|
+
}
|
|
17737
17815
|
if (bytes < buffer.length) {
|
|
17738
17816
|
break;
|
|
17739
17817
|
}
|
|
@@ -19682,7 +19760,7 @@
|
|
|
19682
19760
|
}
|
|
19683
19761
|
readScore() {
|
|
19684
19762
|
Logger.debug(this.name, 'Loading ZIP entries');
|
|
19685
|
-
const fileSystem = new ZipReader(this.data);
|
|
19763
|
+
const fileSystem = new ZipReader(this.data, this.settings.importer.maxDecodingBufferSize);
|
|
19686
19764
|
let entries;
|
|
19687
19765
|
let xml = null;
|
|
19688
19766
|
entries = fileSystem.read();
|
|
@@ -19812,7 +19890,7 @@
|
|
|
19812
19890
|
this._initialTempo = Automation.buildTempoAutomation(false, 0, 0, 0);
|
|
19813
19891
|
if (this._versionNumber >= 500) {
|
|
19814
19892
|
this.readPageSetup();
|
|
19815
|
-
this._initialTempo.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
19893
|
+
this._initialTempo.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19816
19894
|
}
|
|
19817
19895
|
// tempo stuff
|
|
19818
19896
|
this._initialTempo.value = IOHelper.readInt32LE(this.data);
|
|
@@ -19851,7 +19929,9 @@
|
|
|
19851
19929
|
}
|
|
19852
19930
|
// contents
|
|
19853
19931
|
this._barCount = IOHelper.readInt32LE(this.data);
|
|
19932
|
+
this._ensureLoopBoundary(this._barCount, Gp3To5Importer._maxBarCount, 'bar count');
|
|
19854
19933
|
this._trackCount = IOHelper.readInt32LE(this.data);
|
|
19934
|
+
this._ensureLoopBoundary(this._trackCount, Gp3To5Importer._maxTrackCount, 'track count');
|
|
19855
19935
|
this.readMasterBars();
|
|
19856
19936
|
this.readTracks();
|
|
19857
19937
|
this.readBars();
|
|
@@ -19899,35 +19979,54 @@
|
|
|
19899
19979
|
Logger.debug(this.name, `Guitar Pro version ${version} detected`);
|
|
19900
19980
|
}
|
|
19901
19981
|
readScoreInformation() {
|
|
19902
|
-
this._score.title = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19903
|
-
this._score.subTitle = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19904
|
-
this._score.artist = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19905
|
-
this._score.album = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19906
|
-
this._score.words = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19982
|
+
this._score.title = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19983
|
+
this._score.subTitle = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19984
|
+
this._score.artist = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19985
|
+
this._score.album = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19986
|
+
this._score.words = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19907
19987
|
this._score.music =
|
|
19908
19988
|
this._versionNumber >= 500
|
|
19909
|
-
? GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding)
|
|
19989
|
+
? GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize)
|
|
19910
19990
|
: this._score.words;
|
|
19911
|
-
this._score.copyright = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19912
|
-
this._score.tab = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19913
|
-
this._score.instructions = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19991
|
+
this._score.copyright = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19992
|
+
this._score.tab = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19993
|
+
this._score.instructions = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19914
19994
|
const noticeLines = IOHelper.readInt32LE(this.data);
|
|
19995
|
+
this._ensureLoopBoundary(noticeLines, Gp3To5Importer._maxNoticeLines, 'notice line count');
|
|
19915
19996
|
let notice = '';
|
|
19916
19997
|
for (let i = 0; i < noticeLines; i++) {
|
|
19917
19998
|
if (i > 0) {
|
|
19918
19999
|
notice += '\r\n';
|
|
19919
20000
|
}
|
|
19920
|
-
notice += GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding)?.toString();
|
|
20001
|
+
notice += GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize)?.toString();
|
|
19921
20002
|
}
|
|
19922
20003
|
this._score.notices = notice;
|
|
19923
20004
|
}
|
|
20005
|
+
// very generous thresholds for values which control loop boundaries
|
|
20006
|
+
// prevents DoS or resource exhaustion for corrupt files or files with malicious intent
|
|
20007
|
+
// not configurable, as realistically GP3-5 files will not exceed these values,
|
|
20008
|
+
// I don't hink anyone is that verbose in the small GP5 box where you can add notices
|
|
20009
|
+
static _maxNoticeLines = 1000;
|
|
20010
|
+
// I haven't encountered such a long song in the wild. beyond 1000 bars something is clearly off
|
|
20011
|
+
static _maxBarCount = 1000;
|
|
20012
|
+
// I think GP5 itself limits already to ~10. 100 tracks is just unrealistic, proof me wrong
|
|
20013
|
+
static _maxTrackCount = 100;
|
|
20014
|
+
// nobody reallistically writes that many beats in one bar either.
|
|
20015
|
+
static _maxBeatCount = 100;
|
|
20016
|
+
// I think GP5 already limits this to way less, very generous to allow 4 times more than likely the UI supports
|
|
20017
|
+
static _maxBendPointCount = BendPoint.MaxPosition * 4;
|
|
20018
|
+
_ensureLoopBoundary(value, maximumValue, label) {
|
|
20019
|
+
if (value > maximumValue) {
|
|
20020
|
+
throw new OverflowError(`'${label}' with value ${value} has exceeded the internal safety threshold of ${maximumValue}`);
|
|
20021
|
+
}
|
|
20022
|
+
}
|
|
19924
20023
|
readLyrics() {
|
|
19925
20024
|
this._lyrics = [];
|
|
19926
20025
|
this._lyricsTrack = IOHelper.readInt32LE(this.data) - 1;
|
|
19927
20026
|
for (let i = 0; i < 5; i++) {
|
|
19928
20027
|
const lyrics = new Lyrics();
|
|
19929
20028
|
lyrics.startBar = IOHelper.readInt32LE(this.data) - 1;
|
|
19930
|
-
lyrics.text = GpBinaryHelpers.gpReadStringInt(this.data, this.settings.importer.encoding);
|
|
20029
|
+
lyrics.text = GpBinaryHelpers.gpReadStringInt(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19931
20030
|
this._lyrics.push(lyrics);
|
|
19932
20031
|
}
|
|
19933
20032
|
}
|
|
@@ -19944,41 +20043,41 @@
|
|
|
19944
20043
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Title).isVisible =
|
|
19945
20044
|
(flags & (0x01 << 0)) !== 0;
|
|
19946
20045
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Title).template =
|
|
19947
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20046
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19948
20047
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.SubTitle).isVisible =
|
|
19949
20048
|
(flags & (0x01 << 1)) !== 0;
|
|
19950
20049
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.SubTitle).template =
|
|
19951
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20050
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19952
20051
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Artist).isVisible =
|
|
19953
20052
|
(flags & (0x01 << 2)) !== 0;
|
|
19954
20053
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Artist).template =
|
|
19955
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20054
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19956
20055
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Album).isVisible =
|
|
19957
20056
|
(flags & (0x01 << 3)) !== 0;
|
|
19958
20057
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Album).template =
|
|
19959
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20058
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19960
20059
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Words).isVisible =
|
|
19961
20060
|
(flags & (0x01 << 4)) !== 0;
|
|
19962
20061
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Words).template =
|
|
19963
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20062
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19964
20063
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Music).isVisible =
|
|
19965
20064
|
(flags & (0x01 << 5)) !== 0;
|
|
19966
20065
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Music).template =
|
|
19967
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20066
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19968
20067
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.WordsAndMusic).isVisible =
|
|
19969
20068
|
(flags & (0x01 << 6)) !== 0;
|
|
19970
20069
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.WordsAndMusic).template =
|
|
19971
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20070
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19972
20071
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Copyright).isVisible =
|
|
19973
20072
|
(flags & (0x01 << 7)) !== 0;
|
|
19974
20073
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Copyright).template =
|
|
19975
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20074
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19976
20075
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.CopyrightSecondLine).isVisible =
|
|
19977
20076
|
(flags & (0x01 << 7)) !== 0;
|
|
19978
20077
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.CopyrightSecondLine).template =
|
|
19979
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20078
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19980
20079
|
// page number format
|
|
19981
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20080
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19982
20081
|
}
|
|
19983
20082
|
readPlaybackInfos() {
|
|
19984
20083
|
this._playbackInfos = [];
|
|
@@ -20059,7 +20158,7 @@
|
|
|
20059
20158
|
// marker
|
|
20060
20159
|
if ((flags & 0x20) !== 0) {
|
|
20061
20160
|
const section = new Section();
|
|
20062
|
-
section.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20161
|
+
section.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20063
20162
|
section.marker = '';
|
|
20064
20163
|
GpBinaryHelpers.gpReadColor(this.data, false);
|
|
20065
20164
|
newMasterBar.section = section;
|
|
@@ -20226,9 +20325,9 @@
|
|
|
20226
20325
|
// 1 byte PRE
|
|
20227
20326
|
this.data.skip(4);
|
|
20228
20327
|
// RSE: effect name
|
|
20229
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20328
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20230
20329
|
// RSE: effect category
|
|
20231
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20330
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20232
20331
|
}
|
|
20233
20332
|
}
|
|
20234
20333
|
else {
|
|
@@ -20285,6 +20384,7 @@
|
|
|
20285
20384
|
}
|
|
20286
20385
|
const newVoice = new Voice$1();
|
|
20287
20386
|
bar.addVoice(newVoice);
|
|
20387
|
+
this._ensureLoopBoundary(beatCount, Gp3To5Importer._maxBeatCount, 'beat count');
|
|
20288
20388
|
for (let i = 0; i < beatCount; i++) {
|
|
20289
20389
|
this.readBeat(track, bar, newVoice);
|
|
20290
20390
|
}
|
|
@@ -20363,7 +20463,7 @@
|
|
|
20363
20463
|
}
|
|
20364
20464
|
const beatTextAsLyrics = this.settings.importer.beatTextAsLyrics && track.index !== this._lyricsTrack; // detect if not lyrics track
|
|
20365
20465
|
if ((flags & 0x04) !== 0) {
|
|
20366
|
-
const text = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
20466
|
+
const text = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20367
20467
|
if (beatTextAsLyrics) {
|
|
20368
20468
|
const lyrics = new Lyrics();
|
|
20369
20469
|
lyrics.text = text.trim();
|
|
@@ -20538,7 +20638,7 @@
|
|
|
20538
20638
|
}
|
|
20539
20639
|
else {
|
|
20540
20640
|
const strings = this._versionNumber >= 406 ? 7 : 6;
|
|
20541
|
-
chord.name = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20641
|
+
chord.name = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20542
20642
|
chord.firstFret = IOHelper.readInt32LE(this.data);
|
|
20543
20643
|
if (chord.firstFret > 0) {
|
|
20544
20644
|
for (let i = 0; i < strings; i++) {
|
|
@@ -20649,6 +20749,7 @@
|
|
|
20649
20749
|
this.data.readByte(); // type
|
|
20650
20750
|
IOHelper.readInt32LE(this.data); // value
|
|
20651
20751
|
const pointCount = IOHelper.readInt32LE(this.data);
|
|
20752
|
+
this._ensureLoopBoundary(pointCount, Gp3To5Importer._maxBendPointCount, 'tremolo bar point count');
|
|
20652
20753
|
if (pointCount > 0) {
|
|
20653
20754
|
for (let i = 0; i < pointCount; i++) {
|
|
20654
20755
|
const point = new BendPoint(0, 0);
|
|
@@ -20708,7 +20809,7 @@
|
|
|
20708
20809
|
const phaser = IOHelper.readSInt8(this.data);
|
|
20709
20810
|
const tremolo = IOHelper.readSInt8(this.data);
|
|
20710
20811
|
if (this._versionNumber >= 500) {
|
|
20711
|
-
tableChange.tempoName = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20812
|
+
tableChange.tempoName = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20712
20813
|
}
|
|
20713
20814
|
tableChange.tempo = IOHelper.readInt32LE(this.data);
|
|
20714
20815
|
// durations (in number of beats)
|
|
@@ -20752,8 +20853,8 @@
|
|
|
20752
20853
|
}
|
|
20753
20854
|
// unknown
|
|
20754
20855
|
if (this._versionNumber >= 510) {
|
|
20755
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20756
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20856
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20857
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20757
20858
|
}
|
|
20758
20859
|
if (tableChange.volume >= 0) {
|
|
20759
20860
|
const volumeAutomation = new Automation();
|
|
@@ -20917,6 +21018,7 @@
|
|
|
20917
21018
|
this.data.readByte(); // type
|
|
20918
21019
|
IOHelper.readInt32LE(this.data); // value
|
|
20919
21020
|
const pointCount = IOHelper.readInt32LE(this.data);
|
|
21021
|
+
this._ensureLoopBoundary(pointCount, Gp3To5Importer._maxBendPointCount, 'note bend point count');
|
|
20920
21022
|
if (pointCount > 0) {
|
|
20921
21023
|
for (let i = 0; i < pointCount; i++) {
|
|
20922
21024
|
const point = new BendPoint(0, 0);
|
|
@@ -21105,25 +21207,28 @@
|
|
|
21105
21207
|
* Skips an integer (4byte) and reads a string using
|
|
21106
21208
|
* a bytesize
|
|
21107
21209
|
*/
|
|
21108
|
-
static gpReadStringIntUnused(data, encoding) {
|
|
21210
|
+
static gpReadStringIntUnused(data, encoding, maxDecodingBufferSize) {
|
|
21109
21211
|
data.skip(4);
|
|
21110
|
-
return GpBinaryHelpers.gpReadString(data, data.readByte(), encoding);
|
|
21212
|
+
return GpBinaryHelpers.gpReadString(data, data.readByte(), encoding, maxDecodingBufferSize);
|
|
21111
21213
|
}
|
|
21112
21214
|
/**
|
|
21113
21215
|
* Reads an integer as size, and then the string itself
|
|
21114
21216
|
*/
|
|
21115
|
-
static gpReadStringInt(data, encoding) {
|
|
21116
|
-
return GpBinaryHelpers.gpReadString(data, IOHelper.readInt32LE(data), encoding);
|
|
21217
|
+
static gpReadStringInt(data, encoding, maxDecodingBufferSize) {
|
|
21218
|
+
return GpBinaryHelpers.gpReadString(data, IOHelper.readInt32LE(data), encoding, maxDecodingBufferSize);
|
|
21117
21219
|
}
|
|
21118
21220
|
/**
|
|
21119
21221
|
* Reads an integer as size, skips a byte and reads the string itself
|
|
21120
21222
|
*/
|
|
21121
|
-
static gpReadStringIntByte(data, encoding) {
|
|
21223
|
+
static gpReadStringIntByte(data, encoding, maxDecodingBufferSize) {
|
|
21122
21224
|
const length = IOHelper.readInt32LE(data) - 1;
|
|
21123
21225
|
data.readByte();
|
|
21124
|
-
return GpBinaryHelpers.gpReadString(data, length, encoding);
|
|
21226
|
+
return GpBinaryHelpers.gpReadString(data, length, encoding, maxDecodingBufferSize);
|
|
21125
21227
|
}
|
|
21126
|
-
static gpReadString(data, length, encoding) {
|
|
21228
|
+
static gpReadString(data, length, encoding, maxDecodingBufferSize) {
|
|
21229
|
+
if (length > maxDecodingBufferSize) {
|
|
21230
|
+
throw new OverflowError(`Detected string exceeding maxDecodingBufferSize at offset ${data.position}`);
|
|
21231
|
+
}
|
|
21127
21232
|
const b = new Uint8Array(length);
|
|
21128
21233
|
data.read(b, 0, b.length);
|
|
21129
21234
|
return IOHelper.toString(b, encoding);
|
|
@@ -21257,17 +21362,17 @@
|
|
|
21257
21362
|
class BinaryStylesheet {
|
|
21258
21363
|
_types = new Map();
|
|
21259
21364
|
raw = new Map();
|
|
21260
|
-
constructor(data) {
|
|
21365
|
+
constructor(data, maxDecodingBufferSize = 0) {
|
|
21261
21366
|
if (data) {
|
|
21262
|
-
this._read(data);
|
|
21367
|
+
this._read(data, maxDecodingBufferSize);
|
|
21263
21368
|
}
|
|
21264
21369
|
}
|
|
21265
|
-
_read(data) {
|
|
21370
|
+
_read(data, maxDecodingBufferSize) {
|
|
21266
21371
|
// BinaryStylesheet apears to be big-endien
|
|
21267
21372
|
const readable = ByteBuffer.fromBuffer(data);
|
|
21268
21373
|
const entryCount = IOHelper.readInt32BE(readable);
|
|
21269
21374
|
for (let i = 0; i < entryCount; i++) {
|
|
21270
|
-
const key = GpBinaryHelpers.gpReadString(readable, readable.readByte(), 'utf-8');
|
|
21375
|
+
const key = GpBinaryHelpers.gpReadString(readable, readable.readByte(), 'utf-8', maxDecodingBufferSize);
|
|
21271
21376
|
const type = readable.readByte();
|
|
21272
21377
|
this._types.set(key, type);
|
|
21273
21378
|
switch (type) {
|
|
@@ -21284,7 +21389,7 @@
|
|
|
21284
21389
|
this.addValue(key, fvalue);
|
|
21285
21390
|
break;
|
|
21286
21391
|
case DataType.String:
|
|
21287
|
-
const s = GpBinaryHelpers.gpReadString(readable, IOHelper.readInt16BE(readable), 'utf-8');
|
|
21392
|
+
const s = GpBinaryHelpers.gpReadString(readable, IOHelper.readInt16BE(readable), 'utf-8', maxDecodingBufferSize);
|
|
21288
21393
|
this.addValue(key, s);
|
|
21289
21394
|
break;
|
|
21290
21395
|
case DataType.Point:
|
|
@@ -24661,7 +24766,7 @@
|
|
|
24661
24766
|
// at first we need to load the binary file system
|
|
24662
24767
|
// from the GPX container
|
|
24663
24768
|
Logger.debug(this.name, 'Loading ZIP entries');
|
|
24664
|
-
const fileSystem = new ZipReader(this.data);
|
|
24769
|
+
const fileSystem = new ZipReader(this.data, this.settings.importer.maxDecodingBufferSize);
|
|
24665
24770
|
let entries;
|
|
24666
24771
|
try {
|
|
24667
24772
|
entries = fileSystem.read();
|
|
@@ -24710,7 +24815,7 @@
|
|
|
24710
24815
|
const score = gpifParser.score;
|
|
24711
24816
|
if (binaryStylesheetData) {
|
|
24712
24817
|
Logger.debug(this.name, 'Start Parsing BinaryStylesheet');
|
|
24713
|
-
const stylesheet = new BinaryStylesheet(binaryStylesheetData);
|
|
24818
|
+
const stylesheet = new BinaryStylesheet(binaryStylesheetData, this.settings.importer.maxDecodingBufferSize);
|
|
24714
24819
|
stylesheet.apply(score);
|
|
24715
24820
|
Logger.debug(this.name, 'BinaryStylesheet parsed');
|
|
24716
24821
|
}
|
|
@@ -24731,15 +24836,6 @@
|
|
|
24731
24836
|
}
|
|
24732
24837
|
}
|
|
24733
24838
|
|
|
24734
|
-
/**
|
|
24735
|
-
* @internal
|
|
24736
|
-
*/
|
|
24737
|
-
class EndOfReaderError extends AlphaTabError {
|
|
24738
|
-
constructor() {
|
|
24739
|
-
super(exports.AlphaTabErrorType.Format, 'Unexpected end of data within reader');
|
|
24740
|
-
}
|
|
24741
|
-
}
|
|
24742
|
-
|
|
24743
24839
|
/**
|
|
24744
24840
|
* This utility public class allows bitwise reading of a stream
|
|
24745
24841
|
* @internal
|
|
@@ -25085,7 +25181,7 @@
|
|
|
25085
25181
|
const score = gpifParser.score;
|
|
25086
25182
|
if (binaryStylesheetData) {
|
|
25087
25183
|
Logger.debug(this.name, 'Start Parsing BinaryStylesheet');
|
|
25088
|
-
const binaryStylesheet = new BinaryStylesheet(binaryStylesheetData);
|
|
25184
|
+
const binaryStylesheet = new BinaryStylesheet(binaryStylesheetData, this.settings.importer.maxDecodingBufferSize);
|
|
25089
25185
|
binaryStylesheet.apply(score);
|
|
25090
25186
|
Logger.debug(this.name, 'BinaryStylesheet parsed');
|
|
25091
25187
|
}
|
|
@@ -25462,7 +25558,7 @@
|
|
|
25462
25558
|
return this._score;
|
|
25463
25559
|
}
|
|
25464
25560
|
_extractMusicXml() {
|
|
25465
|
-
const zip = new ZipReader(this.data);
|
|
25561
|
+
const zip = new ZipReader(this.data, this.settings.importer.maxDecodingBufferSize);
|
|
25466
25562
|
let entries;
|
|
25467
25563
|
try {
|
|
25468
25564
|
entries = zip.read();
|
|
@@ -32827,6 +32923,17 @@
|
|
|
32827
32923
|
* 
|
|
32828
32924
|
*/
|
|
32829
32925
|
beatTextAsLyrics = false;
|
|
32926
|
+
/**
|
|
32927
|
+
* This setting controls the escape hatch for handling potentially malicous or corrupt
|
|
32928
|
+
* input files. At selected spots in the codebase, we use this buffer size as maximum
|
|
32929
|
+
* allowed sizes. e.g. during unzipping or decoding strings.
|
|
32930
|
+
* This prevents resource exhaustion, especially when alphaTab is used on server side.
|
|
32931
|
+
* Increase this buffer size if you need to handle very big files.
|
|
32932
|
+
* @defaultValue `128000000`
|
|
32933
|
+
* @category Core
|
|
32934
|
+
* @since 1.9.0
|
|
32935
|
+
*/
|
|
32936
|
+
maxDecodingBufferSize = 128000000;
|
|
32830
32937
|
}
|
|
32831
32938
|
|
|
32832
32939
|
/**
|
|
@@ -34152,6 +34259,7 @@
|
|
|
34152
34259
|
o.set("encoding", obj.encoding);
|
|
34153
34260
|
o.set("mergepartgroupsinmusicxml", obj.mergePartGroupsInMusicXml);
|
|
34154
34261
|
o.set("beattextaslyrics", obj.beatTextAsLyrics);
|
|
34262
|
+
o.set("maxdecodingbuffersize", obj.maxDecodingBufferSize);
|
|
34155
34263
|
return o;
|
|
34156
34264
|
}
|
|
34157
34265
|
static setProperty(obj, property, v) {
|
|
@@ -34165,6 +34273,9 @@
|
|
|
34165
34273
|
case "beattextaslyrics":
|
|
34166
34274
|
obj.beatTextAsLyrics = v;
|
|
34167
34275
|
return true;
|
|
34276
|
+
case "maxdecodingbuffersize":
|
|
34277
|
+
obj.maxDecodingBufferSize = v;
|
|
34278
|
+
return true;
|
|
34168
34279
|
}
|
|
34169
34280
|
return false;
|
|
34170
34281
|
}
|
|
@@ -34688,12 +34799,12 @@
|
|
|
34688
34799
|
const importers = Environment.buildImporters();
|
|
34689
34800
|
Logger.debug('ScoreLoader', `Loading score from ${data.length} bytes using ${importers.length} importers`);
|
|
34690
34801
|
let score = null;
|
|
34691
|
-
const
|
|
34802
|
+
const readable = new ThrowingReadable(ByteBuffer.fromBuffer(data));
|
|
34692
34803
|
for (const importer of importers) {
|
|
34693
|
-
|
|
34804
|
+
readable.reset();
|
|
34694
34805
|
try {
|
|
34695
34806
|
Logger.debug('ScoreLoader', `Importing using importer ${importer.name}`);
|
|
34696
|
-
importer.init(
|
|
34807
|
+
importer.init(readable, settings);
|
|
34697
34808
|
score = importer.readScore();
|
|
34698
34809
|
Logger.debug('ScoreLoader', `Score imported using ${importer.name}`);
|
|
34699
34810
|
break;
|