@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.core.mjs
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
|
*
|
|
@@ -203,9 +203,9 @@ class AlphaTabError extends Error {
|
|
|
203
203
|
* @internal
|
|
204
204
|
*/
|
|
205
205
|
class VersionInfo {
|
|
206
|
-
static version = '1.9.0-alpha.
|
|
207
|
-
static date = '2026-05-
|
|
208
|
-
static commit = '
|
|
206
|
+
static version = '1.9.0-alpha.1806';
|
|
207
|
+
static date = '2026-05-18T04:36:35.809Z';
|
|
208
|
+
static commit = 'e926f2b6bcfbaa219a04140bf34fdd9431a6ca17';
|
|
209
209
|
static print(print) {
|
|
210
210
|
print(`alphaTab ${VersionInfo.version}`);
|
|
211
211
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -16001,6 +16001,68 @@ class AlphaTex1LanguageHandler {
|
|
|
16001
16001
|
}
|
|
16002
16002
|
}
|
|
16003
16003
|
|
|
16004
|
+
/**
|
|
16005
|
+
* Thrown whenever we hit the end of input data unexpectedly.
|
|
16006
|
+
* @public
|
|
16007
|
+
*/
|
|
16008
|
+
class EndOfReaderError extends AlphaTabError {
|
|
16009
|
+
constructor() {
|
|
16010
|
+
super(AlphaTabErrorType.Format, 'Unexpected end of data within reader');
|
|
16011
|
+
}
|
|
16012
|
+
}
|
|
16013
|
+
/**
|
|
16014
|
+
* Thrown whenever an overflow in data or buffer sizes is detected.
|
|
16015
|
+
* @public
|
|
16016
|
+
*/
|
|
16017
|
+
class OverflowError extends AlphaTabError {
|
|
16018
|
+
constructor(message) {
|
|
16019
|
+
super(AlphaTabErrorType.Format, message);
|
|
16020
|
+
}
|
|
16021
|
+
}
|
|
16022
|
+
/**
|
|
16023
|
+
* An {@see IReadable} implementation throwing when the end of stream is reached guarding against
|
|
16024
|
+
* corrupted or maliciously crafted files leading to endless reading
|
|
16025
|
+
* @internal
|
|
16026
|
+
*/
|
|
16027
|
+
class ThrowingReadable {
|
|
16028
|
+
_readable;
|
|
16029
|
+
constructor(readable) {
|
|
16030
|
+
this._readable = readable;
|
|
16031
|
+
}
|
|
16032
|
+
get position() {
|
|
16033
|
+
return this._readable.position;
|
|
16034
|
+
}
|
|
16035
|
+
set position(value) {
|
|
16036
|
+
this._readable.position = value;
|
|
16037
|
+
}
|
|
16038
|
+
get length() {
|
|
16039
|
+
return this._readable.length;
|
|
16040
|
+
}
|
|
16041
|
+
reset() {
|
|
16042
|
+
this._readable.reset();
|
|
16043
|
+
}
|
|
16044
|
+
skip(offset) {
|
|
16045
|
+
this._readable.skip(offset);
|
|
16046
|
+
}
|
|
16047
|
+
_requireBytes(bytes) {
|
|
16048
|
+
const remaining = this.length - this.position;
|
|
16049
|
+
if (remaining < bytes) {
|
|
16050
|
+
throw new EndOfReaderError();
|
|
16051
|
+
}
|
|
16052
|
+
}
|
|
16053
|
+
readByte() {
|
|
16054
|
+
this._requireBytes(1);
|
|
16055
|
+
return this._readable.readByte();
|
|
16056
|
+
}
|
|
16057
|
+
read(buffer, offset, count) {
|
|
16058
|
+
this._requireBytes(count);
|
|
16059
|
+
return this._readable.read(buffer, offset, count);
|
|
16060
|
+
}
|
|
16061
|
+
readAll() {
|
|
16062
|
+
return this._readable.readAll();
|
|
16063
|
+
}
|
|
16064
|
+
}
|
|
16065
|
+
|
|
16004
16066
|
/**
|
|
16005
16067
|
* This is the base public class for creating new song importers which
|
|
16006
16068
|
* enable reading scores from any binary datasource
|
|
@@ -16013,7 +16075,12 @@ class ScoreImporter {
|
|
|
16013
16075
|
* Initializes the importer with the given data and settings.
|
|
16014
16076
|
*/
|
|
16015
16077
|
init(data, settings) {
|
|
16016
|
-
|
|
16078
|
+
if (data instanceof ThrowingReadable) {
|
|
16079
|
+
this.data = data;
|
|
16080
|
+
}
|
|
16081
|
+
else {
|
|
16082
|
+
this.data = new ThrowingReadable(data);
|
|
16083
|
+
}
|
|
16017
16084
|
this.settings = settings;
|
|
16018
16085
|
// when beginning reading a new score we reset the IDs.
|
|
16019
16086
|
Score.resetIds();
|
|
@@ -17682,8 +17749,10 @@ class ZipEntry {
|
|
|
17682
17749
|
*/
|
|
17683
17750
|
class ZipReader {
|
|
17684
17751
|
_readable;
|
|
17685
|
-
|
|
17752
|
+
_maxDecodingBufferSize;
|
|
17753
|
+
constructor(readable, maxDecodingBufferSize) {
|
|
17686
17754
|
this._readable = readable;
|
|
17755
|
+
this._maxDecodingBufferSize = maxDecodingBufferSize;
|
|
17687
17756
|
}
|
|
17688
17757
|
read() {
|
|
17689
17758
|
const entries = [];
|
|
@@ -17715,7 +17784,13 @@ class ZipReader {
|
|
|
17715
17784
|
IOHelper.readInt32LE(readable); // crc-32
|
|
17716
17785
|
IOHelper.readInt32LE(readable); // compressed size
|
|
17717
17786
|
const uncompressedSize = IOHelper.readInt32LE(readable);
|
|
17787
|
+
if (uncompressedSize > this._maxDecodingBufferSize) {
|
|
17788
|
+
throw new OverflowError(`Zip contains files exceeding the configured maxDecodingBufferSize`);
|
|
17789
|
+
}
|
|
17718
17790
|
const fileNameLength = IOHelper.readInt16LE(readable);
|
|
17791
|
+
if (fileNameLength > this._maxDecodingBufferSize) {
|
|
17792
|
+
throw new OverflowError(`Zip contains file names exceeding the configured maxDecodingBufferSize`);
|
|
17793
|
+
}
|
|
17719
17794
|
const extraFieldLength = IOHelper.readInt16LE(readable);
|
|
17720
17795
|
const fname = IOHelper.toString(IOHelper.readByteArray(readable, fileNameLength), 'utf-8');
|
|
17721
17796
|
readable.skip(extraFieldLength);
|
|
@@ -17728,6 +17803,9 @@ class ZipReader {
|
|
|
17728
17803
|
while (true) {
|
|
17729
17804
|
const bytes = z.readBytes(buffer, 0, buffer.length);
|
|
17730
17805
|
target.write(buffer, 0, bytes);
|
|
17806
|
+
if (target.length > this._maxDecodingBufferSize) {
|
|
17807
|
+
throw new OverflowError(`Zip entry "${fname}" contains data exceeding the configured maxDecodingBufferSize`);
|
|
17808
|
+
}
|
|
17731
17809
|
if (bytes < buffer.length) {
|
|
17732
17810
|
break;
|
|
17733
17811
|
}
|
|
@@ -19676,7 +19754,7 @@ class CapellaImporter extends ScoreImporter {
|
|
|
19676
19754
|
}
|
|
19677
19755
|
readScore() {
|
|
19678
19756
|
Logger.debug(this.name, 'Loading ZIP entries');
|
|
19679
|
-
const fileSystem = new ZipReader(this.data);
|
|
19757
|
+
const fileSystem = new ZipReader(this.data, this.settings.importer.maxDecodingBufferSize);
|
|
19680
19758
|
let entries;
|
|
19681
19759
|
let xml = null;
|
|
19682
19760
|
entries = fileSystem.read();
|
|
@@ -19806,7 +19884,7 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
19806
19884
|
this._initialTempo = Automation.buildTempoAutomation(false, 0, 0, 0);
|
|
19807
19885
|
if (this._versionNumber >= 500) {
|
|
19808
19886
|
this.readPageSetup();
|
|
19809
|
-
this._initialTempo.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
19887
|
+
this._initialTempo.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19810
19888
|
}
|
|
19811
19889
|
// tempo stuff
|
|
19812
19890
|
this._initialTempo.value = IOHelper.readInt32LE(this.data);
|
|
@@ -19845,7 +19923,9 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
19845
19923
|
}
|
|
19846
19924
|
// contents
|
|
19847
19925
|
this._barCount = IOHelper.readInt32LE(this.data);
|
|
19926
|
+
this._ensureLoopBoundary(this._barCount, Gp3To5Importer._maxBarCount, 'bar count');
|
|
19848
19927
|
this._trackCount = IOHelper.readInt32LE(this.data);
|
|
19928
|
+
this._ensureLoopBoundary(this._trackCount, Gp3To5Importer._maxTrackCount, 'track count');
|
|
19849
19929
|
this.readMasterBars();
|
|
19850
19930
|
this.readTracks();
|
|
19851
19931
|
this.readBars();
|
|
@@ -19893,35 +19973,54 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
19893
19973
|
Logger.debug(this.name, `Guitar Pro version ${version} detected`);
|
|
19894
19974
|
}
|
|
19895
19975
|
readScoreInformation() {
|
|
19896
|
-
this._score.title = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19897
|
-
this._score.subTitle = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19898
|
-
this._score.artist = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19899
|
-
this._score.album = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19900
|
-
this._score.words = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19976
|
+
this._score.title = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19977
|
+
this._score.subTitle = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19978
|
+
this._score.artist = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19979
|
+
this._score.album = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19980
|
+
this._score.words = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19901
19981
|
this._score.music =
|
|
19902
19982
|
this._versionNumber >= 500
|
|
19903
|
-
? GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding)
|
|
19983
|
+
? GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize)
|
|
19904
19984
|
: this._score.words;
|
|
19905
|
-
this._score.copyright = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19906
|
-
this._score.tab = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19907
|
-
this._score.instructions = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
19985
|
+
this._score.copyright = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19986
|
+
this._score.tab = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19987
|
+
this._score.instructions = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19908
19988
|
const noticeLines = IOHelper.readInt32LE(this.data);
|
|
19989
|
+
this._ensureLoopBoundary(noticeLines, Gp3To5Importer._maxNoticeLines, 'notice line count');
|
|
19909
19990
|
let notice = '';
|
|
19910
19991
|
for (let i = 0; i < noticeLines; i++) {
|
|
19911
19992
|
if (i > 0) {
|
|
19912
19993
|
notice += '\r\n';
|
|
19913
19994
|
}
|
|
19914
|
-
notice += GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding)?.toString();
|
|
19995
|
+
notice += GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize)?.toString();
|
|
19915
19996
|
}
|
|
19916
19997
|
this._score.notices = notice;
|
|
19917
19998
|
}
|
|
19999
|
+
// very generous thresholds for values which control loop boundaries
|
|
20000
|
+
// prevents DoS or resource exhaustion for corrupt files or files with malicious intent
|
|
20001
|
+
// not configurable, as realistically GP3-5 files will not exceed these values,
|
|
20002
|
+
// I don't hink anyone is that verbose in the small GP5 box where you can add notices
|
|
20003
|
+
static _maxNoticeLines = 1000;
|
|
20004
|
+
// I haven't encountered such a long song in the wild. beyond 1000 bars something is clearly off
|
|
20005
|
+
static _maxBarCount = 1000;
|
|
20006
|
+
// I think GP5 itself limits already to ~10. 100 tracks is just unrealistic, proof me wrong
|
|
20007
|
+
static _maxTrackCount = 100;
|
|
20008
|
+
// nobody reallistically writes that many beats in one bar either.
|
|
20009
|
+
static _maxBeatCount = 100;
|
|
20010
|
+
// I think GP5 already limits this to way less, very generous to allow 4 times more than likely the UI supports
|
|
20011
|
+
static _maxBendPointCount = BendPoint.MaxPosition * 4;
|
|
20012
|
+
_ensureLoopBoundary(value, maximumValue, label) {
|
|
20013
|
+
if (value > maximumValue) {
|
|
20014
|
+
throw new OverflowError(`'${label}' with value ${value} has exceeded the internal safety threshold of ${maximumValue}`);
|
|
20015
|
+
}
|
|
20016
|
+
}
|
|
19918
20017
|
readLyrics() {
|
|
19919
20018
|
this._lyrics = [];
|
|
19920
20019
|
this._lyricsTrack = IOHelper.readInt32LE(this.data) - 1;
|
|
19921
20020
|
for (let i = 0; i < 5; i++) {
|
|
19922
20021
|
const lyrics = new Lyrics();
|
|
19923
20022
|
lyrics.startBar = IOHelper.readInt32LE(this.data) - 1;
|
|
19924
|
-
lyrics.text = GpBinaryHelpers.gpReadStringInt(this.data, this.settings.importer.encoding);
|
|
20023
|
+
lyrics.text = GpBinaryHelpers.gpReadStringInt(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19925
20024
|
this._lyrics.push(lyrics);
|
|
19926
20025
|
}
|
|
19927
20026
|
}
|
|
@@ -19938,41 +20037,41 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
19938
20037
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Title).isVisible =
|
|
19939
20038
|
(flags & (0x01 << 0)) !== 0;
|
|
19940
20039
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Title).template =
|
|
19941
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20040
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19942
20041
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.SubTitle).isVisible =
|
|
19943
20042
|
(flags & (0x01 << 1)) !== 0;
|
|
19944
20043
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.SubTitle).template =
|
|
19945
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20044
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19946
20045
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Artist).isVisible =
|
|
19947
20046
|
(flags & (0x01 << 2)) !== 0;
|
|
19948
20047
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Artist).template =
|
|
19949
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20048
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19950
20049
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Album).isVisible =
|
|
19951
20050
|
(flags & (0x01 << 3)) !== 0;
|
|
19952
20051
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Album).template =
|
|
19953
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20052
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19954
20053
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Words).isVisible =
|
|
19955
20054
|
(flags & (0x01 << 4)) !== 0;
|
|
19956
20055
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Words).template =
|
|
19957
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20056
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19958
20057
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Music).isVisible =
|
|
19959
20058
|
(flags & (0x01 << 5)) !== 0;
|
|
19960
20059
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Music).template =
|
|
19961
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20060
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19962
20061
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.WordsAndMusic).isVisible =
|
|
19963
20062
|
(flags & (0x01 << 6)) !== 0;
|
|
19964
20063
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.WordsAndMusic).template =
|
|
19965
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20064
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19966
20065
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Copyright).isVisible =
|
|
19967
20066
|
(flags & (0x01 << 7)) !== 0;
|
|
19968
20067
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Copyright).template =
|
|
19969
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20068
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19970
20069
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.CopyrightSecondLine).isVisible =
|
|
19971
20070
|
(flags & (0x01 << 7)) !== 0;
|
|
19972
20071
|
ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.CopyrightSecondLine).template =
|
|
19973
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20072
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19974
20073
|
// page number format
|
|
19975
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20074
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
19976
20075
|
}
|
|
19977
20076
|
readPlaybackInfos() {
|
|
19978
20077
|
this._playbackInfos = [];
|
|
@@ -20053,7 +20152,7 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20053
20152
|
// marker
|
|
20054
20153
|
if ((flags & 0x20) !== 0) {
|
|
20055
20154
|
const section = new Section();
|
|
20056
|
-
section.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20155
|
+
section.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20057
20156
|
section.marker = '';
|
|
20058
20157
|
GpBinaryHelpers.gpReadColor(this.data, false);
|
|
20059
20158
|
newMasterBar.section = section;
|
|
@@ -20220,9 +20319,9 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20220
20319
|
// 1 byte PRE
|
|
20221
20320
|
this.data.skip(4);
|
|
20222
20321
|
// RSE: effect name
|
|
20223
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20322
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20224
20323
|
// RSE: effect category
|
|
20225
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20324
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20226
20325
|
}
|
|
20227
20326
|
}
|
|
20228
20327
|
else {
|
|
@@ -20279,6 +20378,7 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20279
20378
|
}
|
|
20280
20379
|
const newVoice = new Voice$1();
|
|
20281
20380
|
bar.addVoice(newVoice);
|
|
20381
|
+
this._ensureLoopBoundary(beatCount, Gp3To5Importer._maxBeatCount, 'beat count');
|
|
20282
20382
|
for (let i = 0; i < beatCount; i++) {
|
|
20283
20383
|
this.readBeat(track, bar, newVoice);
|
|
20284
20384
|
}
|
|
@@ -20357,7 +20457,7 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20357
20457
|
}
|
|
20358
20458
|
const beatTextAsLyrics = this.settings.importer.beatTextAsLyrics && track.index !== this._lyricsTrack; // detect if not lyrics track
|
|
20359
20459
|
if ((flags & 0x04) !== 0) {
|
|
20360
|
-
const text = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding);
|
|
20460
|
+
const text = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20361
20461
|
if (beatTextAsLyrics) {
|
|
20362
20462
|
const lyrics = new Lyrics();
|
|
20363
20463
|
lyrics.text = text.trim();
|
|
@@ -20532,7 +20632,7 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20532
20632
|
}
|
|
20533
20633
|
else {
|
|
20534
20634
|
const strings = this._versionNumber >= 406 ? 7 : 6;
|
|
20535
|
-
chord.name = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20635
|
+
chord.name = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20536
20636
|
chord.firstFret = IOHelper.readInt32LE(this.data);
|
|
20537
20637
|
if (chord.firstFret > 0) {
|
|
20538
20638
|
for (let i = 0; i < strings; i++) {
|
|
@@ -20643,6 +20743,7 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20643
20743
|
this.data.readByte(); // type
|
|
20644
20744
|
IOHelper.readInt32LE(this.data); // value
|
|
20645
20745
|
const pointCount = IOHelper.readInt32LE(this.data);
|
|
20746
|
+
this._ensureLoopBoundary(pointCount, Gp3To5Importer._maxBendPointCount, 'tremolo bar point count');
|
|
20646
20747
|
if (pointCount > 0) {
|
|
20647
20748
|
for (let i = 0; i < pointCount; i++) {
|
|
20648
20749
|
const point = new BendPoint(0, 0);
|
|
@@ -20702,7 +20803,7 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20702
20803
|
const phaser = IOHelper.readSInt8(this.data);
|
|
20703
20804
|
const tremolo = IOHelper.readSInt8(this.data);
|
|
20704
20805
|
if (this._versionNumber >= 500) {
|
|
20705
|
-
tableChange.tempoName = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20806
|
+
tableChange.tempoName = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20706
20807
|
}
|
|
20707
20808
|
tableChange.tempo = IOHelper.readInt32LE(this.data);
|
|
20708
20809
|
// durations (in number of beats)
|
|
@@ -20746,8 +20847,8 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20746
20847
|
}
|
|
20747
20848
|
// unknown
|
|
20748
20849
|
if (this._versionNumber >= 510) {
|
|
20749
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20750
|
-
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding);
|
|
20850
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20851
|
+
GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
|
|
20751
20852
|
}
|
|
20752
20853
|
if (tableChange.volume >= 0) {
|
|
20753
20854
|
const volumeAutomation = new Automation();
|
|
@@ -20911,6 +21012,7 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20911
21012
|
this.data.readByte(); // type
|
|
20912
21013
|
IOHelper.readInt32LE(this.data); // value
|
|
20913
21014
|
const pointCount = IOHelper.readInt32LE(this.data);
|
|
21015
|
+
this._ensureLoopBoundary(pointCount, Gp3To5Importer._maxBendPointCount, 'note bend point count');
|
|
20914
21016
|
if (pointCount > 0) {
|
|
20915
21017
|
for (let i = 0; i < pointCount; i++) {
|
|
20916
21018
|
const point = new BendPoint(0, 0);
|
|
@@ -21099,25 +21201,28 @@ class GpBinaryHelpers {
|
|
|
21099
21201
|
* Skips an integer (4byte) and reads a string using
|
|
21100
21202
|
* a bytesize
|
|
21101
21203
|
*/
|
|
21102
|
-
static gpReadStringIntUnused(data, encoding) {
|
|
21204
|
+
static gpReadStringIntUnused(data, encoding, maxDecodingBufferSize) {
|
|
21103
21205
|
data.skip(4);
|
|
21104
|
-
return GpBinaryHelpers.gpReadString(data, data.readByte(), encoding);
|
|
21206
|
+
return GpBinaryHelpers.gpReadString(data, data.readByte(), encoding, maxDecodingBufferSize);
|
|
21105
21207
|
}
|
|
21106
21208
|
/**
|
|
21107
21209
|
* Reads an integer as size, and then the string itself
|
|
21108
21210
|
*/
|
|
21109
|
-
static gpReadStringInt(data, encoding) {
|
|
21110
|
-
return GpBinaryHelpers.gpReadString(data, IOHelper.readInt32LE(data), encoding);
|
|
21211
|
+
static gpReadStringInt(data, encoding, maxDecodingBufferSize) {
|
|
21212
|
+
return GpBinaryHelpers.gpReadString(data, IOHelper.readInt32LE(data), encoding, maxDecodingBufferSize);
|
|
21111
21213
|
}
|
|
21112
21214
|
/**
|
|
21113
21215
|
* Reads an integer as size, skips a byte and reads the string itself
|
|
21114
21216
|
*/
|
|
21115
|
-
static gpReadStringIntByte(data, encoding) {
|
|
21217
|
+
static gpReadStringIntByte(data, encoding, maxDecodingBufferSize) {
|
|
21116
21218
|
const length = IOHelper.readInt32LE(data) - 1;
|
|
21117
21219
|
data.readByte();
|
|
21118
|
-
return GpBinaryHelpers.gpReadString(data, length, encoding);
|
|
21220
|
+
return GpBinaryHelpers.gpReadString(data, length, encoding, maxDecodingBufferSize);
|
|
21119
21221
|
}
|
|
21120
|
-
static gpReadString(data, length, encoding) {
|
|
21222
|
+
static gpReadString(data, length, encoding, maxDecodingBufferSize) {
|
|
21223
|
+
if (length > maxDecodingBufferSize) {
|
|
21224
|
+
throw new OverflowError(`Detected string exceeding maxDecodingBufferSize at offset ${data.position}`);
|
|
21225
|
+
}
|
|
21121
21226
|
const b = new Uint8Array(length);
|
|
21122
21227
|
data.read(b, 0, b.length);
|
|
21123
21228
|
return IOHelper.toString(b, encoding);
|
|
@@ -21251,17 +21356,17 @@ var DataType;
|
|
|
21251
21356
|
class BinaryStylesheet {
|
|
21252
21357
|
_types = new Map();
|
|
21253
21358
|
raw = new Map();
|
|
21254
|
-
constructor(data) {
|
|
21359
|
+
constructor(data, maxDecodingBufferSize = 0) {
|
|
21255
21360
|
if (data) {
|
|
21256
|
-
this._read(data);
|
|
21361
|
+
this._read(data, maxDecodingBufferSize);
|
|
21257
21362
|
}
|
|
21258
21363
|
}
|
|
21259
|
-
_read(data) {
|
|
21364
|
+
_read(data, maxDecodingBufferSize) {
|
|
21260
21365
|
// BinaryStylesheet apears to be big-endien
|
|
21261
21366
|
const readable = ByteBuffer.fromBuffer(data);
|
|
21262
21367
|
const entryCount = IOHelper.readInt32BE(readable);
|
|
21263
21368
|
for (let i = 0; i < entryCount; i++) {
|
|
21264
|
-
const key = GpBinaryHelpers.gpReadString(readable, readable.readByte(), 'utf-8');
|
|
21369
|
+
const key = GpBinaryHelpers.gpReadString(readable, readable.readByte(), 'utf-8', maxDecodingBufferSize);
|
|
21265
21370
|
const type = readable.readByte();
|
|
21266
21371
|
this._types.set(key, type);
|
|
21267
21372
|
switch (type) {
|
|
@@ -21278,7 +21383,7 @@ class BinaryStylesheet {
|
|
|
21278
21383
|
this.addValue(key, fvalue);
|
|
21279
21384
|
break;
|
|
21280
21385
|
case DataType.String:
|
|
21281
|
-
const s = GpBinaryHelpers.gpReadString(readable, IOHelper.readInt16BE(readable), 'utf-8');
|
|
21386
|
+
const s = GpBinaryHelpers.gpReadString(readable, IOHelper.readInt16BE(readable), 'utf-8', maxDecodingBufferSize);
|
|
21282
21387
|
this.addValue(key, s);
|
|
21283
21388
|
break;
|
|
21284
21389
|
case DataType.Point:
|
|
@@ -24655,7 +24760,7 @@ class Gp7To8Importer extends ScoreImporter {
|
|
|
24655
24760
|
// at first we need to load the binary file system
|
|
24656
24761
|
// from the GPX container
|
|
24657
24762
|
Logger.debug(this.name, 'Loading ZIP entries');
|
|
24658
|
-
const fileSystem = new ZipReader(this.data);
|
|
24763
|
+
const fileSystem = new ZipReader(this.data, this.settings.importer.maxDecodingBufferSize);
|
|
24659
24764
|
let entries;
|
|
24660
24765
|
try {
|
|
24661
24766
|
entries = fileSystem.read();
|
|
@@ -24704,7 +24809,7 @@ class Gp7To8Importer extends ScoreImporter {
|
|
|
24704
24809
|
const score = gpifParser.score;
|
|
24705
24810
|
if (binaryStylesheetData) {
|
|
24706
24811
|
Logger.debug(this.name, 'Start Parsing BinaryStylesheet');
|
|
24707
|
-
const stylesheet = new BinaryStylesheet(binaryStylesheetData);
|
|
24812
|
+
const stylesheet = new BinaryStylesheet(binaryStylesheetData, this.settings.importer.maxDecodingBufferSize);
|
|
24708
24813
|
stylesheet.apply(score);
|
|
24709
24814
|
Logger.debug(this.name, 'BinaryStylesheet parsed');
|
|
24710
24815
|
}
|
|
@@ -24725,15 +24830,6 @@ class Gp7To8Importer extends ScoreImporter {
|
|
|
24725
24830
|
}
|
|
24726
24831
|
}
|
|
24727
24832
|
|
|
24728
|
-
/**
|
|
24729
|
-
* @internal
|
|
24730
|
-
*/
|
|
24731
|
-
class EndOfReaderError extends AlphaTabError {
|
|
24732
|
-
constructor() {
|
|
24733
|
-
super(AlphaTabErrorType.Format, 'Unexpected end of data within reader');
|
|
24734
|
-
}
|
|
24735
|
-
}
|
|
24736
|
-
|
|
24737
24833
|
/**
|
|
24738
24834
|
* This utility public class allows bitwise reading of a stream
|
|
24739
24835
|
* @internal
|
|
@@ -25079,7 +25175,7 @@ class GpxImporter extends ScoreImporter {
|
|
|
25079
25175
|
const score = gpifParser.score;
|
|
25080
25176
|
if (binaryStylesheetData) {
|
|
25081
25177
|
Logger.debug(this.name, 'Start Parsing BinaryStylesheet');
|
|
25082
|
-
const binaryStylesheet = new BinaryStylesheet(binaryStylesheetData);
|
|
25178
|
+
const binaryStylesheet = new BinaryStylesheet(binaryStylesheetData, this.settings.importer.maxDecodingBufferSize);
|
|
25083
25179
|
binaryStylesheet.apply(score);
|
|
25084
25180
|
Logger.debug(this.name, 'BinaryStylesheet parsed');
|
|
25085
25181
|
}
|
|
@@ -25456,7 +25552,7 @@ class MusicXmlImporter extends ScoreImporter {
|
|
|
25456
25552
|
return this._score;
|
|
25457
25553
|
}
|
|
25458
25554
|
_extractMusicXml() {
|
|
25459
|
-
const zip = new ZipReader(this.data);
|
|
25555
|
+
const zip = new ZipReader(this.data, this.settings.importer.maxDecodingBufferSize);
|
|
25460
25556
|
let entries;
|
|
25461
25557
|
try {
|
|
25462
25558
|
entries = zip.read();
|
|
@@ -32821,6 +32917,17 @@ class ImporterSettings {
|
|
|
32821
32917
|
* 
|
|
32822
32918
|
*/
|
|
32823
32919
|
beatTextAsLyrics = false;
|
|
32920
|
+
/**
|
|
32921
|
+
* This setting controls the escape hatch for handling potentially malicous or corrupt
|
|
32922
|
+
* input files. At selected spots in the codebase, we use this buffer size as maximum
|
|
32923
|
+
* allowed sizes. e.g. during unzipping or decoding strings.
|
|
32924
|
+
* This prevents resource exhaustion, especially when alphaTab is used on server side.
|
|
32925
|
+
* Increase this buffer size if you need to handle very big files.
|
|
32926
|
+
* @defaultValue `128000000`
|
|
32927
|
+
* @category Core
|
|
32928
|
+
* @since 1.9.0
|
|
32929
|
+
*/
|
|
32930
|
+
maxDecodingBufferSize = 128000000;
|
|
32824
32931
|
}
|
|
32825
32932
|
|
|
32826
32933
|
/**
|
|
@@ -34146,6 +34253,7 @@ class ImporterSettingsSerializer {
|
|
|
34146
34253
|
o.set("encoding", obj.encoding);
|
|
34147
34254
|
o.set("mergepartgroupsinmusicxml", obj.mergePartGroupsInMusicXml);
|
|
34148
34255
|
o.set("beattextaslyrics", obj.beatTextAsLyrics);
|
|
34256
|
+
o.set("maxdecodingbuffersize", obj.maxDecodingBufferSize);
|
|
34149
34257
|
return o;
|
|
34150
34258
|
}
|
|
34151
34259
|
static setProperty(obj, property, v) {
|
|
@@ -34159,6 +34267,9 @@ class ImporterSettingsSerializer {
|
|
|
34159
34267
|
case "beattextaslyrics":
|
|
34160
34268
|
obj.beatTextAsLyrics = v;
|
|
34161
34269
|
return true;
|
|
34270
|
+
case "maxdecodingbuffersize":
|
|
34271
|
+
obj.maxDecodingBufferSize = v;
|
|
34272
|
+
return true;
|
|
34162
34273
|
}
|
|
34163
34274
|
return false;
|
|
34164
34275
|
}
|
|
@@ -34682,12 +34793,12 @@ class ScoreLoader {
|
|
|
34682
34793
|
const importers = Environment.buildImporters();
|
|
34683
34794
|
Logger.debug('ScoreLoader', `Loading score from ${data.length} bytes using ${importers.length} importers`);
|
|
34684
34795
|
let score = null;
|
|
34685
|
-
const
|
|
34796
|
+
const readable = new ThrowingReadable(ByteBuffer.fromBuffer(data));
|
|
34686
34797
|
for (const importer of importers) {
|
|
34687
|
-
|
|
34798
|
+
readable.reset();
|
|
34688
34799
|
try {
|
|
34689
34800
|
Logger.debug('ScoreLoader', `Importing using importer ${importer.name}`);
|
|
34690
|
-
importer.init(
|
|
34801
|
+
importer.init(readable, settings);
|
|
34691
34802
|
score = importer.readScore();
|
|
34692
34803
|
Logger.debug('ScoreLoader', `Score imported using ${importer.name}`);
|
|
34693
34804
|
break;
|
package/dist/alphaTab.d.ts
CHANGED
|
@@ -7272,6 +7272,14 @@ declare class ElementStyle<TSubElements extends number> {
|
|
|
7272
7272
|
colors: Map<TSubElements, Color | null>;
|
|
7273
7273
|
}
|
|
7274
7274
|
|
|
7275
|
+
/**
|
|
7276
|
+
* Thrown whenever we hit the end of input data unexpectedly.
|
|
7277
|
+
* @public
|
|
7278
|
+
*/
|
|
7279
|
+
declare class EndOfReaderError extends AlphaTabError {
|
|
7280
|
+
constructor();
|
|
7281
|
+
}
|
|
7282
|
+
|
|
7275
7283
|
/**
|
|
7276
7284
|
* Represents the end of the track indicating that no more events for this track follow.
|
|
7277
7285
|
* @public
|
|
@@ -9645,6 +9653,17 @@ export declare class ImporterSettings {
|
|
|
9645
9653
|
* 
|
|
9646
9654
|
*/
|
|
9647
9655
|
beatTextAsLyrics: boolean;
|
|
9656
|
+
/**
|
|
9657
|
+
* This setting controls the escape hatch for handling potentially malicous or corrupt
|
|
9658
|
+
* input files. At selected spots in the codebase, we use this buffer size as maximum
|
|
9659
|
+
* allowed sizes. e.g. during unzipping or decoding strings.
|
|
9660
|
+
* This prevents resource exhaustion, especially when alphaTab is used on server side.
|
|
9661
|
+
* Increase this buffer size if you need to handle very big files.
|
|
9662
|
+
* @defaultValue `128000000`
|
|
9663
|
+
* @category Core
|
|
9664
|
+
* @since 1.9.0
|
|
9665
|
+
*/
|
|
9666
|
+
maxDecodingBufferSize: number;
|
|
9648
9667
|
}
|
|
9649
9668
|
|
|
9650
9669
|
/**
|
|
@@ -9711,6 +9730,17 @@ declare interface ImporterSettingsJson {
|
|
|
9711
9730
|
* 
|
|
9712
9731
|
*/
|
|
9713
9732
|
beatTextAsLyrics?: boolean;
|
|
9733
|
+
/**
|
|
9734
|
+
* This setting controls the escape hatch for handling potentially malicous or corrupt
|
|
9735
|
+
* input files. At selected spots in the codebase, we use this buffer size as maximum
|
|
9736
|
+
* allowed sizes. e.g. during unzipping or decoding strings.
|
|
9737
|
+
* This prevents resource exhaustion, especially when alphaTab is used on server side.
|
|
9738
|
+
* Increase this buffer size if you need to handle very big files.
|
|
9739
|
+
* @defaultValue `128000000`
|
|
9740
|
+
* @category Core
|
|
9741
|
+
* @since 1.9.0
|
|
9742
|
+
*/
|
|
9743
|
+
maxDecodingBufferSize?: number;
|
|
9714
9744
|
}
|
|
9715
9745
|
|
|
9716
9746
|
/**
|
|
@@ -9775,6 +9805,8 @@ export declare namespace io {
|
|
|
9775
9805
|
export {
|
|
9776
9806
|
IWriteable,
|
|
9777
9807
|
IReadable,
|
|
9808
|
+
OverflowError,
|
|
9809
|
+
EndOfReaderError,
|
|
9778
9810
|
ByteBuffer,
|
|
9779
9811
|
IOHelper
|
|
9780
9812
|
}
|
|
@@ -13346,6 +13378,14 @@ declare enum Ottavia {
|
|
|
13346
13378
|
_15mb = 4
|
|
13347
13379
|
}
|
|
13348
13380
|
|
|
13381
|
+
/**
|
|
13382
|
+
* Thrown whenever an overflow in data or buffer sizes is detected.
|
|
13383
|
+
* @public
|
|
13384
|
+
*/
|
|
13385
|
+
declare class OverflowError extends AlphaTabError {
|
|
13386
|
+
constructor(message: string);
|
|
13387
|
+
}
|
|
13388
|
+
|
|
13349
13389
|
/**
|
|
13350
13390
|
* Lists all types of pick strokes.
|
|
13351
13391
|
* @public
|