mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-27 18:38:14 -05:00
Update #44 - WebAssembly GC support, fix more WebRTC bugs
This commit is contained in:
@ -198,6 +198,11 @@ public class DesktopClientConfigAdapter implements IClientConfigAdapter {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnforceVSync() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClientConfigAdapterHooks getHooks() {
|
||||
return hooks;
|
||||
|
@ -10,6 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.IEaglerFilesystem;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.lwjgl.DesktopClientConfigAdapter;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.IWASMCrashCallback;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.lwjgl.MemoryConnection;
|
||||
|
||||
/**
|
||||
@ -91,4 +92,8 @@ public class ServerPlatformSingleplayer {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void setCrashCallbackWASM(IWASMCrashCallback callback) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -99,4 +99,9 @@ public class EagUtils {
|
||||
return EaglercraftUUID.nameUUIDFromBytes(("EaglercraftXClientOld:" + name).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static void sleepPrint(String string) {
|
||||
System.out.println(string);
|
||||
PlatformRuntime.sleep(500);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ public class EaglercraftVersion {
|
||||
/// Customize these to fit your fork:
|
||||
|
||||
public static final String projectForkName = "EaglercraftX";
|
||||
public static final String projectForkVersion = "u43";
|
||||
public static final String projectForkVersion = "u44";
|
||||
public static final String projectForkVendor = "lax1dude";
|
||||
|
||||
public static final String projectForkURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8";
|
||||
@ -20,20 +20,20 @@ public class EaglercraftVersion {
|
||||
public static final String projectOriginName = "EaglercraftX";
|
||||
public static final String projectOriginAuthor = "lax1dude";
|
||||
public static final String projectOriginRevision = "1.8";
|
||||
public static final String projectOriginVersion = "u43";
|
||||
public static final String projectOriginVersion = "u44";
|
||||
|
||||
public static final String projectOriginURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; // rest in peace
|
||||
|
||||
// EPK Version Identifier
|
||||
|
||||
public static final String EPKVersionIdentifier = "u43"; // Set to null to disable EPK version check
|
||||
public static final String EPKVersionIdentifier = "u44"; // Set to null to disable EPK version check
|
||||
|
||||
// Updating configuration
|
||||
|
||||
public static final boolean enableUpdateService = true;
|
||||
|
||||
public static final String updateBundlePackageName = "net.lax1dude.eaglercraft.v1_8.client";
|
||||
public static final int updateBundlePackageVersionInt = 43;
|
||||
public static final int updateBundlePackageVersionInt = 44;
|
||||
|
||||
public static final String updateLatestLocalStorageKey = "latestUpdate_" + updateBundlePackageName;
|
||||
|
||||
@ -52,8 +52,8 @@ public class EaglercraftVersion {
|
||||
// Miscellaneous variables:
|
||||
|
||||
public static final String mainMenuStringA = "Minecraft 1.8.8";
|
||||
public static final String mainMenuStringB = projectOriginName + " " +
|
||||
projectOriginRevision + "-" + projectOriginVersion + " ultimate";
|
||||
public static final String mainMenuStringB = projectOriginName + " " + projectOriginRevision + "-"
|
||||
+ projectOriginVersion + " ultimate [" + EagRuntime.getPlatformType().getName() + "]";
|
||||
public static final String mainMenuStringC = "";
|
||||
public static final String mainMenuStringD = "Resources Copyright Mojang AB";
|
||||
|
||||
@ -63,6 +63,9 @@ public class EaglercraftVersion {
|
||||
public static final String mainMenuStringG = "Collector's Edition";
|
||||
public static final String mainMenuStringH = "PBR Shaders";
|
||||
|
||||
public static final String screenRecordingFilePrefix = projectOriginName + " "
|
||||
+ projectOriginRevision + "-" + projectOriginVersion;
|
||||
|
||||
public static final long demoWorldSeed = (long) "North Carolina".hashCode();
|
||||
|
||||
public static final boolean mainMenuEnableGithubButton = false;
|
||||
|
@ -16,7 +16,7 @@ package net.lax1dude.eaglercraft.v1_8.internal;
|
||||
*
|
||||
*/
|
||||
public enum EnumPlatformType {
|
||||
DESKTOP("Desktop"), JAVASCRIPT("JavaScript"), WASM_GC("ASM");
|
||||
DESKTOP("Desktop"), JAVASCRIPT("JS"), WASM_GC("WASM-GC");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
@ -98,6 +98,8 @@ public interface IClientConfigAdapter {
|
||||
|
||||
boolean isRamdiskMode();
|
||||
|
||||
boolean isEnforceVSync();
|
||||
|
||||
IClientConfigAdapterHooks getHooks();
|
||||
|
||||
}
|
||||
|
@ -39,11 +39,9 @@ class VFileOutputStream extends EaglerOutputStream {
|
||||
try {
|
||||
copyBuffer.put(buf, 0, count);
|
||||
copyBuffer.flip();
|
||||
try {
|
||||
vfsFile.getFS().eaglerWrite(vfsFile.path, copyBuffer);
|
||||
}catch(Throwable t) {
|
||||
throw new IOException("Could not write stream contents to file!", t);
|
||||
}
|
||||
vfsFile.getFS().eaglerWrite(vfsFile.path, copyBuffer);
|
||||
}catch(Throwable t) {
|
||||
throw new IOException("Could not write stream contents to file!", t);
|
||||
}finally {
|
||||
PlatformRuntime.freeByteBuffer(copyBuffer);
|
||||
}
|
||||
|
@ -159,6 +159,10 @@ public class Logger {
|
||||
}
|
||||
|
||||
private void logExcp(final Level level, String h, Throwable msg) {
|
||||
if(msg == null) {
|
||||
log(level, "{}: <null>", h);
|
||||
return;
|
||||
}
|
||||
log(level, "{}: {}", h, msg.toString());
|
||||
EagRuntime.getStackTrace(msg, (e) -> log(level, " at {}", e));
|
||||
PlatformRuntime.printJSExceptionIfBrowser(msg);
|
||||
|
@ -189,11 +189,15 @@ public class EaglerFontRenderer extends FontRenderer {
|
||||
if(hasStrike) {
|
||||
GlStateManager.color(0.25f, 0.25f, 0.25f, 1.0f);
|
||||
GlStateManager.translate(1.0f, 1.0f, 0.0f);
|
||||
GlStateManager.disableTexture2D();
|
||||
tessellator.draw();
|
||||
GlStateManager.translate(-1.0f, -1.0f, 0.0f);
|
||||
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
GlStateManager.enableTexture2D();
|
||||
InstancedFontRenderer.render(8, 8, texScale, texScale, true);
|
||||
GlStateManager.disableTexture2D();
|
||||
EaglercraftGPU.renderAgain();
|
||||
GlStateManager.enableTexture2D();
|
||||
}else {
|
||||
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
InstancedFontRenderer.render(8, 8, texScale, texScale, true);
|
||||
@ -201,7 +205,9 @@ public class EaglerFontRenderer extends FontRenderer {
|
||||
}else {
|
||||
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
if(hasStrike) {
|
||||
GlStateManager.disableTexture2D();
|
||||
tessellator.draw();
|
||||
GlStateManager.enableTexture2D();
|
||||
}
|
||||
InstancedFontRenderer.render(8, 8, texScale, texScale, false);
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.minecraft;
|
||||
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class GuiScreenVSyncReEnabled extends GuiScreen {
|
||||
|
||||
private GuiScreen cont;
|
||||
|
||||
public GuiScreenVSyncReEnabled(GuiScreen cont) {
|
||||
this.cont = cont;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 136, I18n.format("options.vsyncReEnabled.continue")));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("options.vsyncReEnabled.title"), this.width / 2, 70, 11184810);
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("options.vsyncReEnabled.0"), this.width / 2, 95, 16777215);
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("options.vsyncReEnabled.1"), this.width / 2, 120, 16777215);
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("options.vsyncReEnabled.2"), this.width / 2, 145, 16777215);
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("options.vsyncReEnabled.3"), this.width / 2, 160, 16777215);
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
this.mc.displayGuiScreen(cont);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -65,7 +65,7 @@ class ServerQueryImpl implements IServerQuery {
|
||||
IWebSocketFrame frame = lst.get(i);
|
||||
alive = true;
|
||||
if(pingTimer == -1) {
|
||||
pingTimer = PlatformRuntime.steadyTimeMillis() - pingStart;
|
||||
pingTimer = frame.getTimestamp() - pingStart;
|
||||
if(pingTimer < 1) {
|
||||
pingTimer = 1;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.EnumPlatformType;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
@ -84,6 +85,7 @@ public class SingleplayerServerController implements ISaveFormat {
|
||||
issuesDetected.clear();
|
||||
statusState = IntegratedServerState.WORLD_WORKER_BOOTING;
|
||||
loggingState = true;
|
||||
callFailed = false;
|
||||
boolean singleThreadSupport = ClientPlatformSingleplayer.isSingleThreadModeSupported();
|
||||
if(!singleThreadSupport && forceSingleThread) {
|
||||
throw new UnsupportedOperationException("Single thread mode is not supported!");
|
||||
@ -294,10 +296,12 @@ public class SingleplayerServerController implements ISaveFormat {
|
||||
}
|
||||
}
|
||||
|
||||
boolean logWindowState = PlatformApplication.isShowingDebugConsole();
|
||||
if(loggingState != logWindowState) {
|
||||
loggingState = logWindowState;
|
||||
sendIPCPacket(new IPCPacket1BEnableLogging(logWindowState));
|
||||
if(EagRuntime.getPlatformType() == EnumPlatformType.JAVASCRIPT) {
|
||||
boolean logWindowState = PlatformApplication.isShowingDebugConsole();
|
||||
if(loggingState != logWindowState) {
|
||||
loggingState = logWindowState;
|
||||
sendIPCPacket(new IPCPacket1BEnableLogging(logWindowState));
|
||||
}
|
||||
}
|
||||
|
||||
if(ClientPlatformSingleplayer.isRunningSingleThreadMode()) {
|
||||
|
@ -41,6 +41,8 @@ class LANClientPeer {
|
||||
|
||||
protected long startTime;
|
||||
|
||||
protected String localICECandidate = null;
|
||||
|
||||
protected LANClientPeer(String clientId) {
|
||||
this.clientId = clientId;
|
||||
this.startTime = EagRuntime.steadyTimeMillis();
|
||||
@ -50,7 +52,13 @@ class LANClientPeer {
|
||||
protected void handleICECandidates(String candidates) {
|
||||
if(state == SENT_DESCRIPTION) {
|
||||
PlatformWebRTC.serverLANPeerICECandidates(clientId, candidates);
|
||||
state = RECEIVED_ICE_CANDIDATE;
|
||||
if(localICECandidate != null) {
|
||||
LANServerController.lanRelaySocket.writePacket(new RelayPacket03ICECandidate(clientId, localICECandidate));
|
||||
localICECandidate = null;
|
||||
state = SENT_ICE_CANDIDATE;
|
||||
}else {
|
||||
state = RECEIVED_ICE_CANDIDATE;
|
||||
}
|
||||
}else {
|
||||
logger.error("Relay [{}] unexpected IPacket03ICECandidate for '{}'", LANServerController.lanRelaySocket.getURI(), clientId);
|
||||
}
|
||||
@ -100,6 +108,12 @@ class LANClientPeer {
|
||||
disconnect();
|
||||
}else {
|
||||
switch(state) {
|
||||
case SENT_DESCRIPTION:{
|
||||
if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
|
||||
localICECandidate = ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates;
|
||||
continue read_loop;
|
||||
}
|
||||
}
|
||||
case RECEIVED_ICE_CANDIDATE: {
|
||||
if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
|
||||
LANServerController.lanRelaySocket.writePacket(new RelayPacket03ICECandidate(clientId, ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates));
|
||||
@ -136,7 +150,7 @@ class LANClientPeer {
|
||||
}
|
||||
}
|
||||
if(state != CLOSED) {
|
||||
logger.error("LAN client '{}' had an accident: {}", clientId, evt.getClass().getSimpleName());
|
||||
logger.error("LAN client '{}' had an accident: {} (state {})", clientId, evt.getClass().getSimpleName(), state);
|
||||
}
|
||||
disconnect();
|
||||
return;
|
||||
|
@ -82,7 +82,7 @@ public class LANServerController {
|
||||
}
|
||||
}
|
||||
EagUtils.sleep(50);
|
||||
}while(EagRuntime.steadyTimeMillis() - millis < 1000l);
|
||||
}while(EagRuntime.steadyTimeMillis() - millis < 2500l);
|
||||
logger.info("Relay [{}] relay provide ICE servers timeout", sock.getURI());
|
||||
closeLAN();
|
||||
return null;
|
||||
|
@ -8,7 +8,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.minecraft.world.ChunkCoordIntPair;
|
||||
import net.minecraft.world.MinecraftException;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
|
||||
@ -88,7 +87,7 @@ public class EaglerChunkLoader extends AnvilChunkLoader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveChunk(World var1, Chunk var2) throws IOException, MinecraftException {
|
||||
public void saveChunk(World var1, Chunk var2) throws IOException {
|
||||
NBTTagCompound chunkData = new NBTTagCompound();
|
||||
this.writeChunkToNBT(var2, var1, chunkData);
|
||||
NBTTagCompound fileData = new NBTTagCompound();
|
||||
|
@ -485,6 +485,8 @@ public class EaglerIntegratedServerWorker {
|
||||
// signal thread startup successful
|
||||
sendIPCPacket(new IPCPacketFFProcessKeepAlive(0xFF));
|
||||
|
||||
ServerPlatformSingleplayer.setCrashCallbackWASM(EaglerIntegratedServerWorker::sendIntegratedServerCrashWASMCB);
|
||||
|
||||
while(true) {
|
||||
mainLoop(false);
|
||||
ServerPlatformSingleplayer.immediateContinue();
|
||||
@ -525,4 +527,11 @@ public class EaglerIntegratedServerWorker {
|
||||
mainLoop(true);
|
||||
}
|
||||
|
||||
public static void sendIntegratedServerCrashWASMCB(String stringValue, boolean terminated) {
|
||||
sendIPCPacket(new IPCPacket15Crashed(stringValue));
|
||||
if(terminated) {
|
||||
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacketFFProcessKeepAlive.EXITED));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public interface IWASMCrashCallback {
|
||||
|
||||
void callback(String crashReport, boolean terminated);
|
||||
|
||||
}
|
@ -139,14 +139,24 @@ public class IntegratedVoiceService {
|
||||
}
|
||||
|
||||
public void handleVoiceSignalPacketTypeConnect(EntityPlayerMP sender) {
|
||||
if (voicePlayers.containsKey(sender.getUniqueID())) {
|
||||
EaglercraftUUID senderUuid = sender.getUniqueID();
|
||||
if (voicePlayers.containsKey(senderUuid)) {
|
||||
return;
|
||||
}
|
||||
boolean hasNoOtherPlayers = voicePlayers.isEmpty();
|
||||
voicePlayers.put(sender.getUniqueID(), sender);
|
||||
voicePlayers.put(senderUuid, sender);
|
||||
if (hasNoOtherPlayers) {
|
||||
return;
|
||||
}
|
||||
GameMessagePacket v3p = null;
|
||||
GameMessagePacket v4p = null;
|
||||
for(EntityPlayerMP conn : voicePlayers.values()) {
|
||||
if(conn.playerNetServerHandler.getEaglerMessageProtocol().ver <= 3) {
|
||||
conn.playerNetServerHandler.sendEaglerMessage(v3p == null ? (v3p = new SPacketVoiceSignalConnectV3EAG(senderUuid.msb, senderUuid.lsb, true, false)) : v3p);
|
||||
} else {
|
||||
conn.playerNetServerHandler.sendEaglerMessage(v4p == null ? (v4p = new SPacketVoiceSignalConnectAnnounceV4EAG(senderUuid.msb, senderUuid.lsb)) : v4p);
|
||||
}
|
||||
}
|
||||
Collection<SPacketVoiceSignalGlobalEAG.UserData> userDatas = new ArrayList<>(voicePlayers.size());
|
||||
for(EntityPlayerMP player : voicePlayers.values()) {
|
||||
EaglercraftUUID uuid = player.getUniqueID();
|
||||
|
@ -94,13 +94,16 @@ public class VoiceClientController {
|
||||
}
|
||||
|
||||
public static void handleVoiceSignalPacketTypeGlobalNew(Collection<SPacketVoiceSignalGlobalEAG.UserData> voicePlayers) {
|
||||
boolean isGlobal = voiceChannel == EnumVoiceChannelType.GLOBAL;
|
||||
uuidToNameLookup.clear();
|
||||
for (SPacketVoiceSignalGlobalEAG.UserData player : voicePlayers) {
|
||||
EaglercraftUUID uuid = new EaglercraftUUID(player.uuidMost, player.uuidLeast);
|
||||
if(player.username != null) {
|
||||
uuidToNameLookup.put(uuid, player.username);
|
||||
}
|
||||
sendPacketRequestIfNeeded(uuid);
|
||||
if (isGlobal) {
|
||||
sendPacketRequestIfNeeded(uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +141,7 @@ public class VoiceClientController {
|
||||
}
|
||||
|
||||
public static void handleVoiceSignalPacketTypeConnectAnnounce(EaglercraftUUID user) {
|
||||
if (voiceChannel != EnumVoiceChannelType.NONE) sendPacketRequest(user);
|
||||
if (voiceChannel != EnumVoiceChannelType.NONE && (voiceChannel == EnumVoiceChannelType.GLOBAL || listeningSet.contains(user))) sendPacketRequest(user);
|
||||
}
|
||||
|
||||
public static void handleVoiceSignalPacketTypeDisconnect(EaglercraftUUID user) {
|
||||
|
@ -1 +1 @@
|
||||
u43
|
||||
u44
|
@ -785,3 +785,78 @@
|
||||
* THE SOFTWARE.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Project Name: Emscripten
|
||||
Project Author: Emscripten authors
|
||||
Project URL: https://emscripten.org/
|
||||
|
||||
Used For: Compiling the WASM runtime's loader.wasm program
|
||||
|
||||
* Emscripten is available under 2 licenses, the MIT license and the
|
||||
* University of Illinois/NCSA Open Source License.
|
||||
*
|
||||
* Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Project Name: XZ Embedded
|
||||
Project Author: Lasse Collin (Larhzu)
|
||||
Project URL: https://tukaani.org/xz/embedded.html
|
||||
|
||||
Used For: Decompressing the WASM runtime
|
||||
|
||||
* Copyright (C) The XZ Embedded authors and contributors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this
|
||||
* software for any purpose with or without fee is hereby granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Project Name: XZ for Java
|
||||
Project Author: Lasse Collin (Larhzu)
|
||||
Project URL: https://tukaani.org/xz/java.html
|
||||
|
||||
Used For: Compression in the MakeWASMClientBundle command
|
||||
|
||||
* Copyright (C) The XZ for Java authors and contributors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this
|
||||
* software for any purpose with or without fee is hereby granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
Binary file not shown.
@ -1 +1 @@
|
||||
{"pluginName":"EaglercraftXBungee","pluginVersion":"1.3.3","pluginButton":"Download \"EaglerXBungee-1.3.3.jar\"","pluginFilename":"EaglerXBungee.zip"}
|
||||
{"pluginName":"EaglercraftXBungee","pluginVersion":"1.3.4","pluginButton":"Download \"EaglerXBungee-1.3.4.jar\"","pluginFilename":"EaglerXBungee.zip"}
|
@ -0,0 +1,12 @@
|
||||
.gradle
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
build
|
||||
bin
|
||||
javascript/eagruntime.js
|
||||
javascript/classes.wasm
|
||||
javascript/classes.wasm.teadbg
|
||||
javascript/assets.epk
|
||||
javascript_dist/assets.epw
|
||||
javascript_dist/EaglercraftX_1.8_*
|
@ -0,0 +1,6 @@
|
||||
@echo off
|
||||
title CompileEPWBootstrapJS
|
||||
set srcFolder=../src/wasm-gc-teavm-bootstrap/js
|
||||
echo Compiling %srcFolder%
|
||||
java -jar buildtools/closure-compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --assume_function_wrapper --emit_use_strict --isolation_mode IIFE --js "%srcFolder%/externs.js" "%srcFolder%/main.js" --js_output_file javascript_dist/bootstrap.js
|
||||
pause
|
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
srcFolder=../src/wasm-gc-teavm-bootstrap/js
|
||||
echo Compiling $srcFolder
|
||||
java -jar buildtools/closure-compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --assume_function_wrapper --emit_use_strict --isolation_mode IIFE --js $srcFolder/externs.js $srcFolder/main.js --js_output_file javascript_dist/bootstrap.js
|
@ -0,0 +1,6 @@
|
||||
@echo off
|
||||
title epkcompiler
|
||||
echo compiling, please wait...
|
||||
java -jar "../desktopRuntime/CompileEPK.jar" "../desktopRuntime/resources" "javascript/assets.epk" none
|
||||
echo finished compiling epk
|
||||
pause
|
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
java -jar "../desktopRuntime/CompileEPK.jar" "../desktopRuntime/resources" "javascript/assets.epk" none
|
@ -0,0 +1,6 @@
|
||||
@echo off
|
||||
title CompileEagRuntimeJS
|
||||
set srcFolder=../src/wasm-gc-teavm/js
|
||||
echo Compiling %srcFolder%
|
||||
java -jar buildtools/closure-compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --assume_function_wrapper --emit_use_strict --isolation_mode IIFE --js "%srcFolder%/externs.js" "%srcFolder%/eagruntime_util.js" "%srcFolder%/eagruntime_main.js" "%srcFolder%/platformApplication.js" "%srcFolder%/platformAssets.js" "%srcFolder%/platformAudio.js" "%srcFolder%/platformFilesystem.js" "%srcFolder%/platformInput.js" "%srcFolder%/platformNetworking.js" "%srcFolder%/platformOpenGL.js" "%srcFolder%/platformRuntime.js" "%srcFolder%/platformScreenRecord.js" "%srcFolder%/platformVoiceClient.js" "%srcFolder%/platformWebRTC.js" "%srcFolder%/platformWebView.js" "%srcFolder%/clientPlatformSingleplayer.js" "%srcFolder%/serverPlatformSingleplayer.js" "%srcFolder%/WASMGCBufferAllocator.js" "%srcFolder%/fix-webm-duration.js" "%srcFolder%/teavm_runtime.js" "%srcFolder%/eagruntime_entrypoint.js" --js_output_file javascript/eagruntime.js
|
||||
pause
|
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
srcFolder=../src/wasm-gc-teavm/js
|
||||
echo Compiling $srcFolder
|
||||
java -jar buildtools/closure-compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --assume_function_wrapper --emit_use_strict --isolation_mode IIFE --js $srcFolder/externs.js $srcFolder/eagruntime_util.js $srcFolder/eagruntime_main.js $srcFolder/platformApplication.js $srcFolder/platformAssets.js $srcFolder/platformAudio.js $srcFolder/platformFilesystem.js $srcFolder/platformInput.js $srcFolder/platformNetworking.js $srcFolder/platformOpenGL.js $srcFolder/platformRuntime.js $srcFolder/platformScreenRecord.js $srcFolder/platformVoiceClient.js $srcFolder/platformWebRTC.js $srcFolder/platformWebView.js $srcFolder/clientPlatformSingleplayer.js $srcFolder/serverPlatformSingleplayer.js $srcFolder/WASMGCBufferAllocator.js $srcFolder/fix-webm-duration.js $srcFolder/teavm_runtime.js $srcFolder/eagruntime_entrypoint.js --js_output_file javascript/eagruntime.js
|
@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
title CompileLoaderWASM
|
||||
mkdir "bin/emscripten"
|
||||
call emcc -c -O3 ../src/wasm-gc-teavm-loader/c/main.c -o bin/emscripten/main.o
|
||||
call emcc -c -O3 ../src/wasm-gc-teavm-loader/c/xz/xz_crc32.c -o bin/emscripten/xz_crc32.o
|
||||
call emcc -c -O3 ../src/wasm-gc-teavm-loader/c/xz/xz_dec_lzma2.c -o bin/emscripten/xz_dec_lzma2.o
|
||||
call emcc -c -O3 ../src/wasm-gc-teavm-loader/c/xz/xz_dec_stream.c -o bin/emscripten/xz_dec_stream.o
|
||||
call emcc -O3 -sMALLOC=dlmalloc -sALLOW_MEMORY_GROWTH -sINITIAL_HEAP=16777216 -sMAXIMUM_MEMORY=67108864 --pre-js ../src/wasm-gc-teavm-loader/js/pre.js --js-library ../src/wasm-gc-teavm-loader/js/library.js bin/emscripten/main.o bin/emscripten/xz_crc32.o bin/emscripten/xz_dec_lzma2.o bin/emscripten/xz_dec_stream.o -o javascript/loader.js
|
||||
pause
|
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
mkdir -p bin/emscripten
|
||||
emcc -c -O3 ../src/wasm-gc-teavm-loader/c/main.c -o bin/emscripten/main.o
|
||||
emcc -c -O3 ../src/wasm-gc-teavm-loader/c/xz/xz_crc32.c -o bin/emscripten/xz_crc32.o
|
||||
emcc -c -O3 ../src/wasm-gc-teavm-loader/c/xz/xz_dec_lzma2.c -o bin/emscripten/xz_dec_lzma2.o
|
||||
emcc -c -O3 ../src/wasm-gc-teavm-loader/c/xz/xz_dec_stream.c -o bin/emscripten/xz_dec_stream.o
|
||||
emcc -O3 -sMALLOC=dlmalloc -sALLOW_MEMORY_GROWTH -sINITIAL_HEAP=16777216 -sMAXIMUM_MEMORY=67108864 --pre-js ../src/wasm-gc-teavm-loader/js/pre.js --js-library ../src/wasm-gc-teavm-loader/js/library.js bin/emscripten/main.o bin/emscripten/xz_crc32.o bin/emscripten/xz_dec_lzma2.o bin/emscripten/xz_dec_stream.o -o javascript/loader.js
|
@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
title gradlew generateWasmGC
|
||||
call gradlew generateWasmGC
|
||||
pause
|
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
chmod +x gradlew
|
||||
./gradlew generateWasmGC
|
@ -0,0 +1,5 @@
|
||||
@echo off
|
||||
title MakeWASMClientBundle
|
||||
cd javascript
|
||||
java -cp "../buildtools/org.tukanni.xz.jar;../buildtools/MakeWASMClientBundle.jar;../../desktopRuntime/CompileEPK.jar;../../desktopRuntime/MakeOfflineDownload.jar" net.lax1dude.eaglercraft.v1_8.buildtools.workspace.MakeWASMClientBundle epw_src.txt epw_meta.txt "../javascript_dist"
|
||||
pause
|
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
cd javascript
|
||||
java -cp "../buildtools/org.tukanni.xz.jar:../buildtools/MakeWASMClientBundle.jar:../../desktopRuntime/CompileEPK.jar:../../desktopRuntime/MakeOfflineDownload.jar" net.lax1dude.eaglercraft.v1_8.buildtools.workspace.MakeWASMClientBundle epw_src.txt epw_meta.txt "../javascript_dist"
|
25
sources/setup/workspace_template/wasm_gc_teavm/README.md
Normal file
25
sources/setup/workspace_template/wasm_gc_teavm/README.md
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
# EaglercraftX WASM-GC Runtime
|
||||
|
||||
This folder contains the Gradle project for compiling the EaglercraftX 1.8 client to WASM. This requires a special fork of TeaVM that has been modified for Eaglercraft. The `settings.gradle` and `build.gradle` are set up to download the binaries automatically but if you would like to build the TeaVM fork yourself you can use the TeaVM fork's `publishToMavenLocal` gradle task and replace the URL maven repository declarations in the gradle build scripts with `mavenLocal()` instead.
|
||||
|
||||
**TeaVM Fork: [https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm/tree/eagler-r1](https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm/tree/eagler-r1)**
|
||||
|
||||
### To compile the client:
|
||||
1. Run `CompileEPK` to compile the assets.epk file
|
||||
2. Run `CompileWASM` to compile the classes.wasm file
|
||||
3. Run `CompileEagRuntimeJS` to compile the eagruntime.js file
|
||||
4. Run `MakeWASMClientBundle` to bundle the client into an EPW file
|
||||
|
||||
The final assets.epw and offline download will be in the "javascript_dist" folder
|
||||
|
||||
### Optional Steps:
|
||||
- Run `CompileBootstrapJS` to recompile bootstrap.js in the javascript_dist folder
|
||||
- Run `CompileLoaderWASM`to recompile loader.js and loader.wasm (requires emscripten)
|
||||
|
||||
### Potential issues when porting:
|
||||
- Disabling VSync causes bad input lag, the solution to this problem is to remove the vsync option and force people to play with vsync enabled, like all other browser games
|
||||
- TeaVM's WASM GC backend is still under development and will sometimes generate broken code with nested try/finally statements in a try/catch block, or other strange runtime glitches
|
||||
- Fewer reflection features are supported in WASM GC than the JavaScript backend (so far)
|
||||
- Do not use `@Async` or any sort of callback (like addEventListener) in your Java, you must implement async functions in JavaScript in `../src/wasm-gc-teavm/js`, using JSPI to suspend/resume the thread for promises, or by pushing events into a queue that you can poll from your Java for event handlers.
|
||||
- Functions imported via the `@Import` will not catch exceptions, if you want proper exception handling you must call the imported function through the JSO
|
56
sources/setup/workspace_template/wasm_gc_teavm/build.gradle
Normal file
56
sources/setup/workspace_template/wasm_gc_teavm/build.gradle
Normal file
@ -0,0 +1,56 @@
|
||||
import org.teavm.gradle.api.OptimizationLevel
|
||||
import org.teavm.gradle.api.WasmDebugInfoLocation
|
||||
import org.teavm.gradle.api.WasmDebugInfoLevel
|
||||
|
||||
plugins {
|
||||
id "java"
|
||||
id "eclipse"
|
||||
id "org.teavm" version "0.11.0-EAGLER-R1"
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs(
|
||||
"../src/main/java",
|
||||
"../src/game/java",
|
||||
"../src/protocol-game/java",
|
||||
"../src/protocol-relay/java",
|
||||
"../src/wasm-gc-teavm/java"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://eaglercraft-teavm-fork.github.io/maven/")
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly "org.teavm:teavm-core:0.11.0-EAGLER-R1" // workaround for a few hacks
|
||||
}
|
||||
|
||||
def folder = "javascript"
|
||||
def name = "classes.wasm"
|
||||
|
||||
teavm.wasmGC {
|
||||
targetFileName = "../" + name
|
||||
optimization = OptimizationLevel.AGGRESSIVE
|
||||
outOfProcess = false
|
||||
fastGlobalAnalysis = false
|
||||
processMemory = 512
|
||||
mainClass = "net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.MainClass"
|
||||
outputDir = file(folder)
|
||||
properties = [ "java.util.TimeZone.autodetect": "true" ]
|
||||
debugInformation = true
|
||||
debugInfoLocation = WasmDebugInfoLocation.EXTERNAL;
|
||||
debugInfoLevel = WasmDebugInfoLevel.DEOBFUSCATION;
|
||||
directMallocSupport = true
|
||||
minHeapSize = 32
|
||||
maxHeapSize = 384
|
||||
disassembly = true
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
org.gradle.jvmargs=-Xmx4G -Xms4G
|
BIN
sources/setup/workspace_template/wasm_gc_teavm/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
sources/setup/workspace_template/wasm_gc_teavm/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
sources/setup/workspace_template/wasm_gc_teavm/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
sources/setup/workspace_template/wasm_gc_teavm/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
249
sources/setup/workspace_template/wasm_gc_teavm/gradlew
vendored
Normal file
249
sources/setup/workspace_template/wasm_gc_teavm/gradlew
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
92
sources/setup/workspace_template/wasm_gc_teavm/gradlew.bat
vendored
Normal file
92
sources/setup/workspace_template/wasm_gc_teavm/gradlew.bat
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
@ -0,0 +1,104 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
This file is from ${date}, there is no official eagler download link anymore, check the websites and discords of your favorite eagler servers for new versions
|
||||
|
||||
Be aware that some server owners are lazy and do not update their client regularly
|
||||
|
||||
This is the WASM-GC version of EaglercraftX and may not be compatible with outdated browsers
|
||||
|
||||
-->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<html style="width:100%;height:100%;background-color:black;">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
|
||||
<meta name="description" content="EaglercraftX 1.8 WASM-GC Offline" />
|
||||
<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
|
||||
<title>EaglercraftX 1.8 WASM-GC</title>
|
||||
<meta property="og:locale" content="en-US" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="EaglercraftX 1.8 WASM-GC Offline" />
|
||||
<meta property="og:description" content="this file is not a website, whoever uploaded it to this URL is a dumbass" />
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
var relayId = Math.floor(Math.random() * 3);
|
||||
|
||||
// %%%%%%%%% launch options %%%%%%%%%%%%
|
||||
|
||||
window.eaglercraftXOpts = {
|
||||
container: "game_frame",
|
||||
worldsDB: "worlds",
|
||||
relays: [
|
||||
{ addr: "wss://relay.deev.is/", comment: "lax1dude relay #1", primary: relayId == 0 },
|
||||
{ addr: "wss://relay.lax1dude.net/", comment: "lax1dude relay #2", primary: relayId == 1 },
|
||||
{ addr: "wss://relay.shhnowisnottheti.me/", comment: "ayunami relay #1", primary: relayId == 2 }
|
||||
]
|
||||
};
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
if(typeof window !== "undefined") window.eaglercraftXClientScriptElement = document.currentScript;
|
||||
${classes_js}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
(function(){
|
||||
window.eaglercraftXOpts.assetsURI = ${assets_epk};
|
||||
|
||||
var launchInterval = -1;
|
||||
var launchCounter = 1;
|
||||
var launchCountdownNumberElement = null;
|
||||
var launchCountdownProgressElement = null;
|
||||
var launchSkipCountdown = false;
|
||||
|
||||
var launchTick = function() {
|
||||
launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
|
||||
launchCountdownProgressElement.style.width = "" + launchCounter + "%";
|
||||
if(++launchCounter > 100 || launchSkipCountdown) {
|
||||
clearInterval(launchInterval);
|
||||
setTimeout(function() { document.body.removeChild(document.getElementById("launch_countdown_screen")); document.body.style.backgroundColor = "black"; main(); }, 50);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
|
||||
launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
|
||||
launchInterval = setInterval(launchTick, 50);
|
||||
document.getElementById("skipCountdown").addEventListener("click", function() {
|
||||
launchSkipCountdown = true;
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<link type="image/png" rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAR/SURBVEhLtZXZK3ZRFMYPcqXc+gv413DHxVuGIpIhkciQWaRccCNjSCkligwXSOZ5nmfv9zvn2e8+58V753sudmuvvdZ61l5r7XOc8H+GS/D19aUNkPz5+aktQH5/f//4+LBKZKuRkpUtQjCUYG5gD2T38vLy/PwsDfL9/f3Dw8PT05M0b29vnKLhCKCBT4L4gvBLBIei4//4+Hh1dUVEQutUuLu7E83FxQUGnKLBWKfQaA3S+AREVxaEOD8/Pzk50XpzcyMDcH19zdZG3N3d3dzc3Nvb01aX5pQUpQGGQJxcQpfNysoKhUIdHR1o1tbWbInYAgxIPDMzMy8vLzc3FxqOdMoRqwJK8G8ALUYIhHMiSEhIwI6CyIb0qQzC4eGhsXCc1tZWnZIEKzdQJQSXgKxfX18RCM3Z5eWlcfVAxKOjo+Pj49PTU88lTOk2NjbMsePc3t6SAfcgFdszOyMuAdeBg0CQi2lhYUHOeOLDCisN8FzcPFZXV3t7ezHY3t5GQ+6it+2xMASsKhEEWKsmRLRBBUpPvpJ/TpFKFBwKYAiITmicsbYhdHfJAltqhUCVsCQhwslmeXmZxiBQT9c0Ar9E2O3v72sYSE0N1yQArkKy0kBMXLqlZqIZHR3t6empqqqSDcBdhXEJSJ/bUc3q6uq+vj629GB9fR1WsLW1NTs7u7S0RN2locMjIyOEm5ubQ7+4uJienk4/+vv77Y1hwhLBEKhwWHitdVFfX9/Y2Gg2HuLi4owUAysrK8yCG97rh0+ApP5Q2ZycHFlPTExUVFRIBvn5+WhKSkp2dnaMKhptbW2426GgQ/rwuAQCZ1hwFayLiork9hMFBQV1dXVmE0BLS4vqw3QFB8kn4IAxoGPkYpxi4FeDmpqas7Mz4pClAgqGwD48rjY2NmacYqC0tJQ1KSlJWyE5OZkpUKkBAxZVIntAoZh04+Q48fHxPNGBgYHExMT29naj9cBodnZ2mo3jlJWVMeW2OGQck4B1amqqoaGhqamJjx2lGxwcpL0mUgR8fJhsWqJtSkoKU2SbHHUDpkhPBujd8xuQG6PJRM/Pz09PT7O1NNnZ2Tw3fgZkXVhYKCUlUhBATP+hCVyKZGky17RV0g04laayslJ6hlVeFHB4eFhKaogGd0LxtmTgE+hbhKDnPjMzgw8E3qGL2tpaBWpubjYqj2BoaEj6rq4uNATRZ0ZwCbiL6gXEzINk5vCBQJ9rMD4+rkA8QNK036uDg4Py8vLu7m680KjIBNR3zBDoWQM1g98snyB+VSoRW8C/UwR81/SvhgNj9JOTkwwVERUdRBEI0BAdLRVERkhLS8vIyEDQlrsTPTU1lVFhKxARvZgUlFLbegCf4BvIsbi4mIg4E5EogIHhiKCMtU0WUFiVy06j5fAJIDdSBDQw+PegDfBRcbOPwH4F9LuFWIIQdQNKwWqzIE0aoFUaBsw+SQuFw0uNtC9A+F4i3QNrbg3IDn+SAsHh+wYiEpeyBEMLv/cAO6KzAijxxB+Y4wisBhssJUhjEbPJf4Nw+B+JXqLW3bw+wQAAAABJRU5ErkJggg==" />
|
||||
</head>
|
||||
<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:white;" id="game_frame">
|
||||
<div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
|
||||
<div style="margin:auto;text-align:center;">
|
||||
<h1>This file is from <span style="color:#AA0000;">${date}</span></h1>
|
||||
<h2>Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
|
||||
<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div>
|
||||
<p style="margin-top:30px;"><button id="skipCountdown" autofocus>Skip Countdown</button></p></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
File diff suppressed because one or more lines are too long
@ -0,0 +1,8 @@
|
||||
client-version-integer=44
|
||||
client-package-name=net.lax1dude.eaglercraft.v1_8.client
|
||||
client-origin-name=EaglercraftX
|
||||
client-origin-version=u44
|
||||
client-origin-vendor=lax1dude
|
||||
client-fork-name=EaglercraftX
|
||||
client-fork-version=u44
|
||||
client-fork-vendor=lax1dude
|
@ -0,0 +1,22 @@
|
||||
loader-js-file=loader.js
|
||||
loader-wasm-file=loader.wasm
|
||||
eagruntime-js-file=eagruntime.js
|
||||
classes-wasm-file=classes.wasm
|
||||
classes-deobf-teadbg-file=classes.wasm.teadbg
|
||||
classes-deobf-wasm-file=classes.wasm-deobfuscator.wasm
|
||||
assets-epk-0-file=assets.epk
|
||||
assets-epk-0-path=/
|
||||
assets-epk-1-file=../../javascript/lang
|
||||
assets-epk-1-path=/assets/minecraft/lang/
|
||||
splash-logo-image-file=splash.png
|
||||
splash-logo-image-mime=image/png
|
||||
press-any-key-image-file=pressAnyKey.png
|
||||
press-any-key-image-mime=image/png
|
||||
crash-logo-image-file=crashLogo.png
|
||||
crash-logo-image-mime=image/png
|
||||
favicon-image-file=favicon.png
|
||||
favicon-image-mime=image/png
|
||||
jspi-unavailable-file=enableJSPIScreen.html
|
||||
offline-download-template=OfflineDownloadTemplate.txt
|
||||
offline-download-script=../javascript_dist/bootstrap.js
|
||||
offline-download-name=EaglercraftX_1.8_WASM-GC_Offline_Download.html
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="width:100%;height:100%;background-color:black;">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
|
||||
<meta name="description" content="EaglercraftX 1.8 WASM-GC test directory HTML page" />
|
||||
<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
|
||||
<title>EaglercraftX 1.8 WASM-GC</title>
|
||||
<meta property="og:locale" content="en-US" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="EaglercraftX 1.8 WASM-GC" />
|
||||
<meta property="og:description" content="test directory HTML page" />
|
||||
<link type="image/png" rel="shortcut icon" href="favicon.png" />
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
window.addEventListener("load", async function() {
|
||||
if(window.location.href.indexOf("file:") === 0) {
|
||||
alert("HTTP please, do not open this file locally, run a local HTTP server and load it via HTTP");
|
||||
}else if(typeof WebAssembly.Suspending === "undefined") {
|
||||
alert("JSPI is not enabled, please enable it in chrome://flags");
|
||||
}else {
|
||||
const splash = document.createElement("div");
|
||||
splash.style.width = "100%";
|
||||
splash.style.height = "100%";
|
||||
splash.style.imageRendering = "pixelated";
|
||||
splash.style.background = "center / contain no-repeat url(splash.png), 0px 0px / 1000000% 1000000% no-repeat url(splash.png) white";
|
||||
document.body.appendChild(splash);
|
||||
|
||||
console.log("Downloading assets.epk...");
|
||||
var assetsEPK;
|
||||
try {
|
||||
assetsEPK = new Uint8Array(await fetch("assets.epk").then(resp => resp.arrayBuffer()));
|
||||
}catch(ex) {
|
||||
alert("Could not download assets.epk!");
|
||||
console.error("Could not download assets.epk!");
|
||||
console.error(ex);
|
||||
return;
|
||||
}
|
||||
console.log("Downloaded " + assetsEPK.length + " byte file");
|
||||
|
||||
const relayId = Math.floor(Math.random() * 3);
|
||||
const eaglercraftXOpts = {
|
||||
demoMode: false,
|
||||
localesURI: "lang/",
|
||||
worldsDB: "worlds",
|
||||
servers: [
|
||||
{ addr: "ws://localhost:8081/", name: "Local test server" }
|
||||
],
|
||||
relays: [
|
||||
{ addr: "wss://relay.deev.is/", comment: "lax1dude relay #1", primary: relayId === 0 },
|
||||
{ addr: "wss://relay.lax1dude.net/", comment: "lax1dude relay #2", primary: relayId === 1 },
|
||||
{ addr: "wss://relay.shhnowisnottheti.me/", comment: "ayunami relay #1", primary: relayId === 2 }
|
||||
]
|
||||
};
|
||||
|
||||
window.__eaglercraftXLoaderContext = {
|
||||
getEaglercraftXOpts: function() {
|
||||
return eaglercraftXOpts;
|
||||
},
|
||||
getEagRuntimeJSURL: function() {
|
||||
return "eagruntime.js";
|
||||
},
|
||||
getClassesWASMURL: function() {
|
||||
return "classes.wasm";
|
||||
},
|
||||
getClassesDeobfWASMURL: function() {
|
||||
return "classes.wasm-deobfuscator.wasm";
|
||||
},
|
||||
getClassesTEADBGURL: function() {
|
||||
return "classes.wasm.teadbg";
|
||||
},
|
||||
getEPKFiles: function() {
|
||||
return [{
|
||||
name: "assets.epk",
|
||||
path: "",
|
||||
data: assetsEPK
|
||||
}];
|
||||
},
|
||||
getRootElement: function() {
|
||||
return document.body;
|
||||
},
|
||||
getMainArgs: function() {
|
||||
return [];
|
||||
},
|
||||
getImageURL: function(idx) {
|
||||
switch(idx) {
|
||||
case 0:
|
||||
return "splash.png";
|
||||
case 1:
|
||||
return "pressAnyKey.png";
|
||||
case 2:
|
||||
return "crashLogo.png";
|
||||
case 3:
|
||||
return "favicon.png";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
runMain: function(fn) {
|
||||
setTimeout(fn, 10);
|
||||
}
|
||||
};
|
||||
|
||||
var q = window.location.search;
|
||||
if((typeof q === "string") && q[0] === "?" && (typeof URLSearchParams !== "undefined")) {
|
||||
q = new URLSearchParams(q);
|
||||
var s = q.get("server");
|
||||
if(s) eaglercraftXOpts.joinServer = s;
|
||||
}
|
||||
|
||||
const scriptElement = document.createElement("script");
|
||||
scriptElement.type = "text/javascript";
|
||||
scriptElement.src = "eagruntime.js";
|
||||
document.head.appendChild(scriptElement);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:black;" id="game_frame"></body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
12
sources/setup/workspace_template/wasm_gc_teavm/javascript_dist/bootstrap.js
vendored
Normal file
12
sources/setup/workspace_template/wasm_gc_teavm/javascript_dist/bootstrap.js
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
(function(){'use strict';function g(a){console.log("LoaderBootstrap: [INFO] "+a)}function n(a){console.error("LoaderBootstrap: [ERROR] "+a)}var q=null;
|
||||
function r(){const a=[];for(var c=0;64>c;++c)a["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(c)]=c;a[45]=62;a[95]=63;return function(b,d){var e=b.length-d;if(0<e%4)throw Error("Invalid string. Length must be a multiple of 4");var f=b.indexOf("=",d);f=-1===f?e:f-d;e=[f,f===e?0:4-f%4];var l=e[0];e=e[1];f=new Uint8Array(3*(l+e)/4-e);var h=0;l=(0<e?l-4:l)+d;var k;for(k=d;k<l;k+=4)d=a[b.charCodeAt(k)]<<18|a[b.charCodeAt(k+1)]<<12|a[b.charCodeAt(k+2)]<<6|a[b.charCodeAt(k+
|
||||
3)],f[h++]=d>>16&255,f[h++]=d>>8&255,f[h++]=d&255;2===e?(d=a[b.charCodeAt(k)]<<2|a[b.charCodeAt(k+1)]>>4,f[h++]=d&255):1===e&&(d=a[b.charCodeAt(k)]<<10|a[b.charCodeAt(k+1)]<<4|a[b.charCodeAt(k+2)]>>2,f[h++]=d>>8&255,f[h++]=d&255);return f.buffer}}function u(){return new Promise(function(a){setTimeout(a,20)})}function v(a){return new Promise(function(c){fetch(a,{cache:"force-cache"}).then(function(b){return b.arrayBuffer()}).then(c).catch(function(b){n("Failed to fetch URL! "+b);c(null)})})}
|
||||
function w(a){return a.startsWith("data:application/octet-stream;base64,")?new Promise(function(c){v(a).then(function(b){if(b)c(b);else{console.log("LoaderBootstrap: [WARN] Failed to decode base64 via fetch, doing it the slow way instead...");try{q||=r();var d=q(a,37);c(d)}catch(e){n("Failed to decode base64! "+e),c(null)}}})}):v(a)}
|
||||
function x(a,c){const b=document.createElement("h2");b.style.color="#AA0000";b.style.padding="25px";b.style.fontFamily="sans-serif";b.style.marginBlock="0px";b.appendChild(document.createTextNode(c));a.appendChild(b);c=document.createElement("h4");c.style.color="#AA0000";c.style.padding="25px";c.style.fontFamily="sans-serif";c.style.marginBlock="0px";c.appendChild(document.createTextNode("Try again later"));a.style.backgroundColor="white";a.appendChild(c)}
|
||||
window.main=async function(){if("undefined"===typeof window.eaglercraftXOpts)n("window.eaglercraftXOpts is not defined!"),alert("window.eaglercraftXOpts is not defined!");else{var a=window.eaglercraftXOpts.container;if("string"!==typeof a)n("window.eaglercraftXOpts.container is not a string!"),alert("window.eaglercraftXOpts.container is not a string!");else{var c=window.eaglercraftXOpts.assetsURI;if("string"!==typeof c)if("object"===typeof c&&"object"===typeof c[0]&&"string"===typeof c[0].url)c=c[0].url;
|
||||
else{n("window.eaglercraftXOpts.assetsURI is not a string!");alert("window.eaglercraftXOpts.assetsURI is not a string!");return}var b=document.getElementById(a);if(b){for(;a=b.lastChild;)b.removeChild(a);a=document.createElement("div");a.style.width="100%";a.style.height="100%";a.style.setProperty("image-rendering","pixelated");a.style.background='center / contain no-repeat url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAAAAAB3tzPbAAAACXBIWXMAAC4jAAAuIwF4pT92AAAG+UlEQVR42u2cy23jOhRATwbTwGwFvAJoF6BFGjColcGkASNuIPA6C68DN+BADZiCVxLSQBYqIGYBAbSdEvwWkvUzZWfymwlwCQwQUZeXPOT9URPkYs/3bj8QAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAH4x9vPvzFpAhAzM98UILmqfjDf1YT0N/cBk+71v+wDSczHmDeJ6TqO+SIfyD7IvC9g33Yc7dP6CQDxB+q62Hc2xnyJD2Sf5vuzL3Hi5MM0WbCN51u/Y/30ryEGmDVHlhwsY9Y7xlq0CuzVc4lh2n7NkGsnQ1nB7IefmrY/araJcbrq6Ryk9YqW4l3J/dHww1jdej+8kte042EW0Nba1hyWdl+9irq/FNXaD6BbQoexuvf+tQC2vX1+AFvP0kxiuyidfWwEbOtQtK0n0r6xbYCKsLcM21+pLZX3u4984Kq2xlnWDimllRudAXEpkGSHfqMzsmxfWnLWNf9aQznW4wMZWOMJxvGs/Ff5X+yPcD0g3dqZesdsI2f7Z2/73W2JSok9Gqu7P1q/I2qtj0qn/ZkTaCPWO2a0VyjrxY7sNUG1LxRlaE90MpDpGVeAxpaGobN2XPWH0aQVE1stfXPAj0+XzUmcob3aTRdVZ2+tRv+gMNBDaTkZ4k6uhtYPaK7iUkUcx9lgij92gZ6aXmxoDeK8D1hPfm18oBvTfPGwXoVG+4VfXcwl8dEOtCJS7De9M0VTqTA2p081O3kJ+uk5cU/RVN8C262Ms9HMlLHSmhNFTcc9u1uQRX4jMhqyNIk1GRk69a6hb0IDZ3pITnbfNqFuJWE9gbYrfmSqen/SiKy27G0VS20VWc+UEn59/YDPkc+0EunrAXQ/JXucYL+3VutyAqvP5wFvtEoyQPsMJMpKc3v7/Su9ALLkhAJDPCObGTDmonfNHAij3sg5866fmTHGnFt/crroh6vEv/Rq6vhEoP7hWWb2ylSQZP5zOVrDqVxSZnm/xL6OFnZwF3/4JoyGjyXu1X3n0rEFyE5Jzc5KEDfT7s2ZYs52s5e1HU88hB17nKTqAroXWPpXiHbN7R3Q8fVDbjzU6vb8hUbX67FWN8Xo4U5SIWjbukr1knY9XrcwS30aOuTatqa0vkA6cI05dyPrzWBbj7ZZrPUT2O7pdpKFtp4rph0E0AxtfN0u9kNVg25d4BPiDF0+R83dPol7/l4m4yQmQzdX+ISewqTnc8ngp94yaCan4vT+Hc228q8/T35+e8+XueSqCaPmEz9ofdbX6eSqE5iN/m4A8Qd9w/1bAEl2fPmafT3Axdv/ytlFeXUwTZyyf+NA3hWDGPrm+HXtHSdQ7nrz7fvv+MPFe/9Q3nAS+iYA3zcKCYAACIAACIAACIAACIAACIAACIAA1C2Komh++r9cogdv90M0+GoZAVHkSiGSaFmOmJdTRdESiKJ5Je4eovnSldoGNJ44gTBNbx+XH7tDYxwOniAPgEdygGWxTm/jBCAHV0u7xa90PV64IW0uOWdCapK7t600vfF2j4Ad5FCE4IopCSWMSg0Q4NgRVNKrwIBJ1ZDGxXO/5+fxhDvFQ87EsHxZMy9Sli/raMbjf9eqMpiciQG3yYOJwW1eQoBoesNBzG3yKdvqNwie1HMwiXFcwo7L7aMBtlSrC7c79RzyUm5w0f66Gk1vcJs8vFYHxUvy/u8leJz4N8t8vX5ccl04Chz5BOLR+mVVWXX5lsU4ncSOFevL7WFsJbYiPfQpcvJwhNsBxKiwcHDPNnoojzp8Jh8PnusiSMcLd1B8R5i+Igq5/BZKU3IEO8cIpoqw6L5NR8kjuOIaFR6GlmKdvmnhuFTsfqNwTBnzBOo+ZFua+jh3jAZtnksMu/b850wIfh1sVwVPhMEzKK9lz/+7Hi3Kx8CjOajVbVCEz3kIT1wyYnsD6s5t8tUaGLFpTfC7q2TH4rjzHMCoGgqTOJiMFi/TY5kduOJWHfzdtzdFrS4PYBwzhi0LAKcAdTcvKhur+VWQ3/TWcq/+LJG5VahUsILHUDGiGCmKy26cOrxlxwZUsMHlvVDW7lMQwghGOGZpmt6zcdFD47EhtQVyWySQRHUgVDzhmkeClyZFlGmiA5BH0WpyB+twPp/cgQpQBH0Lqt6qaTwfs+OW6Kl/RrdET/WqQi5BgWLDqNxmdV/Mo1X1QX5Ms0Pq/jmaP7d2/b6IVq3HW+a9qT7v6/TDNv2+tVA0hzz8klroc07AbXKmN98YQMppARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAD2//A2iD9ZsgY5XpAAAAAElFTkSuQmCC") white';
|
||||
b.appendChild(a);c.startsWith("data:")?(g('Downloading EPW file "<data: '+c.length+' chars>"...'),c=await w(c)):(g('Downloading EPW file "'+c+'"...'),c=await v(c));var d=!1;c?384>c.byteLength&&(n("The EPW file is too short"),d=!0):d=!0;if(d)b.removeChild(a),x(b,"Failed to download EPW file!"),n("Failed to download EPW file!");else{var e=new DataView(c);if(608649541!==e.getUint32(0,!0)||1297301847!==e.getUint32(4,!0))n("The file is not an EPW file"),d=!0;var f=c.byteLength;e.getUint32(8,!0)!==f&&(n("The EPW file is the wrong length"),
|
||||
d=!0);if(d)b.removeChild(a),x(b,"EPW file is invalid!"),n("EPW file is invalid!");else{var l=new TextDecoder("utf-8"),h=e.getUint32(100,!0),k=e.getUint32(104,!0),m=e.getUint32(108,!0),p=e.getUint32(112,!0);if(0>h||h+k>f||0>m||m+p>f)n("The EPW file contains an invalid offset (component: splash)"),d=!0;if(d)b.removeChild(a),x(b,"EPW file is invalid!"),n("EPW file is invalid!");else{h=new Uint8Array(c,h,k);m=new Uint8Array(c,m,p);l=URL.createObjectURL(new Blob([h],{type:l.decode(m)}));g("Loaded splash img: "+
|
||||
l);a.style.background='center / contain no-repeat url("'+l+'"), 0px 0px / 1000000% 1000000% no-repeat url("'+l+'") white';await u();p=e.getUint32(164,!0);h=e.getUint32(168,!0);m=e.getUint32(180,!0);e=e.getUint32(184,!0);if(0>p||p+h>f||0>m||m+e>f)n("The EPW file contains an invalid offset (component: loader)"),d=!0;if(d)b.removeChild(a),x(b,"EPW file is invalid!"),n("EPW file is invalid!");else{a=new Uint8Array(c,p,h);a=URL.createObjectURL(new Blob([a],{type:"text/javascript;charset=utf-8"}));g("Loaded loader.js: "+
|
||||
l);d=new Uint8Array(c,m,e);d=URL.createObjectURL(new Blob([d],{type:"application/wasm"}));g("Loaded loader.wasm: "+d);f={};for(const [t,y]of Object.entries(window.eaglercraftXOpts))"container"!==t&&"assetsURI"!==t&&(f[t]=y);window.__eaglercraftXLoaderContextPre={rootElement:b,eaglercraftXOpts:f,theEPWFileBuffer:c,loaderWASMURL:d,splashURL:l};g("Appending loader.js to document...");b=document.createElement("script");b.type="text/javascript";b.src=a;document.head.appendChild(b)}}}}}else b='window.eaglercraftXOpts.container "'+
|
||||
a+'" is not a known element id!',n(b),alert(b)}}};}).call(this);
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="width:100%;height:100%;background-color:black;">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
|
||||
<meta name="description" content="Play minecraft 1.8 in your browser" />
|
||||
<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
|
||||
<title>EaglercraftX 1.8 WASM-GC</title>
|
||||
<meta property="og:locale" content="en-US" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="EaglercraftX 1.8 WASM-GC" />
|
||||
<meta property="og:description" content="Play minecraft 1.8 in your browser" />
|
||||
<meta property="og:image" content="favicon.png" />
|
||||
<link type="image/png" rel="shortcut icon" href="favicon.png" />
|
||||
<script type="text/javascript" src="bootstrap.js"></script>
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
window.addEventListener("load", function() {
|
||||
if(window.location.href.indexOf("file:") === 0) {
|
||||
alert("HTTP please, do not open this file locally, run a local HTTP server and load it via HTTP");
|
||||
}else {
|
||||
|
||||
// %%%%%%%%% launch options %%%%%%%%%%%%
|
||||
|
||||
var relayId = Math.floor(Math.random() * 3);
|
||||
window.eaglercraftXOpts = {
|
||||
demoMode: false,
|
||||
container: "game_frame",
|
||||
assetsURI: "assets.epw",
|
||||
worldsDB: "worlds",
|
||||
servers: [
|
||||
/* example: { addr: "ws://localhost:8081/", name: "Local test server" } */
|
||||
],
|
||||
relays: [
|
||||
{ addr: "wss://relay.deev.is/", comment: "lax1dude relay #1", primary: relayId == 0 },
|
||||
{ addr: "wss://relay.lax1dude.net/", comment: "lax1dude relay #2", primary: relayId == 1 },
|
||||
{ addr: "wss://relay.shhnowisnottheti.me/", comment: "ayunami relay #1", primary: relayId == 2 }
|
||||
]
|
||||
};
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
var q = window.location.search;
|
||||
if((typeof q === "string") && q[0] === "?" && (typeof window.URLSearchParams !== "undefined")) {
|
||||
q = new window.URLSearchParams(q);
|
||||
var s = q.get("server");
|
||||
if(s) window.eaglercraftXOpts.joinServer = s;
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body style="margin:0px;width:100%;height:100%;overflow:hidden;background-color:black;" id="game_frame"></body>
|
||||
</html>
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
*
|
||||
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||
* in the user manual at https://docs.gradle.org/6.0/userguide/multi_project_builds.html
|
||||
*/
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://eaglercraft-teavm-fork.github.io/maven/")
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = 'eagler-workspace-wasm-gc-teavm'
|
@ -48,11 +48,13 @@ public class BootMenuEntryPoint {
|
||||
private static native void setHasAlreadyBooted();
|
||||
|
||||
public static boolean checkShouldLaunchFlag(Window win) {
|
||||
wasManuallyInvoked = false;
|
||||
int flag = BootMenuDataManager.getBootMenuFlags(win);
|
||||
if(flag == -1) {
|
||||
return IBootMenuConfigAdapter.instance.isShowBootMenuOnLaunch() && !getHasAlreadyBooted();
|
||||
}
|
||||
if((flag & 2) != 0) {
|
||||
wasManuallyInvoked = true;
|
||||
BootMenuDataManager.setBootMenuFlags(win, flag & ~2);
|
||||
setHasAlreadyBooted();
|
||||
return true;
|
||||
@ -63,6 +65,7 @@ public class BootMenuEntryPoint {
|
||||
private static boolean hasInit = false;
|
||||
private static byte[] signatureData = null;
|
||||
private static byte[] bundleData = null;
|
||||
public static boolean wasManuallyInvoked = false;
|
||||
|
||||
public static void launchMenu(Window parentWindow, HTMLElement parentElement) {
|
||||
signatureData = PlatformUpdateSvc.getClientSignatureData();
|
||||
|
@ -144,7 +144,7 @@ public class BootMenuMain {
|
||||
bootMenuFatOfflineLoader = new BootMenuFatOfflineLoader(parentWindow.getDocument().getHead());
|
||||
logger.info("Entering boot menu display state");
|
||||
eventQueue.clear();
|
||||
changeState(new MenuStateBoot(true));
|
||||
changeState(new MenuStateBoot(!BootMenuEntryPoint.wasManuallyInvoked));
|
||||
enterUpdateLoop();
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,12 @@ public class OfflineDownloadParser {
|
||||
logger.info("Detected format: EAGLERCRAFTX_1_8_OFFLINE (International)");
|
||||
return EnumOfflineParseType.EAGLERCRAFTX_1_8_OFFLINE;
|
||||
}
|
||||
if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse("]OFNI[ :partstooBredaoL")), 0, 16384)) {
|
||||
if(offlineDownloadData.indexOf(StringUtils.reverse(",46esab;maerts-tetco/noitacilppa:atad\" = IRUstessa.stpOXtfarcrelgae.wodniw")) != -1) {
|
||||
logger.info("Detected format: EAGLERCRAFTX_1_8_OFFLINE (WASM-GC)");
|
||||
return EnumOfflineParseType.EAGLERCRAFTX_1_8_OFFLINE;
|
||||
}
|
||||
}
|
||||
if(foundWithin(offlineDownloadData.indexOf(StringUtils.reverse("{ = stpOtfarcrelgae.wodniw")), 32, 2048) && foundWithin(offlineDownloadData.indexOf(StringUtils.reverse(">\"rekrow_ps\"=di \"rekrowrelgae/txet\"=epyt tpircs<")), 4194304, offlineDownloadData.length() - 1048576)) {
|
||||
logger.info("Detected format: EAGLERCRAFTX_1_5_NEW_OFFLINE");
|
||||
return EnumOfflineParseType.EAGLERCRAFT_1_5_NEW_OFFLINE;
|
||||
|
@ -1569,7 +1569,7 @@ public class PlatformInput {
|
||||
isOnMobilePressAnyKey = true;
|
||||
setupAnyKeyScreenMobile(allowBootMenu);
|
||||
if(pressAnyKeyScreenMobile() && allowBootMenu) {
|
||||
PlatformRuntime.enterBootMenu();
|
||||
PlatformRuntime.enterBootMenu(true);
|
||||
}
|
||||
}finally {
|
||||
isOnMobilePressAnyKey = false;
|
||||
|
@ -185,8 +185,7 @@ public class PlatformRuntime {
|
||||
}
|
||||
|
||||
CSSStyleDeclaration style = root.getStyle();
|
||||
style.setProperty("overflowX", "hidden");
|
||||
style.setProperty("overflowY", "hidden");
|
||||
style.setProperty("overflow", "hidden");
|
||||
|
||||
TeaVMClientConfigAdapter teavmCfg = (TeaVMClientConfigAdapter) getClientConfigAdapter();
|
||||
boolean allowBootMenu = teavmCfg.isAllowBootMenu();
|
||||
@ -241,8 +240,7 @@ public class PlatformRuntime {
|
||||
style.setProperty("position", "relative");
|
||||
style.setProperty("width", "100%");
|
||||
style.setProperty("height", "100%");
|
||||
style.setProperty("overflowX", "hidden");
|
||||
style.setProperty("overflowY", "hidden");
|
||||
style.setProperty("overflow", "hidden");
|
||||
root.appendChild(parent);
|
||||
ClientMain.configRootElement = parent; // hack
|
||||
|
||||
@ -421,7 +419,7 @@ public class PlatformRuntime {
|
||||
Collections.sort(exts);
|
||||
logger.info("Unlocked the following OpenGL ES extensions:");
|
||||
for(int i = 0, l = exts.size(); i < l; ++i) {
|
||||
logger.info(" - " + exts.get(i));
|
||||
logger.info(" - {}", exts.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,7 +441,7 @@ public class PlatformRuntime {
|
||||
|
||||
if(allowBootMenu && BootMenuEntryPoint.checkShouldLaunchFlag(win)) {
|
||||
logger.info("Boot menu enable flag is set, entering boot menu...");
|
||||
enterBootMenu();
|
||||
enterBootMenu(BootMenuEntryPoint.wasManuallyInvoked);
|
||||
}
|
||||
|
||||
byte[] finalLoadScreen = PlatformAssets.getResourceBytes("/assets/eagler/eagtek.png");
|
||||
@ -1134,7 +1132,7 @@ public class PlatformRuntime {
|
||||
if(PlatformInput.keyboardGetEventKeyState()) {
|
||||
int key = PlatformInput.keyboardGetEventKey();
|
||||
if(key == KeyboardConstants.KEY_DELETE || key == KeyboardConstants.KEY_BACK) {
|
||||
enterBootMenu();
|
||||
enterBootMenu(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1143,7 +1141,7 @@ public class PlatformRuntime {
|
||||
@JSBody(params = {}, script = "delete __isEaglerX188Running;")
|
||||
private static native void clearRunningFlag();
|
||||
|
||||
static void enterBootMenu() {
|
||||
static void enterBootMenu(boolean manual) {
|
||||
if(!getClientConfigAdapter().isAllowBootMenu()) {
|
||||
throw new IllegalStateException("Boot menu is disabled");
|
||||
}
|
||||
@ -1170,7 +1168,7 @@ public class PlatformRuntime {
|
||||
immediateContinueChannel = null;
|
||||
clearRunningFlag();
|
||||
logger.info("Firing boot menu escape signal...");
|
||||
throw new TeaVMEnterBootMenuException();
|
||||
throw new TeaVMEnterBootMenuException(manual);
|
||||
}
|
||||
|
||||
public static void postCreate() {
|
||||
|
@ -188,7 +188,7 @@ public class PlatformScreenRecord {
|
||||
TeaVMUtils.addEventListener(mediaRec, "dataavailable", new EventListener<DataAvailableEvent>() {
|
||||
@Override
|
||||
public void handleEvent(DataAvailableEvent evt) {
|
||||
final String fileName = EaglercraftVersion.mainMenuStringB + " - " + EaglerProfile.getName() + " - " + fmt.format(new Date()) + "." + params.codec.fileExt;
|
||||
final String fileName = EaglercraftVersion.screenRecordingFilePrefix + " - " + EaglerProfile.getName() + " - " + fmt.format(new Date()) + "." + params.codec.fileExt;
|
||||
if("video/webm".equals(params.codec.container)) {
|
||||
FixWebMDurationJS.getRecUrl(evt, (int) (PlatformRuntime.steadyTimeMillis() - startTime), url -> {
|
||||
PlatformApplication.downloadURLWithNameTeaVM(fileName, url, () -> TeaVMUtils.freeDataURL(url));
|
||||
|
@ -421,7 +421,7 @@ public class PlatformWebRTC {
|
||||
final Object[] evtHandler = new Object[1];
|
||||
evtHandler[0] = (EventListener<Event>) evt -> {
|
||||
if (!iceCandidates.isEmpty()) {
|
||||
Window.setTimeout(() -> ((EventListener<Event>)evtHandler[0]).handleEvent(evt), 1);
|
||||
Window.setTimeout(() -> ((EventListener<Event>)evtHandler[0]).handleEvent(evt), 10);
|
||||
return;
|
||||
}
|
||||
clientDataChannelClosed = false;
|
||||
@ -541,7 +541,7 @@ public class PlatformWebRTC {
|
||||
final Object[] evtHandler = new Object[1];
|
||||
evtHandler[0] = (EventListener<Event>) evt -> {
|
||||
if (!iceCandidates.isEmpty()) {
|
||||
Window.setTimeout(() -> ((EventListener<Event>)evtHandler[0]).handleEvent(evt), 1);
|
||||
Window.setTimeout(() -> ((EventListener<Event>)evtHandler[0]).handleEvent(evt), 10);
|
||||
return;
|
||||
}
|
||||
if (getChannel(evt) == null) return;
|
||||
|
@ -200,7 +200,6 @@ public class PlatformWebView {
|
||||
try {
|
||||
List<String> sandboxArgs = new ArrayList<>();
|
||||
sandboxArgs.add("allow-downloads");
|
||||
sandboxArgs.add("allow-same-origin");
|
||||
if(options.scriptEnabled) {
|
||||
sandboxArgs.add("allow-scripts");
|
||||
sandboxArgs.add("allow-pointer-lock");
|
||||
|
@ -202,6 +202,7 @@ public class ClientMain {
|
||||
}catch(TeaVMEnterBootMenuException ee) {
|
||||
try {
|
||||
systemOut.println("ClientMain: [INFO] launching eaglercraftx boot menu");
|
||||
BootMenuEntryPoint.wasManuallyInvoked = ee.isManual;
|
||||
BootMenuEntryPoint.launchMenu(Window.current(), configRootElement);
|
||||
}catch(Throwable t) {
|
||||
showCrashScreen("Failed to enter boot menu!", t);
|
||||
@ -550,6 +551,7 @@ public class ClientMain {
|
||||
}
|
||||
|
||||
if(el == null) {
|
||||
Window.alert("Compatibility error: " + t);
|
||||
System.err.println("Compatibility error: " + t);
|
||||
return;
|
||||
}
|
||||
@ -573,11 +575,9 @@ public class ClientMain {
|
||||
+ "<p><br /><span style=\"font-size:1.1em;border-bottom:1px dashed #AAAAAA;padding-bottom:5px;\">Things you can try:</span></p>"
|
||||
+ "<ol>"
|
||||
+ "<li><span style=\"font-weight:bold;\">Just try using Eaglercraft on a different device</span>, it isn't a bug it's common sense</li>"
|
||||
+ "<li style=\"margin-top:7px;\">If you are on a mobile device, please try a proper desktop or a laptop computer</li>"
|
||||
+ "<li style=\"margin-top:7px;\">If you are using a device with no mouse cursor, please use a device with a mouse cursor</li>"
|
||||
+ "<li style=\"margin-top:7px;\">If this screen just appeared randomly, try restarting your browser or device</li>"
|
||||
+ "<li style=\"margin-top:7px;\">If you are not using Chrome/Edge, try installing the latest Google Chrome</li>"
|
||||
+ "<li style=\"margin-top:7px;\">If your browser is out of date, please update it to the latest version</li>"
|
||||
+ "<li style=\"margin-top:7px;\">If you are using an old OS such as Windows 7, please try Windows 10 or 11</li>"
|
||||
+ "</ol>"
|
||||
+ "</div>");
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
|
||||
private boolean openDebugConsoleOnLaunch = false;
|
||||
private boolean fixDebugConsoleUnloadListener = false;
|
||||
private boolean forceWebViewSupport = false;
|
||||
private boolean enableWebViewCSP = false;
|
||||
private boolean enableWebViewCSP = true;
|
||||
private boolean autoFixLegacyStyleAttr = false;
|
||||
private boolean showBootMenuOnLaunch = false;
|
||||
private boolean bootMenuBlocksUnsignedClients = false;
|
||||
@ -77,7 +77,7 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
|
||||
private boolean forceProfanityFilter = false;
|
||||
private boolean forceWebGL1 = false;
|
||||
private boolean forceWebGL2 = false;
|
||||
private boolean allowExperimentalWebGL1 = false;
|
||||
private boolean allowExperimentalWebGL1 = true;
|
||||
private boolean useWebGLExt = true;
|
||||
private boolean useDelayOnSwap = false;
|
||||
private boolean useJOrbisAudioDecoder = false;
|
||||
@ -550,6 +550,11 @@ public class TeaVMClientConfigAdapter implements IClientConfigAdapter, IBootMenu
|
||||
return ramdiskMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnforceVSync() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IClientConfigAdapterHooks getHooks() {
|
||||
return hooks;
|
||||
|
@ -17,4 +17,10 @@ package net.lax1dude.eaglercraft.v1_8.internal.teavm;
|
||||
*/
|
||||
public class TeaVMEnterBootMenuException extends RuntimeException {
|
||||
|
||||
public final boolean isManual;
|
||||
|
||||
public TeaVMEnterBootMenuException(boolean manual) {
|
||||
this.isManual = manual;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.IWASMCrashCallback;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
@ -291,4 +292,8 @@ public class ServerPlatformSingleplayer {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setCrashCallbackWASM(IWASMCrashCallback callback) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
45
sources/wasm-gc-teavm-bootstrap/js/externs.js
Normal file
45
sources/wasm-gc-teavm-bootstrap/js/externs.js
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @fileoverview loader bootstrap externs
|
||||
* @externs
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
window.main = function() {};
|
||||
|
||||
window.eaglercraftXOpts = {};
|
||||
|
||||
window.eaglercraftXOpts.assetsURI = "";
|
||||
|
||||
window.eaglercraftXOpts.container = "";
|
||||
|
||||
window.__eaglercraftXLoaderContextPre = {};
|
||||
|
||||
/** @type {!HTMLElement} */
|
||||
window.__eaglercraftXLoaderContextPre.rootElement;
|
||||
|
||||
/** @type {!Object} */
|
||||
window.__eaglercraftXLoaderContextPre.eaglercraftXOpts;
|
||||
|
||||
/** @type {!ArrayBuffer} */
|
||||
window.__eaglercraftXLoaderContextPre.theEPWFileBuffer;
|
||||
|
||||
/** @type {string} */
|
||||
window.__eaglercraftXLoaderContextPre.loaderWASMURL;
|
||||
|
||||
/** @type {string} */
|
||||
window.__eaglercraftXLoaderContextPre.splashURL;
|
377
sources/wasm-gc-teavm-bootstrap/js/main.js
Normal file
377
sources/wasm-gc-teavm-bootstrap/js/main.js
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {*} msg
|
||||
*/
|
||||
function logInfo(msg) {
|
||||
console.log("LoaderBootstrap: [INFO] " + msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} msg
|
||||
*/
|
||||
function logWarn(msg) {
|
||||
console.log("LoaderBootstrap: [WARN] " + msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} msg
|
||||
*/
|
||||
function logError(msg) {
|
||||
console.error("LoaderBootstrap: [ERROR] " + msg);
|
||||
}
|
||||
|
||||
/** @type {function(string,number):ArrayBuffer|null} */
|
||||
var decodeBase64Impl = null;
|
||||
|
||||
/**
|
||||
* @return {function(string,number):ArrayBuffer}
|
||||
*/
|
||||
function createBase64Decoder() {
|
||||
const revLookup = [];
|
||||
const code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
for (var i = 0, len = code.length; i < len; ++i) {
|
||||
revLookup[code.charCodeAt(i)] = i;
|
||||
}
|
||||
|
||||
revLookup["-".charCodeAt(0)] = 62;
|
||||
revLookup["_".charCodeAt(0)] = 63;
|
||||
|
||||
/**
|
||||
* @param {string} b64
|
||||
* @param {number} start
|
||||
* @return {!Array<number>}
|
||||
*/
|
||||
function getLens(b64, start) {
|
||||
const len = b64.length - start;
|
||||
if (len % 4 > 0) {
|
||||
throw new Error("Invalid string. Length must be a multiple of 4");
|
||||
}
|
||||
var validLen = b64.indexOf("=", start);
|
||||
if (validLen === -1) {
|
||||
validLen = len;
|
||||
}else {
|
||||
validLen -= start;
|
||||
}
|
||||
const placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4);
|
||||
return [validLen, placeHoldersLen];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} b64
|
||||
* @param {number} start
|
||||
* @return {ArrayBuffer}
|
||||
*/
|
||||
function decodeImpl(b64, start) {
|
||||
var tmp;
|
||||
const lens = getLens(b64, start);
|
||||
const validLen = lens[0];
|
||||
const placeHoldersLen = lens[1];
|
||||
const arr = new Uint8Array(((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen);
|
||||
var curByte = 0;
|
||||
const len = (placeHoldersLen > 0 ? validLen - 4 : validLen) + start;
|
||||
var i;
|
||||
for (i = start; i < len; i += 4) {
|
||||
tmp = (revLookup[b64.charCodeAt(i)] << 18) |
|
||||
(revLookup[b64.charCodeAt(i + 1)] << 12) |
|
||||
(revLookup[b64.charCodeAt(i + 2)] << 6) |
|
||||
revLookup[b64.charCodeAt(i + 3)]
|
||||
arr[curByte++] = (tmp >> 16) & 0xFF
|
||||
arr[curByte++] = (tmp >> 8) & 0xFF
|
||||
arr[curByte++] = tmp & 0xFF
|
||||
}
|
||||
if (placeHoldersLen === 2) {
|
||||
tmp = (revLookup[b64.charCodeAt(i)] << 2) |
|
||||
(revLookup[b64.charCodeAt(i + 1)] >> 4)
|
||||
arr[curByte++] = tmp & 0xFF
|
||||
}else if (placeHoldersLen === 1) {
|
||||
tmp = (revLookup[b64.charCodeAt(i)] << 10) |
|
||||
(revLookup[b64.charCodeAt(i + 1)] << 4) |
|
||||
(revLookup[b64.charCodeAt(i + 2)] >> 2)
|
||||
arr[curByte++] = (tmp >> 8) & 0xFF
|
||||
arr[curByte++] = tmp & 0xFF
|
||||
}
|
||||
return arr.buffer;
|
||||
}
|
||||
|
||||
return decodeImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @param {number} start
|
||||
* @return {ArrayBuffer}
|
||||
*/
|
||||
function decodeBase64(url, start) {
|
||||
if(!decodeBase64Impl) {
|
||||
decodeBase64Impl = createBase64Decoder();
|
||||
}
|
||||
return decodeBase64Impl(url, start);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} ms
|
||||
* @return {!Promise}
|
||||
*/
|
||||
function asyncSleep(ms) {
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @return {!Promise<ArrayBuffer>}
|
||||
*/
|
||||
function downloadURL(url) {
|
||||
return new Promise(function(resolve) {
|
||||
fetch(url, { "cache": "force-cache" })
|
||||
.then(function(res) {
|
||||
return res.arrayBuffer();
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(function(ex) {
|
||||
logError("Failed to fetch URL! " + ex);
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @return {!Promise<ArrayBuffer>}
|
||||
*/
|
||||
function downloadDataURL(url) {
|
||||
if(!url.startsWith("data:application/octet-stream;base64,")) {
|
||||
return downloadURL(url);
|
||||
}else {
|
||||
return new Promise(function(resolve) {
|
||||
downloadURL(url).then(function(res) {
|
||||
if(res) {
|
||||
resolve(res);
|
||||
}else {
|
||||
logWarn("Failed to decode base64 via fetch, doing it the slow way instead...");
|
||||
try {
|
||||
resolve(decodeBase64(url, 37));
|
||||
}catch(ex) {
|
||||
logError("Failed to decode base64! " + ex);
|
||||
resolve(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} rootElement
|
||||
* @param {string} msg
|
||||
*/
|
||||
function displayInvalidEPW(rootElement, msg) {
|
||||
const downloadFailureMsg = /** @type {HTMLElement} */ (document.createElement("h2"));
|
||||
downloadFailureMsg.style.color = "#AA0000";
|
||||
downloadFailureMsg.style.padding = "25px";
|
||||
downloadFailureMsg.style.fontFamily = "sans-serif";
|
||||
downloadFailureMsg.style["marginBlock"] = "0px";
|
||||
downloadFailureMsg.appendChild(document.createTextNode(msg));
|
||||
rootElement.appendChild(downloadFailureMsg);
|
||||
const downloadFailureMsg2 = /** @type {HTMLElement} */ (document.createElement("h4"));
|
||||
downloadFailureMsg2.style.color = "#AA0000";
|
||||
downloadFailureMsg2.style.padding = "25px";
|
||||
downloadFailureMsg2.style.fontFamily = "sans-serif";
|
||||
downloadFailureMsg2.style["marginBlock"] = "0px";
|
||||
downloadFailureMsg2.appendChild(document.createTextNode("Try again later"));
|
||||
rootElement.style.backgroundColor = "white";
|
||||
rootElement.appendChild(downloadFailureMsg2);
|
||||
}
|
||||
|
||||
window.main = async function() {
|
||||
if(typeof window.eaglercraftXOpts === "undefined") {
|
||||
const msg = "window.eaglercraftXOpts is not defined!";
|
||||
logError(msg);
|
||||
alert(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const containerId = window.eaglercraftXOpts.container;
|
||||
if(typeof containerId !== "string") {
|
||||
const msg = "window.eaglercraftXOpts.container is not a string!";
|
||||
logError(msg);
|
||||
alert(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
var assetsURI = window.eaglercraftXOpts.assetsURI;
|
||||
if(typeof assetsURI !== "string") {
|
||||
if((typeof assetsURI === "object") && (typeof assetsURI[0] === "object") && (typeof assetsURI[0]["url"] === "string")) {
|
||||
assetsURI = assetsURI[0]["url"];
|
||||
}else {
|
||||
const msg = "window.eaglercraftXOpts.assetsURI is not a string!";
|
||||
logError(msg);
|
||||
alert(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const rootElement = /** @type {HTMLElement} */ (document.getElementById(containerId));
|
||||
|
||||
if(!rootElement) {
|
||||
const msg = "window.eaglercraftXOpts.container \"" + containerId + "\" is not a known element id!";
|
||||
logError(msg);
|
||||
alert(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
var node;
|
||||
while(node = rootElement.lastChild) {
|
||||
rootElement.removeChild(node);
|
||||
}
|
||||
|
||||
const splashElement = /** @type {HTMLElement} */ (document.createElement("div"));
|
||||
splashElement.style.width = "100%";
|
||||
splashElement.style.height = "100%";
|
||||
splashElement.style.setProperty("image-rendering", "pixelated");
|
||||
splashElement.style.background = "center / contain no-repeat url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAAAAAB3tzPbAAAACXBIWXMAAC4jAAAuIwF4pT92AAAG+UlEQVR42u2cy23jOhRATwbTwGwFvAJoF6BFGjColcGkASNuIPA6C68DN+BADZiCVxLSQBYqIGYBAbSdEvwWkvUzZWfymwlwCQwQUZeXPOT9URPkYs/3bj8QAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAH4x9vPvzFpAhAzM98UILmqfjDf1YT0N/cBk+71v+wDSczHmDeJ6TqO+SIfyD7IvC9g33Yc7dP6CQDxB+q62Hc2xnyJD2Sf5vuzL3Hi5MM0WbCN51u/Y/30ryEGmDVHlhwsY9Y7xlq0CuzVc4lh2n7NkGsnQ1nB7IefmrY/araJcbrq6Ryk9YqW4l3J/dHww1jdej+8kte042EW0Nba1hyWdl+9irq/FNXaD6BbQoexuvf+tQC2vX1+AFvP0kxiuyidfWwEbOtQtK0n0r6xbYCKsLcM21+pLZX3u4984Kq2xlnWDimllRudAXEpkGSHfqMzsmxfWnLWNf9aQznW4wMZWOMJxvGs/Ff5X+yPcD0g3dqZesdsI2f7Z2/73W2JSok9Gqu7P1q/I2qtj0qn/ZkTaCPWO2a0VyjrxY7sNUG1LxRlaE90MpDpGVeAxpaGobN2XPWH0aQVE1stfXPAj0+XzUmcob3aTRdVZ2+tRv+gMNBDaTkZ4k6uhtYPaK7iUkUcx9lgij92gZ6aXmxoDeK8D1hPfm18oBvTfPGwXoVG+4VfXcwl8dEOtCJS7De9M0VTqTA2p081O3kJ+uk5cU/RVN8C262Ms9HMlLHSmhNFTcc9u1uQRX4jMhqyNIk1GRk69a6hb0IDZ3pITnbfNqFuJWE9gbYrfmSqen/SiKy27G0VS20VWc+UEn59/YDPkc+0EunrAXQ/JXucYL+3VutyAqvP5wFvtEoyQPsMJMpKc3v7/Su9ALLkhAJDPCObGTDmonfNHAij3sg5866fmTHGnFt/crroh6vEv/Rq6vhEoP7hWWb2ylSQZP5zOVrDqVxSZnm/xL6OFnZwF3/4JoyGjyXu1X3n0rEFyE5Jzc5KEDfT7s2ZYs52s5e1HU88hB17nKTqAroXWPpXiHbN7R3Q8fVDbjzU6vb8hUbX67FWN8Xo4U5SIWjbukr1knY9XrcwS30aOuTatqa0vkA6cI05dyPrzWBbj7ZZrPUT2O7pdpKFtp4rph0E0AxtfN0u9kNVg25d4BPiDF0+R83dPol7/l4m4yQmQzdX+ISewqTnc8ngp94yaCan4vT+Hc228q8/T35+e8+XueSqCaPmEz9ofdbX6eSqE5iN/m4A8Qd9w/1bAEl2fPmafT3Axdv/ytlFeXUwTZyyf+NA3hWDGPrm+HXtHSdQ7nrz7fvv+MPFe/9Q3nAS+iYA3zcKCYAACIAACIAACIAACIAACIAACIAA1C2Komh++r9cogdv90M0+GoZAVHkSiGSaFmOmJdTRdESiKJ5Je4eovnSldoGNJ44gTBNbx+XH7tDYxwOniAPgEdygGWxTm/jBCAHV0u7xa90PV64IW0uOWdCapK7t600vfF2j4Ad5FCE4IopCSWMSg0Q4NgRVNKrwIBJ1ZDGxXO/5+fxhDvFQ87EsHxZMy9Sli/raMbjf9eqMpiciQG3yYOJwW1eQoBoesNBzG3yKdvqNwie1HMwiXFcwo7L7aMBtlSrC7c79RzyUm5w0f66Gk1vcJs8vFYHxUvy/u8leJz4N8t8vX5ccl04Chz5BOLR+mVVWXX5lsU4ncSOFevL7WFsJbYiPfQpcvJwhNsBxKiwcHDPNnoojzp8Jh8PnusiSMcLd1B8R5i+Igq5/BZKU3IEO8cIpoqw6L5NR8kjuOIaFR6GlmKdvmnhuFTsfqNwTBnzBOo+ZFua+jh3jAZtnksMu/b850wIfh1sVwVPhMEzKK9lz/+7Hi3Kx8CjOajVbVCEz3kIT1wyYnsD6s5t8tUaGLFpTfC7q2TH4rjzHMCoGgqTOJiMFi/TY5kduOJWHfzdtzdFrS4PYBwzhi0LAKcAdTcvKhur+VWQ3/TWcq/+LJG5VahUsILHUDGiGCmKy26cOrxlxwZUsMHlvVDW7lMQwghGOGZpmt6zcdFD47EhtQVyWySQRHUgVDzhmkeClyZFlGmiA5BH0WpyB+twPp/cgQpQBH0Lqt6qaTwfs+OW6Kl/RrdET/WqQi5BgWLDqNxmdV/Mo1X1QX5Ms0Pq/jmaP7d2/b6IVq3HW+a9qT7v6/TDNv2+tVA0hzz8klroc07AbXKmN98YQMppARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAD2//A2iD9ZsgY5XpAAAAAElFTkSuQmCC\") white";
|
||||
rootElement.appendChild(splashElement);
|
||||
|
||||
/** @type {ArrayBuffer} */
|
||||
var theEPWFileBuffer;
|
||||
if(assetsURI.startsWith("data:")) {
|
||||
logInfo("Downloading EPW file \"<data: " + assetsURI.length + " chars>\"...");
|
||||
theEPWFileBuffer = await downloadDataURL(assetsURI);
|
||||
}else {
|
||||
logInfo("Downloading EPW file \"" + assetsURI + "\"...");
|
||||
theEPWFileBuffer = await downloadURL(assetsURI);
|
||||
}
|
||||
|
||||
var isInvalid = false;
|
||||
if(!theEPWFileBuffer) {
|
||||
isInvalid = true;
|
||||
}else if(theEPWFileBuffer.byteLength < 384) {
|
||||
logError("The EPW file is too short");
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if(isInvalid) {
|
||||
rootElement.removeChild(splashElement);
|
||||
const msg = "Failed to download EPW file!";
|
||||
displayInvalidEPW(rootElement, msg);
|
||||
logError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const dataView = new DataView(theEPWFileBuffer);
|
||||
|
||||
if(dataView.getUint32(0, true) !== 608649541 || dataView.getUint32(4, true) !== 1297301847) {
|
||||
logError("The file is not an EPW file");
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
const phileLength = theEPWFileBuffer.byteLength;
|
||||
if(dataView.getUint32(8, true) !== phileLength) {
|
||||
logError("The EPW file is the wrong length");
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if(isInvalid) {
|
||||
rootElement.removeChild(splashElement);
|
||||
const msg = "EPW file is invalid!";
|
||||
displayInvalidEPW(rootElement, msg);
|
||||
logError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const textDecoder = new TextDecoder("utf-8");
|
||||
|
||||
const splashDataOffset = dataView.getUint32(100, true);
|
||||
const splashDataLength = dataView.getUint32(104, true);
|
||||
const splashMIMEOffset = dataView.getUint32(108, true);
|
||||
const splashMIMELength = dataView.getUint32(112, true);
|
||||
|
||||
if(splashDataOffset < 0 || splashDataOffset + splashDataLength > phileLength
|
||||
|| splashMIMEOffset < 0 || splashMIMEOffset + splashMIMELength > phileLength) {
|
||||
logError("The EPW file contains an invalid offset (component: splash)");
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if(isInvalid) {
|
||||
rootElement.removeChild(splashElement);
|
||||
const msg = "EPW file is invalid!";
|
||||
displayInvalidEPW(rootElement, msg);
|
||||
logError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const splashBinSlice = new Uint8Array(theEPWFileBuffer, splashDataOffset, splashDataLength);
|
||||
const splashMIMESlice = new Uint8Array(theEPWFileBuffer, splashMIMEOffset, splashMIMELength);
|
||||
const splashURL = URL.createObjectURL(new Blob([ splashBinSlice ], { "type": textDecoder.decode(splashMIMESlice) }));
|
||||
logInfo("Loaded splash img: " + splashURL);
|
||||
splashElement.style.background = "center / contain no-repeat url(\"" + splashURL + "\"), 0px 0px / 1000000% 1000000% no-repeat url(\"" + splashURL + "\") white";
|
||||
|
||||
// allow the screen to update
|
||||
await asyncSleep(20);
|
||||
|
||||
const loaderJSOffset = dataView.getUint32(164, true);
|
||||
const loaderJSLength = dataView.getUint32(168, true);
|
||||
const loaderWASMOffset = dataView.getUint32(180, true);
|
||||
const loaderWASMLength = dataView.getUint32(184, true);
|
||||
|
||||
if(loaderJSOffset < 0 || loaderJSOffset + loaderJSLength > phileLength
|
||||
|| loaderWASMOffset < 0 || loaderWASMOffset + loaderWASMLength > phileLength) {
|
||||
logError("The EPW file contains an invalid offset (component: loader)");
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if(isInvalid) {
|
||||
rootElement.removeChild(splashElement);
|
||||
const msg = "EPW file is invalid!";
|
||||
displayInvalidEPW(rootElement, msg);
|
||||
logError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const loaderJSSlice = new Uint8Array(theEPWFileBuffer, loaderJSOffset, loaderJSLength);
|
||||
const loaderJSURL = URL.createObjectURL(new Blob([ loaderJSSlice ], { "type": "text/javascript;charset=utf-8" }));
|
||||
logInfo("Loaded loader.js: " + splashURL);
|
||||
const loaderWASMSlice = new Uint8Array(theEPWFileBuffer, loaderWASMOffset, loaderWASMLength);
|
||||
const loaderWASMURL = URL.createObjectURL(new Blob([ loaderWASMSlice ], { "type": "application/wasm" }));
|
||||
logInfo("Loaded loader.wasm: " + loaderWASMURL);
|
||||
|
||||
const optsObj = {};
|
||||
for(const [key, value] of Object.entries(window.eaglercraftXOpts)) {
|
||||
if(key !== "container" && key !== "assetsURI") {
|
||||
optsObj[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
window.__eaglercraftXLoaderContextPre = {
|
||||
"rootElement": rootElement,
|
||||
"eaglercraftXOpts": optsObj,
|
||||
"theEPWFileBuffer": theEPWFileBuffer,
|
||||
"loaderWASMURL": loaderWASMURL,
|
||||
"splashURL": splashURL
|
||||
};
|
||||
|
||||
logInfo("Appending loader.js to document...");
|
||||
|
||||
const scriptElement = /** @type {HTMLScriptElement} */ (document.createElement("script"));
|
||||
scriptElement.type = "text/javascript";
|
||||
scriptElement.src = loaderJSURL;
|
||||
document.head.appendChild(scriptElement);
|
||||
|
||||
};
|
||||
|
88
sources/wasm-gc-teavm-loader/c/epw_header.h
Normal file
88
sources/wasm-gc-teavm-loader/c/epw_header.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDED_EPW_HEADER_H
|
||||
#define _INCLUDED_EPW_HEADER_H
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
struct epw_slice {
|
||||
uint32_t sliceOffset;
|
||||
uint32_t sliceLength;
|
||||
};
|
||||
|
||||
struct epw_slice_compressed {
|
||||
uint32_t sliceOffset;
|
||||
uint32_t sliceCompressedLength;
|
||||
uint32_t sliceDecompressedLength;
|
||||
uint32_t _reserved;
|
||||
};
|
||||
|
||||
struct epw_assets_epk_file {
|
||||
struct epw_slice filePath;
|
||||
struct epw_slice loadPath;
|
||||
struct epw_slice_compressed fileData;
|
||||
};
|
||||
|
||||
struct epw_header {
|
||||
uint8_t magic[8];
|
||||
|
||||
uint32_t fileLength;
|
||||
uint32_t fileCRC32;
|
||||
uint16_t versionMajor;
|
||||
uint16_t versionMinor;
|
||||
|
||||
uint32_t clientVersionInt;
|
||||
|
||||
struct epw_slice clientPackageName;
|
||||
struct epw_slice clientOriginName;
|
||||
struct epw_slice clientOriginVersion;
|
||||
struct epw_slice clientOriginVendor;
|
||||
struct epw_slice clientForkName;
|
||||
struct epw_slice clientForkVersion;
|
||||
struct epw_slice clientForkVendor;
|
||||
struct epw_slice metadataSegment;
|
||||
|
||||
uint64_t creationTime;
|
||||
uint32_t numEPKs;
|
||||
|
||||
struct epw_slice splashImageData;
|
||||
struct epw_slice splashImageMIME;
|
||||
struct epw_slice pressAnyKeyImageData;
|
||||
struct epw_slice pressAnyKeyImageMIME;
|
||||
struct epw_slice crashImageData;
|
||||
struct epw_slice crashImageMIME;
|
||||
struct epw_slice faviconImageData;
|
||||
struct epw_slice faviconImageMIME;
|
||||
|
||||
struct epw_slice loaderJSData;
|
||||
uint32_t _reserved_0;
|
||||
uint32_t _reserved_1;
|
||||
|
||||
struct epw_slice loaderWASMData;
|
||||
uint32_t _reserved_2;
|
||||
uint32_t _reserved_3;
|
||||
|
||||
struct epw_slice_compressed JSPIUnavailableData;
|
||||
struct epw_slice_compressed eagruntimeJSData;
|
||||
struct epw_slice_compressed classesWASMData;
|
||||
struct epw_slice_compressed classesDeobfTEADBGData;
|
||||
struct epw_slice_compressed classesDeobfWASMData;
|
||||
|
||||
struct epw_assets_epk_file assetsEPKs[];
|
||||
};
|
||||
|
||||
#endif
|
67
sources/wasm-gc-teavm-loader/c/imports.h
Normal file
67
sources/wasm-gc-teavm-loader/c/imports.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDED_IMPORTS_H
|
||||
#define _INCLUDED_IMPORTS_H
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
struct epw_load_result_epk {
|
||||
uint32_t epkData;
|
||||
uint32_t epkName;
|
||||
uint32_t epkPath;
|
||||
};
|
||||
|
||||
struct epw_load_result {
|
||||
uint32_t eagruntimeJSData;
|
||||
uint32_t classesWASMData;
|
||||
uint32_t classesDeobfTEADBGData;
|
||||
uint32_t classesDeobfWASMData;
|
||||
uint32_t pressAnyKeyImgData;
|
||||
uint32_t pressAnyKeyImgMIME;
|
||||
uint32_t crashImgData;
|
||||
uint32_t crashImgMIME;
|
||||
uint32_t faviconImgData;
|
||||
uint32_t faviconImgMIME;
|
||||
uint32_t numEPKs;
|
||||
struct epw_load_result_epk epkData[];
|
||||
};
|
||||
|
||||
struct jspi_unsupported_load_result {
|
||||
uint32_t crashImgData;
|
||||
uint32_t crashImgMIME;
|
||||
uint32_t markup;
|
||||
};
|
||||
|
||||
#define LOAD_RESULT_SIZE(numEPKs) (sizeof(struct epw_load_result) + sizeof(struct epw_load_result_epk) * (numEPKs))
|
||||
|
||||
extern uint8_t getJSPISupported();
|
||||
|
||||
extern uint32_t getEPWLength();
|
||||
extern void memcpyFromEPW(void* dest, uint32_t off, uint32_t len);
|
||||
extern uint32_t initResult(uint32_t bufLen);
|
||||
extern void memcpyToResult(uint32_t bufId, const void* src, uint32_t off, uint32_t len);
|
||||
extern void memcpyFromEPWToResult(uint32_t bufId, uint32_t dest, uint32_t off, uint32_t len);
|
||||
extern uint32_t initEPWStringResult(uint32_t off, uint32_t len);
|
||||
|
||||
extern void resultFailed(const char* msg);
|
||||
extern void resultSuccess(const struct epw_load_result* result);
|
||||
extern void resultJSPIUnsupported(struct jspi_unsupported_load_result* result);
|
||||
|
||||
extern void dbgLog(const char* msg);
|
||||
extern void dbgErr(const char* msg);
|
||||
|
||||
#endif
|
355
sources/wasm-gc-teavm-loader/c/main.c
Normal file
355
sources/wasm-gc-teavm-loader/c/main.c
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "epw_header.h"
|
||||
#include "imports.h"
|
||||
#include "xz/xz.h"
|
||||
|
||||
static uint32_t initEPWBinaryCompressedHelper(struct epw_slice_compressed* sliceIn, uint32_t epwLen);
|
||||
static uint32_t initEPWBinaryHelper(struct epw_slice* sliceIn, uint32_t epwLen);
|
||||
static uint32_t initEPWStringHelper(struct epw_slice* sliceIn, uint32_t epwLen);
|
||||
|
||||
#define SLICE_IN_BOUNDS(pSlice, epwLen) (((struct epw_slice*)(pSlice))->sliceOffset + ((struct epw_slice*)(pSlice))->sliceLength <= (epwLen))
|
||||
|
||||
// Note: Linux kernel uses 4096
|
||||
#define DEC_CHUNK_SIZE 16384
|
||||
|
||||
static char sprintfBuffer[65];
|
||||
static uint8_t inputBuffer[DEC_CHUNK_SIZE];
|
||||
static uint8_t outputBuffer[DEC_CHUNK_SIZE];
|
||||
|
||||
const char *const BAD_ALLOC = "Memory allocation failed";
|
||||
const char *const EPW_INCOMPLETE = "EPW file is incomplete";
|
||||
const char *const EPW_INVALID = "EPW file is invalid";
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
dbgLog("Executing loader WASM binary...");
|
||||
|
||||
uint32_t epwLen = getEPWLength();
|
||||
|
||||
snprintf(sprintfBuffer, sizeof(sprintfBuffer), "(Loading a %u byte EPW file)", epwLen);
|
||||
dbgLog(sprintfBuffer);
|
||||
|
||||
if(epwLen < 384) {
|
||||
resultFailed(EPW_INCOMPLETE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct epw_header* headerPtr = (struct epw_header*)malloc(384);
|
||||
if(!headerPtr) {
|
||||
resultFailed(BAD_ALLOC);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpyFromEPW(headerPtr, 0, 384);
|
||||
|
||||
// hehehe
|
||||
if(*(uint64_t*)&headerPtr->magic != *(const uint64_t*)"EAG$WASM") {
|
||||
resultFailed("The data provided is not an EPW file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbgLog("Checking primary CRC32 checksum...");
|
||||
|
||||
uint32_t crc32Val = 0;
|
||||
uint32_t epwRem = epwLen - 16;
|
||||
uint32_t j;
|
||||
|
||||
xz_crc32_init();
|
||||
|
||||
while(epwRem > 0) {
|
||||
j = epwRem < DEC_CHUNK_SIZE ? epwRem : DEC_CHUNK_SIZE;
|
||||
memcpyFromEPW(inputBuffer, epwLen - epwRem, j);
|
||||
epwRem -= j;
|
||||
crc32Val = xz_crc32(inputBuffer, (size_t)j, crc32Val);
|
||||
}
|
||||
|
||||
if(crc32Val != headerPtr->fileCRC32) {
|
||||
resultFailed("EPW file has an invalid checksum");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t numEPKs = headerPtr->numEPKs;
|
||||
uint32_t headerLen = ((276 + 32 * numEPKs) + 127) & ~127;
|
||||
|
||||
if(headerLen > 384) {
|
||||
snprintf(sprintfBuffer, sizeof(sprintfBuffer), "Note: Has %u EPK files, extending header to %u bytes", numEPKs, headerLen);
|
||||
dbgLog(sprintfBuffer);
|
||||
free(headerPtr);
|
||||
if(headerLen > epwLen) {
|
||||
resultFailed(EPW_INCOMPLETE);
|
||||
return -1;
|
||||
}
|
||||
headerPtr = (struct epw_header*)malloc((size_t)headerLen);
|
||||
if(!headerPtr) {
|
||||
resultFailed("Memory allocation failed");
|
||||
return -1;
|
||||
}
|
||||
memcpyFromEPW(headerPtr, 0, headerLen);
|
||||
}
|
||||
|
||||
if(!getJSPISupported()) {
|
||||
dbgErr("JSPI is not supported! The client cannot start");
|
||||
|
||||
struct jspi_unsupported_load_result result;
|
||||
|
||||
dbgLog("Copying crash image...");
|
||||
|
||||
result.crashImgData = initEPWBinaryHelper(&headerPtr->crashImageData, epwLen);
|
||||
result.crashImgMIME = initEPWStringHelper(&headerPtr->crashImageMIME, epwLen);
|
||||
|
||||
dbgLog("Decompressing error screen...");
|
||||
|
||||
result.markup = initEPWBinaryCompressedHelper(&headerPtr->JSPIUnavailableData, epwLen);
|
||||
if(!result.markup) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbgLog("Displaying error screen...");
|
||||
|
||||
resultJSPIUnsupported(&result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct epw_load_result* result = (struct epw_load_result*)malloc(sizeof(struct epw_load_result) + sizeof(struct epw_load_result_epk) * numEPKs);
|
||||
|
||||
dbgLog("Copying non-compressed segments...");
|
||||
|
||||
result->pressAnyKeyImgData = initEPWBinaryHelper(&headerPtr->pressAnyKeyImageData, epwLen);
|
||||
if(!result->pressAnyKeyImgData) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result->pressAnyKeyImgMIME = initEPWStringHelper(&headerPtr->pressAnyKeyImageMIME, epwLen);
|
||||
if(!result->pressAnyKeyImgMIME) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result->crashImgData = initEPWBinaryHelper(&headerPtr->crashImageData, epwLen);
|
||||
if(!result->crashImgData) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result->crashImgMIME = initEPWStringHelper(&headerPtr->crashImageMIME, epwLen);
|
||||
if(!result->crashImgMIME) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result->faviconImgData = initEPWBinaryHelper(&headerPtr->faviconImageData, epwLen);
|
||||
if(!result->faviconImgData) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result->faviconImgMIME = initEPWStringHelper(&headerPtr->faviconImageMIME, epwLen);
|
||||
if(!result->faviconImgMIME) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbgLog("Decompressing eagruntime.js...");
|
||||
|
||||
result->eagruntimeJSData = initEPWBinaryCompressedHelper(&headerPtr->eagruntimeJSData, epwLen);
|
||||
if(!result->eagruntimeJSData) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbgLog("Decompressing classes.wasm...");
|
||||
|
||||
result->classesWASMData = initEPWBinaryCompressedHelper(&headerPtr->classesWASMData, epwLen);
|
||||
if(!result->classesWASMData) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbgLog("Decompressing classes.wasm.teadbg...");
|
||||
|
||||
result->classesDeobfTEADBGData = initEPWBinaryCompressedHelper(&headerPtr->classesDeobfTEADBGData, epwLen);
|
||||
if(!result->classesDeobfTEADBGData) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbgLog("Decompressing deobfuscator...");
|
||||
|
||||
result->classesDeobfWASMData = initEPWBinaryCompressedHelper(&headerPtr->classesDeobfWASMData, epwLen);
|
||||
if(!result->classesDeobfWASMData) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result->numEPKs = numEPKs;
|
||||
|
||||
for(uint32_t i = 0; i < numEPKs; ++i) {
|
||||
struct epw_assets_epk_file* epkFile = &headerPtr->assetsEPKs[i];
|
||||
|
||||
if(!SLICE_IN_BOUNDS(&epkFile->filePath, epwLen)) {
|
||||
resultFailed("EPW file contains an invalid offset");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char nameBuffer[33];
|
||||
|
||||
uint32_t nameStrLen = epkFile->filePath.sliceLength;
|
||||
if(nameStrLen > 32) {
|
||||
nameStrLen = 32;
|
||||
}
|
||||
|
||||
memcpyFromEPW(nameBuffer, epkFile->filePath.sliceOffset, nameStrLen);
|
||||
nameBuffer[nameStrLen] = 0;
|
||||
|
||||
snprintf(sprintfBuffer, sizeof(sprintfBuffer), "Decompressing assets EPK \"%s\"...", nameBuffer);
|
||||
dbgLog(sprintfBuffer);
|
||||
|
||||
struct epw_load_result_epk* epkId = &result->epkData[i];
|
||||
|
||||
epkId->epkData = initEPWBinaryCompressedHelper(&epkFile->fileData, epwLen);
|
||||
epkId->epkName = initEPWStringHelper(&epkFile->filePath, epwLen);
|
||||
epkId->epkPath = initEPWStringHelper(&epkFile->loadPath, epwLen);
|
||||
|
||||
if(!epkId->epkData || !epkId->epkName || !epkId->epkPath) {
|
||||
resultFailed(EPW_INVALID);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
dbgLog("Loader WASM binary executed successfully!");
|
||||
|
||||
resultSuccess(result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t initEPWBinaryCompressedHelper(struct epw_slice_compressed* sliceIn, uint32_t epwLen) {
|
||||
if(!SLICE_IN_BOUNDS(sliceIn, epwLen)) {
|
||||
dbgErr("EPW file contains an invalid compressed offset");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t bufId = initResult(sliceIn->sliceDecompressedLength);
|
||||
|
||||
struct xz_buf b;
|
||||
|
||||
b.in = inputBuffer;
|
||||
b.in_pos = 0;
|
||||
b.in_size = 0;
|
||||
b.out = outputBuffer;
|
||||
b.out_pos = 0;
|
||||
b.out_size = DEC_CHUNK_SIZE;
|
||||
|
||||
struct xz_dec* s;
|
||||
enum xz_ret ret;
|
||||
|
||||
s = xz_dec_init(XZ_DYNALLOC, (uint32_t)33554432);
|
||||
if(!s) {
|
||||
dbgErr("Failed to initialize XZ decompression stream");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t bufInPos = 0;
|
||||
uint32_t bufOutPos = 0;
|
||||
uint32_t remainingIn = sliceIn->sliceCompressedLength;
|
||||
uint32_t remainingOut = sliceIn->sliceDecompressedLength;
|
||||
uint32_t toRead = 0;
|
||||
uint32_t i;
|
||||
|
||||
do {
|
||||
if(b.in_pos == b.in_size) {
|
||||
i = (uint32_t)b.in_pos;
|
||||
if(i > remainingIn) {
|
||||
dbgErr("Decompression input buffer overflowed");
|
||||
xz_dec_end(s);
|
||||
return 0;
|
||||
}
|
||||
remainingIn -= i;
|
||||
|
||||
toRead = remainingIn < DEC_CHUNK_SIZE ? remainingIn : DEC_CHUNK_SIZE;
|
||||
b.in_pos = 0;
|
||||
b.in_size = (size_t)toRead;
|
||||
|
||||
memcpyFromEPW(inputBuffer, sliceIn->sliceOffset + bufInPos, toRead);
|
||||
|
||||
bufInPos += toRead;
|
||||
}
|
||||
|
||||
ret = xz_dec_run(s, &b);
|
||||
|
||||
if(b.out_pos == b.out_size || (ret == XZ_STREAM_END && b.out_pos > 0)) {
|
||||
i = (uint32_t)b.out_pos;
|
||||
if(i > remainingOut) {
|
||||
dbgErr("Decompression output buffer overflowed");
|
||||
xz_dec_end(s);
|
||||
return 0;
|
||||
}
|
||||
memcpyToResult(bufId, outputBuffer, bufOutPos, i);
|
||||
remainingOut -= i;
|
||||
bufOutPos += i;
|
||||
b.out_pos = 0;
|
||||
}
|
||||
}while(ret == XZ_OK);
|
||||
|
||||
xz_dec_end(s);
|
||||
|
||||
if(ret != XZ_STREAM_END) {
|
||||
snprintf(sprintfBuffer, sizeof(sprintfBuffer), "Decompression failed, code %u!", (uint32_t)ret);
|
||||
dbgErr(sprintfBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(b.in_pos > remainingIn) {
|
||||
dbgErr("Decompression input buffer overflowed");
|
||||
return 0;
|
||||
}
|
||||
remainingIn -= (uint32_t)b.in_pos;
|
||||
|
||||
if(remainingIn > 0) {
|
||||
dbgErr("Decompression completed, but there is still some input data remaining");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bufId;
|
||||
}
|
||||
|
||||
static uint32_t initEPWBinaryHelper(struct epw_slice* sliceIn, uint32_t epwLen) {
|
||||
if(!SLICE_IN_BOUNDS(sliceIn, epwLen)) {
|
||||
dbgErr("EPW file contains an invalid offset");
|
||||
return 0;
|
||||
}else {
|
||||
uint32_t ret = initResult(sliceIn->sliceLength);
|
||||
memcpyFromEPWToResult(ret, 0, sliceIn->sliceOffset, sliceIn->sliceLength);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t initEPWStringHelper(struct epw_slice* sliceIn, uint32_t epwLen) {
|
||||
if(!SLICE_IN_BOUNDS(sliceIn, epwLen)) {
|
||||
dbgErr("EPW file contains an invalid offset");
|
||||
return 0;
|
||||
}else {
|
||||
return initEPWStringResult(sliceIn->sliceOffset, sliceIn->sliceLength);
|
||||
}
|
||||
}
|
452
sources/wasm-gc-teavm-loader/c/xz/xz.h
Normal file
452
sources/wasm-gc-teavm-loader/c/xz/xz.h
Normal file
@ -0,0 +1,452 @@
|
||||
/* SPDX-License-Identifier: 0BSD */
|
||||
|
||||
/*
|
||||
* XZ decompressor
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <https://7-zip.org/>
|
||||
*/
|
||||
|
||||
#ifndef XZ_H
|
||||
#define XZ_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/stddef.h>
|
||||
# include <linux/types.h>
|
||||
#else
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* In Linux, this is used to make extern functions static when needed. */
|
||||
#ifndef XZ_EXTERN
|
||||
# define XZ_EXTERN extern
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum xz_mode - Operation mode
|
||||
*
|
||||
* @XZ_SINGLE: Single-call mode. This uses less RAM than
|
||||
* multi-call modes, because the LZMA2
|
||||
* dictionary doesn't need to be allocated as
|
||||
* part of the decoder state. All required data
|
||||
* structures are allocated at initialization,
|
||||
* so xz_dec_run() cannot return XZ_MEM_ERROR.
|
||||
* @XZ_PREALLOC: Multi-call mode with preallocated LZMA2
|
||||
* dictionary buffer. All data structures are
|
||||
* allocated at initialization, so xz_dec_run()
|
||||
* cannot return XZ_MEM_ERROR.
|
||||
* @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is
|
||||
* allocated once the required size has been
|
||||
* parsed from the stream headers. If the
|
||||
* allocation fails, xz_dec_run() will return
|
||||
* XZ_MEM_ERROR.
|
||||
*
|
||||
* It is possible to enable support only for a subset of the above
|
||||
* modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC,
|
||||
* or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled
|
||||
* with support for all operation modes, but the preboot code may
|
||||
* be built with fewer features to minimize code size.
|
||||
*/
|
||||
enum xz_mode {
|
||||
XZ_SINGLE,
|
||||
XZ_PREALLOC,
|
||||
XZ_DYNALLOC
|
||||
};
|
||||
|
||||
/**
|
||||
* enum xz_ret - Return codes
|
||||
* @XZ_OK: Everything is OK so far. More input or more
|
||||
* output space is required to continue. This
|
||||
* return code is possible only in multi-call mode
|
||||
* (XZ_PREALLOC or XZ_DYNALLOC).
|
||||
* @XZ_STREAM_END: Operation finished successfully.
|
||||
* @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
|
||||
* is still possible in multi-call mode by simply
|
||||
* calling xz_dec_run() again.
|
||||
* Note that this return value is used only if
|
||||
* XZ_DEC_ANY_CHECK was defined at build time,
|
||||
* which is not used in the kernel. Unsupported
|
||||
* check types return XZ_OPTIONS_ERROR if
|
||||
* XZ_DEC_ANY_CHECK was not defined at build time.
|
||||
* @XZ_MEM_ERROR: Allocating memory failed. This return code is
|
||||
* possible only if the decoder was initialized
|
||||
* with XZ_DYNALLOC. The amount of memory that was
|
||||
* tried to be allocated was no more than the
|
||||
* dict_max argument given to xz_dec_init().
|
||||
* @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than
|
||||
* allowed by the dict_max argument given to
|
||||
* xz_dec_init(). This return value is possible
|
||||
* only in multi-call mode (XZ_PREALLOC or
|
||||
* XZ_DYNALLOC); the single-call mode (XZ_SINGLE)
|
||||
* ignores the dict_max argument.
|
||||
* @XZ_FORMAT_ERROR: File format was not recognized (wrong magic
|
||||
* bytes).
|
||||
* @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
|
||||
* compression options. In the decoder this means
|
||||
* that the header CRC32 matches, but the header
|
||||
* itself specifies something that we don't support.
|
||||
* @XZ_DATA_ERROR: Compressed data is corrupt.
|
||||
* @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
|
||||
* different between multi-call and single-call
|
||||
* mode; more information below.
|
||||
*
|
||||
* In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
|
||||
* to XZ code cannot consume any input and cannot produce any new output.
|
||||
* This happens when there is no new input available, or the output buffer
|
||||
* is full while at least one output byte is still pending. Assuming your
|
||||
* code is not buggy, you can get this error only when decoding a compressed
|
||||
* stream that is truncated or otherwise corrupt.
|
||||
*
|
||||
* In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
|
||||
* is too small or the compressed input is corrupt in a way that makes the
|
||||
* decoder produce more output than the caller expected. When it is
|
||||
* (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
|
||||
* is used instead of XZ_BUF_ERROR.
|
||||
*/
|
||||
enum xz_ret {
|
||||
XZ_OK,
|
||||
XZ_STREAM_END,
|
||||
XZ_UNSUPPORTED_CHECK,
|
||||
XZ_MEM_ERROR,
|
||||
XZ_MEMLIMIT_ERROR,
|
||||
XZ_FORMAT_ERROR,
|
||||
XZ_OPTIONS_ERROR,
|
||||
XZ_DATA_ERROR,
|
||||
XZ_BUF_ERROR
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xz_buf - Passing input and output buffers to XZ code
|
||||
* @in: Beginning of the input buffer. This may be NULL if and only
|
||||
* if in_pos is equal to in_size.
|
||||
* @in_pos: Current position in the input buffer. This must not exceed
|
||||
* in_size.
|
||||
* @in_size: Size of the input buffer
|
||||
* @out: Beginning of the output buffer. This may be NULL if and only
|
||||
* if out_pos is equal to out_size.
|
||||
* @out_pos: Current position in the output buffer. This must not exceed
|
||||
* out_size.
|
||||
* @out_size: Size of the output buffer
|
||||
*
|
||||
* Only the contents of the output buffer from out[out_pos] onward, and
|
||||
* the variables in_pos and out_pos are modified by the XZ code.
|
||||
*/
|
||||
struct xz_buf {
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_size;
|
||||
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct xz_dec - Opaque type to hold the XZ decoder state
|
||||
*/
|
||||
struct xz_dec;
|
||||
|
||||
/**
|
||||
* xz_dec_init() - Allocate and initialize a XZ decoder state
|
||||
* @mode: Operation mode
|
||||
* @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
|
||||
* multi-call decoding. This is ignored in single-call mode
|
||||
* (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes
|
||||
* or 2^n + 2^(n-1) bytes (the latter sizes are less common
|
||||
* in practice), so other values for dict_max don't make sense.
|
||||
* In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
|
||||
* 512 KiB, and 1 MiB are probably the only reasonable values,
|
||||
* except for kernel and initramfs images where a bigger
|
||||
* dictionary can be fine and useful.
|
||||
*
|
||||
* Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at
|
||||
* once. The caller must provide enough output space or the decoding will
|
||||
* fail. The output space is used as the dictionary buffer, which is why
|
||||
* there is no need to allocate the dictionary as part of the decoder's
|
||||
* internal state.
|
||||
*
|
||||
* Because the output buffer is used as the workspace, streams encoded using
|
||||
* a big dictionary are not a problem in single-call mode. It is enough that
|
||||
* the output buffer is big enough to hold the actual uncompressed data; it
|
||||
* can be smaller than the dictionary size stored in the stream headers.
|
||||
*
|
||||
* Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes
|
||||
* of memory is preallocated for the LZMA2 dictionary. This way there is no
|
||||
* risk that xz_dec_run() could run out of memory, since xz_dec_run() will
|
||||
* never allocate any memory. Instead, if the preallocated dictionary is too
|
||||
* small for decoding the given input stream, xz_dec_run() will return
|
||||
* XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be
|
||||
* decoded to avoid allocating excessive amount of memory for the dictionary.
|
||||
*
|
||||
* Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC):
|
||||
* dict_max specifies the maximum allowed dictionary size that xz_dec_run()
|
||||
* may allocate once it has parsed the dictionary size from the stream
|
||||
* headers. This way excessive allocations can be avoided while still
|
||||
* limiting the maximum memory usage to a sane value to prevent running the
|
||||
* system out of memory when decompressing streams from untrusted sources.
|
||||
*
|
||||
* On success, xz_dec_init() returns a pointer to struct xz_dec, which is
|
||||
* ready to be used with xz_dec_run(). If memory allocation fails,
|
||||
* xz_dec_init() returns NULL.
|
||||
*/
|
||||
XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max);
|
||||
|
||||
/**
|
||||
* xz_dec_run() - Run the XZ decoder for a single XZ stream
|
||||
* @s: Decoder state allocated using xz_dec_init()
|
||||
* @b: Input and output buffers
|
||||
*
|
||||
* The possible return values depend on build options and operation mode.
|
||||
* See enum xz_ret for details.
|
||||
*
|
||||
* Note that if an error occurs in single-call mode (return value is not
|
||||
* XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the
|
||||
* contents of the output buffer from b->out[b->out_pos] onward are
|
||||
* undefined. This is true even after XZ_BUF_ERROR, because with some filter
|
||||
* chains, there may be a second pass over the output buffer, and this pass
|
||||
* cannot be properly done if the output buffer is truncated. Thus, you
|
||||
* cannot give the single-call decoder a too small buffer and then expect to
|
||||
* get that amount valid data from the beginning of the stream. You must use
|
||||
* the multi-call decoder if you don't want to uncompress the whole stream.
|
||||
*
|
||||
* Use xz_dec_run() when XZ data is stored inside some other file format.
|
||||
* The decoding will stop after one XZ stream has been decompressed. To
|
||||
* decompress regular .xz files which might have multiple concatenated
|
||||
* streams, use xz_dec_catrun() instead.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
|
||||
|
||||
/**
|
||||
* xz_dec_catrun() - Run the XZ decoder with support for concatenated streams
|
||||
* @s: Decoder state allocated using xz_dec_init()
|
||||
* @b: Input and output buffers
|
||||
* @finish: This is an int instead of bool to avoid requiring stdbool.h.
|
||||
* As long as more input might be coming, finish must be false.
|
||||
* When the caller knows that it has provided all the input to
|
||||
* the decoder (some possibly still in b->in), it must set finish
|
||||
* to true. Only when finish is true can this function return
|
||||
* XZ_STREAM_END to indicate successful decompression of the
|
||||
* file. In single-call mode (XZ_SINGLE) finish is assumed to
|
||||
* always be true; the caller-provided value is ignored.
|
||||
*
|
||||
* This is like xz_dec_run() except that this makes it easy to decode .xz
|
||||
* files with multiple streams (multiple .xz files concatenated as is).
|
||||
* The rarely-used Stream Padding feature is supported too, that is, there
|
||||
* can be null bytes after or between the streams. The number of null bytes
|
||||
* must be a multiple of four.
|
||||
*
|
||||
* When finish is false and b->in_pos == b->in_size, it is possible that
|
||||
* XZ_BUF_ERROR isn't returned even when no progress is possible (XZ_OK is
|
||||
* returned instead). This shouldn't matter because in this situation a
|
||||
* reasonable caller will attempt to provide more input or set finish to
|
||||
* true for the next xz_dec_catrun() call anyway.
|
||||
*
|
||||
* For any struct xz_dec that has been initialized for multi-call mode:
|
||||
* Once decoding has been started with xz_dec_run() or xz_dec_catrun(),
|
||||
* the same function must be used until xz_dec_reset() or xz_dec_end().
|
||||
* Switching between the two decoding functions without resetting results
|
||||
* in undefined behavior.
|
||||
*
|
||||
* xz_dec_catrun() is only available if XZ_DEC_CONCATENATED was defined
|
||||
* at compile time.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_catrun(struct xz_dec *s, struct xz_buf *b,
|
||||
int finish);
|
||||
|
||||
/**
|
||||
* xz_dec_reset() - Reset an already allocated decoder state
|
||||
* @s: Decoder state allocated using xz_dec_init()
|
||||
*
|
||||
* This function can be used to reset the multi-call decoder state without
|
||||
* freeing and reallocating memory with xz_dec_end() and xz_dec_init().
|
||||
*
|
||||
* In single-call mode, xz_dec_reset() is always called in the beginning of
|
||||
* xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
|
||||
* multi-call mode.
|
||||
*/
|
||||
XZ_EXTERN void xz_dec_reset(struct xz_dec *s);
|
||||
|
||||
/**
|
||||
* xz_dec_end() - Free the memory allocated for the decoder state
|
||||
* @s: Decoder state allocated using xz_dec_init(). If s is NULL,
|
||||
* this function does nothing.
|
||||
*/
|
||||
XZ_EXTERN void xz_dec_end(struct xz_dec *s);
|
||||
|
||||
/**
|
||||
* DOC: MicroLZMA decompressor
|
||||
*
|
||||
* This MicroLZMA header format was created for use in EROFS but may be used
|
||||
* by others too. **In most cases one needs the XZ APIs above instead.**
|
||||
*
|
||||
* The compressed format supported by this decoder is a raw LZMA stream
|
||||
* whose first byte (always 0x00) has been replaced with bitwise-negation
|
||||
* of the LZMA properties (lc/lp/pb) byte. For example, if lc/lp/pb is
|
||||
* 3/0/2, the first byte is 0xA2. This way the first byte can never be 0x00.
|
||||
* Just like with LZMA2, lc + lp <= 4 must be true. The LZMA end-of-stream
|
||||
* marker must not be used. The unused values are reserved for future use.
|
||||
*
|
||||
* These functions aren't used or available in preboot code and thus aren't
|
||||
* marked with XZ_EXTERN. This avoids warnings about static functions that
|
||||
* are never defined.
|
||||
*/
|
||||
|
||||
/*
|
||||
* struct xz_dec_microlzma - Opaque type to hold the MicroLZMA decoder state
|
||||
*/
|
||||
struct xz_dec_microlzma;
|
||||
|
||||
/**
|
||||
* xz_dec_microlzma_alloc() - Allocate memory for the MicroLZMA decoder
|
||||
* @mode: XZ_SINGLE or XZ_PREALLOC
|
||||
* @dict_size: LZMA dictionary size. This must be at least 4 KiB and
|
||||
* at most 3 GiB.
|
||||
*
|
||||
* In contrast to xz_dec_init(), this function only allocates the memory
|
||||
* and remembers the dictionary size. xz_dec_microlzma_reset() must be used
|
||||
* before calling xz_dec_microlzma_run().
|
||||
*
|
||||
* The amount of allocated memory is a little less than 30 KiB with XZ_SINGLE.
|
||||
* With XZ_PREALLOC also a dictionary buffer of dict_size bytes is allocated.
|
||||
*
|
||||
* On success, xz_dec_microlzma_alloc() returns a pointer to
|
||||
* struct xz_dec_microlzma. If memory allocation fails or
|
||||
* dict_size is invalid, NULL is returned.
|
||||
*/
|
||||
extern struct xz_dec_microlzma *xz_dec_microlzma_alloc(enum xz_mode mode,
|
||||
uint32_t dict_size);
|
||||
|
||||
/**
|
||||
* xz_dec_microlzma_reset() - Reset the MicroLZMA decoder state
|
||||
* @s: Decoder state allocated using xz_dec_microlzma_alloc()
|
||||
* @comp_size: Compressed size of the input stream
|
||||
* @uncomp_size: Uncompressed size of the input stream. A value smaller
|
||||
* than the real uncompressed size of the input stream can
|
||||
* be specified if uncomp_size_is_exact is set to false.
|
||||
* uncomp_size can never be set to a value larger than the
|
||||
* expected real uncompressed size because it would eventually
|
||||
* result in XZ_DATA_ERROR.
|
||||
* @uncomp_size_is_exact: This is an int instead of bool to avoid
|
||||
* requiring stdbool.h. This should normally be set to true.
|
||||
* When this is set to false, error detection is weaker.
|
||||
*/
|
||||
extern void xz_dec_microlzma_reset(struct xz_dec_microlzma *s,
|
||||
uint32_t comp_size, uint32_t uncomp_size,
|
||||
int uncomp_size_is_exact);
|
||||
|
||||
/**
|
||||
* xz_dec_microlzma_run() - Run the MicroLZMA decoder
|
||||
* @s: Decoder state initialized using xz_dec_microlzma_reset()
|
||||
* @b: Input and output buffers
|
||||
*
|
||||
* This works similarly to xz_dec_run() with a few important differences.
|
||||
* Only the differences are documented here.
|
||||
*
|
||||
* The only possible return values are XZ_OK, XZ_STREAM_END, and
|
||||
* XZ_DATA_ERROR. This function cannot return XZ_BUF_ERROR: if no progress
|
||||
* is possible due to lack of input data or output space, this function will
|
||||
* keep returning XZ_OK. Thus, the calling code must be written so that it
|
||||
* will eventually provide input and output space matching (or exceeding)
|
||||
* comp_size and uncomp_size arguments given to xz_dec_microlzma_reset().
|
||||
* If the caller cannot do this (for example, if the input file is truncated
|
||||
* or otherwise corrupt), the caller must detect this error by itself to
|
||||
* avoid an infinite loop.
|
||||
*
|
||||
* If the compressed data seems to be corrupt, XZ_DATA_ERROR is returned.
|
||||
* This can happen also when incorrect dictionary, uncompressed, or
|
||||
* compressed sizes have been specified.
|
||||
*
|
||||
* With XZ_PREALLOC only: As an extra feature, b->out may be NULL to skip over
|
||||
* uncompressed data. This way the caller doesn't need to provide a temporary
|
||||
* output buffer for the bytes that will be ignored.
|
||||
*
|
||||
* With XZ_SINGLE only: In contrast to xz_dec_run(), the return value XZ_OK
|
||||
* is also possible and thus XZ_SINGLE is actually a limited multi-call mode.
|
||||
* After XZ_OK the bytes decoded so far may be read from the output buffer.
|
||||
* It is possible to continue decoding but the variables b->out and b->out_pos
|
||||
* MUST NOT be changed by the caller. Increasing the value of b->out_size is
|
||||
* allowed to make more output space available; one doesn't need to provide
|
||||
* space for the whole uncompressed data on the first call. The input buffer
|
||||
* may be changed normally like with XZ_PREALLOC. This way input data can be
|
||||
* provided from non-contiguous memory.
|
||||
*/
|
||||
extern enum xz_ret xz_dec_microlzma_run(struct xz_dec_microlzma *s,
|
||||
struct xz_buf *b);
|
||||
|
||||
/**
|
||||
* xz_dec_microlzma_end() - Free the memory allocated for the decoder state
|
||||
* @s: Decoder state allocated using xz_dec_microlzma_alloc().
|
||||
* If s is NULL, this function does nothing.
|
||||
*/
|
||||
extern void xz_dec_microlzma_end(struct xz_dec_microlzma *s);
|
||||
|
||||
/*
|
||||
* Standalone build (userspace build or in-kernel build for boot time use)
|
||||
* needs a CRC32 implementation. For normal in-kernel use, kernel's own
|
||||
* CRC32 module is used instead, and users of this module don't need to
|
||||
* care about the functions below.
|
||||
*/
|
||||
#ifndef XZ_INTERNAL_CRC32
|
||||
# ifdef __KERNEL__
|
||||
# define XZ_INTERNAL_CRC32 0
|
||||
# else
|
||||
# define XZ_INTERNAL_CRC32 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If CRC64 support has been enabled with XZ_USE_CRC64, a CRC64
|
||||
* implementation is needed too.
|
||||
*/
|
||||
#ifndef XZ_USE_CRC64
|
||||
# undef XZ_INTERNAL_CRC64
|
||||
# define XZ_INTERNAL_CRC64 0
|
||||
#endif
|
||||
#ifndef XZ_INTERNAL_CRC64
|
||||
# ifdef __KERNEL__
|
||||
# error Using CRC64 in the kernel has not been implemented.
|
||||
# else
|
||||
# define XZ_INTERNAL_CRC64 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if XZ_INTERNAL_CRC32
|
||||
/*
|
||||
* This must be called before any other xz_* function to initialize
|
||||
* the CRC32 lookup table.
|
||||
*/
|
||||
XZ_EXTERN void xz_crc32_init(void);
|
||||
|
||||
/*
|
||||
* Update CRC32 value using the polynomial from IEEE-802.3. To start a new
|
||||
* calculation, the third argument must be zero. To continue the calculation,
|
||||
* the previously returned value is passed as the third argument.
|
||||
*/
|
||||
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc);
|
||||
#endif
|
||||
|
||||
#if XZ_INTERNAL_CRC64
|
||||
/*
|
||||
* This must be called before any other xz_* function (except xz_crc32_init())
|
||||
* to initialize the CRC64 lookup table.
|
||||
*/
|
||||
XZ_EXTERN void xz_crc64_init(void);
|
||||
|
||||
/*
|
||||
* Update CRC64 value using the polynomial from ECMA-182. To start a new
|
||||
* calculation, the third argument must be zero. To continue the calculation,
|
||||
* the previously returned value is passed as the third argument.
|
||||
*/
|
||||
XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
134
sources/wasm-gc-teavm-loader/c/xz/xz_config.h
Normal file
134
sources/wasm-gc-teavm-loader/c/xz/xz_config.h
Normal file
@ -0,0 +1,134 @@
|
||||
/* SPDX-License-Identifier: 0BSD */
|
||||
|
||||
/*
|
||||
* Private includes and definitions for userspace use of XZ Embedded
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*/
|
||||
|
||||
#ifndef XZ_CONFIG_H
|
||||
#define XZ_CONFIG_H
|
||||
|
||||
/* Uncomment to enable building of xz_dec_catrun(). */
|
||||
/* #define XZ_DEC_CONCATENATED */
|
||||
|
||||
/* Uncomment to enable CRC64 support. */
|
||||
/* #define XZ_USE_CRC64 */
|
||||
|
||||
/* Uncomment as needed to enable BCJ filter decoders. */
|
||||
/* #define XZ_DEC_X86 */
|
||||
/* #define XZ_DEC_ARM */
|
||||
/* #define XZ_DEC_ARMTHUMB */
|
||||
/* #define XZ_DEC_ARM64 */
|
||||
/* #define XZ_DEC_RISCV */
|
||||
/* #define XZ_DEC_POWERPC */
|
||||
/* #define XZ_DEC_IA64 */
|
||||
/* #define XZ_DEC_SPARC */
|
||||
|
||||
/*
|
||||
* Visual Studio 2013 update 2 supports only __inline, not inline.
|
||||
* MSVC v19.0 / VS 2015 and newer support both.
|
||||
*/
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900 && !defined(inline)
|
||||
# define inline __inline
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "xz.h"
|
||||
|
||||
#define kmalloc(size, flags) malloc(size)
|
||||
#define kfree(ptr) free(ptr)
|
||||
#define vmalloc(size) malloc(size)
|
||||
#define vfree(ptr) free(ptr)
|
||||
|
||||
#define memeq(a, b, size) (memcmp(a, b, size) == 0)
|
||||
#define memzero(buf, size) memset(buf, 0, size)
|
||||
|
||||
#ifndef min
|
||||
# define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
#endif
|
||||
#define min_t(type, x, y) min(x, y)
|
||||
|
||||
#ifndef fallthrough
|
||||
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000
|
||||
# define fallthrough [[fallthrough]]
|
||||
# elif defined(__GNUC__) && __GNUC__ >= 7
|
||||
# define fallthrough __attribute__((__fallthrough__))
|
||||
# else
|
||||
# define fallthrough do {} while (0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some functions have been marked with __always_inline to keep the
|
||||
* performance reasonable even when the compiler is optimizing for
|
||||
* small code size. You may be able to save a few bytes by #defining
|
||||
* __always_inline to plain inline, but don't complain if the code
|
||||
* becomes slow.
|
||||
*
|
||||
* NOTE: System headers on GNU/Linux may #define this macro already,
|
||||
* so if you want to change it, you need to #undef it first.
|
||||
*/
|
||||
#ifndef __always_inline
|
||||
# ifdef __GNUC__
|
||||
# define __always_inline \
|
||||
inline __attribute__((__always_inline__))
|
||||
# else
|
||||
# define __always_inline inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Inline functions to access unaligned unsigned 32-bit integers */
|
||||
#ifndef get_unaligned_le32
|
||||
static inline uint32_t get_unaligned_le32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)buf[0]
|
||||
| ((uint32_t)buf[1] << 8)
|
||||
| ((uint32_t)buf[2] << 16)
|
||||
| ((uint32_t)buf[3] << 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef get_unaligned_be32
|
||||
static inline uint32_t get_unaligned_be32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)(buf[0] << 24)
|
||||
| ((uint32_t)buf[1] << 16)
|
||||
| ((uint32_t)buf[2] << 8)
|
||||
| (uint32_t)buf[3];
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef put_unaligned_le32
|
||||
static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)val;
|
||||
buf[1] = (uint8_t)(val >> 8);
|
||||
buf[2] = (uint8_t)(val >> 16);
|
||||
buf[3] = (uint8_t)(val >> 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef put_unaligned_be32
|
||||
static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)(val >> 16);
|
||||
buf[2] = (uint8_t)(val >> 8);
|
||||
buf[3] = (uint8_t)val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use get_unaligned_le32() also for aligned access for simplicity. On
|
||||
* little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
|
||||
* could save a few bytes in code size.
|
||||
*/
|
||||
#ifndef get_le32
|
||||
# define get_le32 get_unaligned_le32
|
||||
#endif
|
||||
|
||||
#endif
|
58
sources/wasm-gc-teavm-loader/c/xz/xz_crc32.c
Normal file
58
sources/wasm-gc-teavm-loader/c/xz/xz_crc32.c
Normal file
@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
|
||||
/*
|
||||
* CRC32 using the polynomial from IEEE-802.3
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <https://7-zip.org/>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is not the fastest implementation, but it is pretty compact.
|
||||
* The fastest versions of xz_crc32() on modern CPUs without hardware
|
||||
* accelerated CRC instruction are 3-5 times as fast as this version,
|
||||
* but they are bigger and use more memory for the lookup table.
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
/*
|
||||
* STATIC_RW_DATA is used in the pre-boot environment on some architectures.
|
||||
* See <linux/decompress/mm.h> for details.
|
||||
*/
|
||||
#ifndef STATIC_RW_DATA
|
||||
# define STATIC_RW_DATA static
|
||||
#endif
|
||||
|
||||
STATIC_RW_DATA uint32_t xz_crc32_table[256];
|
||||
|
||||
XZ_EXTERN void xz_crc32_init(void)
|
||||
{
|
||||
const uint32_t poly = 0xEDB88320;
|
||||
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t r;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
||||
|
||||
xz_crc32_table[i] = r;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
|
||||
{
|
||||
crc = ~crc;
|
||||
|
||||
while (size != 0) {
|
||||
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--size;
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
1343
sources/wasm-gc-teavm-loader/c/xz/xz_dec_lzma2.c
Normal file
1343
sources/wasm-gc-teavm-loader/c/xz/xz_dec_lzma2.c
Normal file
File diff suppressed because it is too large
Load Diff
940
sources/wasm-gc-teavm-loader/c/xz/xz_dec_stream.c
Normal file
940
sources/wasm-gc-teavm-loader/c/xz/xz_dec_stream.c
Normal file
@ -0,0 +1,940 @@
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
|
||||
/*
|
||||
* .xz Stream decoder
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
#include "xz_stream.h"
|
||||
|
||||
#ifdef XZ_USE_CRC64
|
||||
# define IS_CRC64(check_type) ((check_type) == XZ_CHECK_CRC64)
|
||||
#else
|
||||
# define IS_CRC64(check_type) false
|
||||
#endif
|
||||
|
||||
/* Hash used to validate the Index field */
|
||||
struct xz_dec_hash {
|
||||
vli_type unpadded;
|
||||
vli_type uncompressed;
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
struct xz_dec {
|
||||
/* Position in dec_main() */
|
||||
enum {
|
||||
SEQ_STREAM_HEADER,
|
||||
SEQ_BLOCK_START,
|
||||
SEQ_BLOCK_HEADER,
|
||||
SEQ_BLOCK_UNCOMPRESS,
|
||||
SEQ_BLOCK_PADDING,
|
||||
SEQ_BLOCK_CHECK,
|
||||
SEQ_INDEX,
|
||||
SEQ_INDEX_PADDING,
|
||||
SEQ_INDEX_CRC32,
|
||||
SEQ_STREAM_FOOTER,
|
||||
SEQ_STREAM_PADDING
|
||||
} sequence;
|
||||
|
||||
/* Position in variable-length integers and Check fields */
|
||||
uint32_t pos;
|
||||
|
||||
/* Variable-length integer decoded by dec_vli() */
|
||||
vli_type vli;
|
||||
|
||||
/* Saved in_pos and out_pos */
|
||||
size_t in_start;
|
||||
size_t out_start;
|
||||
|
||||
#ifdef XZ_USE_CRC64
|
||||
/* CRC32 or CRC64 value in Block or CRC32 value in Index */
|
||||
uint64_t crc;
|
||||
#else
|
||||
/* CRC32 value in Block or Index */
|
||||
uint32_t crc;
|
||||
#endif
|
||||
|
||||
/* Type of the integrity check calculated from uncompressed data */
|
||||
enum xz_check check_type;
|
||||
|
||||
/* Operation mode */
|
||||
enum xz_mode mode;
|
||||
|
||||
/*
|
||||
* True if the next call to xz_dec_run() is allowed to return
|
||||
* XZ_BUF_ERROR.
|
||||
*/
|
||||
bool allow_buf_error;
|
||||
|
||||
/* Information stored in Block Header */
|
||||
struct {
|
||||
/*
|
||||
* Value stored in the Compressed Size field, or
|
||||
* VLI_UNKNOWN if Compressed Size is not present.
|
||||
*/
|
||||
vli_type compressed;
|
||||
|
||||
/*
|
||||
* Value stored in the Uncompressed Size field, or
|
||||
* VLI_UNKNOWN if Uncompressed Size is not present.
|
||||
*/
|
||||
vli_type uncompressed;
|
||||
|
||||
/* Size of the Block Header field */
|
||||
uint32_t size;
|
||||
} block_header;
|
||||
|
||||
/* Information collected when decoding Blocks */
|
||||
struct {
|
||||
/* Observed compressed size of the current Block */
|
||||
vli_type compressed;
|
||||
|
||||
/* Observed uncompressed size of the current Block */
|
||||
vli_type uncompressed;
|
||||
|
||||
/* Number of Blocks decoded so far */
|
||||
vli_type count;
|
||||
|
||||
/*
|
||||
* Hash calculated from the Block sizes. This is used to
|
||||
* validate the Index field.
|
||||
*/
|
||||
struct xz_dec_hash hash;
|
||||
} block;
|
||||
|
||||
/* Variables needed when verifying the Index field */
|
||||
struct {
|
||||
/* Position in dec_index() */
|
||||
enum {
|
||||
SEQ_INDEX_COUNT,
|
||||
SEQ_INDEX_UNPADDED,
|
||||
SEQ_INDEX_UNCOMPRESSED
|
||||
} sequence;
|
||||
|
||||
/* Size of the Index in bytes */
|
||||
vli_type size;
|
||||
|
||||
/* Number of Records (matches block.count in valid files) */
|
||||
vli_type count;
|
||||
|
||||
/*
|
||||
* Hash calculated from the Records (matches block.hash in
|
||||
* valid files).
|
||||
*/
|
||||
struct xz_dec_hash hash;
|
||||
} index;
|
||||
|
||||
/*
|
||||
* Temporary buffer needed to hold Stream Header, Block Header,
|
||||
* and Stream Footer. The Block Header is the biggest (1 KiB)
|
||||
* so we reserve space according to that. buf[] has to be aligned
|
||||
* to a multiple of four bytes; the size_t variables before it
|
||||
* should guarantee this.
|
||||
*/
|
||||
struct {
|
||||
size_t pos;
|
||||
size_t size;
|
||||
uint8_t buf[1024];
|
||||
} temp;
|
||||
|
||||
struct xz_dec_lzma2 *lzma2;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
struct xz_dec_bcj *bcj;
|
||||
bool bcj_active;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
/* Sizes of the Check field with different Check IDs */
|
||||
static const uint8_t check_sizes[16] = {
|
||||
0,
|
||||
4, 4, 4,
|
||||
8, 8, 8,
|
||||
16, 16, 16,
|
||||
32, 32, 32,
|
||||
64, 64, 64
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
|
||||
* must have set s->temp.pos to indicate how much data we are supposed
|
||||
* to copy into s->temp.buf. Return true once s->temp.pos has reached
|
||||
* s->temp.size.
|
||||
*/
|
||||
static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size = min_t(size_t,
|
||||
b->in_size - b->in_pos, s->temp.size - s->temp.pos);
|
||||
|
||||
memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
|
||||
b->in_pos += copy_size;
|
||||
s->temp.pos += copy_size;
|
||||
|
||||
if (s->temp.pos == s->temp.size) {
|
||||
s->temp.pos = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Decode a variable-length integer (little-endian base-128 encoding) */
|
||||
static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
|
||||
size_t *in_pos, size_t in_size)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
if (s->pos == 0)
|
||||
s->vli = 0;
|
||||
|
||||
while (*in_pos < in_size) {
|
||||
byte = in[*in_pos];
|
||||
++*in_pos;
|
||||
|
||||
s->vli |= (vli_type)(byte & 0x7F) << s->pos;
|
||||
|
||||
if ((byte & 0x80) == 0) {
|
||||
/* Don't allow non-minimal encodings. */
|
||||
if (byte == 0 && s->pos != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->pos = 0;
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
s->pos += 7;
|
||||
if (s->pos == 7 * VLI_BYTES_MAX)
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the Compressed Data field from a Block. Update and validate
|
||||
* the observed compressed and uncompressed sizes of the Block so that
|
||||
* they don't exceed the values possibly stored in the Block Header
|
||||
* (validation assumes that no integer overflow occurs, since vli_type
|
||||
* is normally uint64_t). Update the CRC32 or CRC64 value if presence of
|
||||
* the CRC32 or CRC64 field was indicated in Stream Header.
|
||||
*
|
||||
* Once the decoding is finished, validate that the observed sizes match
|
||||
* the sizes possibly stored in the Block Header. Update the hash and
|
||||
* Block count, which are later used to validate the Index field.
|
||||
*/
|
||||
static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
s->in_start = b->in_pos;
|
||||
s->out_start = b->out_pos;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
if (s->bcj_active)
|
||||
ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
|
||||
else
|
||||
#endif
|
||||
ret = xz_dec_lzma2_run(s->lzma2, b);
|
||||
|
||||
s->block.compressed += b->in_pos - s->in_start;
|
||||
s->block.uncompressed += b->out_pos - s->out_start;
|
||||
|
||||
/*
|
||||
* There is no need to separately check for VLI_UNKNOWN, since
|
||||
* the observed sizes are always smaller than VLI_UNKNOWN.
|
||||
*/
|
||||
if (s->block.compressed > s->block_header.compressed
|
||||
|| s->block.uncompressed
|
||||
> s->block_header.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->check_type == XZ_CHECK_CRC32)
|
||||
s->crc = xz_crc32(b->out + s->out_start,
|
||||
b->out_pos - s->out_start, s->crc);
|
||||
#ifdef XZ_USE_CRC64
|
||||
else if (s->check_type == XZ_CHECK_CRC64)
|
||||
s->crc = xz_crc64(b->out + s->out_start,
|
||||
b->out_pos - s->out_start, s->crc);
|
||||
#endif
|
||||
|
||||
if (ret == XZ_STREAM_END) {
|
||||
if (s->block_header.compressed != VLI_UNKNOWN
|
||||
&& s->block_header.compressed
|
||||
!= s->block.compressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->block_header.uncompressed != VLI_UNKNOWN
|
||||
&& s->block_header.uncompressed
|
||||
!= s->block.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block.hash.unpadded += s->block_header.size
|
||||
+ s->block.compressed;
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
s->block.hash.unpadded += check_sizes[s->check_type];
|
||||
#else
|
||||
if (s->check_type == XZ_CHECK_CRC32)
|
||||
s->block.hash.unpadded += 4;
|
||||
else if (IS_CRC64(s->check_type))
|
||||
s->block.hash.unpadded += 8;
|
||||
#endif
|
||||
|
||||
s->block.hash.uncompressed += s->block.uncompressed;
|
||||
s->block.hash.crc32 = xz_crc32(
|
||||
(const uint8_t *)&s->block.hash,
|
||||
sizeof(s->block.hash), s->block.hash.crc32);
|
||||
|
||||
++s->block.count;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update the Index size and the CRC32 value. */
|
||||
static void index_update(struct xz_dec *s, const struct xz_buf *b)
|
||||
{
|
||||
size_t in_used = b->in_pos - s->in_start;
|
||||
s->index.size += in_used;
|
||||
s->crc = xz_crc32(b->in + s->in_start, in_used, s->crc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the Number of Records, Unpadded Size, and Uncompressed Size
|
||||
* fields from the Index field. That is, Index Padding and CRC32 are not
|
||||
* decoded by this function.
|
||||
*
|
||||
* This can return XZ_OK (more input needed), XZ_STREAM_END (everything
|
||||
* successfully decoded), or XZ_DATA_ERROR (input is corrupt).
|
||||
*/
|
||||
static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
do {
|
||||
ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
|
||||
if (ret != XZ_STREAM_END) {
|
||||
index_update(s, b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (s->index.sequence) {
|
||||
case SEQ_INDEX_COUNT:
|
||||
s->index.count = s->vli;
|
||||
|
||||
/*
|
||||
* Validate that the Number of Records field
|
||||
* indicates the same number of Records as
|
||||
* there were Blocks in the Stream.
|
||||
*/
|
||||
if (s->index.count != s->block.count)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->index.sequence = SEQ_INDEX_UNPADDED;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX_UNPADDED:
|
||||
s->index.hash.unpadded += s->vli;
|
||||
s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX_UNCOMPRESSED:
|
||||
s->index.hash.uncompressed += s->vli;
|
||||
s->index.hash.crc32 = xz_crc32(
|
||||
(const uint8_t *)&s->index.hash,
|
||||
sizeof(s->index.hash),
|
||||
s->index.hash.crc32);
|
||||
--s->index.count;
|
||||
s->index.sequence = SEQ_INDEX_UNPADDED;
|
||||
break;
|
||||
}
|
||||
} while (s->index.count > 0);
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the next four or eight input bytes match the value
|
||||
* of s->crc. s->pos must be zero when starting to validate the first byte.
|
||||
* The "bits" argument allows using the same code for both CRC32 and CRC64.
|
||||
*/
|
||||
static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b,
|
||||
uint32_t bits)
|
||||
{
|
||||
do {
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
if (((s->crc >> s->pos) & 0xFF) != b->in[b->in_pos++])
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->pos += 8;
|
||||
|
||||
} while (s->pos < bits);
|
||||
|
||||
s->crc = 0;
|
||||
s->pos = 0;
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
/*
|
||||
* Skip over the Check field when the Check ID is not supported.
|
||||
* Returns true once the whole Check field has been skipped over.
|
||||
*/
|
||||
static bool check_skip(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
while (s->pos < check_sizes[s->check_type]) {
|
||||
if (b->in_pos == b->in_size)
|
||||
return false;
|
||||
|
||||
++b->in_pos;
|
||||
++s->pos;
|
||||
}
|
||||
|
||||
s->pos = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
|
||||
static enum xz_ret dec_stream_header(struct xz_dec *s)
|
||||
{
|
||||
if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
|
||||
return XZ_FORMAT_ERROR;
|
||||
|
||||
if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
|
||||
!= get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/*
|
||||
* Of integrity checks, we support none (Check ID = 0),
|
||||
* CRC32 (Check ID = 1), and optionally CRC64 (Check ID = 4).
|
||||
* However, if XZ_DEC_ANY_CHECK is defined, we will accept other
|
||||
* check types too, but then the check won't be verified and
|
||||
* a warning (XZ_UNSUPPORTED_CHECK) will be given.
|
||||
*/
|
||||
if (s->temp.buf[HEADER_MAGIC_SIZE + 1] > XZ_CHECK_MAX)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
|
||||
return XZ_UNSUPPORTED_CHECK;
|
||||
#else
|
||||
if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
|
||||
return XZ_OPTIONS_ERROR;
|
||||
#endif
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
|
||||
static enum xz_ret dec_stream_footer(struct xz_dec *s)
|
||||
{
|
||||
if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Validate Backward Size. Note that we never added the size of the
|
||||
* Index CRC32 field to s->index.size, thus we use s->index.size / 4
|
||||
* instead of s->index.size / 4 - 1.
|
||||
*/
|
||||
if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Use XZ_STREAM_END instead of XZ_OK to be more convenient
|
||||
* for the caller.
|
||||
*/
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/* Decode the Block Header and initialize the filter chain. */
|
||||
static enum xz_ret dec_block_header(struct xz_dec *s)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
/*
|
||||
* Validate the CRC32. We know that the temp buffer is at least
|
||||
* eight bytes so this is safe.
|
||||
*/
|
||||
s->temp.size -= 4;
|
||||
if (xz_crc32(s->temp.buf, s->temp.size, 0)
|
||||
!= get_le32(s->temp.buf + s->temp.size))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->temp.pos = 2;
|
||||
|
||||
/*
|
||||
* Catch unsupported Block Flags. We support only one or two filters
|
||||
* in the chain, so we catch that with the same test.
|
||||
*/
|
||||
#ifdef XZ_DEC_BCJ
|
||||
if (s->temp.buf[1] & 0x3E)
|
||||
#else
|
||||
if (s->temp.buf[1] & 0x3F)
|
||||
#endif
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Compressed Size */
|
||||
if (s->temp.buf[1] & 0x40) {
|
||||
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
|
||||
!= XZ_STREAM_END)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block_header.compressed = s->vli;
|
||||
} else {
|
||||
s->block_header.compressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Uncompressed Size */
|
||||
if (s->temp.buf[1] & 0x80) {
|
||||
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
|
||||
!= XZ_STREAM_END)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block_header.uncompressed = s->vli;
|
||||
} else {
|
||||
s->block_header.uncompressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
/* If there are two filters, the first one must be a BCJ filter. */
|
||||
s->bcj_active = s->temp.buf[1] & 0x01;
|
||||
if (s->bcj_active) {
|
||||
if (s->temp.size - s->temp.pos < 2)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We don't support custom start offset,
|
||||
* so Size of Properties must be zero.
|
||||
*/
|
||||
if (s->temp.buf[s->temp.pos++] != 0x00)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Valid Filter Flags always take at least two bytes. */
|
||||
if (s->temp.size - s->temp.pos < 2)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/* Filter ID = LZMA2 */
|
||||
if (s->temp.buf[s->temp.pos++] != 0x21)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Size of Properties = 1-byte Filter Properties */
|
||||
if (s->temp.buf[s->temp.pos++] != 0x01)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Filter Properties contains LZMA2 dictionary size. */
|
||||
if (s->temp.size - s->temp.pos < 1)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/* The rest must be Header Padding. */
|
||||
while (s->temp.pos < s->temp.size)
|
||||
if (s->temp.buf[s->temp.pos++] != 0x00)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
s->temp.pos = 0;
|
||||
s->block.compressed = 0;
|
||||
s->block.uncompressed = 0;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
/*
|
||||
* Store the start position for the case when we are in the middle
|
||||
* of the Index field.
|
||||
*/
|
||||
s->in_start = b->in_pos;
|
||||
|
||||
while (true) {
|
||||
switch (s->sequence) {
|
||||
case SEQ_STREAM_HEADER:
|
||||
/*
|
||||
* Stream Header is copied to s->temp, and then
|
||||
* decoded from there. This way if the caller
|
||||
* gives us only little input at a time, we can
|
||||
* still keep the Stream Header decoding code
|
||||
* simple. Similar approach is used in many places
|
||||
* in this file.
|
||||
*/
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
/*
|
||||
* If dec_stream_header() returns
|
||||
* XZ_UNSUPPORTED_CHECK, it is still possible
|
||||
* to continue decoding if working in multi-call
|
||||
* mode. Thus, update s->sequence before calling
|
||||
* dec_stream_header().
|
||||
*/
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
|
||||
ret = dec_stream_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_START:
|
||||
/* We need one byte of input to continue. */
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
/* See if this is the beginning of the Index field. */
|
||||
if (b->in[b->in_pos] == 0) {
|
||||
s->in_start = b->in_pos++;
|
||||
s->sequence = SEQ_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the size of the Block Header and
|
||||
* prepare to decode it.
|
||||
*/
|
||||
s->block_header.size
|
||||
= ((uint32_t)b->in[b->in_pos] + 1) * 4;
|
||||
|
||||
s->temp.size = s->block_header.size;
|
||||
s->temp.pos = 0;
|
||||
s->sequence = SEQ_BLOCK_HEADER;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_HEADER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
ret = dec_block_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_UNCOMPRESS;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_UNCOMPRESS:
|
||||
ret = dec_block(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_PADDING;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_PADDING:
|
||||
/*
|
||||
* Size of Compressed Data + Block Padding
|
||||
* must be a multiple of four. We don't need
|
||||
* s->block.compressed for anything else
|
||||
* anymore, so we use it here to test the size
|
||||
* of the Block Padding field.
|
||||
*/
|
||||
while (s->block.compressed & 3) {
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
if (b->in[b->in_pos++] != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
++s->block.compressed;
|
||||
}
|
||||
|
||||
s->sequence = SEQ_BLOCK_CHECK;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SEQ_BLOCK_CHECK:
|
||||
if (s->check_type == XZ_CHECK_CRC32) {
|
||||
ret = crc_validate(s, b, 32);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
}
|
||||
else if (IS_CRC64(s->check_type)) {
|
||||
ret = crc_validate(s, b, 64);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
}
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
else if (!check_skip(s, b)) {
|
||||
return XZ_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX:
|
||||
ret = dec_index(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_INDEX_PADDING;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SEQ_INDEX_PADDING:
|
||||
while ((s->index.size + (b->in_pos - s->in_start))
|
||||
& 3) {
|
||||
if (b->in_pos == b->in_size) {
|
||||
index_update(s, b);
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
if (b->in[b->in_pos++] != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Finish the CRC32 value and Index size. */
|
||||
index_update(s, b);
|
||||
|
||||
/* Compare the hashes to validate the Index field. */
|
||||
if (!memeq(&s->block.hash, &s->index.hash,
|
||||
sizeof(s->block.hash)))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->sequence = SEQ_INDEX_CRC32;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SEQ_INDEX_CRC32:
|
||||
ret = crc_validate(s, b, 32);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
s->sequence = SEQ_STREAM_FOOTER;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SEQ_STREAM_FOOTER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
return dec_stream_footer(s);
|
||||
|
||||
case SEQ_STREAM_PADDING:
|
||||
/* Never reached, only silencing a warning */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached */
|
||||
}
|
||||
|
||||
/*
|
||||
* xz_dec_run() is a wrapper for dec_main() to handle some special cases in
|
||||
* multi-call and single-call decoding.
|
||||
*
|
||||
* In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
|
||||
* are not going to make any progress anymore. This is to prevent the caller
|
||||
* from calling us infinitely when the input file is truncated or otherwise
|
||||
* corrupt. Since zlib-style API allows that the caller fills the input buffer
|
||||
* only when the decoder doesn't produce any new output, we have to be careful
|
||||
* to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
|
||||
* after the second consecutive call to xz_dec_run() that makes no progress.
|
||||
*
|
||||
* In single-call mode, if we couldn't decode everything and no error
|
||||
* occurred, either the input is truncated or the output buffer is too small.
|
||||
* Since we know that the last input byte never produces any output, we know
|
||||
* that if all the input was consumed and decoding wasn't finished, the file
|
||||
* must be corrupt. Otherwise the output buffer has to be too small or the
|
||||
* file is corrupt in a way that decoding it produces too big output.
|
||||
*
|
||||
* If single-call decoding fails, we reset b->in_pos and b->out_pos back to
|
||||
* their original values. This is because with some filter chains there won't
|
||||
* be any valid uncompressed data in the output buffer unless the decoding
|
||||
* actually succeeds (that's the price to pay of using the output buffer as
|
||||
* the workspace).
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
size_t in_start;
|
||||
size_t out_start;
|
||||
enum xz_ret ret;
|
||||
|
||||
if (DEC_IS_SINGLE(s->mode))
|
||||
xz_dec_reset(s);
|
||||
|
||||
in_start = b->in_pos;
|
||||
out_start = b->out_pos;
|
||||
ret = dec_main(s, b);
|
||||
|
||||
if (DEC_IS_SINGLE(s->mode)) {
|
||||
if (ret == XZ_OK)
|
||||
ret = b->in_pos == b->in_size
|
||||
? XZ_DATA_ERROR : XZ_BUF_ERROR;
|
||||
|
||||
if (ret != XZ_STREAM_END) {
|
||||
b->in_pos = in_start;
|
||||
b->out_pos = out_start;
|
||||
}
|
||||
|
||||
} else if (ret == XZ_OK && in_start == b->in_pos
|
||||
&& out_start == b->out_pos) {
|
||||
if (s->allow_buf_error)
|
||||
ret = XZ_BUF_ERROR;
|
||||
|
||||
s->allow_buf_error = true;
|
||||
} else {
|
||||
s->allow_buf_error = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef XZ_DEC_CONCATENATED
|
||||
XZ_EXTERN enum xz_ret xz_dec_catrun(struct xz_dec *s, struct xz_buf *b,
|
||||
int finish)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
if (DEC_IS_SINGLE(s->mode)) {
|
||||
xz_dec_reset(s);
|
||||
finish = true;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (s->sequence == SEQ_STREAM_PADDING) {
|
||||
/*
|
||||
* Skip Stream Padding. Its size must be a multiple
|
||||
* of four bytes which is tracked with s->pos.
|
||||
*/
|
||||
while (true) {
|
||||
if (b->in_pos == b->in_size) {
|
||||
/*
|
||||
* Note that if we are repeatedly
|
||||
* given no input and finish is false,
|
||||
* we will keep returning XZ_OK even
|
||||
* though no progress is being made.
|
||||
* The lack of XZ_BUF_ERROR support
|
||||
* isn't a problem here because a
|
||||
* reasonable caller will eventually
|
||||
* provide more input or set finish
|
||||
* to true.
|
||||
*/
|
||||
if (!finish)
|
||||
return XZ_OK;
|
||||
|
||||
if (s->pos != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
if (b->in[b->in_pos] != 0x00) {
|
||||
if (s->pos != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
++b->in_pos;
|
||||
s->pos = (s->pos + 1) & 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* More input remains. It should be a new Stream.
|
||||
*
|
||||
* In single-call mode xz_dec_run() will always call
|
||||
* xz_dec_reset(). Thus, we need to do it here only
|
||||
* in multi-call mode.
|
||||
*/
|
||||
if (DEC_IS_MULTI(s->mode))
|
||||
xz_dec_reset(s);
|
||||
}
|
||||
|
||||
ret = xz_dec_run(s, b);
|
||||
|
||||
if (ret != XZ_STREAM_END)
|
||||
break;
|
||||
|
||||
s->sequence = SEQ_STREAM_PADDING;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
|
||||
{
|
||||
struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
s->mode = mode;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
|
||||
if (s->bcj == NULL)
|
||||
goto error_bcj;
|
||||
#endif
|
||||
|
||||
s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
|
||||
if (s->lzma2 == NULL)
|
||||
goto error_lzma2;
|
||||
|
||||
xz_dec_reset(s);
|
||||
return s;
|
||||
|
||||
error_lzma2:
|
||||
#ifdef XZ_DEC_BCJ
|
||||
xz_dec_bcj_end(s->bcj);
|
||||
error_bcj:
|
||||
#endif
|
||||
kfree(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XZ_EXTERN void xz_dec_reset(struct xz_dec *s)
|
||||
{
|
||||
s->sequence = SEQ_STREAM_HEADER;
|
||||
s->allow_buf_error = false;
|
||||
s->pos = 0;
|
||||
s->crc = 0;
|
||||
memzero(&s->block, sizeof(s->block));
|
||||
memzero(&s->index, sizeof(s->index));
|
||||
s->temp.pos = 0;
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
}
|
||||
|
||||
XZ_EXTERN void xz_dec_end(struct xz_dec *s)
|
||||
{
|
||||
if (s != NULL) {
|
||||
xz_dec_lzma2_end(s->lzma2);
|
||||
#ifdef XZ_DEC_BCJ
|
||||
xz_dec_bcj_end(s->bcj);
|
||||
#endif
|
||||
kfree(s);
|
||||
}
|
||||
}
|
203
sources/wasm-gc-teavm-loader/c/xz/xz_lzma2.h
Normal file
203
sources/wasm-gc-teavm-loader/c/xz/xz_lzma2.h
Normal file
@ -0,0 +1,203 @@
|
||||
/* SPDX-License-Identifier: 0BSD */
|
||||
|
||||
/*
|
||||
* LZMA2 definitions
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <https://7-zip.org/>
|
||||
*/
|
||||
|
||||
#ifndef XZ_LZMA2_H
|
||||
#define XZ_LZMA2_H
|
||||
|
||||
/* Range coder constants */
|
||||
#define RC_SHIFT_BITS 8
|
||||
#define RC_TOP_BITS 24
|
||||
#define RC_TOP_VALUE (1 << RC_TOP_BITS)
|
||||
#define RC_BIT_MODEL_TOTAL_BITS 11
|
||||
#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
|
||||
#define RC_MOVE_BITS 5
|
||||
|
||||
/*
|
||||
* Maximum number of position states. A position state is the lowest pb
|
||||
* number of bits of the current uncompressed offset. In some places there
|
||||
* are different sets of probabilities for different position states.
|
||||
*/
|
||||
#define POS_STATES_MAX (1 << 4)
|
||||
|
||||
/*
|
||||
* This enum is used to track which LZMA symbols have occurred most recently
|
||||
* and in which order. This information is used to predict the next symbol.
|
||||
*
|
||||
* Symbols:
|
||||
* - Literal: One 8-bit byte
|
||||
* - Match: Repeat a chunk of data at some distance
|
||||
* - Long repeat: Multi-byte match at a recently seen distance
|
||||
* - Short repeat: One-byte repeat at a recently seen distance
|
||||
*
|
||||
* The symbol names are in from STATE_oldest_older_previous. REP means
|
||||
* either short or long repeated match, and NONLIT means any non-literal.
|
||||
*/
|
||||
enum lzma_state {
|
||||
STATE_LIT_LIT,
|
||||
STATE_MATCH_LIT_LIT,
|
||||
STATE_REP_LIT_LIT,
|
||||
STATE_SHORTREP_LIT_LIT,
|
||||
STATE_MATCH_LIT,
|
||||
STATE_REP_LIT,
|
||||
STATE_SHORTREP_LIT,
|
||||
STATE_LIT_MATCH,
|
||||
STATE_LIT_LONGREP,
|
||||
STATE_LIT_SHORTREP,
|
||||
STATE_NONLIT_MATCH,
|
||||
STATE_NONLIT_REP
|
||||
};
|
||||
|
||||
/* Total number of states */
|
||||
#define STATES 12
|
||||
|
||||
/* The lowest 7 states indicate that the previous state was a literal. */
|
||||
#define LIT_STATES 7
|
||||
|
||||
/* Indicate that the latest symbol was a literal. */
|
||||
static inline void lzma_state_literal(enum lzma_state *state)
|
||||
{
|
||||
if (*state <= STATE_SHORTREP_LIT_LIT)
|
||||
*state = STATE_LIT_LIT;
|
||||
else if (*state <= STATE_LIT_SHORTREP)
|
||||
*state -= 3;
|
||||
else
|
||||
*state -= 6;
|
||||
}
|
||||
|
||||
/* Indicate that the latest symbol was a match. */
|
||||
static inline void lzma_state_match(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
|
||||
}
|
||||
|
||||
/* Indicate that the latest state was a long repeated match. */
|
||||
static inline void lzma_state_long_rep(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
|
||||
}
|
||||
|
||||
/* Indicate that the latest symbol was a short match. */
|
||||
static inline void lzma_state_short_rep(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
|
||||
}
|
||||
|
||||
/* Test if the previous symbol was a literal. */
|
||||
static inline bool lzma_state_is_literal(enum lzma_state state)
|
||||
{
|
||||
return state < LIT_STATES;
|
||||
}
|
||||
|
||||
/* Each literal coder is divided in three sections:
|
||||
* - 0x001-0x0FF: Without match byte
|
||||
* - 0x101-0x1FF: With match byte; match bit is 0
|
||||
* - 0x201-0x2FF: With match byte; match bit is 1
|
||||
*
|
||||
* Match byte is used when the previous LZMA symbol was something else than
|
||||
* a literal (that is, it was some kind of match).
|
||||
*/
|
||||
#define LITERAL_CODER_SIZE 0x300
|
||||
|
||||
/* Maximum number of literal coders */
|
||||
#define LITERAL_CODERS_MAX (1 << 4)
|
||||
|
||||
/* Minimum length of a match is two bytes. */
|
||||
#define MATCH_LEN_MIN 2
|
||||
|
||||
/* Match length is encoded with 4, 5, or 10 bits.
|
||||
*
|
||||
* Length Bits
|
||||
* 2-9 4 = Choice=0 + 3 bits
|
||||
* 10-17 5 = Choice=1 + Choice2=0 + 3 bits
|
||||
* 18-273 10 = Choice=1 + Choice2=1 + 8 bits
|
||||
*/
|
||||
#define LEN_LOW_BITS 3
|
||||
#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
|
||||
#define LEN_MID_BITS 3
|
||||
#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
|
||||
#define LEN_HIGH_BITS 8
|
||||
#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
|
||||
#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
|
||||
|
||||
/*
|
||||
* Maximum length of a match is 273 which is a result of the encoding
|
||||
* described above.
|
||||
*/
|
||||
#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
|
||||
|
||||
/*
|
||||
* Different sets of probabilities are used for match distances that have
|
||||
* very short match length: Lengths of 2, 3, and 4 bytes have a separate
|
||||
* set of probabilities for each length. The matches with longer length
|
||||
* use a shared set of probabilities.
|
||||
*/
|
||||
#define DIST_STATES 4
|
||||
|
||||
/*
|
||||
* Get the index of the appropriate probability array for decoding
|
||||
* the distance slot.
|
||||
*/
|
||||
static inline uint32_t lzma_get_dist_state(uint32_t len)
|
||||
{
|
||||
return len < DIST_STATES + MATCH_LEN_MIN
|
||||
? len - MATCH_LEN_MIN : DIST_STATES - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The highest two bits of a 32-bit match distance are encoded using six bits.
|
||||
* This six-bit value is called a distance slot. This way encoding a 32-bit
|
||||
* value takes 6-36 bits, larger values taking more bits.
|
||||
*/
|
||||
#define DIST_SLOT_BITS 6
|
||||
#define DIST_SLOTS (1 << DIST_SLOT_BITS)
|
||||
|
||||
/* Match distances up to 127 are fully encoded using probabilities. Since
|
||||
* the highest two bits (distance slot) are always encoded using six bits,
|
||||
* the distances 0-3 don't need any additional bits to encode, since the
|
||||
* distance slot itself is the same as the actual distance. DIST_MODEL_START
|
||||
* indicates the first distance slot where at least one additional bit is
|
||||
* needed.
|
||||
*/
|
||||
#define DIST_MODEL_START 4
|
||||
|
||||
/*
|
||||
* Match distances greater than 127 are encoded in three pieces:
|
||||
* - distance slot: the highest two bits
|
||||
* - direct bits: 2-26 bits below the highest two bits
|
||||
* - alignment bits: four lowest bits
|
||||
*
|
||||
* Direct bits don't use any probabilities.
|
||||
*
|
||||
* The distance slot value of 14 is for distances 128-191.
|
||||
*/
|
||||
#define DIST_MODEL_END 14
|
||||
|
||||
/* Distance slots that indicate a distance <= 127. */
|
||||
#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
|
||||
#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
|
||||
|
||||
/*
|
||||
* For match distances greater than 127, only the highest two bits and the
|
||||
* lowest four bits (alignment) is encoded using probabilities.
|
||||
*/
|
||||
#define ALIGN_BITS 4
|
||||
#define ALIGN_SIZE (1 << ALIGN_BITS)
|
||||
#define ALIGN_MASK (ALIGN_SIZE - 1)
|
||||
|
||||
/* Total number of all probability variables */
|
||||
#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
|
||||
|
||||
/*
|
||||
* LZMA remembers the four most recent match distances. Reusing these
|
||||
* distances tends to take less space than re-encoding the actual
|
||||
* distance value.
|
||||
*/
|
||||
#define REPS 4
|
||||
|
||||
#endif
|
165
sources/wasm-gc-teavm-loader/c/xz/xz_private.h
Normal file
165
sources/wasm-gc-teavm-loader/c/xz/xz_private.h
Normal file
@ -0,0 +1,165 @@
|
||||
/* SPDX-License-Identifier: 0BSD */
|
||||
|
||||
/*
|
||||
* Private includes and definitions
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*/
|
||||
|
||||
#ifndef XZ_PRIVATE_H
|
||||
#define XZ_PRIVATE_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/xz.h>
|
||||
# include <linux/kernel.h>
|
||||
# include <asm/unaligned.h>
|
||||
/* XZ_PREBOOT may be defined only via decompress_unxz.c. */
|
||||
# ifndef XZ_PREBOOT
|
||||
# include <linux/slab.h>
|
||||
# include <linux/vmalloc.h>
|
||||
# include <linux/string.h>
|
||||
# ifdef CONFIG_XZ_DEC_X86
|
||||
# define XZ_DEC_X86
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_POWERPC
|
||||
# define XZ_DEC_POWERPC
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_IA64
|
||||
# define XZ_DEC_IA64
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_ARM
|
||||
# define XZ_DEC_ARM
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_ARMTHUMB
|
||||
# define XZ_DEC_ARMTHUMB
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_SPARC
|
||||
# define XZ_DEC_SPARC
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_ARM64
|
||||
# define XZ_DEC_ARM64
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_RISCV
|
||||
# define XZ_DEC_RISCV
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_MICROLZMA
|
||||
# define XZ_DEC_MICROLZMA
|
||||
# endif
|
||||
# define memeq(a, b, size) (memcmp(a, b, size) == 0)
|
||||
# define memzero(buf, size) memset(buf, 0, size)
|
||||
# endif
|
||||
# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
|
||||
#else
|
||||
/*
|
||||
* For userspace builds, use a separate header to define the required
|
||||
* macros and functions. This makes it easier to adapt the code into
|
||||
* different environments and avoids clutter in the Linux kernel tree.
|
||||
*/
|
||||
# include "xz_config.h"
|
||||
#endif
|
||||
|
||||
/* If no specific decoding mode is requested, enable support for all modes. */
|
||||
#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
|
||||
&& !defined(XZ_DEC_DYNALLOC)
|
||||
# define XZ_DEC_SINGLE
|
||||
# define XZ_DEC_PREALLOC
|
||||
# define XZ_DEC_DYNALLOC
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The DEC_IS_foo(mode) macros are used in "if" statements. If only some
|
||||
* of the supported modes are enabled, these macros will evaluate to true or
|
||||
* false at compile time and thus allow the compiler to omit unneeded code.
|
||||
*/
|
||||
#ifdef XZ_DEC_SINGLE
|
||||
# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE)
|
||||
#else
|
||||
# define DEC_IS_SINGLE(mode) (false)
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_PREALLOC
|
||||
# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC)
|
||||
#else
|
||||
# define DEC_IS_PREALLOC(mode) (false)
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_DYNALLOC
|
||||
# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC)
|
||||
#else
|
||||
# define DEC_IS_DYNALLOC(mode) (false)
|
||||
#endif
|
||||
|
||||
#if !defined(XZ_DEC_SINGLE)
|
||||
# define DEC_IS_MULTI(mode) (true)
|
||||
#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC)
|
||||
# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE)
|
||||
#else
|
||||
# define DEC_IS_MULTI(mode) (false)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
|
||||
* XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
|
||||
*/
|
||||
#ifndef XZ_DEC_BCJ
|
||||
# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
|
||||
|| defined(XZ_DEC_IA64) \
|
||||
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|
||||
|| defined(XZ_DEC_SPARC) || defined(XZ_DEC_ARM64) \
|
||||
|| defined(XZ_DEC_RISCV)
|
||||
# define XZ_DEC_BCJ
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
|
||||
* before calling xz_dec_lzma2_run().
|
||||
*/
|
||||
XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
|
||||
uint32_t dict_max);
|
||||
|
||||
/*
|
||||
* Decode the LZMA2 properties (one byte) and reset the decoder. Return
|
||||
* XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
|
||||
* big enough, and XZ_OPTIONS_ERROR if props indicates something that this
|
||||
* decoder doesn't support.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s,
|
||||
uint8_t props);
|
||||
|
||||
/* Decode raw LZMA2 stream from b->in to b->out. */
|
||||
XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
|
||||
struct xz_buf *b);
|
||||
|
||||
/* Free the memory allocated for the LZMA2 decoder. */
|
||||
XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
/*
|
||||
* Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
|
||||
* calling xz_dec_bcj_run().
|
||||
*/
|
||||
XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call);
|
||||
|
||||
/*
|
||||
* Decode the Filter ID of a BCJ filter. This implementation doesn't
|
||||
* support custom start offsets, so no decoding of Filter Properties
|
||||
* is needed. Returns XZ_OK if the given Filter ID is supported.
|
||||
* Otherwise XZ_OPTIONS_ERROR is returned.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id);
|
||||
|
||||
/*
|
||||
* Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
|
||||
* a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
|
||||
* must be called directly.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
|
||||
struct xz_dec_lzma2 *lzma2,
|
||||
struct xz_buf *b);
|
||||
|
||||
/* Free the memory allocated for the BCJ filters. */
|
||||
#define xz_dec_bcj_end(s) kfree(s)
|
||||
#endif
|
||||
|
||||
#endif
|
61
sources/wasm-gc-teavm-loader/c/xz/xz_stream.h
Normal file
61
sources/wasm-gc-teavm-loader/c/xz/xz_stream.h
Normal file
@ -0,0 +1,61 @@
|
||||
/* SPDX-License-Identifier: 0BSD */
|
||||
|
||||
/*
|
||||
* Definitions for handling the .xz file format
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*/
|
||||
|
||||
#ifndef XZ_STREAM_H
|
||||
#define XZ_STREAM_H
|
||||
|
||||
#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32
|
||||
# include <linux/crc32.h>
|
||||
# undef crc32
|
||||
# define xz_crc32(buf, size, crc) \
|
||||
(~crc32_le(~(uint32_t)(crc), buf, size))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* See the .xz file format specification at
|
||||
* https://tukaani.org/xz/xz-file-format.txt
|
||||
* to understand the container format.
|
||||
*/
|
||||
|
||||
#define STREAM_HEADER_SIZE 12
|
||||
|
||||
#define HEADER_MAGIC "\3757zXZ"
|
||||
#define HEADER_MAGIC_SIZE 6
|
||||
|
||||
#define FOOTER_MAGIC "YZ"
|
||||
#define FOOTER_MAGIC_SIZE 2
|
||||
|
||||
/*
|
||||
* Variable-length integer can hold a 63-bit unsigned integer or a special
|
||||
* value indicating that the value is unknown.
|
||||
*
|
||||
* Experimental: vli_type can be defined to uint32_t to save a few bytes
|
||||
* in code size (no effect on speed). Doing so limits the uncompressed and
|
||||
* compressed size of the file to less than 256 MiB and may also weaken
|
||||
* error detection slightly.
|
||||
*/
|
||||
typedef uint64_t vli_type;
|
||||
|
||||
#define VLI_MAX ((vli_type)-1 / 2)
|
||||
#define VLI_UNKNOWN ((vli_type)-1)
|
||||
|
||||
/* Maximum encoded size of a VLI */
|
||||
#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
|
||||
|
||||
/* Integrity Check types */
|
||||
enum xz_check {
|
||||
XZ_CHECK_NONE = 0,
|
||||
XZ_CHECK_CRC32 = 1,
|
||||
XZ_CHECK_CRC64 = 4,
|
||||
XZ_CHECK_SHA256 = 10
|
||||
};
|
||||
|
||||
/* Maximum possible Check ID */
|
||||
#define XZ_CHECK_MAX 15
|
||||
|
||||
#endif
|
180
sources/wasm-gc-teavm-loader/js/library.js
Normal file
180
sources/wasm-gc-teavm-loader/js/library.js
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
addToLibrary({
|
||||
getJSPISupported: function() {
|
||||
return (typeof WebAssembly.Suspending !== "undefined");
|
||||
},
|
||||
getEPWLength: function() {
|
||||
return epwFile.byteLength;
|
||||
},
|
||||
memcpyFromEPW: function(dest, off, len) {
|
||||
HEAPU8.set(new Uint8Array(epwFile, off, len), dest);
|
||||
},
|
||||
initResult: function(bufLen) {
|
||||
const id = results.length;
|
||||
results.push(new Uint8Array(bufLen));
|
||||
return id;
|
||||
},
|
||||
memcpyToResult: function(bufId, src, off, len) {
|
||||
results[bufId].set(new Uint8Array(HEAPU8.buffer, src, len), off);
|
||||
},
|
||||
memcpyFromEPWToResult: function(bufId, dest, off, len) {
|
||||
results[bufId].set(new Uint8Array(epwFile, off, len), dest);
|
||||
},
|
||||
initEPWStringResult: function(off, len) {
|
||||
const id = results.length;
|
||||
results.push(UTF8Decoder.decode(new Uint8Array(epwFile, off, len)));
|
||||
return id;
|
||||
},
|
||||
resultFailed: function(msg) {
|
||||
const parentElement = createCrashParentElement();
|
||||
|
||||
const messageContainer = document.createElement("div");
|
||||
messageContainer.setAttribute("style", "z-index:100;position:absolute;top:10%;left:10%;right:10%;bottom:10%;background-color:white;border:2px solid #cccccc;overflow-x:hidden;overflow-y:scroll;");
|
||||
messageContainer.classList.add("_eaglercraftX_loader_failed_container");
|
||||
|
||||
const failMsg = UTF8ToString(msg);
|
||||
console.error("LoaderMain: [FAILED] " + failMsg);
|
||||
|
||||
const failureMsgElement = document.createElement("h2");
|
||||
failureMsgElement.style.color = "#AA0000";
|
||||
failureMsgElement.style.padding = "25px";
|
||||
failureMsgElement.style.fontFamily = "sans-serif";
|
||||
failureMsgElement.style["marginBlock"] = "0px";
|
||||
failureMsgElement.appendChild(document.createTextNode(failMsg));
|
||||
messageContainer.appendChild(failureMsgElement);
|
||||
|
||||
const failureMsgElement2 = document.createElement("h4");
|
||||
failureMsgElement2.style.color = "#AA0000";
|
||||
failureMsgElement2.style.padding = "25px";
|
||||
failureMsgElement2.style.fontFamily = "sans-serif";
|
||||
failureMsgElement2.style["marginBlock"] = "0px";
|
||||
failureMsgElement2.appendChild(document.createTextNode("Try again later"));
|
||||
messageContainer.appendChild(failureMsgElement2);
|
||||
|
||||
parentElement.appendChild(messageContainer);
|
||||
},
|
||||
resultSuccess: function(result) {
|
||||
const idx = result >> 2;
|
||||
|
||||
const eagRuntimeJSURL = URL.createObjectURL(new Blob([results[HEAP32[idx]]], { type: "text/javascript;charset=utf-8" }));
|
||||
const classesWASMURL = URL.createObjectURL(new Blob([results[HEAP32[idx + 1]]], { type: "application/wasm" }));
|
||||
const classesDeobfTEADBGURL = URL.createObjectURL(new Blob([results[HEAP32[idx + 2]]], { type: "application/octet-stream" }));
|
||||
const classesDeobfWASMURL = URL.createObjectURL(new Blob([results[HEAP32[idx + 3]]], { type: "application/wasm" }));
|
||||
|
||||
const pressAnyKey = URL.createObjectURL(new Blob([results[HEAP32[idx + 4]]], { type: results[HEAP32[idx + 5]] }));
|
||||
const crashImg = URL.createObjectURL(new Blob([results[HEAP32[idx + 6]]], { type: results[HEAP32[idx + 7]] }));
|
||||
const faviconImg = URL.createObjectURL(new Blob([results[HEAP32[idx + 8]]], { type: results[HEAP32[idx + 9]] }));
|
||||
|
||||
const numEPKs = HEAP32[idx + 10];
|
||||
const epkFiles = new Array(numEPKs);
|
||||
for(var i = 0, j; i < numEPKs; ++i) {
|
||||
j = idx + 11 + i * 3;
|
||||
epkFiles[i] = {
|
||||
data: results[HEAP32[j]],
|
||||
name: results[HEAP32[j + 1]],
|
||||
path: results[HEAP32[j + 2]]
|
||||
};
|
||||
}
|
||||
|
||||
results.length = 0;
|
||||
|
||||
window.__eaglercraftXLoaderContext = {
|
||||
getEaglercraftXOpts: function() {
|
||||
return optsObj;
|
||||
},
|
||||
getEagRuntimeJSURL: function() {
|
||||
return eagRuntimeJSURL;
|
||||
},
|
||||
getClassesWASMURL: function() {
|
||||
return classesWASMURL;
|
||||
},
|
||||
getClassesDeobfWASMURL: function() {
|
||||
return classesDeobfWASMURL;
|
||||
},
|
||||
getClassesTEADBGURL: function() {
|
||||
return classesDeobfTEADBGURL;
|
||||
},
|
||||
getEPKFiles: function() {
|
||||
return epkFiles;
|
||||
},
|
||||
getRootElement: function() {
|
||||
return rootElement;
|
||||
},
|
||||
getMainArgs: function() {
|
||||
return [];
|
||||
},
|
||||
getImageURL: function(idx) {
|
||||
switch(idx) {
|
||||
case 0:
|
||||
return splashURL;
|
||||
case 1:
|
||||
return pressAnyKey;
|
||||
case 2:
|
||||
return crashImg;
|
||||
case 3:
|
||||
return faviconImg;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
runMain: function(fn) {
|
||||
setTimeout(fn, 10);
|
||||
}
|
||||
};
|
||||
|
||||
const scriptElement = document.createElement("script");
|
||||
scriptElement.type = "text/javascript";
|
||||
scriptElement.src = eagRuntimeJSURL;
|
||||
document.head.appendChild(scriptElement);
|
||||
},
|
||||
resultJSPIUnsupported: function(result) {
|
||||
const idx = result >> 2;
|
||||
|
||||
const crashImgData = results[HEAP32[idx]];
|
||||
const crashImgMIME = results[HEAP32[idx + 1]];
|
||||
const crashImg = crashImgData ? URL.createObjectURL(new Blob([crashImgData], { type: (crashImgMIME || "image/png") })) : null;
|
||||
|
||||
const markupData = results[HEAP32[idx + 2]];
|
||||
const markup = markupData ? UTF8Decoder.decode(markupData) : "<h1>Failed to load error screen</h1>";
|
||||
|
||||
const parentElement = createCrashParentElement();
|
||||
|
||||
const img = document.createElement("img");
|
||||
img.setAttribute("style", "z-index:100;position:absolute;top:10px;left:calc(50% - 151px);");
|
||||
img.src = crashImg;
|
||||
parentElement.appendChild(img);
|
||||
|
||||
const iframeContainer = document.createElement("div");
|
||||
iframeContainer.setAttribute("style", "z-index:100;position:absolute;top:135px;left:10%;right:10%;bottom:50px;background-color:white;border:2px solid #cccccc;");
|
||||
iframeContainer.classList.add("_eaglercraftX_jspi_unsupported_container");
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.classList.add("_eaglercraftX_jspi_unsupported_frame");
|
||||
iframe.setAttribute("style", "border:none;width:100%;height:100%;");
|
||||
iframe.srcdoc = markup;
|
||||
|
||||
iframeContainer.appendChild(iframe);
|
||||
parentElement.appendChild(iframeContainer);
|
||||
},
|
||||
dbgLog: function(msg) {
|
||||
console.log("LoaderMain: [INFO] " + UTF8ToString(msg));
|
||||
},
|
||||
dbgErr: function(msg) {
|
||||
console.error("LoaderMain: [ERROR] " + UTF8ToString(msg));
|
||||
}
|
||||
});
|
61
sources/wasm-gc-teavm-loader/js/pre.js
Normal file
61
sources/wasm-gc-teavm-loader/js/pre.js
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
Module["locateFile"] = function(path) {
|
||||
if(path === "loader.wasm") {
|
||||
return window.__eaglercraftXLoaderContextPre.loaderWASMURL;
|
||||
}else {
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
const rootElement = window.__eaglercraftXLoaderContextPre.rootElement;
|
||||
const optsObj = window.__eaglercraftXLoaderContextPre.eaglercraftXOpts;
|
||||
const epwFile = window.__eaglercraftXLoaderContextPre.theEPWFileBuffer;
|
||||
const splashURL = window.__eaglercraftXLoaderContextPre.splashURL;
|
||||
|
||||
const results = [ null ];
|
||||
|
||||
function createCrashParentElement() {
|
||||
var oldSplash = null;
|
||||
|
||||
var node;
|
||||
while(node = rootElement.lastChild) {
|
||||
if(!oldSplash) {
|
||||
oldSplash = node;
|
||||
}
|
||||
rootElement.removeChild(node);
|
||||
}
|
||||
|
||||
const parentElement = document.createElement("div");
|
||||
parentElement.classList.add("_eaglercraftX_wrapper_element");
|
||||
parentElement.setAttribute("style", "position:relative;width:100%;height:100%;overflow:hidden;");
|
||||
|
||||
if(oldSplash) {
|
||||
oldSplash.classList.add("_eaglercraftX_early_splash_element");
|
||||
oldSplash.style.position = "absolute";
|
||||
oldSplash.style.top = "0px";
|
||||
oldSplash.style.left = "0px";
|
||||
oldSplash.style.right = "0px";
|
||||
oldSplash.style.bottom = "0px";
|
||||
oldSplash.style.zIndex = "2";
|
||||
parentElement.appendChild(oldSplash);
|
||||
}
|
||||
|
||||
rootElement.appendChild(parentElement);
|
||||
|
||||
return parentElement;
|
||||
}
|
293
sources/wasm-gc-teavm/java/com/jcraft/jogg/Buffer.java
Normal file
293
sources/wasm-gc-teavm/java/com/jcraft/jogg/Buffer.java
Normal file
@ -0,0 +1,293 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jogg;
|
||||
|
||||
public class Buffer {
|
||||
private static final int BUFFER_INCREMENT = 256;
|
||||
|
||||
private static final int[] mask = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f,
|
||||
0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
|
||||
0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
|
||||
0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
|
||||
0xffffffff };
|
||||
|
||||
int ptr = 0;
|
||||
byte[] buffer = null;
|
||||
int endbit = 0;
|
||||
int endbyte = 0;
|
||||
int storage = 0;
|
||||
|
||||
public void writeinit() {
|
||||
buffer = new byte[BUFFER_INCREMENT];
|
||||
ptr = 0;
|
||||
buffer[0] = (byte) '\0';
|
||||
storage = BUFFER_INCREMENT;
|
||||
}
|
||||
|
||||
public void write(byte[] s) {
|
||||
for (int i = 0; i < s.length; i++) {
|
||||
if (s[i] == 0)
|
||||
break;
|
||||
write(s[i], 8);
|
||||
}
|
||||
}
|
||||
|
||||
public void read(byte[] s, int bytes) {
|
||||
int i = 0;
|
||||
while (bytes-- != 0) {
|
||||
s[i++] = (byte) (read(8));
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
ptr = 0;
|
||||
buffer[0] = (byte) '\0';
|
||||
endbit = endbyte = 0;
|
||||
}
|
||||
|
||||
public void writeclear() {
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
public void readinit(byte[] buf, int bytes) {
|
||||
readinit(buf, 0, bytes);
|
||||
}
|
||||
|
||||
public void readinit(byte[] buf, int start, int bytes) {
|
||||
ptr = start;
|
||||
buffer = buf;
|
||||
endbit = endbyte = 0;
|
||||
storage = bytes;
|
||||
}
|
||||
|
||||
public void write(int value, int bits) {
|
||||
if (endbyte + 4 >= storage) {
|
||||
byte[] foo = new byte[storage + BUFFER_INCREMENT];
|
||||
System.arraycopy(buffer, 0, foo, 0, storage);
|
||||
buffer = foo;
|
||||
storage += BUFFER_INCREMENT;
|
||||
}
|
||||
|
||||
value &= mask[bits];
|
||||
bits += endbit;
|
||||
buffer[ptr] |= (byte) (value << endbit);
|
||||
|
||||
if (bits >= 8) {
|
||||
buffer[ptr + 1] = (byte) (value >>> (8 - endbit));
|
||||
if (bits >= 16) {
|
||||
buffer[ptr + 2] = (byte) (value >>> (16 - endbit));
|
||||
if (bits >= 24) {
|
||||
buffer[ptr + 3] = (byte) (value >>> (24 - endbit));
|
||||
if (bits >= 32) {
|
||||
if (endbit > 0)
|
||||
buffer[ptr + 4] = (byte) (value >>> (32 - endbit));
|
||||
else
|
||||
buffer[ptr + 4] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endbyte += bits / 8;
|
||||
ptr += bits / 8;
|
||||
endbit = bits & 7;
|
||||
}
|
||||
|
||||
public int look(int bits) {
|
||||
int ret;
|
||||
int m = mask[bits];
|
||||
|
||||
bits += endbit;
|
||||
|
||||
if (endbyte + 4 >= storage) {
|
||||
if (endbyte + (bits - 1) / 8 >= storage)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ret = ((buffer[ptr]) & 0xff) >>> endbit;
|
||||
if (bits > 8) {
|
||||
ret |= ((buffer[ptr + 1]) & 0xff) << (8 - endbit);
|
||||
if (bits > 16) {
|
||||
ret |= ((buffer[ptr + 2]) & 0xff) << (16 - endbit);
|
||||
if (bits > 24) {
|
||||
ret |= ((buffer[ptr + 3]) & 0xff) << (24 - endbit);
|
||||
if (bits > 32 && endbit != 0) {
|
||||
ret |= ((buffer[ptr + 4]) & 0xff) << (32 - endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (m & ret);
|
||||
}
|
||||
|
||||
public int look1() {
|
||||
if (endbyte >= storage)
|
||||
return (-1);
|
||||
return ((buffer[ptr] >> endbit) & 1);
|
||||
}
|
||||
|
||||
public void adv(int bits) {
|
||||
bits += endbit;
|
||||
ptr += bits / 8;
|
||||
endbyte += bits / 8;
|
||||
endbit = bits & 7;
|
||||
}
|
||||
|
||||
public void adv1() {
|
||||
++endbit;
|
||||
if (endbit > 7) {
|
||||
endbit = 0;
|
||||
ptr++;
|
||||
endbyte++;
|
||||
}
|
||||
}
|
||||
|
||||
public int read(int bits) {
|
||||
int ret;
|
||||
int m = mask[bits];
|
||||
|
||||
bits += endbit;
|
||||
|
||||
if (endbyte + 4 >= storage) {
|
||||
ret = -1;
|
||||
if (endbyte + (bits - 1) / 8 >= storage) {
|
||||
ptr += bits / 8;
|
||||
endbyte += bits / 8;
|
||||
endbit = bits & 7;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret = ((buffer[ptr]) & 0xff) >>> endbit;
|
||||
if (bits > 8) {
|
||||
ret |= ((buffer[ptr + 1]) & 0xff) << (8 - endbit);
|
||||
if (bits > 16) {
|
||||
ret |= ((buffer[ptr + 2]) & 0xff) << (16 - endbit);
|
||||
if (bits > 24) {
|
||||
ret |= ((buffer[ptr + 3]) & 0xff) << (24 - endbit);
|
||||
if (bits > 32 && endbit != 0) {
|
||||
ret |= ((buffer[ptr + 4]) & 0xff) << (32 - endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret &= m;
|
||||
|
||||
ptr += bits / 8;
|
||||
endbyte += bits / 8;
|
||||
endbit = bits & 7;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public int readB(int bits) {
|
||||
int ret;
|
||||
int m = 32 - bits;
|
||||
|
||||
bits += endbit;
|
||||
|
||||
if (endbyte + 4 >= storage) {
|
||||
/* not the main path */
|
||||
ret = -1;
|
||||
if (endbyte * 8 + bits > storage * 8) {
|
||||
ptr += bits / 8;
|
||||
endbyte += bits / 8;
|
||||
endbit = bits & 7;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret = (buffer[ptr] & 0xff) << (24 + endbit);
|
||||
if (bits > 8) {
|
||||
ret |= (buffer[ptr + 1] & 0xff) << (16 + endbit);
|
||||
if (bits > 16) {
|
||||
ret |= (buffer[ptr + 2] & 0xff) << (8 + endbit);
|
||||
if (bits > 24) {
|
||||
ret |= (buffer[ptr + 3] & 0xff) << (endbit);
|
||||
if (bits > 32 && (endbit != 0))
|
||||
ret |= (buffer[ptr + 4] & 0xff) >> (8 - endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = (ret >>> (m >> 1)) >>> ((m + 1) >> 1);
|
||||
|
||||
ptr += bits / 8;
|
||||
endbyte += bits / 8;
|
||||
endbit = bits & 7;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public int read1() {
|
||||
int ret;
|
||||
if (endbyte >= storage) {
|
||||
ret = -1;
|
||||
endbit++;
|
||||
if (endbit > 7) {
|
||||
endbit = 0;
|
||||
ptr++;
|
||||
endbyte++;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ret = (buffer[ptr] >> endbit) & 1;
|
||||
|
||||
endbit++;
|
||||
if (endbit > 7) {
|
||||
endbit = 0;
|
||||
ptr++;
|
||||
endbyte++;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public int bytes() {
|
||||
return (endbyte + (endbit + 7) / 8);
|
||||
}
|
||||
|
||||
public int bits() {
|
||||
return (endbyte * 8 + endbit);
|
||||
}
|
||||
|
||||
public byte[] buffer() {
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
public static int ilog(int v) {
|
||||
int ret = 0;
|
||||
while (v > 0) {
|
||||
ret++;
|
||||
v >>>= 1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public static void report(String in) {
|
||||
System.err.println(in);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
45
sources/wasm-gc-teavm/java/com/jcraft/jogg/Packet.java
Normal file
45
sources/wasm-gc-teavm/java/com/jcraft/jogg/Packet.java
Normal file
@ -0,0 +1,45 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jogg;
|
||||
|
||||
public class Packet {
|
||||
public byte[] packet_base;
|
||||
public int packet;
|
||||
public int bytes;
|
||||
public int b_o_s;
|
||||
public int e_o_s;
|
||||
|
||||
public long granulepos;
|
||||
|
||||
/**
|
||||
* sequence number for decode; the framing knows where there's a hole in the
|
||||
* data, but we need coupling so that the codec (which is in a seperate
|
||||
* abstraction layer) also knows about the gap
|
||||
*/
|
||||
public long packetno;
|
||||
|
||||
}
|
130
sources/wasm-gc-teavm/java/com/jcraft/jogg/Page.java
Normal file
130
sources/wasm-gc-teavm/java/com/jcraft/jogg/Page.java
Normal file
@ -0,0 +1,130 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jogg;
|
||||
|
||||
public class Page {
|
||||
private static int[] crc_lookup = new int[256];
|
||||
static {
|
||||
for (int i = 0; i < crc_lookup.length; i++) {
|
||||
crc_lookup[i] = crc_entry(i);
|
||||
}
|
||||
}
|
||||
|
||||
private static int crc_entry(int index) {
|
||||
int r = index << 24;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if ((r & 0x80000000) != 0) {
|
||||
r = (r << 1) ^ 0x04c11db7; /*
|
||||
* The same as the ethernet generator polynomial, although we use an
|
||||
* unreflected alg and an init/final of 0, not 0xffffffff
|
||||
*/
|
||||
} else {
|
||||
r <<= 1;
|
||||
}
|
||||
}
|
||||
return (r & 0xffffffff);
|
||||
}
|
||||
|
||||
public byte[] header_base;
|
||||
public int header;
|
||||
public int header_len;
|
||||
public byte[] body_base;
|
||||
public int body;
|
||||
public int body_len;
|
||||
|
||||
int version() {
|
||||
return header_base[header + 4] & 0xff;
|
||||
}
|
||||
|
||||
int continued() {
|
||||
return (header_base[header + 5] & 0x01);
|
||||
}
|
||||
|
||||
public int bos() {
|
||||
return (header_base[header + 5] & 0x02);
|
||||
}
|
||||
|
||||
public int eos() {
|
||||
return (header_base[header + 5] & 0x04);
|
||||
}
|
||||
|
||||
public long granulepos() {
|
||||
long foo = header_base[header + 13] & 0xff;
|
||||
foo = (foo << 8) | (header_base[header + 12] & 0xff);
|
||||
foo = (foo << 8) | (header_base[header + 11] & 0xff);
|
||||
foo = (foo << 8) | (header_base[header + 10] & 0xff);
|
||||
foo = (foo << 8) | (header_base[header + 9] & 0xff);
|
||||
foo = (foo << 8) | (header_base[header + 8] & 0xff);
|
||||
foo = (foo << 8) | (header_base[header + 7] & 0xff);
|
||||
foo = (foo << 8) | (header_base[header + 6] & 0xff);
|
||||
return (foo);
|
||||
}
|
||||
|
||||
public int serialno() {
|
||||
return (header_base[header + 14] & 0xff) | ((header_base[header + 15] & 0xff) << 8)
|
||||
| ((header_base[header + 16] & 0xff) << 16) | ((header_base[header + 17] & 0xff) << 24);
|
||||
}
|
||||
|
||||
int pageno() {
|
||||
return (header_base[header + 18] & 0xff) | ((header_base[header + 19] & 0xff) << 8)
|
||||
| ((header_base[header + 20] & 0xff) << 16) | ((header_base[header + 21] & 0xff) << 24);
|
||||
}
|
||||
|
||||
void checksum() {
|
||||
int crc_reg = 0;
|
||||
|
||||
for (int i = 0; i < header_len; i++) {
|
||||
crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (header_base[header + i] & 0xff)];
|
||||
}
|
||||
for (int i = 0; i < body_len; i++) {
|
||||
crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (body_base[body + i] & 0xff)];
|
||||
}
|
||||
header_base[header + 22] = (byte) crc_reg;
|
||||
header_base[header + 23] = (byte) (crc_reg >>> 8);
|
||||
header_base[header + 24] = (byte) (crc_reg >>> 16);
|
||||
header_base[header + 25] = (byte) (crc_reg >>> 24);
|
||||
}
|
||||
|
||||
public Page copy() {
|
||||
return copy(new Page());
|
||||
}
|
||||
|
||||
public Page copy(Page p) {
|
||||
byte[] tmp = new byte[header_len];
|
||||
System.arraycopy(header_base, header, tmp, 0, header_len);
|
||||
p.header_len = header_len;
|
||||
p.header_base = tmp;
|
||||
p.header = 0;
|
||||
tmp = new byte[body_len];
|
||||
System.arraycopy(body_base, body, tmp, 0, body_len);
|
||||
p.body_len = body_len;
|
||||
p.body_base = tmp;
|
||||
p.body = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
}
|
538
sources/wasm-gc-teavm/java/com/jcraft/jogg/StreamState.java
Normal file
538
sources/wasm-gc-teavm/java/com/jcraft/jogg/StreamState.java
Normal file
@ -0,0 +1,538 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jogg;
|
||||
|
||||
public class StreamState {
|
||||
byte[] body_data; /* bytes from packet bodies */
|
||||
int body_storage; /* storage elements allocated */
|
||||
int body_fill; /* elements stored; fill mark */
|
||||
private int body_returned; /* elements of fill returned */
|
||||
|
||||
int[] lacing_vals; /* The values that will go to the segment table */
|
||||
long[] granule_vals; /*
|
||||
* pcm_pos values for headers. Not compact this way, but it is simple coupled to
|
||||
* the lacing fifo
|
||||
*/
|
||||
int lacing_storage;
|
||||
int lacing_fill;
|
||||
int lacing_packet;
|
||||
int lacing_returned;
|
||||
|
||||
byte[] header = new byte[282]; /* working space for header encode */
|
||||
int header_fill;
|
||||
|
||||
public int e_o_s; /*
|
||||
* set when we have buffered the last packet in the logical bitstream
|
||||
*/
|
||||
int b_o_s; /*
|
||||
* set after we've written the initial page of a logical bitstream
|
||||
*/
|
||||
int serialno;
|
||||
int pageno;
|
||||
long packetno; /*
|
||||
* sequence number for decode; the framing knows where there's a hole in the
|
||||
* data, but we need coupling so that the codec (which is in a seperate
|
||||
* abstraction layer) also knows about the gap
|
||||
*/
|
||||
long granulepos;
|
||||
|
||||
public StreamState() {
|
||||
init();
|
||||
}
|
||||
|
||||
StreamState(int serialno) {
|
||||
this();
|
||||
init(serialno);
|
||||
}
|
||||
|
||||
void init() {
|
||||
body_storage = 16 * 1024;
|
||||
body_data = new byte[body_storage];
|
||||
lacing_storage = 1024;
|
||||
lacing_vals = new int[lacing_storage];
|
||||
granule_vals = new long[lacing_storage];
|
||||
}
|
||||
|
||||
public void init(int serialno) {
|
||||
if (body_data == null) {
|
||||
init();
|
||||
} else {
|
||||
for (int i = 0; i < body_data.length; i++)
|
||||
body_data[i] = 0;
|
||||
for (int i = 0; i < lacing_vals.length; i++)
|
||||
lacing_vals[i] = 0;
|
||||
for (int i = 0; i < granule_vals.length; i++)
|
||||
granule_vals[i] = 0;
|
||||
}
|
||||
this.serialno = serialno;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
body_data = null;
|
||||
lacing_vals = null;
|
||||
granule_vals = null;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void body_expand(int needed) {
|
||||
if (body_storage <= body_fill + needed) {
|
||||
body_storage += (needed + 1024);
|
||||
byte[] foo = new byte[body_storage];
|
||||
System.arraycopy(body_data, 0, foo, 0, body_data.length);
|
||||
body_data = foo;
|
||||
}
|
||||
}
|
||||
|
||||
void lacing_expand(int needed) {
|
||||
if (lacing_storage <= lacing_fill + needed) {
|
||||
lacing_storage += (needed + 32);
|
||||
int[] foo = new int[lacing_storage];
|
||||
System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
|
||||
lacing_vals = foo;
|
||||
|
||||
long[] bar = new long[lacing_storage];
|
||||
System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
|
||||
granule_vals = bar;
|
||||
}
|
||||
}
|
||||
|
||||
/* submit data to the internal buffer of the framing engine */
|
||||
public int packetin(Packet op) {
|
||||
int lacing_val = op.bytes / 255 + 1;
|
||||
|
||||
if (body_returned != 0) {
|
||||
/*
|
||||
* advance packet data according to the body_returned pointer. We had to keep it
|
||||
* around to return a pointer into the buffer last call
|
||||
*/
|
||||
|
||||
body_fill -= body_returned;
|
||||
if (body_fill != 0) {
|
||||
System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
|
||||
}
|
||||
body_returned = 0;
|
||||
}
|
||||
|
||||
/* make sure we have the buffer storage */
|
||||
body_expand(op.bytes);
|
||||
lacing_expand(lacing_val);
|
||||
|
||||
/*
|
||||
* Copy in the submitted packet. Yes, the copy is a waste; this is the liability
|
||||
* of overly clean abstraction for the time being. It will actually be fairly
|
||||
* easy to eliminate the extra copy in the future
|
||||
*/
|
||||
|
||||
System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes);
|
||||
body_fill += op.bytes;
|
||||
|
||||
/* Store lacing vals for this packet */
|
||||
int j;
|
||||
for (j = 0; j < lacing_val - 1; j++) {
|
||||
lacing_vals[lacing_fill + j] = 255;
|
||||
granule_vals[lacing_fill + j] = granulepos;
|
||||
}
|
||||
lacing_vals[lacing_fill + j] = (op.bytes) % 255;
|
||||
granulepos = granule_vals[lacing_fill + j] = op.granulepos;
|
||||
|
||||
/* flag the first segment as the beginning of the packet */
|
||||
lacing_vals[lacing_fill] |= 0x100;
|
||||
|
||||
lacing_fill += lacing_val;
|
||||
|
||||
/* for the sake of completeness */
|
||||
packetno++;
|
||||
|
||||
if (op.e_o_s != 0)
|
||||
e_o_s = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int packetout(Packet op) {
|
||||
|
||||
/*
|
||||
* The last part of decode. We have the stream broken into packet segments. Now
|
||||
* we need to group them into packets (or return the out of sync markers)
|
||||
*/
|
||||
|
||||
int ptr = lacing_returned;
|
||||
|
||||
if (lacing_packet <= ptr) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ((lacing_vals[ptr] & 0x400) != 0) {
|
||||
/* We lost sync here; let the app know */
|
||||
lacing_returned++;
|
||||
|
||||
/*
|
||||
* we need to tell the codec there's a gap; it might need to handle previous
|
||||
* packet dependencies.
|
||||
*/
|
||||
packetno++;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Gather the whole packet. We'll have no holes or a partial packet */
|
||||
{
|
||||
int size = lacing_vals[ptr] & 0xff;
|
||||
int bytes = 0;
|
||||
|
||||
op.packet_base = body_data;
|
||||
op.packet = body_returned;
|
||||
op.e_o_s = lacing_vals[ptr] & 0x200; /* last packet of the stream? */
|
||||
op.b_o_s = lacing_vals[ptr] & 0x100; /* first packet of the stream? */
|
||||
bytes += size;
|
||||
|
||||
while (size == 255) {
|
||||
int val = lacing_vals[++ptr];
|
||||
size = val & 0xff;
|
||||
if ((val & 0x200) != 0)
|
||||
op.e_o_s = 0x200;
|
||||
bytes += size;
|
||||
}
|
||||
|
||||
op.packetno = packetno;
|
||||
op.granulepos = granule_vals[ptr];
|
||||
op.bytes = bytes;
|
||||
|
||||
body_returned += bytes;
|
||||
|
||||
lacing_returned = ptr + 1;
|
||||
}
|
||||
packetno++;
|
||||
return (1);
|
||||
}
|
||||
|
||||
// add the incoming page to the stream state; we decompose the page
|
||||
// into packet segments here as well.
|
||||
|
||||
public int pagein(Page og) {
|
||||
byte[] header_base = og.header_base;
|
||||
int header = og.header;
|
||||
byte[] body_base = og.body_base;
|
||||
int body = og.body;
|
||||
int bodysize = og.body_len;
|
||||
int segptr = 0;
|
||||
|
||||
int version = og.version();
|
||||
int continued = og.continued();
|
||||
int bos = og.bos();
|
||||
int eos = og.eos();
|
||||
long granulepos = og.granulepos();
|
||||
int _serialno = og.serialno();
|
||||
int _pageno = og.pageno();
|
||||
int segments = header_base[header + 26] & 0xff;
|
||||
|
||||
// clean up 'returned data'
|
||||
{
|
||||
int lr = lacing_returned;
|
||||
int br = body_returned;
|
||||
|
||||
// body data
|
||||
if (br != 0) {
|
||||
body_fill -= br;
|
||||
if (body_fill != 0) {
|
||||
System.arraycopy(body_data, br, body_data, 0, body_fill);
|
||||
}
|
||||
body_returned = 0;
|
||||
}
|
||||
|
||||
if (lr != 0) {
|
||||
// segment table
|
||||
if ((lacing_fill - lr) != 0) {
|
||||
System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill - lr);
|
||||
System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill - lr);
|
||||
}
|
||||
lacing_fill -= lr;
|
||||
lacing_packet -= lr;
|
||||
lacing_returned = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check the serial number
|
||||
if (_serialno != serialno)
|
||||
return (-1);
|
||||
if (version > 0)
|
||||
return (-1);
|
||||
|
||||
lacing_expand(segments + 1);
|
||||
|
||||
// are we in sequence?
|
||||
if (_pageno != pageno) {
|
||||
int i;
|
||||
|
||||
// unroll previous partial packet (if any)
|
||||
for (i = lacing_packet; i < lacing_fill; i++) {
|
||||
body_fill -= lacing_vals[i] & 0xff;
|
||||
// System.out.println("??");
|
||||
}
|
||||
lacing_fill = lacing_packet;
|
||||
|
||||
// make a note of dropped data in segment table
|
||||
if (pageno != -1) {
|
||||
lacing_vals[lacing_fill++] = 0x400;
|
||||
lacing_packet++;
|
||||
}
|
||||
|
||||
// are we a 'continued packet' page? If so, we'll need to skip
|
||||
// some segments
|
||||
if (continued != 0) {
|
||||
bos = 0;
|
||||
for (; segptr < segments; segptr++) {
|
||||
int val = (header_base[header + 27 + segptr] & 0xff);
|
||||
body += val;
|
||||
bodysize -= val;
|
||||
if (val < 255) {
|
||||
segptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bodysize != 0) {
|
||||
body_expand(bodysize);
|
||||
System.arraycopy(body_base, body, body_data, body_fill, bodysize);
|
||||
body_fill += bodysize;
|
||||
}
|
||||
|
||||
{
|
||||
int saved = -1;
|
||||
while (segptr < segments) {
|
||||
int val = (header_base[header + 27 + segptr] & 0xff);
|
||||
lacing_vals[lacing_fill] = val;
|
||||
granule_vals[lacing_fill] = -1;
|
||||
|
||||
if (bos != 0) {
|
||||
lacing_vals[lacing_fill] |= 0x100;
|
||||
bos = 0;
|
||||
}
|
||||
|
||||
if (val < 255)
|
||||
saved = lacing_fill;
|
||||
|
||||
lacing_fill++;
|
||||
segptr++;
|
||||
|
||||
if (val < 255)
|
||||
lacing_packet = lacing_fill;
|
||||
}
|
||||
|
||||
/* set the granulepos on the last pcmval of the last full packet */
|
||||
if (saved != -1) {
|
||||
granule_vals[saved] = granulepos;
|
||||
}
|
||||
}
|
||||
|
||||
if (eos != 0) {
|
||||
e_o_s = 1;
|
||||
if (lacing_fill > 0)
|
||||
lacing_vals[lacing_fill - 1] |= 0x200;
|
||||
}
|
||||
|
||||
pageno = _pageno + 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This will flush remaining packets into a page (returning nonzero), even if
|
||||
* there is not enough data to trigger a flush normally (undersized page). If
|
||||
* there are no packets or partial packets to flush, ogg_stream_flush returns 0.
|
||||
* Note that ogg_stream_flush will try to flush a normal sized page like
|
||||
* ogg_stream_pageout; a call to ogg_stream_flush does not gurantee that all
|
||||
* packets have flushed. Only a return value of 0 from ogg_stream_flush
|
||||
* indicates all packet data is flushed into pages.
|
||||
*
|
||||
* ogg_stream_page will flush the last page in a stream even if it's undersized;
|
||||
* you almost certainly want to use ogg_stream_pageout (and *not*
|
||||
* ogg_stream_flush) unless you need to flush an undersized page in the middle
|
||||
* of a stream for some reason.
|
||||
*/
|
||||
|
||||
public int flush(Page og) {
|
||||
|
||||
int i;
|
||||
int vals = 0;
|
||||
int maxvals = (lacing_fill > 255 ? 255 : lacing_fill);
|
||||
int bytes = 0;
|
||||
int acc = 0;
|
||||
long granule_pos = granule_vals[0];
|
||||
|
||||
if (maxvals == 0)
|
||||
return (0);
|
||||
|
||||
/* construct a page */
|
||||
/* decide how many segments to include */
|
||||
|
||||
/*
|
||||
* If this is the initial header case, the first page must only include the
|
||||
* initial header packet
|
||||
*/
|
||||
if (b_o_s == 0) { /* 'initial header page' case */
|
||||
granule_pos = 0;
|
||||
for (vals = 0; vals < maxvals; vals++) {
|
||||
if ((lacing_vals[vals] & 0x0ff) < 255) {
|
||||
vals++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (vals = 0; vals < maxvals; vals++) {
|
||||
if (acc > 4096)
|
||||
break;
|
||||
acc += (lacing_vals[vals] & 0x0ff);
|
||||
granule_pos = granule_vals[vals];
|
||||
}
|
||||
}
|
||||
|
||||
/* construct the header in temp storage */
|
||||
System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
|
||||
|
||||
/* stream structure version */
|
||||
header[4] = 0x00;
|
||||
|
||||
/* continued packet flag? */
|
||||
header[5] = 0x00;
|
||||
if ((lacing_vals[0] & 0x100) == 0)
|
||||
header[5] |= 0x01;
|
||||
/* first page flag? */
|
||||
if (b_o_s == 0)
|
||||
header[5] |= 0x02;
|
||||
/* last page flag? */
|
||||
if (e_o_s != 0 && lacing_fill == vals)
|
||||
header[5] |= 0x04;
|
||||
b_o_s = 1;
|
||||
|
||||
/* 64 bits of PCM position */
|
||||
for (i = 6; i < 14; i++) {
|
||||
header[i] = (byte) granule_pos;
|
||||
granule_pos >>>= 8;
|
||||
}
|
||||
|
||||
/* 32 bits of stream serial number */
|
||||
{
|
||||
int _serialno = serialno;
|
||||
for (i = 14; i < 18; i++) {
|
||||
header[i] = (byte) _serialno;
|
||||
_serialno >>>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 32 bits of page counter (we have both counter and page header because this
|
||||
* val can roll over)
|
||||
*/
|
||||
if (pageno == -1)
|
||||
pageno = 0; /*
|
||||
* because someone called stream_reset; this would be a strange thing to do in
|
||||
* an encode stream, but it has plausible uses
|
||||
*/
|
||||
{
|
||||
int _pageno = pageno++;
|
||||
for (i = 18; i < 22; i++) {
|
||||
header[i] = (byte) _pageno;
|
||||
_pageno >>>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* zero for computation; filled in later */
|
||||
header[22] = 0;
|
||||
header[23] = 0;
|
||||
header[24] = 0;
|
||||
header[25] = 0;
|
||||
|
||||
/* segment table */
|
||||
header[26] = (byte) vals;
|
||||
for (i = 0; i < vals; i++) {
|
||||
header[i + 27] = (byte) lacing_vals[i];
|
||||
bytes += (header[i + 27] & 0xff);
|
||||
}
|
||||
|
||||
/* set pointers in the ogg_page struct */
|
||||
og.header_base = header;
|
||||
og.header = 0;
|
||||
og.header_len = header_fill = vals + 27;
|
||||
og.body_base = body_data;
|
||||
og.body = body_returned;
|
||||
og.body_len = bytes;
|
||||
|
||||
/* advance the lacing data and set the body_returned pointer */
|
||||
|
||||
lacing_fill -= vals;
|
||||
System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill * 4);
|
||||
System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill * 8);
|
||||
body_returned += bytes;
|
||||
|
||||
/* calculate the checksum */
|
||||
|
||||
og.checksum();
|
||||
|
||||
/* done */
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This constructs pages from buffered packet segments. The pointers returned
|
||||
* are to static buffers; do not free. The returned buffers are good only until
|
||||
* the next call (using the same ogg_stream_state)
|
||||
*/
|
||||
public int pageout(Page og) {
|
||||
if ((e_o_s != 0 && lacing_fill != 0) || /* 'were done, now flush' case */
|
||||
body_fill - body_returned > 4096 || /* 'page nominal size' case */
|
||||
lacing_fill >= 255 || /* 'segment table full' case */
|
||||
(lacing_fill != 0 && b_o_s == 0)) { /* 'initial header page' case */
|
||||
return flush(og);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int eof() {
|
||||
return e_o_s;
|
||||
}
|
||||
|
||||
public int reset() {
|
||||
body_fill = 0;
|
||||
body_returned = 0;
|
||||
|
||||
lacing_fill = 0;
|
||||
lacing_packet = 0;
|
||||
lacing_returned = 0;
|
||||
|
||||
header_fill = 0;
|
||||
|
||||
e_o_s = 0;
|
||||
b_o_s = 0;
|
||||
pageno = -1;
|
||||
packetno = 0;
|
||||
granulepos = 0;
|
||||
return (0);
|
||||
}
|
||||
}
|
273
sources/wasm-gc-teavm/java/com/jcraft/jogg/SyncState.java
Normal file
273
sources/wasm-gc-teavm/java/com/jcraft/jogg/SyncState.java
Normal file
@ -0,0 +1,273 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jogg;
|
||||
|
||||
// DECODING PRIMITIVES: packet streaming layer
|
||||
|
||||
// This has two layers to place more of the multi-serialno and paging
|
||||
// control in the application's hands. First, we expose a data buffer
|
||||
// using ogg_decode_buffer(). The app either copies into the
|
||||
// buffer, or passes it directly to read(), etc. We then call
|
||||
// ogg_decode_wrote() to tell how many bytes we just added.
|
||||
//
|
||||
// Pages are returned (pointers into the buffer in ogg_sync_state)
|
||||
// by ogg_decode_stream(). The page is then submitted to
|
||||
// ogg_decode_page() along with the appropriate
|
||||
// ogg_stream_state* (ie, matching serialno). We then get raw
|
||||
// packets out calling ogg_stream_packet() with a
|
||||
// ogg_stream_state. See the 'frame-prog.txt' docs for details and
|
||||
// example code.
|
||||
|
||||
public class SyncState {
|
||||
|
||||
public byte[] data;
|
||||
int storage;
|
||||
int fill;
|
||||
int returned;
|
||||
|
||||
int unsynced;
|
||||
int headerbytes;
|
||||
int bodybytes;
|
||||
|
||||
public int clear() {
|
||||
data = null;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int buffer(int size) {
|
||||
// first, clear out any space that has been previously returned
|
||||
if (returned != 0) {
|
||||
fill -= returned;
|
||||
if (fill > 0) {
|
||||
System.arraycopy(data, returned, data, 0, fill);
|
||||
}
|
||||
returned = 0;
|
||||
}
|
||||
|
||||
if (size > storage - fill) {
|
||||
// We need to extend the internal buffer
|
||||
int newsize = size + fill + 4096; // an extra page to be nice
|
||||
if (data != null) {
|
||||
byte[] foo = new byte[newsize];
|
||||
System.arraycopy(data, 0, foo, 0, data.length);
|
||||
data = foo;
|
||||
} else {
|
||||
data = new byte[newsize];
|
||||
}
|
||||
storage = newsize;
|
||||
}
|
||||
|
||||
return (fill);
|
||||
}
|
||||
|
||||
public int wrote(int bytes) {
|
||||
if (fill + bytes > storage)
|
||||
return (-1);
|
||||
fill += bytes;
|
||||
return (0);
|
||||
}
|
||||
|
||||
// sync the stream. This is meant to be useful for finding page
|
||||
// boundaries.
|
||||
//
|
||||
// return values for this:
|
||||
// -n) skipped n bytes
|
||||
// 0) page not ready; more data (no bytes skipped)
|
||||
// n) page synced at current location; page length n bytes
|
||||
private Page pageseek = new Page();
|
||||
private byte[] chksum = new byte[4];
|
||||
|
||||
public int pageseek(Page og) {
|
||||
int page = returned;
|
||||
int next;
|
||||
int bytes = fill - returned;
|
||||
|
||||
if (headerbytes == 0) {
|
||||
int _headerbytes, i;
|
||||
if (bytes < 27)
|
||||
return (0); // not enough for a header
|
||||
|
||||
/* verify capture pattern */
|
||||
if (data[page] != 'O' || data[page + 1] != 'g' || data[page + 2] != 'g' || data[page + 3] != 'S') {
|
||||
headerbytes = 0;
|
||||
bodybytes = 0;
|
||||
|
||||
// search for possible capture
|
||||
next = 0;
|
||||
for (int ii = 0; ii < bytes - 1; ii++) {
|
||||
if (data[page + 1 + ii] == 'O') {
|
||||
next = page + 1 + ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// next=memchr(page+1,'O',bytes-1);
|
||||
if (next == 0)
|
||||
next = fill;
|
||||
|
||||
returned = next;
|
||||
return (-(next - page));
|
||||
}
|
||||
_headerbytes = (data[page + 26] & 0xff) + 27;
|
||||
if (bytes < _headerbytes)
|
||||
return (0); // not enough for header + seg table
|
||||
|
||||
// count up body length in the segment table
|
||||
|
||||
for (i = 0; i < (data[page + 26] & 0xff); i++) {
|
||||
bodybytes += (data[page + 27 + i] & 0xff);
|
||||
}
|
||||
headerbytes = _headerbytes;
|
||||
}
|
||||
|
||||
if (bodybytes + headerbytes > bytes)
|
||||
return (0);
|
||||
|
||||
// The whole test page is buffered. Verify the checksum
|
||||
synchronized (chksum) {
|
||||
// Grab the checksum bytes, set the header field to zero
|
||||
|
||||
System.arraycopy(data, page + 22, chksum, 0, 4);
|
||||
data[page + 22] = 0;
|
||||
data[page + 23] = 0;
|
||||
data[page + 24] = 0;
|
||||
data[page + 25] = 0;
|
||||
|
||||
// set up a temp page struct and recompute the checksum
|
||||
Page log = pageseek;
|
||||
log.header_base = data;
|
||||
log.header = page;
|
||||
log.header_len = headerbytes;
|
||||
|
||||
log.body_base = data;
|
||||
log.body = page + headerbytes;
|
||||
log.body_len = bodybytes;
|
||||
log.checksum();
|
||||
|
||||
// Compare
|
||||
if (chksum[0] != data[page + 22] || chksum[1] != data[page + 23] || chksum[2] != data[page + 24]
|
||||
|| chksum[3] != data[page + 25]) {
|
||||
// D'oh. Mismatch! Corrupt page (or miscapture and not a page at all)
|
||||
// replace the computed checksum with the one actually read in
|
||||
System.arraycopy(chksum, 0, data, page + 22, 4);
|
||||
// Bad checksum. Lose sync */
|
||||
|
||||
headerbytes = 0;
|
||||
bodybytes = 0;
|
||||
// search for possible capture
|
||||
next = 0;
|
||||
for (int ii = 0; ii < bytes - 1; ii++) {
|
||||
if (data[page + 1 + ii] == 'O') {
|
||||
next = page + 1 + ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// next=memchr(page+1,'O',bytes-1);
|
||||
if (next == 0)
|
||||
next = fill;
|
||||
returned = next;
|
||||
return (-(next - page));
|
||||
}
|
||||
}
|
||||
|
||||
// yes, have a whole page all ready to go
|
||||
{
|
||||
page = returned;
|
||||
|
||||
if (og != null) {
|
||||
og.header_base = data;
|
||||
og.header = page;
|
||||
og.header_len = headerbytes;
|
||||
og.body_base = data;
|
||||
og.body = page + headerbytes;
|
||||
og.body_len = bodybytes;
|
||||
}
|
||||
|
||||
unsynced = 0;
|
||||
returned += (bytes = headerbytes + bodybytes);
|
||||
headerbytes = 0;
|
||||
bodybytes = 0;
|
||||
return (bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// sync the stream and get a page. Keep trying until we find a page.
|
||||
// Supress 'sync errors' after reporting the first.
|
||||
//
|
||||
// return values:
|
||||
// -1) recapture (hole in data)
|
||||
// 0) need more data
|
||||
// 1) page returned
|
||||
//
|
||||
// Returns pointers into buffered data; invalidated by next call to
|
||||
// _stream, _clear, _init, or _buffer
|
||||
|
||||
public int pageout(Page og) {
|
||||
// all we need to do is verify a page at the head of the stream
|
||||
// buffer. If it doesn't verify, we look for the next potential
|
||||
// frame
|
||||
|
||||
while (true) {
|
||||
int ret = pageseek(og);
|
||||
if (ret > 0) {
|
||||
// have a page
|
||||
return (1);
|
||||
}
|
||||
if (ret == 0) {
|
||||
// need more data
|
||||
return (0);
|
||||
}
|
||||
|
||||
// head did not start a synced page... skipped some bytes
|
||||
if (unsynced == 0) {
|
||||
unsynced = 1;
|
||||
return (-1);
|
||||
}
|
||||
// loop. keep looking
|
||||
}
|
||||
}
|
||||
|
||||
// clear things to an initial state. Good to call, eg, before seeking
|
||||
public int reset() {
|
||||
fill = 0;
|
||||
returned = 0;
|
||||
unsynced = 0;
|
||||
headerbytes = 0;
|
||||
bodybytes = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
}
|
||||
|
||||
public int getDataOffset() {
|
||||
return returned;
|
||||
}
|
||||
|
||||
public int getBufferOffset() {
|
||||
return fill;
|
||||
}
|
||||
}
|
126
sources/wasm-gc-teavm/java/com/jcraft/jorbis/Block.java
Normal file
126
sources/wasm-gc-teavm/java/com/jcraft/jorbis/Block.java
Normal file
@ -0,0 +1,126 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
public class Block {
|
||||
/// necessary stream state for linking to the framing abstraction
|
||||
float[][] pcm = new float[0][]; // this is a pointer into local storage
|
||||
Buffer opb = new Buffer();
|
||||
|
||||
int lW;
|
||||
int W;
|
||||
int nW;
|
||||
int pcmend;
|
||||
int mode;
|
||||
|
||||
int eofflag;
|
||||
long granulepos;
|
||||
long sequence;
|
||||
DspState vd; // For read-only access of configuration
|
||||
|
||||
// bitmetrics for the frame
|
||||
int glue_bits;
|
||||
int time_bits;
|
||||
int floor_bits;
|
||||
int res_bits;
|
||||
|
||||
public Block(DspState vd) {
|
||||
this.vd = vd;
|
||||
if (vd.analysisp != 0) {
|
||||
opb.writeinit();
|
||||
}
|
||||
}
|
||||
|
||||
public void init(DspState vd) {
|
||||
this.vd = vd;
|
||||
}
|
||||
|
||||
public int clear() {
|
||||
if (vd != null) {
|
||||
if (vd.analysisp != 0) {
|
||||
opb.writeclear();
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int synthesis(Packet op) {
|
||||
Info vi = vd.vi;
|
||||
|
||||
// first things first. Make sure decode is ready
|
||||
opb.readinit(op.packet_base, op.packet, op.bytes);
|
||||
|
||||
// Check the packet type
|
||||
if (opb.read(1) != 0) {
|
||||
// Oops. This is not an audio data packet
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// read our mode and pre/post windowsize
|
||||
int _mode = opb.read(vd.modebits);
|
||||
if (_mode == -1)
|
||||
return (-1);
|
||||
|
||||
mode = _mode;
|
||||
W = vi.mode_param[mode].blockflag;
|
||||
if (W != 0) {
|
||||
lW = opb.read(1);
|
||||
nW = opb.read(1);
|
||||
if (nW == -1)
|
||||
return (-1);
|
||||
} else {
|
||||
lW = 0;
|
||||
nW = 0;
|
||||
}
|
||||
|
||||
// more setup
|
||||
granulepos = op.granulepos;
|
||||
sequence = op.packetno - 3; // first block is third packet
|
||||
eofflag = op.e_o_s;
|
||||
|
||||
// alloc pcm passback storage
|
||||
pcmend = vi.blocksizes[W];
|
||||
if (pcm.length < vi.channels) {
|
||||
pcm = new float[vi.channels][];
|
||||
}
|
||||
for (int i = 0; i < vi.channels; i++) {
|
||||
if (pcm[i] == null || pcm[i].length < pcmend) {
|
||||
pcm[i] = new float[pcmend];
|
||||
} else {
|
||||
for (int j = 0; j < pcmend; j++) {
|
||||
pcm[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unpack_header enforces range checking
|
||||
int type = vi.map_type[vi.mode_param[mode].mapping];
|
||||
return (FuncMapping.mapping_P[type].inverse(this, vd.mode[mode]));
|
||||
}
|
||||
}
|
471
sources/wasm-gc-teavm/java/com/jcraft/jorbis/CodeBook.java
Normal file
471
sources/wasm-gc-teavm/java/com/jcraft/jorbis/CodeBook.java
Normal file
@ -0,0 +1,471 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
class CodeBook {
|
||||
int dim; // codebook dimensions (elements per vector)
|
||||
int entries; // codebook entries
|
||||
StaticCodeBook c = new StaticCodeBook();
|
||||
|
||||
float[] valuelist; // list of dim*entries actual entry values
|
||||
int[] codelist; // list of bitstream codewords for each entry
|
||||
DecodeAux decode_tree;
|
||||
|
||||
// returns the number of bits
|
||||
int encode(int a, Buffer b) {
|
||||
b.write(codelist[a], c.lengthlist[a]);
|
||||
return (c.lengthlist[a]);
|
||||
}
|
||||
|
||||
// One the encode side, our vector writers are each designed for a
|
||||
// specific purpose, and the encoder is not flexible without modification:
|
||||
//
|
||||
// The LSP vector coder uses a single stage nearest-match with no
|
||||
// interleave, so no step and no error return. This is specced by floor0
|
||||
// and doesn't change.
|
||||
//
|
||||
// Residue0 encoding interleaves, uses multiple stages, and each stage
|
||||
// peels of a specific amount of resolution from a lattice (thus we want
|
||||
// to match by threshhold, not nearest match). Residue doesn't *have* to
|
||||
// be encoded that way, but to change it, one will need to add more
|
||||
// infrastructure on the encode side (decode side is specced and simpler)
|
||||
|
||||
// floor0 LSP (single stage, non interleaved, nearest match)
|
||||
// returns entry number and *modifies a* to the quantization value
|
||||
int errorv(float[] a) {
|
||||
int best = best(a, 1);
|
||||
for (int k = 0; k < dim; k++) {
|
||||
a[k] = valuelist[best * dim + k];
|
||||
}
|
||||
return (best);
|
||||
}
|
||||
|
||||
// returns the number of bits and *modifies a* to the quantization value
|
||||
int encodev(int best, float[] a, Buffer b) {
|
||||
for (int k = 0; k < dim; k++) {
|
||||
a[k] = valuelist[best * dim + k];
|
||||
}
|
||||
return (encode(best, b));
|
||||
}
|
||||
|
||||
// res0 (multistage, interleave, lattice)
|
||||
// returns the number of bits and *modifies a* to the remainder value
|
||||
int encodevs(float[] a, Buffer b, int step, int addmul) {
|
||||
int best = besterror(a, step, addmul);
|
||||
return (encode(best, b));
|
||||
}
|
||||
|
||||
private int[] t = new int[15]; // decodevs_add is synchronized for re-using t.
|
||||
|
||||
synchronized int decodevs_add(float[] a, int offset, Buffer b, int n) {
|
||||
int step = n / dim;
|
||||
int entry;
|
||||
int i, j, o;
|
||||
|
||||
if (t.length < step) {
|
||||
t = new int[step];
|
||||
}
|
||||
|
||||
for (i = 0; i < step; i++) {
|
||||
entry = decode(b);
|
||||
if (entry == -1)
|
||||
return (-1);
|
||||
t[i] = entry * dim;
|
||||
}
|
||||
for (i = 0, o = 0; i < dim; i++, o += step) {
|
||||
for (j = 0; j < step; j++) {
|
||||
a[offset + o + j] += valuelist[t[j] + i];
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int decodev_add(float[] a, int offset, Buffer b, int n) {
|
||||
int i, j, entry;
|
||||
int t;
|
||||
|
||||
if (dim > 8) {
|
||||
for (i = 0; i < n;) {
|
||||
entry = decode(b);
|
||||
if (entry == -1)
|
||||
return (-1);
|
||||
t = entry * dim;
|
||||
for (j = 0; j < dim;) {
|
||||
a[offset + (i++)] += valuelist[t + (j++)];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < n;) {
|
||||
entry = decode(b);
|
||||
if (entry == -1)
|
||||
return (-1);
|
||||
t = entry * dim;
|
||||
j = 0;
|
||||
switch (dim) {
|
||||
case 8:
|
||||
a[offset + (i++)] += valuelist[t + (j++)];
|
||||
case 7:
|
||||
a[offset + (i++)] += valuelist[t + (j++)];
|
||||
case 6:
|
||||
a[offset + (i++)] += valuelist[t + (j++)];
|
||||
case 5:
|
||||
a[offset + (i++)] += valuelist[t + (j++)];
|
||||
case 4:
|
||||
a[offset + (i++)] += valuelist[t + (j++)];
|
||||
case 3:
|
||||
a[offset + (i++)] += valuelist[t + (j++)];
|
||||
case 2:
|
||||
a[offset + (i++)] += valuelist[t + (j++)];
|
||||
case 1:
|
||||
a[offset + (i++)] += valuelist[t + (j++)];
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int decodev_set(float[] a, int offset, Buffer b, int n) {
|
||||
int i, j, entry;
|
||||
int t;
|
||||
|
||||
for (i = 0; i < n;) {
|
||||
entry = decode(b);
|
||||
if (entry == -1)
|
||||
return (-1);
|
||||
t = entry * dim;
|
||||
for (j = 0; j < dim;) {
|
||||
a[offset + i++] = valuelist[t + (j++)];
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int decodevv_add(float[][] a, int offset, int ch, Buffer b, int n) {
|
||||
int i, j, entry;
|
||||
int chptr = 0;
|
||||
|
||||
for (i = offset / ch; i < (offset + n) / ch;) {
|
||||
entry = decode(b);
|
||||
if (entry == -1)
|
||||
return (-1);
|
||||
|
||||
int t = entry * dim;
|
||||
for (j = 0; j < dim; j++) {
|
||||
a[chptr++][i] += valuelist[t + j];
|
||||
if (chptr == ch) {
|
||||
chptr = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Decode side is specced and easier, because we don't need to find
|
||||
// matches using different criteria; we simply read and map. There are
|
||||
// two things we need to do 'depending':
|
||||
//
|
||||
// We may need to support interleave. We don't really, but it's
|
||||
// convenient to do it here rather than rebuild the vector later.
|
||||
//
|
||||
// Cascades may be additive or multiplicitive; this is not inherent in
|
||||
// the codebook, but set in the code using the codebook. Like
|
||||
// interleaving, it's easiest to do it here.
|
||||
// stage==0 -> declarative (set the value)
|
||||
// stage==1 -> additive
|
||||
// stage==2 -> multiplicitive
|
||||
|
||||
// returns the entry number or -1 on eof
|
||||
int decode(Buffer b) {
|
||||
int ptr = 0;
|
||||
DecodeAux t = decode_tree;
|
||||
int lok = b.look(t.tabn);
|
||||
|
||||
if (lok >= 0) {
|
||||
ptr = t.tab[lok];
|
||||
b.adv(t.tabl[lok]);
|
||||
if (ptr <= 0) {
|
||||
return -ptr;
|
||||
}
|
||||
}
|
||||
do {
|
||||
switch (b.read1()) {
|
||||
case 0:
|
||||
ptr = t.ptr0[ptr];
|
||||
break;
|
||||
case 1:
|
||||
ptr = t.ptr1[ptr];
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
} while (ptr > 0);
|
||||
return (-ptr);
|
||||
}
|
||||
|
||||
// returns the entry number or -1 on eof
|
||||
int decodevs(float[] a, int index, Buffer b, int step, int addmul) {
|
||||
int entry = decode(b);
|
||||
if (entry == -1)
|
||||
return (-1);
|
||||
switch (addmul) {
|
||||
case -1:
|
||||
for (int i = 0, o = 0; i < dim; i++, o += step)
|
||||
a[index + o] = valuelist[entry * dim + i];
|
||||
break;
|
||||
case 0:
|
||||
for (int i = 0, o = 0; i < dim; i++, o += step)
|
||||
a[index + o] += valuelist[entry * dim + i];
|
||||
break;
|
||||
case 1:
|
||||
for (int i = 0, o = 0; i < dim; i++, o += step)
|
||||
a[index + o] *= valuelist[entry * dim + i];
|
||||
break;
|
||||
default:
|
||||
// System.err.println("CodeBook.decodeves: addmul="+addmul);
|
||||
}
|
||||
return (entry);
|
||||
}
|
||||
|
||||
int best(float[] a, int step) {
|
||||
// brute force it!
|
||||
{
|
||||
int besti = -1;
|
||||
float best = 0.f;
|
||||
int e = 0;
|
||||
for (int i = 0; i < entries; i++) {
|
||||
if (c.lengthlist[i] > 0) {
|
||||
float _this = dist(dim, valuelist, e, a, step);
|
||||
if (besti == -1 || _this < best) {
|
||||
best = _this;
|
||||
besti = i;
|
||||
}
|
||||
}
|
||||
e += dim;
|
||||
}
|
||||
return (besti);
|
||||
}
|
||||
}
|
||||
|
||||
// returns the entry number and *modifies a* to the remainder value
|
||||
int besterror(float[] a, int step, int addmul) {
|
||||
int best = best(a, step);
|
||||
switch (addmul) {
|
||||
case 0:
|
||||
for (int i = 0, o = 0; i < dim; i++, o += step)
|
||||
a[o] -= valuelist[best * dim + i];
|
||||
break;
|
||||
case 1:
|
||||
for (int i = 0, o = 0; i < dim; i++, o += step) {
|
||||
float val = valuelist[best * dim + i];
|
||||
if (val == 0) {
|
||||
a[o] = 0;
|
||||
} else {
|
||||
a[o] /= val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (best);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
}
|
||||
|
||||
private static float dist(int el, float[] ref, int index, float[] b, int step) {
|
||||
float acc = (float) 0.;
|
||||
for (int i = 0; i < el; i++) {
|
||||
float val = (ref[index + i] - b[i * step]);
|
||||
acc += val * val;
|
||||
}
|
||||
return (acc);
|
||||
}
|
||||
|
||||
int init_decode(StaticCodeBook s) {
|
||||
c = s;
|
||||
entries = s.entries;
|
||||
dim = s.dim;
|
||||
valuelist = s.unquantize();
|
||||
|
||||
decode_tree = make_decode_tree();
|
||||
if (decode_tree == null) {
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// given a list of word lengths, generate a list of codewords. Works
|
||||
// for length ordered or unordered, always assigns the lowest valued
|
||||
// codewords first. Extended to handle unused entries (length 0)
|
||||
static int[] make_words(int[] l, int n) {
|
||||
int[] marker = new int[33];
|
||||
int[] r = new int[n];
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
int length = l[i];
|
||||
if (length > 0) {
|
||||
int entry = marker[length];
|
||||
|
||||
// when we claim a node for an entry, we also claim the nodes
|
||||
// below it (pruning off the imagined tree that may have dangled
|
||||
// from it) as well as blocking the use of any nodes directly
|
||||
// above for leaves
|
||||
|
||||
// update ourself
|
||||
if (length < 32 && (entry >>> length) != 0) {
|
||||
// error condition; the lengths must specify an overpopulated tree
|
||||
// free(r);
|
||||
return (null);
|
||||
}
|
||||
r[i] = entry;
|
||||
|
||||
// Look to see if the next shorter marker points to the node
|
||||
// above. if so, update it and repeat.
|
||||
{
|
||||
for (int j = length; j > 0; j--) {
|
||||
if ((marker[j] & 1) != 0) {
|
||||
// have to jump branches
|
||||
if (j == 1)
|
||||
marker[1]++;
|
||||
else
|
||||
marker[j] = marker[j - 1] << 1;
|
||||
break; // invariant says next upper marker would already
|
||||
// have been moved if it was on the same path
|
||||
}
|
||||
marker[j]++;
|
||||
}
|
||||
}
|
||||
|
||||
// prune the tree; the implicit invariant says all the longer
|
||||
// markers were dangling from our just-taken node. Dangle them
|
||||
// from our *new* node.
|
||||
for (int j = length + 1; j < 33; j++) {
|
||||
if ((marker[j] >>> 1) == entry) {
|
||||
entry = marker[j];
|
||||
marker[j] = marker[j - 1] << 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bitreverse the words because our bitwise packer/unpacker is LSb
|
||||
// endian
|
||||
for (int i = 0; i < n; i++) {
|
||||
int temp = 0;
|
||||
for (int j = 0; j < l[i]; j++) {
|
||||
temp <<= 1;
|
||||
temp |= (r[i] >>> j) & 1;
|
||||
}
|
||||
r[i] = temp;
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
// build the decode helper tree from the codewords
|
||||
DecodeAux make_decode_tree() {
|
||||
int top = 0;
|
||||
DecodeAux t = new DecodeAux();
|
||||
int[] ptr0 = t.ptr0 = new int[entries * 2];
|
||||
int[] ptr1 = t.ptr1 = new int[entries * 2];
|
||||
int[] codelist = make_words(c.lengthlist, c.entries);
|
||||
|
||||
if (codelist == null)
|
||||
return (null);
|
||||
t.aux = entries * 2;
|
||||
|
||||
for (int i = 0; i < entries; i++) {
|
||||
if (c.lengthlist[i] > 0) {
|
||||
int ptr = 0;
|
||||
int j;
|
||||
for (j = 0; j < c.lengthlist[i] - 1; j++) {
|
||||
int bit = (codelist[i] >>> j) & 1;
|
||||
if (bit == 0) {
|
||||
if (ptr0[ptr] == 0) {
|
||||
ptr0[ptr] = ++top;
|
||||
}
|
||||
ptr = ptr0[ptr];
|
||||
} else {
|
||||
if (ptr1[ptr] == 0) {
|
||||
ptr1[ptr] = ++top;
|
||||
}
|
||||
ptr = ptr1[ptr];
|
||||
}
|
||||
}
|
||||
|
||||
if (((codelist[i] >>> j) & 1) == 0) {
|
||||
ptr0[ptr] = -i;
|
||||
} else {
|
||||
ptr1[ptr] = -i;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
t.tabn = Util.ilog(entries) - 4;
|
||||
|
||||
if (t.tabn < 5)
|
||||
t.tabn = 5;
|
||||
int n = 1 << t.tabn;
|
||||
t.tab = new int[n];
|
||||
t.tabl = new int[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
int p = 0;
|
||||
int j = 0;
|
||||
for (j = 0; j < t.tabn && (p > 0 || j == 0); j++) {
|
||||
if ((i & (1 << j)) != 0) {
|
||||
p = ptr1[p];
|
||||
} else {
|
||||
p = ptr0[p];
|
||||
}
|
||||
}
|
||||
t.tab[i] = p; // -code
|
||||
t.tabl[i] = j; // length
|
||||
}
|
||||
|
||||
return (t);
|
||||
}
|
||||
|
||||
class DecodeAux {
|
||||
int[] tab;
|
||||
int[] tabl;
|
||||
int tabn;
|
||||
|
||||
int[] ptr0;
|
||||
int[] ptr1;
|
||||
int aux; // number of tree entries
|
||||
}
|
||||
}
|
240
sources/wasm-gc-teavm/java/com/jcraft/jorbis/Comment.java
Normal file
240
sources/wasm-gc-teavm/java/com/jcraft/jorbis/Comment.java
Normal file
@ -0,0 +1,240 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
// the comments are not part of vorbis_info so that vorbis_info can be
|
||||
// static storage
|
||||
public class Comment {
|
||||
private static byte[] _vorbis = "vorbis".getBytes();
|
||||
private static byte[] _vendor = "Xiphophorus libVorbis I 20000508".getBytes();
|
||||
|
||||
private static final int OV_EIMPL = -130;
|
||||
|
||||
// unlimited user comment fields.
|
||||
public byte[][] user_comments;
|
||||
public int[] comment_lengths;
|
||||
public int comments;
|
||||
public byte[] vendor;
|
||||
|
||||
public void init() {
|
||||
user_comments = null;
|
||||
comments = 0;
|
||||
vendor = null;
|
||||
}
|
||||
|
||||
public void add(String comment) {
|
||||
add(comment.getBytes());
|
||||
}
|
||||
|
||||
private void add(byte[] comment) {
|
||||
byte[][] foo = new byte[comments + 2][];
|
||||
if (user_comments != null) {
|
||||
System.arraycopy(user_comments, 0, foo, 0, comments);
|
||||
}
|
||||
user_comments = foo;
|
||||
|
||||
int[] goo = new int[comments + 2];
|
||||
if (comment_lengths != null) {
|
||||
System.arraycopy(comment_lengths, 0, goo, 0, comments);
|
||||
}
|
||||
comment_lengths = goo;
|
||||
|
||||
byte[] bar = new byte[comment.length + 1];
|
||||
System.arraycopy(comment, 0, bar, 0, comment.length);
|
||||
user_comments[comments] = bar;
|
||||
comment_lengths[comments] = comment.length;
|
||||
comments++;
|
||||
user_comments[comments] = null;
|
||||
}
|
||||
|
||||
public void add_tag(String tag, String contents) {
|
||||
if (contents == null)
|
||||
contents = "";
|
||||
add(tag + "=" + contents);
|
||||
}
|
||||
|
||||
static boolean tagcompare(byte[] s1, byte[] s2, int n) {
|
||||
int c = 0;
|
||||
byte u1, u2;
|
||||
while (c < n) {
|
||||
u1 = s1[c];
|
||||
u2 = s2[c];
|
||||
if ('Z' >= u1 && u1 >= 'A')
|
||||
u1 = (byte) (u1 - 'A' + 'a');
|
||||
if ('Z' >= u2 && u2 >= 'A')
|
||||
u2 = (byte) (u2 - 'A' + 'a');
|
||||
if (u1 != u2) {
|
||||
return false;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String query(String tag) {
|
||||
return query(tag, 0);
|
||||
}
|
||||
|
||||
public String query(String tag, int count) {
|
||||
int foo = query(tag.getBytes(), count);
|
||||
if (foo == -1)
|
||||
return null;
|
||||
byte[] comment = user_comments[foo];
|
||||
for (int i = 0; i < comment_lengths[foo]; i++) {
|
||||
if (comment[i] == '=') {
|
||||
return new String(comment, i + 1, comment_lengths[foo] - (i + 1));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int query(byte[] tag, int count) {
|
||||
int i = 0;
|
||||
int found = 0;
|
||||
int fulltaglen = tag.length + 1;
|
||||
byte[] fulltag = new byte[fulltaglen];
|
||||
System.arraycopy(tag, 0, fulltag, 0, tag.length);
|
||||
fulltag[tag.length] = (byte) '=';
|
||||
|
||||
for (i = 0; i < comments; i++) {
|
||||
if (tagcompare(user_comments[i], fulltag, fulltaglen)) {
|
||||
if (count == found) {
|
||||
// We return a pointer to the data, not a copy
|
||||
// return user_comments[i] + taglen + 1;
|
||||
return i;
|
||||
} else {
|
||||
found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unpack(Buffer opb) {
|
||||
int vendorlen = opb.read(32);
|
||||
if (vendorlen < 0) {
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
vendor = new byte[vendorlen + 1];
|
||||
opb.read(vendor, vendorlen);
|
||||
comments = opb.read(32);
|
||||
if (comments < 0) {
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
user_comments = new byte[comments + 1][];
|
||||
comment_lengths = new int[comments + 1];
|
||||
|
||||
for (int i = 0; i < comments; i++) {
|
||||
int len = opb.read(32);
|
||||
if (len < 0) {
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
comment_lengths[i] = len;
|
||||
user_comments[i] = new byte[len + 1];
|
||||
opb.read(user_comments[i], len);
|
||||
}
|
||||
if (opb.read(1) != 1) {
|
||||
clear();
|
||||
return (-1);
|
||||
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int pack(Buffer opb) {
|
||||
// preamble
|
||||
opb.write(0x03, 8);
|
||||
opb.write(_vorbis);
|
||||
|
||||
// vendor
|
||||
opb.write(_vendor.length, 32);
|
||||
opb.write(_vendor);
|
||||
|
||||
// comments
|
||||
opb.write(comments, 32);
|
||||
if (comments != 0) {
|
||||
for (int i = 0; i < comments; i++) {
|
||||
if (user_comments[i] != null) {
|
||||
opb.write(comment_lengths[i], 32);
|
||||
opb.write(user_comments[i]);
|
||||
} else {
|
||||
opb.write(0, 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
opb.write(1, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int header_out(Packet op) {
|
||||
Buffer opb = new Buffer();
|
||||
opb.writeinit();
|
||||
|
||||
if (pack(opb) != 0)
|
||||
return OV_EIMPL;
|
||||
|
||||
op.packet_base = new byte[opb.bytes()];
|
||||
op.packet = 0;
|
||||
op.bytes = opb.bytes();
|
||||
System.arraycopy(opb.buffer(), 0, op.packet_base, 0, op.bytes);
|
||||
op.b_o_s = 0;
|
||||
op.e_o_s = 0;
|
||||
op.granulepos = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (int i = 0; i < comments; i++)
|
||||
user_comments[i] = null;
|
||||
user_comments = null;
|
||||
vendor = null;
|
||||
}
|
||||
|
||||
public String getVendor() {
|
||||
return new String(vendor, 0, vendor.length - 1);
|
||||
}
|
||||
|
||||
public String getComment(int i) {
|
||||
if (comments <= i)
|
||||
return null;
|
||||
return new String(user_comments[i], 0, user_comments[i].length - 1);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String foo = "Vendor: " + new String(vendor, 0, vendor.length - 1);
|
||||
for (int i = 0; i < comments; i++) {
|
||||
foo = foo + "\nComment: " + new String(user_comments[i], 0, user_comments[i].length - 1);
|
||||
}
|
||||
foo = foo + "\n";
|
||||
return foo;
|
||||
}
|
||||
}
|
1319
sources/wasm-gc-teavm/java/com/jcraft/jorbis/Drft.java
Normal file
1319
sources/wasm-gc-teavm/java/com/jcraft/jorbis/Drft.java
Normal file
File diff suppressed because it is too large
Load Diff
369
sources/wasm-gc-teavm/java/com/jcraft/jorbis/DspState.java
Normal file
369
sources/wasm-gc-teavm/java/com/jcraft/jorbis/DspState.java
Normal file
@ -0,0 +1,369 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jorbis;
|
||||
|
||||
public class DspState {
|
||||
static final float M_PI = 3.1415926539f;
|
||||
static final int VI_TRANSFORMB = 1;
|
||||
static final int VI_WINDOWB = 1;
|
||||
|
||||
int analysisp;
|
||||
Info vi;
|
||||
int modebits;
|
||||
|
||||
float[][] pcm;
|
||||
int pcm_storage;
|
||||
int pcm_current;
|
||||
int pcm_returned;
|
||||
|
||||
float[] multipliers;
|
||||
int envelope_storage;
|
||||
int envelope_current;
|
||||
|
||||
int eofflag;
|
||||
|
||||
int lW;
|
||||
int W;
|
||||
int nW;
|
||||
int centerW;
|
||||
|
||||
long granulepos;
|
||||
long sequence;
|
||||
|
||||
long glue_bits;
|
||||
long time_bits;
|
||||
long floor_bits;
|
||||
long res_bits;
|
||||
|
||||
// local lookup storage
|
||||
float[][][][][] window; // block, leadin, leadout, type
|
||||
Object[][] transform;
|
||||
CodeBook[] fullbooks;
|
||||
// backend lookups are tied to the mode, not the backend or naked mapping
|
||||
Object[] mode;
|
||||
|
||||
// local storage, only used on the encoding side. This way the
|
||||
// application does not need to worry about freeing some packets'
|
||||
// memory and not others'; packet storage is always tracked.
|
||||
// Cleared next call to a _dsp_ function
|
||||
byte[] header;
|
||||
byte[] header1;
|
||||
byte[] header2;
|
||||
|
||||
public DspState() {
|
||||
transform = new Object[2][];
|
||||
window = new float[2][][][][];
|
||||
window[0] = new float[2][][][];
|
||||
window[0][0] = new float[2][][];
|
||||
window[0][1] = new float[2][][];
|
||||
window[0][0][0] = new float[2][];
|
||||
window[0][0][1] = new float[2][];
|
||||
window[0][1][0] = new float[2][];
|
||||
window[0][1][1] = new float[2][];
|
||||
window[1] = new float[2][][][];
|
||||
window[1][0] = new float[2][][];
|
||||
window[1][1] = new float[2][][];
|
||||
window[1][0][0] = new float[2][];
|
||||
window[1][0][1] = new float[2][];
|
||||
window[1][1][0] = new float[2][];
|
||||
window[1][1][1] = new float[2][];
|
||||
}
|
||||
|
||||
static float[] window(int type, int window, int left, int right) {
|
||||
float[] ret = new float[window];
|
||||
switch (type) {
|
||||
case 0:
|
||||
// The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi)
|
||||
{
|
||||
int leftbegin = window / 4 - left / 2;
|
||||
int rightbegin = window - window / 4 - right / 2;
|
||||
|
||||
for (int i = 0; i < left; i++) {
|
||||
float x = (float) ((i + .5) / left * M_PI / 2.);
|
||||
x = (float) Math.sin(x);
|
||||
x *= x;
|
||||
x *= M_PI / 2.;
|
||||
x = (float) Math.sin(x);
|
||||
ret[i + leftbegin] = x;
|
||||
}
|
||||
|
||||
for (int i = leftbegin + left; i < rightbegin; i++) {
|
||||
ret[i] = 1.f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < right; i++) {
|
||||
float x = (float) ((right - i - .5) / right * M_PI / 2.);
|
||||
x = (float) Math.sin(x);
|
||||
x *= x;
|
||||
x *= M_PI / 2.;
|
||||
x = (float) Math.sin(x);
|
||||
ret[i + rightbegin] = x;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// free(ret);
|
||||
return (null);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
// Analysis side code, but directly related to blocking. Thus it's
|
||||
// here and not in analysis.c (which is for analysis transforms only).
|
||||
// The init is here because some of it is shared
|
||||
|
||||
int init(Info vi, boolean encp) {
|
||||
this.vi = vi;
|
||||
modebits = Util.ilog2(vi.modes);
|
||||
|
||||
transform[0] = new Object[VI_TRANSFORMB];
|
||||
transform[1] = new Object[VI_TRANSFORMB];
|
||||
|
||||
// MDCT is tranform 0
|
||||
|
||||
transform[0][0] = new Mdct();
|
||||
transform[1][0] = new Mdct();
|
||||
((Mdct) transform[0][0]).init(vi.blocksizes[0]);
|
||||
((Mdct) transform[1][0]).init(vi.blocksizes[1]);
|
||||
|
||||
window[0][0][0] = new float[VI_WINDOWB][];
|
||||
window[0][0][1] = window[0][0][0];
|
||||
window[0][1][0] = window[0][0][0];
|
||||
window[0][1][1] = window[0][0][0];
|
||||
window[1][0][0] = new float[VI_WINDOWB][];
|
||||
window[1][0][1] = new float[VI_WINDOWB][];
|
||||
window[1][1][0] = new float[VI_WINDOWB][];
|
||||
window[1][1][1] = new float[VI_WINDOWB][];
|
||||
|
||||
for (int i = 0; i < VI_WINDOWB; i++) {
|
||||
window[0][0][0][i] = window(i, vi.blocksizes[0], vi.blocksizes[0] / 2, vi.blocksizes[0] / 2);
|
||||
window[1][0][0][i] = window(i, vi.blocksizes[1], vi.blocksizes[0] / 2, vi.blocksizes[0] / 2);
|
||||
window[1][0][1][i] = window(i, vi.blocksizes[1], vi.blocksizes[0] / 2, vi.blocksizes[1] / 2);
|
||||
window[1][1][0][i] = window(i, vi.blocksizes[1], vi.blocksizes[1] / 2, vi.blocksizes[0] / 2);
|
||||
window[1][1][1][i] = window(i, vi.blocksizes[1], vi.blocksizes[1] / 2, vi.blocksizes[1] / 2);
|
||||
}
|
||||
|
||||
fullbooks = new CodeBook[vi.books];
|
||||
for (int i = 0; i < vi.books; i++) {
|
||||
fullbooks[i] = new CodeBook();
|
||||
fullbooks[i].init_decode(vi.book_param[i]);
|
||||
}
|
||||
|
||||
// initialize the storage vectors to a decent size greater than the
|
||||
// minimum
|
||||
|
||||
pcm_storage = 8192; // we'll assume later that we have
|
||||
// a minimum of twice the blocksize of
|
||||
// accumulated samples in analysis
|
||||
pcm = new float[vi.channels][];
|
||||
{
|
||||
for (int i = 0; i < vi.channels; i++) {
|
||||
pcm[i] = new float[pcm_storage];
|
||||
}
|
||||
}
|
||||
|
||||
// all 1 (large block) or 0 (small block)
|
||||
// explicitly set for the sake of clarity
|
||||
lW = 0; // previous window size
|
||||
W = 0; // current window size
|
||||
|
||||
// all vector indexes; multiples of samples_per_envelope_step
|
||||
centerW = vi.blocksizes[1] / 2;
|
||||
|
||||
pcm_current = centerW;
|
||||
|
||||
// initialize all the mapping/backend lookups
|
||||
mode = new Object[vi.modes];
|
||||
for (int i = 0; i < vi.modes; i++) {
|
||||
int mapnum = vi.mode_param[i].mapping;
|
||||
int maptype = vi.map_type[mapnum];
|
||||
mode[i] = FuncMapping.mapping_P[maptype].look(this, vi.mode_param[i], vi.map_param[mapnum]);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int synthesis_init(Info vi) {
|
||||
init(vi, false);
|
||||
// Adjust centerW to allow an easier mechanism for determining output
|
||||
pcm_returned = centerW;
|
||||
centerW -= vi.blocksizes[W] / 4 + vi.blocksizes[lW] / 4;
|
||||
granulepos = -1;
|
||||
sequence = -1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
DspState(Info vi) {
|
||||
this();
|
||||
init(vi, false);
|
||||
// Adjust centerW to allow an easier mechanism for determining output
|
||||
pcm_returned = centerW;
|
||||
centerW -= vi.blocksizes[W] / 4 + vi.blocksizes[lW] / 4;
|
||||
granulepos = -1;
|
||||
sequence = -1;
|
||||
}
|
||||
|
||||
// Unike in analysis, the window is only partially applied for each
|
||||
// block. The time domain envelope is not yet handled at the point of
|
||||
// calling (as it relies on the previous block).
|
||||
|
||||
public int synthesis_blockin(Block vb) {
|
||||
// Shift out any PCM/multipliers that we returned previously
|
||||
// centerW is currently the center of the last block added
|
||||
if (centerW > vi.blocksizes[1] / 2 && pcm_returned > 8192) {
|
||||
// don't shift too much; we need to have a minimum PCM buffer of
|
||||
// 1/2 long block
|
||||
|
||||
int shiftPCM = centerW - vi.blocksizes[1] / 2;
|
||||
shiftPCM = (pcm_returned < shiftPCM ? pcm_returned : shiftPCM);
|
||||
|
||||
pcm_current -= shiftPCM;
|
||||
centerW -= shiftPCM;
|
||||
pcm_returned -= shiftPCM;
|
||||
if (shiftPCM != 0) {
|
||||
for (int i = 0; i < vi.channels; i++) {
|
||||
System.arraycopy(pcm[i], shiftPCM, pcm[i], 0, pcm_current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lW = W;
|
||||
W = vb.W;
|
||||
nW = -1;
|
||||
|
||||
glue_bits += vb.glue_bits;
|
||||
time_bits += vb.time_bits;
|
||||
floor_bits += vb.floor_bits;
|
||||
res_bits += vb.res_bits;
|
||||
|
||||
if (sequence + 1 != vb.sequence)
|
||||
granulepos = -1; // out of sequence; lose count
|
||||
|
||||
sequence = vb.sequence;
|
||||
|
||||
{
|
||||
int sizeW = vi.blocksizes[W];
|
||||
int _centerW = centerW + vi.blocksizes[lW] / 4 + sizeW / 4;
|
||||
int beginW = _centerW - sizeW / 2;
|
||||
int endW = beginW + sizeW;
|
||||
int beginSl = 0;
|
||||
int endSl = 0;
|
||||
|
||||
// Do we have enough PCM/mult storage for the block?
|
||||
if (endW > pcm_storage) {
|
||||
// expand the storage
|
||||
pcm_storage = endW + vi.blocksizes[1];
|
||||
for (int i = 0; i < vi.channels; i++) {
|
||||
float[] foo = new float[pcm_storage];
|
||||
System.arraycopy(pcm[i], 0, foo, 0, pcm[i].length);
|
||||
pcm[i] = foo;
|
||||
}
|
||||
}
|
||||
|
||||
// overlap/add PCM
|
||||
switch (W) {
|
||||
case 0:
|
||||
beginSl = 0;
|
||||
endSl = vi.blocksizes[0] / 2;
|
||||
break;
|
||||
case 1:
|
||||
beginSl = vi.blocksizes[1] / 4 - vi.blocksizes[lW] / 4;
|
||||
endSl = beginSl + vi.blocksizes[lW] / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int j = 0; j < vi.channels; j++) {
|
||||
int _pcm = beginW;
|
||||
// the overlap/add section
|
||||
int i = 0;
|
||||
for (i = beginSl; i < endSl; i++) {
|
||||
pcm[j][_pcm + i] += vb.pcm[j][i];
|
||||
}
|
||||
// the remaining section
|
||||
for (; i < sizeW; i++) {
|
||||
pcm[j][_pcm + i] = vb.pcm[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
// track the frame number... This is for convenience, but also
|
||||
// making sure our last packet doesn't end with added padding. If
|
||||
// the last packet is partial, the number of samples we'll have to
|
||||
// return will be past the vb->granulepos.
|
||||
//
|
||||
// This is not foolproof! It will be confused if we begin
|
||||
// decoding at the last page after a seek or hole. In that case,
|
||||
// we don't have a starting point to judge where the last frame
|
||||
// is. For this reason, vorbisfile will always try to make sure
|
||||
// it reads the last two marked pages in proper sequence
|
||||
|
||||
if (granulepos == -1) {
|
||||
granulepos = vb.granulepos;
|
||||
} else {
|
||||
granulepos += (_centerW - centerW);
|
||||
if (vb.granulepos != -1 && granulepos != vb.granulepos) {
|
||||
if (granulepos > vb.granulepos && vb.eofflag != 0) {
|
||||
// partial last frame. Strip the padding off
|
||||
_centerW -= (granulepos - vb.granulepos);
|
||||
} // else{ Shouldn't happen *unless* the bitstream is out of
|
||||
// spec. Either way, believe the bitstream }
|
||||
granulepos = vb.granulepos;
|
||||
}
|
||||
}
|
||||
|
||||
// Update, cleanup
|
||||
|
||||
centerW = _centerW;
|
||||
pcm_current = endW;
|
||||
if (vb.eofflag != 0)
|
||||
eofflag = 1;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// pcm==NULL indicates we just want the pending samples, no more
|
||||
public int synthesis_pcmout(float[][][] _pcm, int[] index) {
|
||||
if (pcm_returned < centerW) {
|
||||
if (_pcm != null) {
|
||||
for (int i = 0; i < vi.channels; i++) {
|
||||
index[i] = pcm_returned;
|
||||
}
|
||||
_pcm[0] = pcm;
|
||||
}
|
||||
return (centerW - pcm_returned);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int synthesis_read(int bytes) {
|
||||
if (bytes != 0 && pcm_returned + bytes > centerW)
|
||||
return (-1);
|
||||
pcm_returned += bytes;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
}
|
||||
}
|
332
sources/wasm-gc-teavm/java/com/jcraft/jorbis/Floor0.java
Normal file
332
sources/wasm-gc-teavm/java/com/jcraft/jorbis/Floor0.java
Normal file
@ -0,0 +1,332 @@
|
||||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
class Floor0 extends FuncFloor {
|
||||
|
||||
void pack(Object i, Buffer opb) {
|
||||
InfoFloor0 info = (InfoFloor0) i;
|
||||
opb.write(info.order, 8);
|
||||
opb.write(info.rate, 16);
|
||||
opb.write(info.barkmap, 16);
|
||||
opb.write(info.ampbits, 6);
|
||||
opb.write(info.ampdB, 8);
|
||||
opb.write(info.numbooks - 1, 4);
|
||||
for (int j = 0; j < info.numbooks; j++)
|
||||
opb.write(info.books[j], 8);
|
||||
}
|
||||
|
||||
Object unpack(Info vi, Buffer opb) {
|
||||
InfoFloor0 info = new InfoFloor0();
|
||||
info.order = opb.read(8);
|
||||
info.rate = opb.read(16);
|
||||
info.barkmap = opb.read(16);
|
||||
info.ampbits = opb.read(6);
|
||||
info.ampdB = opb.read(8);
|
||||
info.numbooks = opb.read(4) + 1;
|
||||
|
||||
if ((info.order < 1) || (info.rate < 1) || (info.barkmap < 1) || (info.numbooks < 1)) {
|
||||
return (null);
|
||||
}
|
||||
|
||||
for (int j = 0; j < info.numbooks; j++) {
|
||||
info.books[j] = opb.read(8);
|
||||
if (info.books[j] < 0 || info.books[j] >= vi.books) {
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
return (info);
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode mi, Object i) {
|
||||
float scale;
|
||||
Info vi = vd.vi;
|
||||
InfoFloor0 info = (InfoFloor0) i;
|
||||
LookFloor0 look = new LookFloor0();
|
||||
look.m = info.order;
|
||||
look.n = vi.blocksizes[mi.blockflag] / 2;
|
||||
look.ln = info.barkmap;
|
||||
look.vi = info;
|
||||
look.lpclook.init(look.ln, look.m);
|
||||
|
||||
// we choose a scaling constant so that:
|
||||
scale = look.ln / toBARK((float) (info.rate / 2.));
|
||||
|
||||
// the mapping from a linear scale to a smaller bark scale is
|
||||
// straightforward. We do *not* make sure that the linear mapping
|
||||
// does not skip bark-scale bins; the decoder simply skips them and
|
||||
// the encoder may do what it wishes in filling them. They're
|
||||
// necessary in some mapping combinations to keep the scale spacing
|
||||
// accurate
|
||||
look.linearmap = new int[look.n];
|
||||
for (int j = 0; j < look.n; j++) {
|
||||
int val = (int) Math.floor(toBARK((float) ((info.rate / 2.) / look.n * j)) * scale); // bark numbers
|
||||
// represent band
|
||||
// edges
|
||||
if (val >= look.ln)
|
||||
val = look.ln; // guard against the approximation
|
||||
look.linearmap[j] = val;
|
||||
}
|
||||
return look;
|
||||
}
|
||||
|
||||
static float toBARK(float f) {
|
||||
return (float) (13.1 * Math.atan(.00074 * (f)) + 2.24 * Math.atan((f) * (f) * 1.85e-8) + 1e-4 * (f));
|
||||
}
|
||||
|
||||
Object state(Object i) {
|
||||
EchstateFloor0 state = new EchstateFloor0();
|
||||
InfoFloor0 info = (InfoFloor0) i;
|
||||
|
||||
// a safe size if usually too big (dim==1)
|
||||
state.codewords = new int[info.order];
|
||||
state.curve = new float[info.barkmap];
|
||||
state.frameno = -1;
|
||||
return (state);
|
||||
}
|
||||
|
||||
void free_info(Object i) {
|
||||
}
|
||||
|
||||
void free_look(Object i) {
|
||||
}
|
||||
|
||||
void free_state(Object vs) {
|
||||
}
|
||||
|
||||
int forward(Block vb, Object i, float[] in, float[] out, Object vs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float[] lsp = null;
|
||||
|
||||
int inverse(Block vb, Object i, float[] out) {
|
||||
// System.err.println("Floor0.inverse "+i.getClass()+"]");
|
||||
LookFloor0 look = (LookFloor0) i;
|
||||
InfoFloor0 info = look.vi;
|
||||
int ampraw = vb.opb.read(info.ampbits);
|
||||
if (ampraw > 0) { // also handles the -1 out of data case
|
||||
int maxval = (1 << info.ampbits) - 1;
|
||||
float amp = (float) ampraw / maxval * info.ampdB;
|
||||
int booknum = vb.opb.read(Util.ilog(info.numbooks));
|
||||
|
||||
if (booknum != -1 && booknum < info.numbooks) {
|
||||
|
||||
synchronized (this) {
|
||||
if (lsp == null || lsp.length < look.m) {
|
||||
lsp = new float[look.m];
|
||||
} else {
|
||||
for (int j = 0; j < look.m; j++)
|
||||
lsp[j] = 0.f;
|
||||
}
|
||||
|
||||
CodeBook b = vb.vd.fullbooks[info.books[booknum]];
|
||||
float last = 0.f;
|
||||
|
||||
for (int j = 0; j < look.m; j++)
|
||||
out[j] = 0.0f;
|
||||
|
||||
for (int j = 0; j < look.m; j += b.dim) {
|
||||
if (b.decodevs(lsp, j, vb.opb, 1, -1) == -1) {
|
||||
for (int k = 0; k < look.n; k++)
|
||||
out[k] = 0.0f;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < look.m;) {
|
||||
for (int k = 0; k < b.dim; k++, j++)
|
||||
lsp[j] += last;
|
||||
last = lsp[j - 1];
|
||||
}
|
||||
// take the coefficients back to a spectral envelope curve
|
||||
Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m, amp, info.ampdB);
|
||||
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
Object inverse1(Block vb, Object i, Object memo) {
|
||||
LookFloor0 look = (LookFloor0) i;
|
||||
InfoFloor0 info = look.vi;
|
||||
float[] lsp = null;
|
||||
if (memo instanceof float[]) {
|
||||
lsp = (float[]) memo;
|
||||
}
|
||||
|
||||
int ampraw = vb.opb.read(info.ampbits);
|
||||
if (ampraw > 0) { // also handles the -1 out of data case
|
||||
int maxval = (1 << info.ampbits) - 1;
|
||||
float amp = (float) ampraw / maxval * info.ampdB;
|
||||
int booknum = vb.opb.read(Util.ilog(info.numbooks));
|
||||
|
||||
if (booknum != -1 && booknum < info.numbooks) {
|
||||
CodeBook b = vb.vd.fullbooks[info.books[booknum]];
|
||||
float last = 0.f;
|
||||
|
||||
if (lsp == null || lsp.length < look.m + 1) {
|
||||
lsp = new float[look.m + 1];
|
||||
} else {
|
||||
for (int j = 0; j < lsp.length; j++)
|
||||
lsp[j] = 0.f;
|
||||
}
|
||||
|
||||
for (int j = 0; j < look.m; j += b.dim) {
|
||||
if (b.decodev_set(lsp, j, vb.opb, b.dim) == -1) {
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < look.m;) {
|
||||
for (int k = 0; k < b.dim; k++, j++)
|
||||
lsp[j] += last;
|
||||
last = lsp[j - 1];
|
||||
}
|
||||
lsp[look.m] = amp;
|
||||
return (lsp);
|
||||
}
|
||||
}
|
||||
return (null);
|
||||
}
|
||||
|
||||
int inverse2(Block vb, Object i, Object memo, float[] out) {
|
||||
LookFloor0 look = (LookFloor0) i;
|
||||
InfoFloor0 info = look.vi;
|
||||
|
||||
if (memo != null) {
|
||||
float[] lsp = (float[]) memo;
|
||||
float amp = lsp[look.m];
|
||||
|
||||
Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m, amp, info.ampdB);
|
||||
return (1);
|
||||
}
|
||||
for (int j = 0; j < look.n; j++) {
|
||||
out[j] = 0.f;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static float fromdB(float x) {
|
||||
return (float) (Math.exp((x) * .11512925));
|
||||
}
|
||||
|
||||
static void lsp_to_lpc(float[] lsp, float[] lpc, int m) {
|
||||
int i, j, m2 = m / 2;
|
||||
float[] O = new float[m2];
|
||||
float[] E = new float[m2];
|
||||
float A;
|
||||
float[] Ae = new float[m2 + 1];
|
||||
float[] Ao = new float[m2 + 1];
|
||||
float B;
|
||||
float[] Be = new float[m2];
|
||||
float[] Bo = new float[m2];
|
||||
float temp;
|
||||
|
||||
// even/odd roots setup
|
||||
for (i = 0; i < m2; i++) {
|
||||
O[i] = (float) (-2. * Math.cos(lsp[i * 2]));
|
||||
E[i] = (float) (-2. * Math.cos(lsp[i * 2 + 1]));
|
||||
}
|
||||
|
||||
// set up impulse response
|
||||
for (j = 0; j < m2; j++) {
|
||||
Ae[j] = 0.f;
|
||||
Ao[j] = 1.f;
|
||||
Be[j] = 0.f;
|
||||
Bo[j] = 1.f;
|
||||
}
|
||||
Ao[j] = 1.f;
|
||||
Ae[j] = 1.f;
|
||||
|
||||
// run impulse response
|
||||
for (i = 1; i < m + 1; i++) {
|
||||
A = B = 0.f;
|
||||
for (j = 0; j < m2; j++) {
|
||||
temp = O[j] * Ao[j] + Ae[j];
|
||||
Ae[j] = Ao[j];
|
||||
Ao[j] = A;
|
||||
A += temp;
|
||||
|
||||
temp = E[j] * Bo[j] + Be[j];
|
||||
Be[j] = Bo[j];
|
||||
Bo[j] = B;
|
||||
B += temp;
|
||||
}
|
||||
lpc[i - 1] = (A + Ao[j] + B - Ae[j]) / 2;
|
||||
Ao[j] = A;
|
||||
Ae[j] = B;
|
||||
}
|
||||
}
|
||||
|
||||
static void lpc_to_curve(float[] curve, float[] lpc, float amp, LookFloor0 l, String name, int frameno) {
|
||||
// l->m+1 must be less than l->ln, but guard in case we get a bad stream
|
||||
float[] lcurve = new float[Math.max(l.ln * 2, l.m * 2 + 2)];
|
||||
|
||||
if (amp == 0) {
|
||||
for (int j = 0; j < l.n; j++)
|
||||
curve[j] = 0.0f;
|
||||
return;
|
||||
}
|
||||
l.lpclook.lpc_to_curve(lcurve, lpc, amp);
|
||||
|
||||
for (int i = 0; i < l.n; i++)
|
||||
curve[i] = lcurve[l.linearmap[i]];
|
||||
}
|
||||
|
||||
class InfoFloor0 {
|
||||
int order;
|
||||
int rate;
|
||||
int barkmap;
|
||||
|
||||
int ampbits;
|
||||
int ampdB;
|
||||
|
||||
int numbooks; // <= 16
|
||||
int[] books = new int[16];
|
||||
}
|
||||
|
||||
class LookFloor0 {
|
||||
int n;
|
||||
int ln;
|
||||
int m;
|
||||
int[] linearmap;
|
||||
|
||||
InfoFloor0 vi;
|
||||
Lpc lpclook = new Lpc();
|
||||
}
|
||||
|
||||
class EchstateFloor0 {
|
||||
int[] codewords;
|
||||
float[] curve;
|
||||
long frameno;
|
||||
long codes;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user