Merge branch 'smartcmd:main' into main

This commit is contained in:
aria 2026-03-08 16:30:38 -05:00 committed by GitHub
commit 1e72339d45
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
146 changed files with 26190 additions and 13621 deletions

8
.gitattributes vendored Normal file
View file

@ -0,0 +1,8 @@
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.binka filter=lfs diff=lfs merge=lfs -text
*.arc filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.ico filter=lfs diff=lfs merge=lfs -text

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: MinecraftConsoles Community Discord
url: https://discord.gg/jrum7HhegA
about: If you need help, please ask for it in our Discord! You will get assistance much faster there, including help getting the project to compile.

View file

@ -30,7 +30,6 @@ jobs:
- name: Update release - name: Update release
uses: andelf/nightly-release@main uses: andelf/nightly-release@main
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:

View file

@ -1,6 +1,9 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.24)
project(MinecraftConsoles LANGUAGES C CXX RC ASM_MASM) project(MinecraftConsoles LANGUAGES C CXX RC ASM_MASM)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if(NOT WIN32) if(NOT WIN32)
message(FATAL_ERROR "This CMake build currently supports Windows only.") message(FATAL_ERROR "This CMake build currently supports Windows only.")
@ -51,6 +54,7 @@ target_include_directories(MinecraftClient PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/include" "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/include"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Xbox/Sentient/Include" "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Xbox/Sentient/Include"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/x64headers" "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/x64headers"
"${CMAKE_CURRENT_SOURCE_DIR}/include/"
) )
target_compile_definitions(MinecraftClient PRIVATE target_compile_definitions(MinecraftClient PRIVATE
$<$<CONFIG:Debug>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_DEBUG;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64> $<$<CONFIG:Debug>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_DEBUG;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64>

View file

@ -1,6 +1,34 @@
# Scope of Project # Scope of Project
At the moment, this project's scope is generally limited outside of adding new content to the game (blocks, mobs, items). We are currently prioritizing stability, quality of life, and platform support over these things. At the moment, this project's scope is generally limited outside of adding new content to the game (blocks, mobs, items). We are currently prioritizing stability, quality of life, and platform support over these things.
## Parity
We are attempting to keep our version of LCE as close to visual and experience parity with the original console experience of LCE as possible. This means that we will not be accepting changes that...
- Backport things from Java Edition that did not ever exist in LCE
- Swap out LCE visuals for Java Edition or Bedrock Edition style visuals
- Change LCE defaults in favor of different defaults if it changes the experience
- For example, increasing mob spawn limits without increasing the area mobs can spawn within, aka increasing mob density past what was the original console experience
- Redesign UI components different than LCE
- Break controller support, or otherwise do not support play with a controller
- Add custom texture packs or DLC that never existed in LCE
- Add any gameplay content (block, item, mob) that has no existing point of reference in any official LCE build
However, we would accept changes that...
- Fix legitimately buggy or inconsistent behavior in LCE that causes unexpected outcomes
- For example, mobs clipping outside of walls, clipping through the world, broken mechanics
- Add features to better support multi-platform use of LCE, such as video and control settings
- These menus need to respect the visual style of LCE, though.
- Replace existing UI systems with SWF-free rendering techniques that are as visually and functionally identical as possible
- Improve the quality of assets (such as sounds) while preserving their contents
- For example, upgrading the quality of all music in-game while preserving any unique cuts / versions, or faithfully remaking those unique cuts / versions with higher quality assets
- Backport things like modern skin rendering
- Change the code from using non-stitched textures to individually named texture PNGs and stitching at runtime
- Adding menus to better support custom dedicated servers with their own fixed IPs
- Add support for things like Steamworks Networking and other P2P networking and auth strategies
- Improve Keyboard and Mouse control support
- Add minimal, non-invasive Quality of Life features that don't otherwise compromise the LCE experience
- For example, adjusting certain crafting recipes or change item behaviors like non-stackable doors
## Current Goals ## Current Goals
- Being a robust Desktop version of LCE - Being a robust Desktop version of LCE
- Having proper controller support across all types, brands on Desktop or Desktop-like platforms (Steam Deck) - Having proper controller support across all types, brands on Desktop or Desktop-like platforms (Steam Deck)

View file

@ -142,6 +142,13 @@ ClientConnection::ClientConnection(Minecraft *minecraft, Socket *socket, int iUs
deferredEntityLinkPackets = vector<DeferredEntityLinkPacket>(); deferredEntityLinkPackets = vector<DeferredEntityLinkPacket>();
} }
bool ClientConnection::isPrimaryConnection() const
{
// On host, all connections are primary (server is authoritative).
// On non-host, only the primary pad processes shared entity state.
return g_NetworkManager.IsHost() || m_userIndex == ProfileManager.GetPrimaryPad();
}
ClientConnection::~ClientConnection() ClientConnection::~ClientConnection()
{ {
delete connection; delete connection;
@ -304,6 +311,10 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
level->isClientSide = true; level->isClientSide = true;
minecraft->setLevel(level); minecraft->setLevel(level);
} }
else
{
level = (MultiPlayerLevel *)dimensionLevel;
}
minecraft->player->setPlayerIndex( packet->m_playerIndex ); minecraft->player->setPlayerIndex( packet->m_playerIndex );
minecraft->player->setCustomSkin( app.GetPlayerSkinId(m_userIndex) ); minecraft->player->setCustomSkin( app.GetPlayerSkinId(m_userIndex) );
@ -427,6 +438,7 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
{ {
case AddEntityPacket::MINECART: case AddEntityPacket::MINECART:
e = Minecart::createMinecart(level, x, y, z, packet->data); e = Minecart::createMinecart(level, x, y, z, packet->data);
break;
case AddEntityPacket::FISH_HOOK: case AddEntityPacket::FISH_HOOK:
{ {
// 4J Stu - Brought forward from 1.4 to be able to drop XP from fishing // 4J Stu - Brought forward from 1.4 to be able to drop XP from fishing
@ -704,6 +716,7 @@ void ClientConnection::handleAddExperienceOrb(shared_ptr<AddExperienceOrbPacket>
void ClientConnection::handleAddGlobalEntity(shared_ptr<AddGlobalEntityPacket> packet) void ClientConnection::handleAddGlobalEntity(shared_ptr<AddGlobalEntityPacket> packet)
{ {
if (!isPrimaryConnection()) return;
double x = packet->x / 32.0; double x = packet->x / 32.0;
double y = packet->y / 32.0; double y = packet->y / 32.0;
double z = packet->z / 32.0; double z = packet->z / 32.0;
@ -729,6 +742,13 @@ void ClientConnection::handleAddPainting(shared_ptr<AddPaintingPacket> packet)
void ClientConnection::handleSetEntityMotion(shared_ptr<SetEntityMotionPacket> packet) void ClientConnection::handleSetEntityMotion(shared_ptr<SetEntityMotionPacket> packet)
{ {
if (!isPrimaryConnection())
{
// Secondary connection: only accept motion for our own local player (knockback)
if (minecraft->localplayers[m_userIndex] == NULL ||
packet->id != minecraft->localplayers[m_userIndex]->entityId)
return;
}
shared_ptr<Entity> e = getEntity(packet->id); shared_ptr<Entity> e = getEntity(packet->id);
if (e == NULL) return; if (e == NULL) return;
e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0); e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0);
@ -952,6 +972,7 @@ void ClientConnection::handleSetCarriedItem(shared_ptr<SetCarriedItemPacket> pac
void ClientConnection::handleMoveEntity(shared_ptr<MoveEntityPacket> packet) void ClientConnection::handleMoveEntity(shared_ptr<MoveEntityPacket> packet)
{ {
if (!isPrimaryConnection()) return;
shared_ptr<Entity> e = getEntity(packet->id); shared_ptr<Entity> e = getEntity(packet->id);
if (e == NULL) return; if (e == NULL) return;
e->xp += packet->xa; e->xp += packet->xa;
@ -981,6 +1002,7 @@ void ClientConnection::handleRotateMob(shared_ptr<RotateHeadPacket> packet)
void ClientConnection::handleMoveEntitySmall(shared_ptr<MoveEntityPacketSmall> packet) void ClientConnection::handleMoveEntitySmall(shared_ptr<MoveEntityPacketSmall> packet)
{ {
if (!isPrimaryConnection()) return;
shared_ptr<Entity> e = getEntity(packet->id); shared_ptr<Entity> e = getEntity(packet->id);
if (e == NULL) return; if (e == NULL) return;
e->xp += packet->xa; e->xp += packet->xa;
@ -1105,6 +1127,7 @@ void ClientConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet)
// 4J Added // 4J Added
void ClientConnection::handleChunkVisibilityArea(shared_ptr<ChunkVisibilityAreaPacket> packet) void ClientConnection::handleChunkVisibilityArea(shared_ptr<ChunkVisibilityAreaPacket> packet)
{ {
if (level == NULL) return;
for(int z = packet->m_minZ; z <= packet->m_maxZ; ++z) for(int z = packet->m_minZ; z <= packet->m_maxZ; ++z)
for(int x = packet->m_minX; x <= packet->m_maxX; ++x) for(int x = packet->m_minX; x <= packet->m_maxX; ++x)
level->setChunkVisible(x, z, true); level->setChunkVisible(x, z, true);
@ -1112,11 +1135,13 @@ void ClientConnection::handleChunkVisibilityArea(shared_ptr<ChunkVisibilityAreaP
void ClientConnection::handleChunkVisibility(shared_ptr<ChunkVisibilityPacket> packet) void ClientConnection::handleChunkVisibility(shared_ptr<ChunkVisibilityPacket> packet)
{ {
if (level == NULL) return;
level->setChunkVisible(packet->x, packet->z, packet->visible); level->setChunkVisible(packet->x, packet->z, packet->visible);
} }
void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket> packet) void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket> packet)
{ {
if (!isPrimaryConnection()) return;
// 4J - changed to encode level in packet // 4J - changed to encode level in packet
MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx]; MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx];
if( dimensionLevel ) if( dimensionLevel )
@ -1186,16 +1211,29 @@ void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket>
void ClientConnection::handleBlockRegionUpdate(shared_ptr<BlockRegionUpdatePacket> packet) void ClientConnection::handleBlockRegionUpdate(shared_ptr<BlockRegionUpdatePacket> packet)
{ {
if (!isPrimaryConnection()) return;
// 4J - changed to encode level in packet // 4J - changed to encode level in packet
MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx]; MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx];
if( dimensionLevel ) if( dimensionLevel )
{ {
PIXBeginNamedEvent(0,"Handle block region update"); PIXBeginNamedEvent(0,"Handle block region update");
if(packet->bIsFullChunk && packet->ys == 0)
{
app.DebugPrintf("[BRUP-CLIENT] *** EMPTY FULL CHUNK received at (%d,%d)! Buffer length=%d\n",
packet->x>>4, packet->z>>4, packet->buffer.length);
}
int y1 = packet->y + packet->ys; int y1 = packet->y + packet->ys;
if(packet->bIsFullChunk) if(packet->bIsFullChunk)
{ {
y1 = Level::maxBuildHeight; y1 = Level::maxBuildHeight;
// Ensure the chunk exists in the cache before writing data.
// The ChunkVisibilityAreaPacket that creates chunks can arrive AFTER the first BRUP,
// causing getChunk() to return EmptyLevelChunk (whose setBlocksAndData is a no-op).
dimensionLevel->setChunkVisible(packet->x >> 4, packet->z >> 4, true);
if(packet->buffer.length > 0) if(packet->buffer.length > 0)
{ {
PIXBeginNamedEvent(0, "Reordering to XZY"); PIXBeginNamedEvent(0, "Reordering to XZY");
@ -1234,6 +1272,7 @@ void ClientConnection::handleBlockRegionUpdate(shared_ptr<BlockRegionUpdatePacke
void ClientConnection::handleTileUpdate(shared_ptr<TileUpdatePacket> packet) void ClientConnection::handleTileUpdate(shared_ptr<TileUpdatePacket> packet)
{ {
if (!isPrimaryConnection()) return;
// 4J added - using a block of 255 to signify that this is a packet for destroying a tile, where we need to inform the level renderer that we are about to do so. // 4J added - using a block of 255 to signify that this is a packet for destroying a tile, where we need to inform the level renderer that we are about to do so.
// This is used in creative mode as the point where a tile is first destroyed at the client end of things. Packets formed like this are potentially sent from // This is used in creative mode as the point where a tile is first destroyed at the client end of things. Packets formed like this are potentially sent from
// ServerPlayerGameMode::destroyBlock // ServerPlayerGameMode::destroyBlock
@ -1348,6 +1387,7 @@ void ClientConnection::send(shared_ptr<Packet> packet)
void ClientConnection::handleTakeItemEntity(shared_ptr<TakeItemEntityPacket> packet) void ClientConnection::handleTakeItemEntity(shared_ptr<TakeItemEntityPacket> packet)
{ {
if (!isPrimaryConnection()) return;
shared_ptr<Entity> from = getEntity(packet->itemId); shared_ptr<Entity> from = getEntity(packet->itemId);
shared_ptr<LivingEntity> to = dynamic_pointer_cast<LivingEntity>(getEntity(packet->playerId)); shared_ptr<LivingEntity> to = dynamic_pointer_cast<LivingEntity>(getEntity(packet->playerId));
@ -2846,31 +2886,34 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
void ClientConnection::handleExplosion(shared_ptr<ExplodePacket> packet) void ClientConnection::handleExplosion(shared_ptr<ExplodePacket> packet)
{ {
if(!packet->m_bKnockbackOnly) // World modification (block destruction) must only happen once
if (isPrimaryConnection())
{ {
//app.DebugPrintf("Received ExplodePacket with explosion data\n"); if(!packet->m_bKnockbackOnly)
PIXBeginNamedEvent(0,"Handling explosion"); {
Explosion *e = new Explosion(minecraft->level, nullptr, packet->x, packet->y, packet->z, packet->r); //app.DebugPrintf("Received ExplodePacket with explosion data\n");
PIXBeginNamedEvent(0,"Finalizing"); PIXBeginNamedEvent(0,"Handling explosion");
Explosion *e = new Explosion(minecraft->level, nullptr, packet->x, packet->y, packet->z, packet->r);
PIXBeginNamedEvent(0,"Finalizing");
// Fix for #81758 - TCR 006 BAS Non-Interactive Pause: TU9: Performance: Gameplay: After detonating bunch of TNT, game enters unresponsive state for couple of seconds. // Fix for #81758 - TCR 006 BAS Non-Interactive Pause: TU9: Performance: Gameplay: After detonating bunch of TNT, game enters unresponsive state for couple of seconds.
// The changes we are making here have been decided by the server, so we don't need to add them to the vector that resets tiles changes made // The changes we are making here have been decided by the server, so we don't need to add them to the vector that resets tiles changes made
// on the client as we KNOW that the server is matching these changes // on the client as we KNOW that the server is matching these changes
MultiPlayerLevel *mpLevel = (MultiPlayerLevel *)minecraft->level; MultiPlayerLevel *mpLevel = (MultiPlayerLevel *)minecraft->level;
mpLevel->enableResetChanges(false); mpLevel->enableResetChanges(false);
// 4J - now directly pass a pointer to the toBlow array in the packet rather than copying around // 4J - now directly pass a pointer to the toBlow array in the packet rather than copying around
e->finalizeExplosion(true, &packet->toBlow); e->finalizeExplosion(true, &packet->toBlow);
mpLevel->enableResetChanges(true); mpLevel->enableResetChanges(true);
PIXEndNamedEvent(); PIXEndNamedEvent();
PIXEndNamedEvent(); PIXEndNamedEvent();
delete e; delete e;
} }
else
{
//app.DebugPrintf("Received ExplodePacket with knockback only data\n");
} }
// Per-player knockback — each connection applies to its own local player
//app.DebugPrintf("Adding knockback (%f,%f,%f) for player %d\n", packet->getKnockbackX(), packet->getKnockbackY(), packet->getKnockbackZ(), m_userIndex); //app.DebugPrintf("Adding knockback (%f,%f,%f) for player %d\n", packet->getKnockbackX(), packet->getKnockbackY(), packet->getKnockbackZ(), m_userIndex);
if (minecraft->localplayers[m_userIndex] == NULL)
return;
minecraft->localplayers[m_userIndex]->xd += packet->getKnockbackX(); minecraft->localplayers[m_userIndex]->xd += packet->getKnockbackX();
minecraft->localplayers[m_userIndex]->yd += packet->getKnockbackY(); minecraft->localplayers[m_userIndex]->yd += packet->getKnockbackY();
minecraft->localplayers[m_userIndex]->zd += packet->getKnockbackZ(); minecraft->localplayers[m_userIndex]->zd += packet->getKnockbackZ();
@ -2880,6 +2923,8 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
{ {
bool failed = false; bool failed = false;
shared_ptr<MultiplayerLocalPlayer> player = minecraft->localplayers[m_userIndex]; shared_ptr<MultiplayerLocalPlayer> player = minecraft->localplayers[m_userIndex];
if (player == NULL)
return;
switch(packet->type) switch(packet->type)
{ {
case ContainerOpenPacket::BONUS_CHEST: case ContainerOpenPacket::BONUS_CHEST:
@ -3186,6 +3231,7 @@ void ClientConnection::handleTileEditorOpen(shared_ptr<TileEditorOpenPacket> pac
void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet) void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)
{ {
if (!isPrimaryConnection()) return;
app.DebugPrintf("ClientConnection::handleSignUpdate - "); app.DebugPrintf("ClientConnection::handleSignUpdate - ");
if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z)) if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z))
{ {
@ -3219,6 +3265,7 @@ void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)
void ClientConnection::handleTileEntityData(shared_ptr<TileEntityDataPacket> packet) void ClientConnection::handleTileEntityData(shared_ptr<TileEntityDataPacket> packet)
{ {
if (!isPrimaryConnection()) return;
if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z)) if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z))
{ {
shared_ptr<TileEntity> te = minecraft->level->getTileEntity(packet->x, packet->y, packet->z); shared_ptr<TileEntity> te = minecraft->level->getTileEntity(packet->x, packet->y, packet->z);
@ -3271,6 +3318,7 @@ void ClientConnection::handleContainerClose(shared_ptr<ContainerClosePacket> pac
void ClientConnection::handleTileEvent(shared_ptr<TileEventPacket> packet) void ClientConnection::handleTileEvent(shared_ptr<TileEventPacket> packet)
{ {
if (!isPrimaryConnection()) return;
PIXBeginNamedEvent(0,"Handle tile event\n"); PIXBeginNamedEvent(0,"Handle tile event\n");
minecraft->level->tileEvent(packet->x, packet->y, packet->z, packet->tile, packet->b0, packet->b1); minecraft->level->tileEvent(packet->x, packet->y, packet->z, packet->tile, packet->b0, packet->b1);
PIXEndNamedEvent(); PIXEndNamedEvent();
@ -3278,6 +3326,7 @@ void ClientConnection::handleTileEvent(shared_ptr<TileEventPacket> packet)
void ClientConnection::handleTileDestruction(shared_ptr<TileDestructionPacket> packet) void ClientConnection::handleTileDestruction(shared_ptr<TileDestructionPacket> packet)
{ {
if (!isPrimaryConnection()) return;
minecraft->level->destroyTileProgress(packet->getEntityId(), packet->getX(), packet->getY(), packet->getZ(), packet->getState()); minecraft->level->destroyTileProgress(packet->getEntityId(), packet->getX(), packet->getY(), packet->getZ(), packet->getState());
} }
@ -3359,6 +3408,7 @@ void ClientConnection::handleGameEvent(shared_ptr<GameEventPacket> gameEventPack
void ClientConnection::handleComplexItemData(shared_ptr<ComplexItemDataPacket> packet) void ClientConnection::handleComplexItemData(shared_ptr<ComplexItemDataPacket> packet)
{ {
if (!isPrimaryConnection()) return;
if (packet->itemType == Item::map->id) if (packet->itemType == Item::map->id)
{ {
MapItem::getSavedData(packet->itemId, minecraft->level)->handleComplexItemData(packet->data); MapItem::getSavedData(packet->itemId, minecraft->level)->handleComplexItemData(packet->data);
@ -3373,6 +3423,7 @@ void ClientConnection::handleComplexItemData(shared_ptr<ComplexItemDataPacket> p
void ClientConnection::handleLevelEvent(shared_ptr<LevelEventPacket> packet) void ClientConnection::handleLevelEvent(shared_ptr<LevelEventPacket> packet)
{ {
if (!isPrimaryConnection()) return;
if (packet->type == LevelEvent::SOUND_DRAGON_DEATH) if (packet->type == LevelEvent::SOUND_DRAGON_DEATH)
{ {
for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
@ -3596,6 +3647,7 @@ void ClientConnection::handlePlayerAbilities(shared_ptr<PlayerAbilitiesPacket> p
void ClientConnection::handleSoundEvent(shared_ptr<LevelSoundPacket> packet) void ClientConnection::handleSoundEvent(shared_ptr<LevelSoundPacket> packet)
{ {
if (!isPrimaryConnection()) return;
minecraft->level->playLocalSound(packet->getX(), packet->getY(), packet->getZ(), packet->getSound(), packet->getVolume(), packet->getPitch(), false); minecraft->level->playLocalSound(packet->getX(), packet->getY(), packet->getZ(), packet->getSound(), packet->getVolume(), packet->getPitch(), false);
} }
@ -3908,6 +3960,7 @@ void ClientConnection::handleSetPlayerTeamPacket(shared_ptr<SetPlayerTeamPacket>
void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet) void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet)
{ {
if (!isPrimaryConnection()) return;
for (int i = 0; i < packet->getCount(); i++) for (int i = 0; i < packet->getCount(); i++)
{ {
double xVarience = random->nextGaussian() * packet->getXDist(); double xVarience = random->nextGaussian() * packet->getXDist();

View file

@ -43,6 +43,7 @@ public:
private: private:
DWORD m_userIndex; // 4J Added DWORD m_userIndex; // 4J Added
bool isPrimaryConnection() const;
public: public:
SavedDataStorage *savedDataStorage; SavedDataStorage *savedDataStorage;
ClientConnection(Minecraft *minecraft, const wstring& ip, int port); ClientConnection(Minecraft *minecraft, const wstring& ip, int port);

View file

@ -1,4 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "ClientConstants.h" #include "ClientConstants.h"
const wstring ClientConstants::VERSION_STRING = wstring(L"Minecraft Xbox ") + VER_FILEVERSION_STR_W;//+ SharedConstants::VERSION_STRING; const wstring ClientConstants::VERSION_STRING = wstring(L"Minecraft LCE ") + VER_FILEVERSION_STR_W;//+ SharedConstants::VERSION_STRING;

View file

@ -25,7 +25,7 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include "..\Filesystem\Filesystem.h" #include <lce_filesystem\lce_filesystem.h>
#ifdef __ORBIS__ #ifdef __ORBIS__
#include <audioout.h> #include <audioout.h>
@ -103,7 +103,7 @@ char SoundEngine::m_szRedistName[]={"redist"};
#endif #endif
char *SoundEngine::m_szStreamFileA[eStream_Max]= const char *SoundEngine::m_szStreamFileA[eStream_Max]=
{ {
"calm1", "calm1",
"calm2", "calm2",

View file

@ -151,7 +151,7 @@ private:
static char m_szSoundPath[]; static char m_szSoundPath[];
static char m_szMusicPath[]; static char m_szMusicPath[];
static char m_szRedistName[]; static char m_szRedistName[];
static char *m_szStreamFileA[eStream_Max]; static const char *m_szStreamFileA[eStream_Max];
AUDIO_LISTENER m_ListenerA[MAX_LOCAL_PLAYERS]; AUDIO_LISTENER m_ListenerA[MAX_LOCAL_PLAYERS];
int m_validListenerCount; int m_validListenerCount;

View file

@ -1,57 +1,6 @@
#pragma once #pragma once
#define VER_PRODUCTBUILD 560
#define VER_PRODUCTMAJORVERSION 0 #define VER_PRODUCTVERSION_STR_W L"DEV (unknown)"
#define VER_PRODUCTMINORVERSION 0 #define VER_FILEVERSION_STR_W VER_PRODUCTVERSION_STR_W
#define VER_NETWORK VER_PRODUCTBUILD
// This goes up with each build
// 4J-JEV: This value is extracted with a regex so it can be placed as the version in the AppX manifest on Durango.
#define VER_PRODUCTBUILD 560
// This goes up if there is any change to network traffic or code in a build
#define VER_NETWORK 560
#define VER_PRODUCTBUILD_QFE 0
#define VER_FILEVERSION_STRING "1.6"
#define VER_PRODUCTVERSION_STRING VER_FILEVERSION_STRING
#define VER_FILEVERSION_STRING_W L"1.6"
#define VER_PRODUCTVERSION_STRING_W VER_FILEVERSION_STRING_W
#define VER_FILEBETA_STR ""
#undef VER_FILEVERSION
#define VER_FILEVERSION VER_PRODUCTMAJORVERSION, VER_PRODUCTMINORVERSION, VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE
#define VER_PRODUCTVERSION VER_PRODUCTMAJORVERSION, VER_PRODUCTMINORVERSION, VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE
#if (VER_PRODUCTBUILD < 10)
#define VER_FILEBPAD "000"
#define VER_FILEBPAD_W L"000"
#elif (VER_PRODUCTBUILD < 100)
#define VER_FILEBPAD "00"
#define VER_FILEBPAD_W L"00"
#elif (VER_PRODUCTBUILD < 1000)
#define VER_FILEBPAD "0"
#define VER_FILEBPAD_W L"0"
#else
#define VER_FILEBPAD
#define VER_FILEBPAD_W
#endif
#define VER_WIDE_PREFIX(x) L##x
#define VER_FILEVERSION_STR2(x,y) VER_FILEVERSION_STRING "." VER_FILEBPAD #x "." #y
#define VER_FILEVERSION_STR2_W(x,y) VER_FILEVERSION_STRING_W L"." VER_FILEBPAD_W VER_WIDE_PREFIX(#x) L"." VER_WIDE_PREFIX(#y)
#define VER_FILEVERSION_STR1(x,y) VER_FILEVERSION_STR2(x, y)
#define VER_FILEVERSION_STR1_W(x,y) VER_FILEVERSION_STR2_W(x, y)
#undef VER_FILEVERSION_STR
#define VER_FILEVERSION_STR VER_FILEVERSION_STR1(VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE)
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR1(VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE)
#define VER_FILEVERSION_STR_W VER_FILEVERSION_STR1_W(VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE)
#define VER_PRODUCTVERSION_STR_W VER_FILEVERSION_STR1_W(VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE)
#if (VER_PRODUCTBUILD_QFE >= 256)
#error "QFE number cannot exceed 255"
#endif

View file

@ -4,7 +4,7 @@
unordered_map<wstring,eMinecraftColour> ColourTable::s_colourNamesMap; unordered_map<wstring,eMinecraftColour> ColourTable::s_colourNamesMap;
wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] = const wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] =
{ {
L"NOTSET", L"NOTSET",

View file

@ -5,7 +5,7 @@ class ColourTable
private: private:
unsigned int m_colourValues[eMinecraftColour_COUNT]; unsigned int m_colourValues[eMinecraftColour_COUNT];
static wchar_t *ColourTableElements[eMinecraftColour_COUNT]; static const wchar_t *ColourTableElements[eMinecraftColour_COUNT];
static unordered_map<wstring,eMinecraftColour> s_colourNamesMap; static unordered_map<wstring,eMinecraftColour> s_colourNamesMap;
public: public:

View file

@ -26,7 +26,7 @@ PBYTE DLCAudioFile::getData(DWORD &dwBytes)
return m_pbData; return m_pbData;
} }
WCHAR *DLCAudioFile::wchTypeNamesA[]= const WCHAR *DLCAudioFile::wchTypeNamesA[]=
{ {
L"CUENAME", L"CUENAME",
L"CREDIT", L"CREDIT",

View file

@ -28,7 +28,7 @@ public:
e_AudioParamType_Max, e_AudioParamType_Max,
}; };
static WCHAR *wchTypeNamesA[e_AudioParamType_Max]; static const WCHAR *wchTypeNamesA[e_AudioParamType_Max];
DLCAudioFile(const wstring &path); DLCAudioFile(const wstring &path);

View file

@ -7,7 +7,7 @@
#include "..\..\Minecraft.h" #include "..\..\Minecraft.h"
#include "..\..\TexturePackRepository.h" #include "..\..\TexturePackRepository.h"
WCHAR *DLCManager::wchTypeNamesA[]= const WCHAR *DLCManager::wchTypeNamesA[]=
{ {
L"DISPLAYNAME", L"DISPLAYNAME",
L"THEMENAME", L"THEMENAME",

View file

@ -48,7 +48,7 @@ public:
e_DLCParamType_Max, e_DLCParamType_Max,
}; };
static WCHAR *wchTypeNamesA[e_DLCParamType_Max]; static const WCHAR *wchTypeNamesA[e_DLCParamType_Max];
private: private:
vector<DLCPack *> m_packs; vector<DLCPack *> m_packs;

View file

@ -12,7 +12,7 @@
#include "ConsoleGameRules.h" #include "ConsoleGameRules.h"
#include "GameRuleManager.h" #include "GameRuleManager.h"
WCHAR *GameRuleManager::wchTagNameA[] = const WCHAR *GameRuleManager::wchTagNameA[] =
{ {
L"", // eGameRuleType_Root L"", // eGameRuleType_Root
L"MapOptions", // eGameRuleType_LevelGenerationOptions L"MapOptions", // eGameRuleType_LevelGenerationOptions
@ -34,7 +34,7 @@ WCHAR *GameRuleManager::wchTagNameA[] =
L"UpdatePlayer", // eGameRuleType_UpdatePlayerRule L"UpdatePlayer", // eGameRuleType_UpdatePlayerRule
}; };
WCHAR *GameRuleManager::wchAttrNameA[] = const WCHAR *GameRuleManager::wchAttrNameA[] =
{ {
L"descriptionName", // eGameRuleAttr_descriptionName L"descriptionName", // eGameRuleAttr_descriptionName
L"promptName", // eGameRuleAttr_promptName L"promptName", // eGameRuleAttr_promptName

View file

@ -24,8 +24,8 @@ class WstringLookup;
class GameRuleManager class GameRuleManager
{ {
public: public:
static WCHAR *wchTagNameA[ConsoleGameRules::eGameRuleType_Count]; static const WCHAR *wchTagNameA[ConsoleGameRules::eGameRuleType_Count];
static WCHAR *wchAttrNameA[ConsoleGameRules::eGameRuleAttr_Count]; static const WCHAR *wchAttrNameA[ConsoleGameRules::eGameRuleAttr_Count];
static const short version_number = 2; static const short version_number = 2;

View file

@ -41,6 +41,11 @@
#include "..\Minecraft.World\DurangoStats.h" #include "..\Minecraft.World\DurangoStats.h"
#endif #endif
#ifdef _WINDOWS64
#include "..\..\Windows64\Network\WinsockNetLayer.h"
#include "..\..\Windows64\Windows64_Xuid.h"
#endif
// Global instance // Global instance
CGameNetworkManager g_NetworkManager; CGameNetworkManager g_NetworkManager;
CPlatformNetworkManager *CGameNetworkManager::s_pPlatformNetworkManager; CPlatformNetworkManager *CGameNetworkManager::s_pPlatformNetworkManager;
@ -1501,6 +1506,45 @@ void CGameNetworkManager::CreateSocket( INetworkPlayer *pNetworkPlayer, bool loc
} }
else else
{ {
#ifdef _WINDOWS64
// Non-host split-screen: open a dedicated TCP connection for this pad
if (localPlayer && !g_NetworkManager.IsHost() && g_NetworkManager.IsInGameplay())
{
int padIdx = pNetworkPlayer->GetUserIndex();
BYTE assignedSmallId = 0;
if (!WinsockNetLayer::JoinSplitScreen(padIdx, &assignedSmallId))
{
app.DebugPrintf("Split-screen pad %d: failed to open TCP to host\n", padIdx);
pMinecraft->connectionDisconnected(padIdx, DisconnectPacket::eDisconnect_ConnectionCreationFailed);
return;
}
// Update the local IQNetPlayer (at pad index) with the host-assigned smallId.
// The NetworkPlayerXbox created by NotifyPlayerJoined already points to
// m_player[padIdx], so we just set the smallId for network routing.
IQNet::m_player[padIdx].m_smallId = assignedSmallId;
IQNet::m_player[padIdx].m_resolvedXuid = Win64Xuid::DeriveXuidForPad(Win64Xuid::ResolvePersistentXuid(), padIdx);
// Network socket (not hostLocal) — data goes through TCP via GetLocalSocket
socket = new Socket(pNetworkPlayer, false, false);
pNetworkPlayer->SetSocket(socket);
ClientConnection* connection = new ClientConnection(pMinecraft, socket, padIdx);
if (connection->createdOk)
{
connection->send(shared_ptr<PreLoginPacket>(new PreLoginPacket(pNetworkPlayer->GetOnlineName())));
pMinecraft->addPendingLocalConnection(padIdx, connection);
}
else
{
pMinecraft->connectionDisconnected(padIdx, DisconnectPacket::eDisconnect_ConnectionCreationFailed);
delete connection;
}
return;
}
#endif
socket = new Socket( pNetworkPlayer, g_NetworkManager.IsHost(), g_NetworkManager.IsHost() && localPlayer ); socket = new Socket( pNetworkPlayer, g_NetworkManager.IsHost(), g_NetworkManager.IsHost() && localPlayer );
pNetworkPlayer->SetSocket( socket ); pNetworkPlayer->SetSocket( socket );

View file

@ -243,10 +243,16 @@ void CPlatformNetworkManagerStub::DoWork()
if (IQNet::s_playerCount > 1) if (IQNet::s_playerCount > 1)
IQNet::s_playerCount--; IQNet::s_playerCount--;
} }
// Always return smallId to the free pool so it can be reused (game may have already cleared the slot). // NOTE: Do NOT call PushFreeSmallId here. The old PlayerConnection's
WinsockNetLayer::PushFreeSmallId(disconnectedSmallId); // write thread may still be alive (it dies in PlayerList::tick when
// Clear O(1) socket lookup so GetSocketForSmallId stays fast (s_connections never shrinks). // m_smallIdsToClose is processed). If we recycle the smallId now,
WinsockNetLayer::ClearSocketForSmallId(disconnectedSmallId); // AcceptThread can reuse it for a new connection, and the old write
// thread's getPlayer() lookup will resolve to the NEW player, sending
// stale game packets to the new client's TCP socket — corrupting its
// login handshake (bad packet id crash). PushFreeSmallId and
// ClearSocketForSmallId are called from PlayerList::tick after the
// old Connection threads are dead.
//
// Clear chunk visibility flags for this system so rejoin gets fresh chunk state. // Clear chunk visibility flags for this system so rejoin gets fresh chunk state.
SystemFlagRemoveBySmallId((int)disconnectedSmallId); SystemFlagRemoveBySmallId((int)disconnectedSmallId);
} }
@ -289,12 +295,40 @@ int CPlatformNetworkManagerStub::GetLocalPlayerMask(int playerIndex)
bool CPlatformNetworkManagerStub::AddLocalPlayerByUserIndex( int userIndex ) bool CPlatformNetworkManagerStub::AddLocalPlayerByUserIndex( int userIndex )
{ {
NotifyPlayerJoined(m_pIQNet->GetLocalPlayerByUserIndex(userIndex)); if ( m_pIQNet->AddLocalPlayerByUserIndex(userIndex) != S_OK )
return ( m_pIQNet->AddLocalPlayerByUserIndex(userIndex) == S_OK ); return false;
// Player is now registered in IQNet — get a pointer and notify the network layer.
// Use the static array directly: GetLocalPlayerByUserIndex checks customData which
// isn't set until addNetworkPlayer runs inside NotifyPlayerJoined.
NotifyPlayerJoined(&IQNet::m_player[userIndex]);
return true;
} }
bool CPlatformNetworkManagerStub::RemoveLocalPlayerByUserIndex( int userIndex ) bool CPlatformNetworkManagerStub::RemoveLocalPlayerByUserIndex( int userIndex )
{ {
#ifdef _WINDOWS64
if (userIndex > 0 && userIndex < XUSER_MAX_COUNT && !m_pIQNet->IsHost())
{
IQNetPlayer* qp = &IQNet::m_player[userIndex];
// Notify the network layer before clearing the slot
if (qp->GetCustomDataValue() != 0)
{
NotifyPlayerLeaving(qp);
}
// Close the split-screen TCP connection and reset WinsockNetLayer state
WinsockNetLayer::CloseSplitScreenConnection(userIndex);
// Clear the IQNet slot so it can be reused on rejoin
qp->m_smallId = 0;
qp->m_isRemote = false;
qp->m_isHostPlayer = false;
qp->m_resolvedXuid = INVALID_XUID;
qp->m_gamertag[0] = 0;
qp->SetCustomDataValue(0);
}
#endif
return true; return true;
} }
@ -777,52 +811,55 @@ void CPlatformNetworkManagerStub::SearchForGames()
friendsSessions[0].push_back(info); friendsSessions[0].push_back(info);
} }
std::FILE* file = std::fopen("servers.txt", "r"); std::FILE* file = std::fopen("servers.db", "rb");
if (file) { if (file) {
wstring wline; char magic[4] = {};
int phase = 0; if (std::fread(magic, 1, 4, file) == 4 && memcmp(magic, "MCSV", 4) == 0)
{
uint32_t version = 0, count = 0;
std::fread(&version, sizeof(uint32_t), 1, file);
std::fread(&count, sizeof(uint32_t), 1, file);
string ip; if (version == 1)
wstring port; {
wstring name; for (uint32_t s = 0; s < count; s++)
{
uint16_t ipLen = 0, port = 0, nameLen = 0;
if (std::fread(&ipLen, sizeof(uint16_t), 1, file) != 1) break;
if (ipLen == 0 || ipLen > 256) break;
char buffer[512]; char ipBuf[257] = {};
while (std::fgets(buffer, sizeof(buffer), file)) { if (std::fread(ipBuf, 1, ipLen, file) != ipLen) break;
if (phase == 0) {
ip = buffer;
if (!ip.empty() && (ip.back() == '\n' || ip.back() == '\r'))
ip.pop_back();
phase = 1;
}
else if (phase == 1) {
wline = convStringToWstring(buffer);
port = wline;
phase = 2;
}
else if (phase == 2) {
wline = convStringToWstring(buffer);
name = wline;
phase = 0;
//THEY GET DELETED AFTER USE LIKE 30 LINES UP!! if (std::fread(&port, sizeof(uint16_t), 1, file) != 1) break;
FriendSessionInfo* info = new FriendSessionInfo();
wchar_t label[128]; if (std::fread(&nameLen, sizeof(uint16_t), 1, file) != 1) break;
wcsncpy_s(label, sizeof(label)/sizeof(wchar_t), name.c_str(), _TRUNCATE); if (nameLen > 256) break;
size_t nameLen = wcslen(label);
info->displayLabel = new wchar_t[nameLen+1]; char nameBuf[257] = {};
wcscpy_s(info->displayLabel, nameLen + 1, label); if (nameLen > 0)
info->displayLabelLength = (unsigned char)nameLen; {
info->displayLabelViewableStartIndex = 0; if (std::fread(nameBuf, 1, nameLen, file) != nameLen) break;
info->data.isReadyToJoin = true; }
info->data.isJoinable = true;
strncpy_s(info->data.hostIP, sizeof(info->data.hostIP), ip.c_str(), _TRUNCATE); wstring wName = convStringToWstring(nameBuf);
info->data.hostPort = stoi(port);
info->sessionId = (SessionID)(static_cast<uint64_t>(inet_addr(ip.c_str())) | (static_cast<uint64_t>(stoi(port)) << 32)); FriendSessionInfo* info = new FriendSessionInfo();
friendsSessions[0].push_back(info); size_t nLen = wName.length();
info->displayLabel = new wchar_t[nLen + 1];
wcscpy_s(info->displayLabel, nLen + 1, wName.c_str());
info->displayLabelLength = (unsigned char)nLen;
info->displayLabelViewableStartIndex = 0;
info->data.isReadyToJoin = true;
info->data.isJoinable = true;
strncpy_s(info->data.hostIP, sizeof(info->data.hostIP), ipBuf, _TRUNCATE);
info->data.hostPort = port;
info->sessionId = (SessionID)(static_cast<uint64_t>(inet_addr(ipBuf)) | (static_cast<uint64_t>(port) << 32));
friendsSessions[0].push_back(info);
}
} }
} }
std::fclose(file); std::fclose(file);
} }
@ -848,7 +885,7 @@ vector<FriendSessionInfo *> *CPlatformNetworkManagerStub::GetSessionList(int iPa
{ {
vector<FriendSessionInfo*>* filteredList = new vector<FriendSessionInfo*>(); vector<FriendSessionInfo*>* filteredList = new vector<FriendSessionInfo*>();
for (size_t i = 0; i < friendsSessions[0].size(); i++) for (size_t i = 0; i < friendsSessions[0].size(); i++)
filteredList->push_back(friendsSessions[0][i]); filteredList->push_back(new FriendSessionInfo(*friendsSessions[0][i]));
return filteredList; return filteredList;
} }

View file

@ -119,9 +119,36 @@ public:
hasPartyMember = false; hasPartyMember = false;
} }
FriendSessionInfo(const FriendSessionInfo& other)
{
sessionId = other.sessionId;
#ifdef _XBOX
searchResult = other.searchResult;
#elif defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__)
searchResult = other.searchResult;
#elif defined(_DURANGO)
searchResult = other.searchResult;
#endif
displayLabelLength = other.displayLabelLength;
displayLabelViewableStartIndex = other.displayLabelViewableStartIndex;
data = other.data;
hasPartyMember = other.hasPartyMember;
if (other.displayLabel != NULL)
{
displayLabel = new wchar_t[displayLabelLength + 1];
wcscpy_s(displayLabel, displayLabelLength + 1, other.displayLabel);
}
else
{
displayLabel = NULL;
}
}
FriendSessionInfo& operator=(const FriendSessionInfo&) = delete;
~FriendSessionInfo() ~FriendSessionInfo()
{ {
if (displayLabel != NULL) if (displayLabel != NULL)
delete displayLabel; delete[] displayLabel;
} }
}; };

View file

@ -45,6 +45,8 @@ private:
bool m_wineMode = false; bool m_wineMode = false;
D3D11_VIEWPORT m_customViewport; D3D11_VIEWPORT m_customViewport;
bool m_useCustomViewport = false; bool m_useCustomViewport = false;
UINT m_gammaTexWidth = 0;
UINT m_gammaTexHeight = 0;
struct GammaCBData struct GammaCBData
{ {

View file

@ -481,25 +481,15 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
#endif #endif
#ifdef _WINDOWS64 #ifdef _WINDOWS64
if (!g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive()) if (iPad == 0 && !g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive())
{ {
int deltaX = g_KBMInput.GetMouseDeltaX(); int deltaX = g_KBMInput.GetMouseDeltaX();
int deltaY = g_KBMInput.GetMouseDeltaY(); int deltaY = g_KBMInput.GetMouseDeltaY();
extern HWND g_hWnd; float scaleX, scaleY;
RECT rc; getMouseToSWFScale(scaleX, scaleY);
GetClientRect(g_hWnd, &rc); vPointerPos.x += (float)deltaX * scaleX;
int winW = rc.right - rc.left; vPointerPos.y += (float)deltaY * scaleY;
int winH = rc.bottom - rc.top;
if (winW > 0 && winH > 0)
{
float scaleX = (float)getMovieWidth() / (float)winW;
float scaleY = (float)getMovieHeight() / (float)winH;
vPointerPos.x += (float)deltaX * scaleX;
vPointerPos.y += (float)deltaY * scaleY;
}
if (deltaX != 0 || deltaY != 0) if (deltaX != 0 || deltaY != 0)
{ {

View file

@ -277,4 +277,5 @@ public:
virtual int getPad() = 0; virtual int getPad() = 0;
virtual int getMovieWidth() = 0; virtual int getMovieWidth() = 0;
virtual int getMovieHeight() = 0; virtual int getMovieHeight() = 0;
virtual void getMouseToSWFScale(float &scaleX, float &scaleY) = 0;
}; };

View file

@ -250,15 +250,22 @@ rrbool UIBitmapFont::GetGlyphBitmap(S32 glyph,F32 pixel_scale,IggyBitmapCharacte
// Choose a reasonable glyph scale. // Choose a reasonable glyph scale.
float glyphScale = 1.0f, truePixelScale = 1.0f / m_cFontData->getFontData()->m_fAdvPerPixel; float glyphScale = 1.0f, truePixelScale = 1.0f / m_cFontData->getFontData()->m_fAdvPerPixel;
F32 targetPixelScale = pixel_scale; while ( (0.5f + glyphScale) * truePixelScale < pixel_scale)
//if(!RenderManager.IsWidescreen())
//{
// // Fix for different scales in 480
// targetPixelScale = pixel_scale*2/3;
//}
while ( (0.5f + glyphScale) * truePixelScale < targetPixelScale)
glyphScale++; glyphScale++;
// Debug: log each unique (font, pixel_scale) pair
{
static std::unordered_set<int> s_loggedScaleKeys;
// Encode font pointer + quantized scale into a key to log each combo once
int scaleKey = (int)(pixel_scale * 100.0f) ^ (int)(uintptr_t)m_cFontData;
if (s_loggedScaleKeys.find(scaleKey) == s_loggedScaleKeys.end() && s_loggedScaleKeys.size() < 50) {
s_loggedScaleKeys.insert(scaleKey);
float tps = truePixelScale;
app.DebugPrintf("[FONT-DBG] GetGlyphBitmap: font=%s glyph=%d pixel_scale=%.3f truePixelScale=%.1f glyphScale=%.0f\n",
m_cFontData->getFontName().c_str(), glyph, pixel_scale, tps, glyphScale);
}
}
// 4J-JEV: Debug code to check which font sizes are being used. // 4J-JEV: Debug code to check which font sizes are being used.
#if (!defined _CONTENT_PACKAGE) && (VERBOSE_FONT_OUTPUT > 0) #if (!defined _CONTENT_PACKAGE) && (VERBOSE_FONT_OUTPUT > 0)
@ -303,9 +310,6 @@ rrbool UIBitmapFont::GetGlyphBitmap(S32 glyph,F32 pixel_scale,IggyBitmapCharacte
} }
#endif #endif
//app.DebugPrintf("Request glyph_%d (U+%.4X) at %f, converted to %f (%f)\n",
// glyph, GetUnicode(glyph), pixel_scale, targetPixelScale, glyphScale);
// It is not necessary to shrink the glyph width here // It is not necessary to shrink the glyph width here
// as its already been done in 'GetGlyphMetrics' by: // as its already been done in 'GetGlyphMetrics' by:
// > metrics->x1 = m_kerningTable[glyph] * ratio; // > metrics->x1 = m_kerningTable[glyph] * ratio;
@ -324,27 +328,57 @@ rrbool UIBitmapFont::GetGlyphBitmap(S32 glyph,F32 pixel_scale,IggyBitmapCharacte
bitmap->top_left_y = -((S32) m_cFontData->getFontData()->m_uiGlyphHeight) * m_cFontData->getFontData()->m_fAscent; bitmap->top_left_y = -((S32) m_cFontData->getFontData()->m_uiGlyphHeight) * m_cFontData->getFontData()->m_fAscent;
bitmap->oversample = 0; bitmap->oversample = 0;
bitmap->point_sample = true;
// 4J-JEV: #ifdef _WINDOWS64
// pixel_scale == font size chosen in flash. // On Windows64 the window can be any size, producing fractional
// bitmap->pixel_scale_correct = (float) m_glyphHeight; // Scales the glyph to desired size. // pixel_scale values that don't align to integer multiples of
// bitmap->pixel_scale_correct = pixel_scale; // Always the same size (not desired size). // truePixelScale. The original console code cached glyphs with a
// bitmap->pixel_scale_correct = pixel_scale * 0.5; // Doubles original size. // broad [truePixelScale, 99] range in the "normal" branch, which
// bitmap->pixel_scale_correct = pixel_scale * 2; // Halves original size. // works on consoles (fixed 1080p — font sizes are exact multiples)
// but causes cache pollution on Windows: the first glyph cached in
// Actual scale, and possible range of scales. // that range sets pixel_scale_correct for ALL subsequent requests,
bitmap->pixel_scale_correct = pixel_scale / glyphScale; // so different font sizes get scaled by wrong ratios, producing
bitmap->pixel_scale_max = 99.0f; // mixed letter sizes on screen.
bitmap->pixel_scale_min = 0.0f; //
// Fix: always use pixel_scale_correct = truePixelScale so every
/* 4J-JEV: Some of Sean's code. // cache entry is consistent. Two ranges: downscale (bilinear for
int glyphScaleMin = 1; // smooth reduction) and upscale (point_sample for crisp pixel-art).
int glyphScaleMax = 3; bitmap->pixel_scale_correct = truePixelScale;
float actualScale = pixel_scale / glyphScale; if (pixel_scale < truePixelScale)
bitmap->pixel_scale_correct = actualScale; {
bitmap->pixel_scale_min = actualScale * glyphScaleMin * 0.999f; bitmap->pixel_scale_min = 0.0f;
bitmap->pixel_scale_max = actualScale * glyphScaleMax * 1.001f; */ bitmap->pixel_scale_max = truePixelScale;
bitmap->point_sample = false;
}
else
{
bitmap->pixel_scale_min = truePixelScale;
bitmap->pixel_scale_max = 99.0f;
bitmap->point_sample = true;
}
#else
if (glyphScale <= 1 && pixel_scale < truePixelScale)
{
// Small display: pixel_scale is less than the native glyph size.
// Report the bitmap at its true native scale so Iggy downscales it
// to match the layout metrics (bilinear for smooth downscaling).
bitmap->pixel_scale_correct = truePixelScale;
bitmap->pixel_scale_min = 0.0f;
bitmap->pixel_scale_max = truePixelScale * 1.001f;
bitmap->point_sample = false;
}
else
{
// Normal/upscale case: integer-multiple scaling for pixel-art look.
// Console-only — fixed resolution means pixel_scale values are exact
// integer multiples of truePixelScale, so cache sharing is safe.
float actualScale = pixel_scale / glyphScale;
bitmap->pixel_scale_correct = actualScale;
bitmap->pixel_scale_min = truePixelScale;
bitmap->pixel_scale_max = 99.0f;
bitmap->point_sample = true;
}
#endif
// 4J-JEV: Nothing to do with glyph placement, // 4J-JEV: Nothing to do with glyph placement,
// entirely to do with cropping your glyph out of an archive. // entirely to do with cropping your glyph out of an archive.

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "UI.h" #include "UI.h"
#include "UIComponent_Chat.h" #include "UIComponent_Chat.h"
#include "UISplitScreenHelpers.h"
#include "..\..\Minecraft.h" #include "..\..\Minecraft.h"
#include "..\..\Gui.h" #include "..\..\Gui.h"
@ -120,6 +121,7 @@ void UIComponent_Chat::render(S32 width, S32 height, C4JRender::eViewportType vi
S32 tileWidth = width; S32 tileWidth = width;
S32 tileHeight = height; S32 tileHeight = height;
bool needsYTile = false;
switch( viewport ) switch( viewport )
{ {
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
@ -127,22 +129,27 @@ void UIComponent_Chat::render(S32 width, S32 height, C4JRender::eViewportType vi
tileHeight = (S32)(ui.getScreenHeight()); tileHeight = (S32)(ui.getScreenHeight());
break; break;
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
tileWidth = (S32)(ui.getScreenWidth());
tileYStart = (S32)(m_movieHeight / 2);
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
tileWidth = (S32)(ui.getScreenWidth()); tileWidth = (S32)(ui.getScreenWidth());
tileYStart = (S32)(m_movieHeight / 2); needsYTile = true;
break; break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
tileYStart = (S32)(m_movieHeight / 2); needsYTile = true;
break; break;
} }
IggyPlayerSetDisplaySize( getMovie(), m_movieWidth, m_movieHeight ); F32 scale;
ComputeTileScale(tileWidth, tileHeight, m_movieWidth, m_movieHeight, needsYTile, scale, tileYStart);
IggyPlayerSetDisplaySize( getMovie(), (S32)(m_movieWidth * scale), (S32)(m_movieHeight * scale) );
S32 contentOffX, contentOffY;
ComputeSplitContentOffset(viewport, m_movieWidth, m_movieHeight, scale, tileWidth, tileHeight, tileYStart, contentOffX, contentOffY);
xPos += contentOffX;
yPos += contentOffY;
ui.setupRenderPosition(xPos, yPos);
IggyPlayerDrawTilesStart ( getMovie() ); IggyPlayerDrawTilesStart ( getMovie() );

View file

@ -68,21 +68,26 @@ void UIComponent_MenuBackground::render(S32 width, S32 height, C4JRender::eViewp
break; break;
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
tileWidth = (S32)(ui.getScreenWidth()); tileWidth = (S32)(ui.getScreenWidth());
tileYStart = (S32)(m_movieHeight / 2); tileYStart = (S32)(ui.getScreenHeight() / 2);
break; break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
tileWidth = (S32)(ui.getScreenWidth()); tileWidth = (S32)(ui.getScreenWidth());
tileYStart = (S32)(m_movieHeight / 2); tileYStart = (S32)(ui.getScreenHeight() / 2);
break; break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
tileYStart = (S32)(m_movieHeight / 2); tileYStart = (S32)(ui.getScreenHeight() / 2);
break; break;
} }
IggyPlayerSetDisplaySize( getMovie(), m_movieWidth, m_movieHeight ); F32 scaleW = (F32)(tileXStart + tileWidth) / (F32)m_movieWidth;
F32 scaleH = (F32)(tileYStart + tileHeight) / (F32)m_movieHeight;
F32 scale = (scaleW > scaleH) ? scaleW : scaleH;
if(scale < 1.0f) scale = 1.0f;
IggyPlayerSetDisplaySize( getMovie(), (S32)(m_movieWidth * scale), (S32)(m_movieHeight * scale) );
IggyPlayerDrawTilesStart ( getMovie() ); IggyPlayerDrawTilesStart ( getMovie() );
@ -98,6 +103,10 @@ void UIComponent_MenuBackground::render(S32 width, S32 height, C4JRender::eViewp
} }
else else
{ {
UIScene::render(width, height, viewport); if(m_bIsReloading) return;
if(!m_hasTickedOnce || !getMovie()) return;
ui.setupRenderPosition(0, 0);
IggyPlayerSetDisplaySize( getMovie(), (S32)ui.getScreenWidth(), (S32)ui.getScreenHeight() );
IggyPlayerDraw( getMovie() );
} }
} }

View file

@ -93,38 +93,47 @@ void UIComponent_Panorama::render(S32 width, S32 height, C4JRender::eViewportTyp
} }
ui.setupRenderPosition(xPos, yPos); ui.setupRenderPosition(xPos, yPos);
if((viewport == C4JRender::VIEWPORT_TYPE_SPLIT_LEFT) || (viewport == C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT)) S32 tileXStart = 0;
S32 tileYStart = 0;
S32 tileWidth = width;
S32 tileHeight = height;
if((viewport == C4JRender::VIEWPORT_TYPE_SPLIT_LEFT) || (viewport == C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT))
{ {
// Need to render at full height, but only the left side of the scene tileHeight = (S32)(ui.getScreenHeight());
S32 tileXStart = 0;
S32 tileYStart = 0;
S32 tileWidth = width;
S32 tileHeight = (S32)(ui.getScreenHeight());
IggyPlayerSetDisplaySize( getMovie(), m_movieWidth, m_movieHeight );
IggyPlayerDrawTilesStart ( getMovie() );
m_renderWidth = tileWidth;
m_renderHeight = tileHeight;
IggyPlayerDrawTile ( getMovie() ,
tileXStart ,
tileYStart ,
tileXStart + tileWidth ,
tileYStart + tileHeight ,
0 );
IggyPlayerDrawTilesEnd ( getMovie() );
} }
else else
{ {
// Need to render at full height, and full width. But compressed into the viewport tileWidth = (S32)(ui.getScreenWidth());
IggyPlayerSetDisplaySize( getMovie(), ui.getScreenWidth(), ui.getScreenHeight()/2 ); tileYStart = (S32)(ui.getScreenHeight() / 2);
IggyPlayerDraw( getMovie() );
} }
F32 scaleW = (F32)(tileXStart + tileWidth) / (F32)m_movieWidth;
F32 scaleH = (F32)(tileYStart + tileHeight) / (F32)m_movieHeight;
F32 scale = (scaleW > scaleH) ? scaleW : scaleH;
if(scale < 1.0f) scale = 1.0f;
IggyPlayerSetDisplaySize( getMovie(), (S32)(m_movieWidth * scale), (S32)(m_movieHeight * scale) );
IggyPlayerDrawTilesStart ( getMovie() );
m_renderWidth = tileWidth;
m_renderHeight = tileHeight;
IggyPlayerDrawTile ( getMovie() ,
tileXStart ,
tileYStart ,
tileXStart + tileWidth ,
tileYStart + tileHeight ,
0 );
IggyPlayerDrawTilesEnd ( getMovie() );
} }
else else
{ {
UIScene::render(width, height, viewport); if(m_bIsReloading) return;
if(!m_hasTickedOnce || !getMovie()) return;
ui.setupRenderPosition(0, 0);
IggyPlayerSetDisplaySize( getMovie(), (S32)ui.getScreenWidth(), (S32)ui.getScreenHeight() );
IggyPlayerDraw( getMovie() );
} }
} }

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "UI.h" #include "UI.h"
#include "UIComponent_Tooltips.h" #include "UIComponent_Tooltips.h"
#include "UISplitScreenHelpers.h"
UIComponent_Tooltips::UIComponent_Tooltips(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) UIComponent_Tooltips::UIComponent_Tooltips(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
{ {
@ -224,6 +225,7 @@ void UIComponent_Tooltips::render(S32 width, S32 height, C4JRender::eViewportTyp
S32 tileWidth = width; S32 tileWidth = width;
S32 tileHeight = height; S32 tileHeight = height;
bool needsYTile = false;
switch( viewport ) switch( viewport )
{ {
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
@ -231,22 +233,27 @@ void UIComponent_Tooltips::render(S32 width, S32 height, C4JRender::eViewportTyp
tileHeight = (S32)(ui.getScreenHeight()); tileHeight = (S32)(ui.getScreenHeight());
break; break;
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
tileWidth = (S32)(ui.getScreenWidth());
tileYStart = (S32)(m_movieHeight / 2);
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
tileWidth = (S32)(ui.getScreenWidth()); tileWidth = (S32)(ui.getScreenWidth());
tileYStart = (S32)(m_movieHeight / 2); needsYTile = true;
break; break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
tileYStart = (S32)(m_movieHeight / 2); needsYTile = true;
break; break;
} }
IggyPlayerSetDisplaySize( getMovie(), m_movieWidth, m_movieHeight ); F32 scale;
ComputeTileScale(tileWidth, tileHeight, m_movieWidth, m_movieHeight, needsYTile, scale, tileYStart);
IggyPlayerSetDisplaySize( getMovie(), (S32)(m_movieWidth * scale), (S32)(m_movieHeight * scale) );
S32 contentOffX, contentOffY;
ComputeSplitContentOffset(viewport, m_movieWidth, m_movieHeight, scale, tileWidth, tileHeight, tileYStart, contentOffX, contentOffY);
xPos += contentOffX;
yPos += contentOffY;
ui.setupRenderPosition(xPos, yPos);
IggyPlayerDrawTilesStart ( getMovie() ); IggyPlayerDrawTilesStart ( getMovie() );

View file

@ -13,6 +13,7 @@
#include "..\..\EnderDragonRenderer.h" #include "..\..\EnderDragonRenderer.h"
#include "..\..\MultiPlayerLocalPlayer.h" #include "..\..\MultiPlayerLocalPlayer.h"
#include "UIFontData.h" #include "UIFontData.h"
#include "UISplitScreenHelpers.h"
#ifdef _WINDOWS64 #ifdef _WINDOWS64
#include "..\..\Windows64\KeyboardMouseInput.h" #include "..\..\Windows64\KeyboardMouseInput.h"
#endif #endif
@ -57,6 +58,8 @@ bool UIController::ms_bReloadSkinCSInitialised = false;
DWORD UIController::m_dwTrialTimerLimitSecs=DYNAMIC_CONFIG_DEFAULT_TRIAL_TIME; DWORD UIController::m_dwTrialTimerLimitSecs=DYNAMIC_CONFIG_DEFAULT_TRIAL_TIME;
// GetViewportRect and Fit16x9 are now in UISplitScreenHelpers.h
#ifdef _WINDOWS64 #ifdef _WINDOWS64
static UIControl_Slider *FindSliderById(UIScene *pScene, int sliderId) static UIControl_Slider *FindSliderById(UIScene *pScene, int sliderId)
{ {
@ -806,13 +809,16 @@ void UIController::tickInput()
eUILayer_Fullscreen, eUILayer_Fullscreen,
eUILayer_Scene, eUILayer_Scene,
}; };
for (int l = 0; l < _countof(mouseLayers) && !pScene; ++l) // Only check the fullscreen group and the primary (KBM) player's group.
// Other splitscreen players use controllers — mouse must not affect them.
const int mouseGroups[] = { (int)eUIGroup_Fullscreen, ProfileManager.GetPrimaryPad() + 1 };
for (int l = 0; l < _countof(mouseLayers) && !pScene; ++l)
{
for (int g = 0; g < _countof(mouseGroups) && !pScene; ++g)
{ {
for (int grp = 0; grp < eUIGroup_COUNT && !pScene; ++grp) pScene = m_groups[mouseGroups[g]]->GetTopScene(mouseLayers[l]);
{
pScene = m_groups[grp]->GetTopScene(mouseLayers[l]);
}
} }
}
if (pScene && pScene->getMovie()) if (pScene && pScene->getMovie())
{ {
int rawMouseX = g_KBMInput.GetMouseX(); int rawMouseX = g_KBMInput.GetMouseX();
@ -825,7 +831,12 @@ void UIController::tickInput()
m_lastHoverMouseX = rawMouseX; m_lastHoverMouseX = rawMouseX;
m_lastHoverMouseY = rawMouseY; m_lastHoverMouseY = rawMouseY;
// Convert mouse to scene/movie coordinates // Convert mouse window-pixel coords to Flash/SWF authoring coords.
// In split-screen the scene is rendered at a tile-origin offset
// and at a smaller display size, so we must:
// 1. Map window pixels -> UIController screen space
// 2. Subtract the viewport tile origin
// 3. Scale from display dimensions to SWF authoring dimensions
F32 sceneMouseX = (F32)rawMouseX; F32 sceneMouseX = (F32)rawMouseX;
F32 sceneMouseY = (F32)rawMouseY; F32 sceneMouseY = (F32)rawMouseY;
{ {
@ -837,8 +848,30 @@ void UIController::tickInput()
int winH = rc.bottom - rc.top; int winH = rc.bottom - rc.top;
if (winW > 0 && winH > 0) if (winW > 0 && winH > 0)
{ {
sceneMouseX = sceneMouseX * ((F32)pScene->getRenderWidth() / (F32)winW); // Step 1: window pixels -> screen space
sceneMouseY = sceneMouseY * ((F32)pScene->getRenderHeight() / (F32)winH); F32 screenX = sceneMouseX * (getScreenWidth() / (F32)winW);
F32 screenY = sceneMouseY * (getScreenHeight() / (F32)winH);
// Step 2 & 3: account for split-screen viewport
C4JRender::eViewportType vp = pScene->GetParentLayer()->getViewport();
S32 displayW = 0, displayH = 0;
getRenderDimensions(vp, displayW, displayH);
F32 vpOriginX, vpOriginY, vpW, vpH;
GetViewportRect(getScreenWidth(), getScreenHeight(), vp, vpOriginX, vpOriginY, vpW, vpH);
// All viewports use Fit16x9 for menu scenes
S32 fitW, fitH, fitOffsetX, fitOffsetY;
Fit16x9(vpW, vpH, fitW, fitH, fitOffsetX, fitOffsetY);
S32 originX = (S32)vpOriginX + fitOffsetX;
S32 originY = (S32)vpOriginY + fitOffsetY;
displayW = fitW;
displayH = fitH;
if (displayW > 0 && displayH > 0)
{
sceneMouseX = (screenX - originX) * ((F32)pScene->getRenderWidth() / (F32)displayW);
sceneMouseY = (screenY - originY) * ((F32)pScene->getRenderHeight() / (F32)displayH);
}
} }
} }
} }
@ -1566,73 +1599,48 @@ void UIController::renderScenes()
void UIController::getRenderDimensions(C4JRender::eViewportType viewport, S32 &width, S32 &height) void UIController::getRenderDimensions(C4JRender::eViewportType viewport, S32 &width, S32 &height)
{ {
switch( viewport ) F32 originX, originY, viewW, viewH;
GetViewportRect(getScreenWidth(), getScreenHeight(), viewport, originX, originY, viewW, viewH);
if(viewport == C4JRender::VIEWPORT_TYPE_FULLSCREEN)
{ {
case C4JRender::VIEWPORT_TYPE_FULLSCREEN: S32 offsetX, offsetY;
width = (S32)(getScreenWidth()); Fit16x9(viewW, viewH, width, height, offsetX, offsetY);
height = (S32)(getScreenHeight()); }
break; else
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: {
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: // Split-screen: use raw viewport dims — the SWF tiling code handles non-16:9
width = (S32)(getScreenWidth() / 2); width = (S32)viewW;
height = (S32)(getScreenHeight() / 2); height = (S32)viewH;
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
width = (S32)(getScreenWidth() / 2);
height = (S32)(getScreenHeight() / 2);
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
width = (S32)(getScreenWidth() / 2);
height = (S32)(getScreenHeight() / 2);
break;
} }
} }
void UIController::setupRenderPosition(C4JRender::eViewportType viewport) void UIController::setupRenderPosition(C4JRender::eViewportType viewport)
{ {
if(m_bCustomRenderPosition || m_currentRenderViewport != viewport) m_currentRenderViewport = viewport;
m_bCustomRenderPosition = false;
F32 vpOriginX, vpOriginY, vpW, vpH;
GetViewportRect(getScreenWidth(), getScreenHeight(), viewport, vpOriginX, vpOriginY, vpW, vpH);
S32 xPos, yPos;
if(viewport == C4JRender::VIEWPORT_TYPE_FULLSCREEN)
{ {
m_currentRenderViewport = viewport; S32 fitW, fitH, fitOffsetX, fitOffsetY;
m_bCustomRenderPosition = false; Fit16x9(vpW, vpH, fitW, fitH, fitOffsetX, fitOffsetY);
S32 xPos = 0; xPos = (S32)vpOriginX + fitOffsetX;
S32 yPos = 0; yPos = (S32)vpOriginY + fitOffsetY;
switch( viewport )
{
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
xPos = (S32)(getScreenWidth() / 4);
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
xPos = (S32)(getScreenWidth() / 4);
yPos = (S32)(getScreenHeight() / 2);
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
yPos = (S32)(getScreenHeight() / 4);
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
xPos = (S32)(getScreenWidth() / 2);
yPos = (S32)(getScreenHeight() / 4);
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
xPos = (S32)(getScreenWidth() / 2);
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
yPos = (S32)(getScreenHeight() / 2);
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
xPos = (S32)(getScreenWidth() / 2);
yPos = (S32)(getScreenHeight() / 2);
break;
}
m_tileOriginX = xPos;
m_tileOriginY = yPos;
setTileOrigin(xPos, yPos);
} }
else
{
// Split-screen: position at viewport origin, no 16:9 fitting
xPos = (S32)vpOriginX;
yPos = (S32)vpOriginY;
}
m_tileOriginX = xPos;
m_tileOriginY = yPos;
setTileOrigin(xPos, yPos);
} }
void UIController::setupRenderPosition(S32 xOrigin, S32 yOrigin) void UIController::setupRenderPosition(S32 xOrigin, S32 yOrigin)
@ -1840,8 +1848,11 @@ void RADLINK UIController::TextureSubstitutionDestroyCallback ( void * user_call
ui.destroySubstitutionTexture(user_callback_data, handle); ui.destroySubstitutionTexture(user_callback_data, handle);
Textures *t = Minecraft::GetInstance()->textures; Minecraft* mc = Minecraft::GetInstance();
t->releaseTexture( id ); if (mc && mc->textures)
{
mc->textures->releaseTexture( id );
}
} }
void UIController::registerSubstitutionTexture(const wstring &textureName, PBYTE pbData, DWORD dwLength) void UIController::registerSubstitutionTexture(const wstring &textureName, PBYTE pbData, DWORD dwLength)

View file

@ -257,6 +257,7 @@ public:
// RENDERING // RENDERING
float getScreenWidth() { return m_fScreenWidth; } float getScreenWidth() { return m_fScreenWidth; }
float getScreenHeight() { return m_fScreenHeight; } float getScreenHeight() { return m_fScreenHeight; }
void updateScreenSize(S32 w, S32 h) { m_fScreenWidth = (float)w; m_fScreenHeight = (float)h; app.DebugPrintf("[UI-INIT] updateScreenSize: %d x %d\n", w, h); }
virtual void render() = 0; virtual void render() = 0;
void getRenderDimensions(C4JRender::eViewportType viewport, S32 &width, S32 &height); void getRenderDimensions(C4JRender::eViewportType viewport, S32 &width, S32 &height);

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "UI.h" #include "UI.h"
#include "UIScene.h" #include "UIScene.h"
#include "UISplitScreenHelpers.h"
#include "..\..\Lighting.h" #include "..\..\Lighting.h"
#include "..\..\LocalPlayer.h" #include "..\..\LocalPlayer.h"
@ -285,26 +286,8 @@ void UIScene::loadMovie()
moviePath.append(L"Vita.swf"); moviePath.append(L"Vita.swf");
m_loadedResolution = eSceneResolution_Vita; m_loadedResolution = eSceneResolution_Vita;
#elif defined _WINDOWS64 #elif defined _WINDOWS64
if(ui.getScreenHeight() == 720) moviePath.append(L"1080.swf");
{ m_loadedResolution = eSceneResolution_1080;
moviePath.append(L"720.swf");
m_loadedResolution = eSceneResolution_720;
}
else if(ui.getScreenHeight() == 480)
{
moviePath.append(L"480.swf");
m_loadedResolution = eSceneResolution_480;
}
else if(ui.getScreenHeight() < 720)
{
moviePath.append(L"Vita.swf");
m_loadedResolution = eSceneResolution_Vita;
}
else
{
moviePath.append(L"1080.swf");
m_loadedResolution = eSceneResolution_1080;
}
#else #else
moviePath.append(L"1080.swf"); moviePath.append(L"1080.swf");
m_loadedResolution = eSceneResolution_1080; m_loadedResolution = eSceneResolution_1080;
@ -332,8 +315,6 @@ void UIScene::loadMovie()
int64_t beforeLoad = ui.iggyAllocCount; int64_t beforeLoad = ui.iggyAllocCount;
swf = IggyPlayerCreateFromMemory ( baFile.data , baFile.length, NULL); swf = IggyPlayerCreateFromMemory ( baFile.data , baFile.length, NULL);
int64_t afterLoad = ui.iggyAllocCount; int64_t afterLoad = ui.iggyAllocCount;
IggyPlayerInitializeAndTickRS ( swf );
int64_t afterTick = ui.iggyAllocCount;
if(!swf) if(!swf)
{ {
@ -343,17 +324,44 @@ void UIScene::loadMovie()
#endif #endif
app.FatalLoadError(); app.FatalLoadError();
} }
app.DebugPrintf( app.USER_SR, "Loaded iggy movie %ls\n", moviePath.c_str() );
// Read movie dimensions from the SWF header (available immediately after
// CreateFromMemory, no init tick needed).
IggyProperties *properties = IggyPlayerProperties ( swf ); IggyProperties *properties = IggyPlayerProperties ( swf );
m_movieHeight = properties->movie_height_in_pixels; m_movieHeight = properties->movie_height_in_pixels;
m_movieWidth = properties->movie_width_in_pixels; m_movieWidth = properties->movie_width_in_pixels;
m_renderWidth = m_movieWidth; m_renderWidth = m_movieWidth;
m_renderHeight = m_movieHeight; m_renderHeight = m_movieHeight;
S32 width, height; // Set display size BEFORE the init tick to match what render() will use.
m_parentLayer->getRenderDimensions(width, height); // InitializeAndTickRS runs ActionScript that creates text fields. If the
IggyPlayerSetDisplaySize( swf, width, height ); // display size here differs from what render() passes to SetDisplaySize,
// Iggy can cache glyph rasterizations at one scale during init and then
// reuse them at a different scale during draw, producing mixed glyph sizes.
#ifdef _WINDOWS64
{
S32 fitW, fitH, fitOffX, fitOffY;
Fit16x9(ui.getScreenWidth(), ui.getScreenHeight(), fitW, fitH, fitOffX, fitOffY);
IggyPlayerSetDisplaySize( swf, fitW, fitH );
}
#else
IggyPlayerSetDisplaySize( swf, m_movieWidth, m_movieHeight );
#endif
IggyPlayerInitializeAndTickRS ( swf );
int64_t afterTick = ui.iggyAllocCount;
#ifdef _WINDOWS64
// Flush Iggy's internal font caches so all glyphs get rasterized fresh
// at the current display scale on the first Draw. Without this, stale
// cache entries from a previous scene (loaded at a different display size)
// cause mixed glyph sizes. ResizeD3D already calls this, which is why
// fonts look correct after a resize but break when a scene reloads
// without one.
IggyFlushInstalledFonts();
#endif
app.DebugPrintf( app.USER_SR, "Loaded iggy movie %ls\n", moviePath.c_str() );
IggyPlayerSetUserdata(swf,this); IggyPlayerSetUserdata(swf,this);
@ -685,9 +693,23 @@ void UIScene::render(S32 width, S32 height, C4JRender::eViewportType viewport)
{ {
if(m_bIsReloading) return; if(m_bIsReloading) return;
if(!m_hasTickedOnce || !swf) return; if(!m_hasTickedOnce || !swf) return;
ui.setupRenderPosition(viewport);
IggyPlayerSetDisplaySize( swf, width, height ); if(viewport != C4JRender::VIEWPORT_TYPE_FULLSCREEN)
IggyPlayerDraw( swf ); {
F32 originX, originY, viewW, viewH;
GetViewportRect(ui.getScreenWidth(), ui.getScreenHeight(), viewport, originX, originY, viewW, viewH);
S32 fitW, fitH, offsetX, offsetY;
Fit16x9(viewW, viewH, fitW, fitH, offsetX, offsetY);
ui.setupRenderPosition((S32)originX + offsetX, (S32)originY + offsetY);
IggyPlayerSetDisplaySize( swf, fitW, fitH );
IggyPlayerDraw( swf );
}
else
{
ui.setupRenderPosition(viewport);
IggyPlayerSetDisplaySize( swf, width, height );
IggyPlayerDraw( swf );
}
} }
void UIScene::setOpacity(float percent) void UIScene::setOpacity(float percent)
@ -1331,11 +1353,17 @@ bool UIScene::hasRegisteredSubstitutionTexture(const wstring &textureName)
void UIScene::_handleFocusChange(F64 controlId, F64 childId) void UIScene::_handleFocusChange(F64 controlId, F64 childId)
{ {
m_iFocusControl = (int)controlId; int newControl = (int)controlId;
m_iFocusChild = (int)childId; int newChild = (int)childId;
handleFocusChange(controlId, childId); if (newControl != m_iFocusControl || newChild != m_iFocusChild)
ui.PlayUISFX(eSFX_Focus); {
m_iFocusControl = newControl;
m_iFocusChild = newChild;
handleFocusChange(controlId, childId);
ui.PlayUISFX(eSFX_Focus);
}
} }
void UIScene::_handleInitFocus(F64 controlId, F64 childId) void UIScene::_handleInitFocus(F64 controlId, F64 childId)

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "UI.h" #include "UI.h"
#include "UIScene_AbstractContainerMenu.h" #include "UIScene_AbstractContainerMenu.h"
#include "UISplitScreenHelpers.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" #include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" #include "..\..\..\Minecraft.World\net.minecraft.world.item.h"
@ -187,6 +188,11 @@ void UIScene_AbstractContainerMenu::PlatformInitialize(int iPad, int startIndex)
IggyEvent mouseEvent; IggyEvent mouseEvent;
S32 width, height; S32 width, height;
m_parentLayer->getRenderDimensions(width, height); m_parentLayer->getRenderDimensions(width, height);
C4JRender::eViewportType vp = m_parentLayer->getViewport();
if(vp != C4JRender::VIEWPORT_TYPE_FULLSCREEN)
Fit16x9(width, height);
S32 x = m_pointerPos.x*((float)width/m_movieWidth); S32 x = m_pointerPos.x*((float)width/m_movieWidth);
S32 y = m_pointerPos.y*((float)height/m_movieHeight); S32 y = m_pointerPos.y*((float)height/m_movieHeight);
IggyMakeEventMouseMove( &mouseEvent, x, y); IggyMakeEventMouseMove( &mouseEvent, x, y);
@ -212,6 +218,10 @@ void UIScene_AbstractContainerMenu::tick()
S32 width, height; S32 width, height;
m_parentLayer->getRenderDimensions(width, height); m_parentLayer->getRenderDimensions(width, height);
C4JRender::eViewportType vp = m_parentLayer->getViewport();
if(vp != C4JRender::VIEWPORT_TYPE_FULLSCREEN)
Fit16x9(width, height);
S32 x = (S32)(m_pointerPos.x * ((float)width / m_movieWidth)); S32 x = (S32)(m_pointerPos.x * ((float)width / m_movieWidth));
S32 y = (S32)(m_pointerPos.y * ((float)height / m_movieHeight)); S32 y = (S32)(m_pointerPos.y * ((float)height / m_movieHeight));
@ -251,6 +261,27 @@ void UIScene_AbstractContainerMenu::render(S32 width, S32 height, C4JRender::eVi
m_needsCacheRendered = false; m_needsCacheRendered = false;
} }
void UIScene_AbstractContainerMenu::getMouseToSWFScale(float &scaleX, float &scaleY)
{
extern HWND g_hWnd;
RECT rc;
GetClientRect(g_hWnd, &rc);
int winW = rc.right - rc.left;
int winH = rc.bottom - rc.top;
if(winW <= 0 || winH <= 0) { scaleX = 1.0f; scaleY = 1.0f; return; }
S32 renderW, renderH;
C4JRender::eViewportType vp = GetParentLayer()->getViewport();
ui.getRenderDimensions(vp, renderW, renderH);
if(vp != C4JRender::VIEWPORT_TYPE_FULLSCREEN)
Fit16x9(renderW, renderH);
float screenW = (float)ui.getScreenWidth();
float screenH = (float)ui.getScreenHeight();
scaleX = (float)m_movieWidth * screenW / ((float)renderW * (float)winW);
scaleY = (float)m_movieHeight * screenH / ((float)renderH * (float)winH);
}
void UIScene_AbstractContainerMenu::customDraw(IggyCustomDrawCallbackRegion *region) void UIScene_AbstractContainerMenu::customDraw(IggyCustomDrawCallbackRegion *region)
{ {
Minecraft *pMinecraft = Minecraft::GetInstance(); Minecraft *pMinecraft = Minecraft::GetInstance();

View file

@ -38,6 +38,7 @@ public:
int getPad() { return m_iPad; } int getPad() { return m_iPad; }
int getMovieWidth() { return m_movieWidth; } int getMovieWidth() { return m_movieWidth; }
int getMovieHeight() { return m_movieHeight; } int getMovieHeight() { return m_movieHeight; }
void getMouseToSWFScale(float &scaleX, float &scaleY);
bool getIgnoreInput() { return m_bIgnoreInput; } bool getIgnoreInput() { return m_bIgnoreInput; }
void setIgnoreInput(bool bVal) { m_bIgnoreInput=bVal; } void setIgnoreInput(bool bVal) { m_bIgnoreInput=bVal; }

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "UI.h" #include "UI.h"
#include "UIScene_HUD.h" #include "UIScene_HUD.h"
#include "UISplitScreenHelpers.h"
#include "BossMobGuiInfo.h" #include "BossMobGuiInfo.h"
#include "..\..\Minecraft.h" #include "..\..\Minecraft.h"
#include "..\..\MultiplayerLocalPlayer.h" #include "..\..\MultiplayerLocalPlayer.h"
@ -266,8 +267,6 @@ void UIScene_HUD::handleReload()
SetDisplayName(ProfileManager.GetDisplayName(m_iPad)); SetDisplayName(ProfileManager.GetDisplayName(m_iPad));
repositionHud();
SetTooltipsEnabled(((ui.GetMenuDisplayed(ProfileManager.GetPrimaryPad())) || (app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_Tooltips) != 0))); SetTooltipsEnabled(((ui.GetMenuDisplayed(ProfileManager.GetPrimaryPad())) || (app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_Tooltips) != 0)));
} }
@ -697,6 +696,7 @@ void UIScene_HUD::render(S32 width, S32 height, C4JRender::eViewportType viewpor
S32 tileWidth = width; S32 tileWidth = width;
S32 tileHeight = height; S32 tileHeight = height;
bool needsYTile = false;
switch( viewport ) switch( viewport )
{ {
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
@ -704,22 +704,24 @@ void UIScene_HUD::render(S32 width, S32 height, C4JRender::eViewportType viewpor
tileHeight = (S32)(ui.getScreenHeight()); tileHeight = (S32)(ui.getScreenHeight());
break; break;
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
tileWidth = (S32)(ui.getScreenWidth());
tileYStart = (S32)(m_movieHeight / 2);
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
tileWidth = (S32)(ui.getScreenWidth()); tileWidth = (S32)(ui.getScreenWidth());
tileYStart = (S32)(m_movieHeight / 2); needsYTile = true;
break; break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
tileYStart = (S32)(m_movieHeight / 2); needsYTile = true;
break; break;
} }
IggyPlayerSetDisplaySize( getMovie(), m_movieWidth, m_movieHeight ); F32 scale;
ComputeTileScale(tileWidth, tileHeight, m_movieWidth, m_movieHeight, needsYTile, scale, tileYStart);
IggyPlayerSetDisplaySize( getMovie(), (S32)(m_movieWidth * scale), (S32)(m_movieHeight * scale) );
repositionHud(tileWidth, tileHeight, scale);
m_renderWidth = tileWidth; m_renderWidth = tileWidth;
m_renderHeight = tileHeight; m_renderHeight = tileHeight;
@ -790,34 +792,24 @@ void UIScene_HUD::handleTimerComplete(int id)
//setVisible(anyVisible); //setVisible(anyVisible);
} }
void UIScene_HUD::repositionHud() void UIScene_HUD::repositionHud(S32 tileWidth, S32 tileHeight, F32 scale)
{ {
if(!m_bSplitscreen) return; if(!m_bSplitscreen) return;
S32 width = 0; // Pass the visible tile area in SWF coordinates so ActionScript
S32 height = 0; // positions elements (crosshair, hotbar, etc.) centered in the
m_parentLayer->getRenderDimensions( width, height ); // actually visible region, not the raw viewport.
S32 visibleW = (S32)(tileWidth / scale);
S32 visibleH = (S32)(tileHeight / scale);
switch( m_parentLayer->getViewport() ) app.DebugPrintf(app.USER_SR, "Reposition HUD: tile %dx%d, scale %.3f, visible SWF %dx%d\n", tileWidth, tileHeight, scale, visibleW, visibleH );
{
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
height = (S32)(ui.getScreenHeight());
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
width = (S32)(ui.getScreenWidth());
break;
}
app.DebugPrintf(app.USER_SR, "Reposition HUD with dims %d, %d\n", width, height );
IggyDataValue result; IggyDataValue result;
IggyDataValue value[2]; IggyDataValue value[2];
value[0].type = IGGY_DATATYPE_number; value[0].type = IGGY_DATATYPE_number;
value[0].number = width; value[0].number = visibleW;
value[1].type = IGGY_DATATYPE_number; value[1].type = IGGY_DATATYPE_number;
value[1].number = height; value[1].number = visibleH;
IggyResult out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcRepositionHud , 2 , value ); IggyResult out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcRepositionHud , 2 , value );
} }

View file

@ -176,5 +176,5 @@ protected:
#endif #endif
private: private:
void repositionHud(); void repositionHud(S32 tileWidth, S32 tileHeight, F32 scale);
}; };

View file

@ -21,12 +21,19 @@ UIScene_JoinMenu::UIScene_JoinMenu(int iPad, void *_initData, UILayer *parentLay
m_friendInfoUpdatedOK = false; m_friendInfoUpdatedOK = false;
m_friendInfoUpdatedERROR = false; m_friendInfoUpdatedERROR = false;
m_friendInfoRequestIssued = false; m_friendInfoRequestIssued = false;
#ifdef _WINDOWS64
m_serverIndex = initData->serverIndex;
m_editServerPhase = eEditServer_Idle;
m_editServerButtonIndex = -1;
m_deleteServerButtonIndex = -1;
#endif
} }
void UIScene_JoinMenu::updateTooltips() void UIScene_JoinMenu::updateTooltips()
{ {
int iA = -1; int iA = -1;
int iY = -1; int iY = -1;
int iX = -1;
if (getControlFocus() == eControl_GamePlayers) if (getControlFocus() == eControl_GamePlayers)
{ {
#ifdef _DURANGO #ifdef _DURANGO
@ -38,7 +45,15 @@ void UIScene_JoinMenu::updateTooltips()
iA = IDS_TOOLTIPS_SELECT; iA = IDS_TOOLTIPS_SELECT;
} }
ui.SetTooltips( DEFAULT_XUI_MENU_USER, iA, IDS_TOOLTIPS_BACK, -1, iY ); #ifdef _WINDOWS64
if (m_serverIndex >= 0)
{
iX = IDS_TOOLTIPS_DELETE;
iY = IDS_TITLE_RENAME;
}
#endif
ui.SetTooltips( DEFAULT_XUI_MENU_USER, iA, IDS_TOOLTIPS_BACK, iX, iY );
} }
@ -107,6 +122,16 @@ void UIScene_JoinMenu::tick()
} }
#endif #endif
#ifdef _WINDOWS64
if (m_serverIndex >= 0)
{
m_editServerButtonIndex = m_buttonListPlayers.getItemCount();
m_buttonListPlayers.addItem(L"Edit Server");
m_deleteServerButtonIndex = m_buttonListPlayers.getItemCount();
m_buttonListPlayers.addItem(L"Delete Server");
}
#endif
m_labelLabels[eLabel_Difficulty].init(app.GetString(IDS_LABEL_DIFFICULTY)); m_labelLabels[eLabel_Difficulty].init(app.GetString(IDS_LABEL_DIFFICULTY));
m_labelLabels[eLabel_GameType].init(app.GetString(IDS_LABEL_GAME_TYPE)); m_labelLabels[eLabel_GameType].init(app.GetString(IDS_LABEL_GAME_TYPE));
m_labelLabels[eLabel_GamertagsOn].init(app.GetString(IDS_LABEL_GAMERTAGS)); m_labelLabels[eLabel_GamertagsOn].init(app.GetString(IDS_LABEL_GAMERTAGS));
@ -278,12 +303,38 @@ void UIScene_JoinMenu::handleInput(int iPad, int key, bool repeat, bool pressed,
if( uid != INVALID_XUID ) ProfileManager.ShowProfileCard(ProfileManager.GetLockedProfile(),uid); if( uid != INVALID_XUID ) ProfileManager.ShowProfileCard(ProfileManager.GetLockedProfile(),uid);
} }
break; break;
#endif
#ifdef _WINDOWS64
case ACTION_MENU_X:
if(pressed && m_serverIndex >= 0)
{
BeginDeleteServer();
handled = true;
}
break;
case ACTION_MENU_Y:
if(pressed && m_serverIndex >= 0)
{
BeginEditServer();
handled = true;
}
break;
#endif #endif
case ACTION_MENU_OK: case ACTION_MENU_OK:
if (getControlFocus() != eControl_GamePlayers) if (getControlFocus() != eControl_GamePlayers)
{ {
sendInputToMovie(key, repeat, pressed, released); sendInputToMovie(key, repeat, pressed, released);
} }
#ifdef _WINDOWS64
else if (pressed && m_serverIndex >= 0)
{
int sel = m_buttonListPlayers.getCurrentSelection();
if (sel == m_editServerButtonIndex)
BeginEditServer();
else if (sel == m_deleteServerButtonIndex)
BeginDeleteServer();
}
#endif
handled = true; handled = true;
break; break;
#ifdef __ORBIS__ #ifdef __ORBIS__
@ -318,6 +369,16 @@ void UIScene_JoinMenu::handlePress(F64 controlId, F64 childId)
} }
break; break;
case eControl_GamePlayers: case eControl_GamePlayers:
#ifdef _WINDOWS64
if (m_serverIndex >= 0)
{
int sel = (int)childId;
if (sel == m_editServerButtonIndex)
BeginEditServer();
else if (sel == m_deleteServerButtonIndex)
BeginDeleteServer();
}
#endif
break; break;
}; };
} }
@ -636,3 +697,278 @@ void UIScene_JoinMenu::handleTimerComplete(int id)
break; break;
}; };
} }
#ifdef _WINDOWS64
void UIScene_JoinMenu::BeginDeleteServer()
{
m_bIgnoreInput = true;
UINT uiIDA[2];
uiIDA[0] = IDS_CONFIRM_CANCEL;
uiIDA[1] = IDS_CONFIRM_OK;
ui.RequestAlertMessage(IDS_TOOLTIPS_DELETE, IDS_TEXT_DELETE_SAVE, uiIDA, 2, m_iPad, &UIScene_JoinMenu::DeleteServerDialogReturned, this);
}
int UIScene_JoinMenu::DeleteServerDialogReturned(void *pParam, int iPad, C4JStorage::EMessageResult result)
{
UIScene_JoinMenu* pClass = (UIScene_JoinMenu*)pParam;
if (result == C4JStorage::EMessage_ResultDecline)
{
pClass->RemoveServerFromFile();
g_NetworkManager.ForceFriendsSessionRefresh();
pClass->navigateBack();
}
else
{
pClass->m_bIgnoreInput = false;
}
return 0;
}
void UIScene_JoinMenu::BeginEditServer()
{
m_bIgnoreInput = true;
m_editServerPhase = eEditServer_IP;
m_editServerIP.clear();
m_editServerPort.clear();
wchar_t wDefaultIP[64] = {};
mbstowcs(wDefaultIP, m_selectedSession->data.hostIP, 63);
UIKeyboardInitData kbData;
kbData.title = L"Server Address";
kbData.defaultText = wDefaultIP;
kbData.maxChars = 128;
kbData.callback = &UIScene_JoinMenu::EditServerKeyboardCallback;
kbData.lpParam = this;
kbData.pcMode = g_KBMInput.IsKBMActive();
ui.NavigateToScene(m_iPad, eUIScene_Keyboard, &kbData);
}
int UIScene_JoinMenu::EditServerKeyboardCallback(LPVOID lpParam, bool bRes)
{
UIScene_JoinMenu *pClass = (UIScene_JoinMenu *)lpParam;
if (!bRes)
{
pClass->m_editServerPhase = eEditServer_Idle;
pClass->m_bIgnoreInput = false;
return 0;
}
uint16_t ui16Text[256];
ZeroMemory(ui16Text, sizeof(ui16Text));
Win64_GetKeyboardText(ui16Text, 256);
wchar_t wBuf[256] = {};
for (int k = 0; k < 255 && ui16Text[k]; k++)
wBuf[k] = (wchar_t)ui16Text[k];
if (wBuf[0] == 0)
{
pClass->m_editServerPhase = eEditServer_Idle;
pClass->m_bIgnoreInput = false;
return 0;
}
switch (pClass->m_editServerPhase)
{
case eEditServer_IP:
{
pClass->m_editServerIP = wBuf;
pClass->m_editServerPhase = eEditServer_Port;
wchar_t wDefaultPort[16] = {};
swprintf(wDefaultPort, 16, L"%d", pClass->m_selectedSession->data.hostPort);
UIKeyboardInitData kbData;
kbData.title = L"Server Port";
kbData.defaultText = wDefaultPort;
kbData.maxChars = 6;
kbData.callback = &UIScene_JoinMenu::EditServerKeyboardCallback;
kbData.lpParam = pClass;
kbData.pcMode = g_KBMInput.IsKBMActive();
ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData);
break;
}
case eEditServer_Port:
{
pClass->m_editServerPort = wBuf;
pClass->m_editServerPhase = eEditServer_Name;
wchar_t wDefaultName[64] = {};
if (pClass->m_selectedSession->displayLabel)
wcsncpy(wDefaultName, pClass->m_selectedSession->displayLabel, 63);
UIKeyboardInitData kbData;
kbData.title = L"Server Name";
kbData.defaultText = wDefaultName;
kbData.maxChars = 64;
kbData.callback = &UIScene_JoinMenu::EditServerKeyboardCallback;
kbData.lpParam = pClass;
kbData.pcMode = g_KBMInput.IsKBMActive();
ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData);
break;
}
case eEditServer_Name:
{
wstring newName = wBuf;
pClass->UpdateServerInFile(pClass->m_editServerIP, pClass->m_editServerPort, newName);
pClass->m_editServerPhase = eEditServer_Idle;
pClass->m_bIgnoreInput = false;
g_NetworkManager.ForceFriendsSessionRefresh();
pClass->navigateBack();
break;
}
default:
pClass->m_editServerPhase = eEditServer_Idle;
pClass->m_bIgnoreInput = false;
break;
}
return 0;
}
void UIScene_JoinMenu::UpdateServerInFile(const wstring& newIP, const wstring& newPort, const wstring& newName)
{
char narrowNewIP[256] = {};
char narrowNewPort[16] = {};
char narrowNewName[256] = {};
wcstombs(narrowNewIP, newIP.c_str(), sizeof(narrowNewIP) - 1);
wcstombs(narrowNewPort, newPort.c_str(), sizeof(narrowNewPort) - 1);
wcstombs(narrowNewName, newName.c_str(), sizeof(narrowNewName) - 1);
uint16_t newPortNum = (uint16_t)atoi(narrowNewPort);
struct ServerEntry { std::string ip; uint16_t port; std::string name; };
std::vector<ServerEntry> entries;
FILE* file = fopen("servers.db", "rb");
if (file)
{
char magic[4] = {};
if (fread(magic, 1, 4, file) == 4 && memcmp(magic, "MCSV", 4) == 0)
{
uint32_t version = 0, count = 0;
fread(&version, sizeof(uint32_t), 1, file);
fread(&count, sizeof(uint32_t), 1, file);
if (version == 1)
{
for (uint32_t s = 0; s < count; s++)
{
uint16_t ipLen = 0, p = 0, nameLen = 0;
if (fread(&ipLen, sizeof(uint16_t), 1, file) != 1) break;
if (ipLen == 0 || ipLen > 256) break;
char ipBuf[257] = {};
if (fread(ipBuf, 1, ipLen, file) != ipLen) break;
if (fread(&p, sizeof(uint16_t), 1, file) != 1) break;
if (fread(&nameLen, sizeof(uint16_t), 1, file) != 1) break;
if (nameLen > 256) break;
char nameBuf[257] = {};
if (nameLen > 0 && fread(nameBuf, 1, nameLen, file) != nameLen) break;
entries.push_back({std::string(ipBuf), p, std::string(nameBuf)});
}
}
}
fclose(file);
}
// Find and update the matching entry by original IP and port
int idx = m_serverIndex;
if (idx >= 0 && idx < (int)entries.size())
{
entries[idx].ip = std::string(narrowNewIP);
entries[idx].port = newPortNum;
entries[idx].name = std::string(narrowNewName);
}
file = fopen("servers.db", "wb");
if (file)
{
fwrite("MCSV", 1, 4, file);
uint32_t version = 1;
uint32_t count = (uint32_t)entries.size();
fwrite(&version, sizeof(uint32_t), 1, file);
fwrite(&count, sizeof(uint32_t), 1, file);
for (size_t i = 0; i < entries.size(); i++)
{
uint16_t ipLen = (uint16_t)entries[i].ip.length();
fwrite(&ipLen, sizeof(uint16_t), 1, file);
fwrite(entries[i].ip.c_str(), 1, ipLen, file);
fwrite(&entries[i].port, sizeof(uint16_t), 1, file);
uint16_t nameLen = (uint16_t)entries[i].name.length();
fwrite(&nameLen, sizeof(uint16_t), 1, file);
fwrite(entries[i].name.c_str(), 1, nameLen, file);
}
fclose(file);
}
}
void UIScene_JoinMenu::RemoveServerFromFile()
{
struct ServerEntry { std::string ip; uint16_t port; std::string name; };
std::vector<ServerEntry> entries;
FILE* file = fopen("servers.db", "rb");
if (file)
{
char magic[4] = {};
if (fread(magic, 1, 4, file) == 4 && memcmp(magic, "MCSV", 4) == 0)
{
uint32_t version = 0, count = 0;
fread(&version, sizeof(uint32_t), 1, file);
fread(&count, sizeof(uint32_t), 1, file);
if (version == 1)
{
for (uint32_t s = 0; s < count; s++)
{
uint16_t ipLen = 0, p = 0, nameLen = 0;
if (fread(&ipLen, sizeof(uint16_t), 1, file) != 1) break;
if (ipLen == 0 || ipLen > 256) break;
char ipBuf[257] = {};
if (fread(ipBuf, 1, ipLen, file) != ipLen) break;
if (fread(&p, sizeof(uint16_t), 1, file) != 1) break;
if (fread(&nameLen, sizeof(uint16_t), 1, file) != 1) break;
if (nameLen > 256) break;
char nameBuf[257] = {};
if (nameLen > 0 && fread(nameBuf, 1, nameLen, file) != nameLen) break;
entries.push_back({std::string(ipBuf), p, std::string(nameBuf)});
}
}
}
fclose(file);
}
// Remove the entry at m_serverIndex
int idx = m_serverIndex;
if (idx >= 0 && idx < (int)entries.size())
{
entries.erase(entries.begin() + idx);
}
file = fopen("servers.db", "wb");
if (file)
{
fwrite("MCSV", 1, 4, file);
uint32_t version = 1;
uint32_t count = (uint32_t)entries.size();
fwrite(&version, sizeof(uint32_t), 1, file);
fwrite(&count, sizeof(uint32_t), 1, file);
for (size_t i = 0; i < entries.size(); i++)
{
uint16_t ipLen = (uint16_t)entries[i].ip.length();
fwrite(&ipLen, sizeof(uint16_t), 1, file);
fwrite(entries[i].ip.c_str(), 1, ipLen, file);
fwrite(&entries[i].port, sizeof(uint16_t), 1, file);
uint16_t nameLen = (uint16_t)entries[i].name.length();
fwrite(&nameLen, sizeof(uint16_t), 1, file);
fwrite(entries[i].name.c_str(), 1, nameLen, file);
}
fclose(file);
}
}
#endif // _WINDOWS64

View file

@ -62,6 +62,16 @@ private:
bool m_friendInfoUpdatedOK; bool m_friendInfoUpdatedOK;
bool m_friendInfoUpdatedERROR; bool m_friendInfoUpdatedERROR;
#ifdef _WINDOWS64
int m_serverIndex; // Index in servers.db, -1 if not a saved server
enum eEditServerPhase { eEditServer_Idle, eEditServer_IP, eEditServer_Port, eEditServer_Name };
eEditServerPhase m_editServerPhase;
wstring m_editServerIP;
wstring m_editServerPort;
int m_editServerButtonIndex;
int m_deleteServerButtonIndex;
#endif
public: public:
UIScene_JoinMenu(int iPad, void *initData, UILayer *parentLayer); UIScene_JoinMenu(int iPad, void *initData, UILayer *parentLayer);
void tick(); void tick();
@ -95,4 +105,13 @@ protected:
static int StartGame_SignInReturned(void *pParam, bool, int); static int StartGame_SignInReturned(void *pParam, bool, int);
static void JoinGame(UIScene_JoinMenu* pClass); static void JoinGame(UIScene_JoinMenu* pClass);
#ifdef _WINDOWS64
void BeginEditServer();
void BeginDeleteServer();
static int EditServerKeyboardCallback(LPVOID lpParam, bool bRes);
static int DeleteServerDialogReturned(void *pParam, int iPad, C4JStorage::EMessageResult result);
void UpdateServerInFile(const wstring& newIP, const wstring& newPort, const wstring& newName);
void RemoveServerFromFile();
#endif
}; };

View file

@ -38,6 +38,7 @@ UIScene_Keyboard::UIScene_Keyboard(int iPad, void *initData, UILayer *parentLaye
} }
m_win64TextBuffer = defaultText; m_win64TextBuffer = defaultText;
m_iCursorPos = (int)m_win64TextBuffer.length();
m_EnterTextLabel.init(titleText); m_EnterTextLabel.init(titleText);
m_KeyboardTextInput.init(defaultText, -1); m_KeyboardTextInput.init(defaultText, -1);
@ -111,6 +112,9 @@ UIScene_Keyboard::UIScene_Keyboard(int iPad, void *initData, UILayer *parentLaye
if (IggyValuePathMakeNameRef(&keyPath, root, s_keyNames[i])) if (IggyValuePathMakeNameRef(&keyPath, root, s_keyNames[i]))
IggyValueSetBooleanRS(&keyPath, nameVisible, NULL, false); IggyValueSetBooleanRS(&keyPath, nameVisible, NULL, false);
} }
m_KeyboardTextInput.setCaretVisible(true);
m_KeyboardTextInput.setCaretIndex(m_iCursorPos);
} }
#endif #endif
@ -165,9 +169,13 @@ void UIScene_Keyboard::tick()
// Sync our buffer from Flash so we pick up changes made via controller/on-screen buttons. // Sync our buffer from Flash so we pick up changes made via controller/on-screen buttons.
// Without this, switching between controller and keyboard would use stale text. // Without this, switching between controller and keyboard would use stale text.
const wchar_t* flashText = m_KeyboardTextInput.getLabel(); // In PC mode we own the buffer — skip sync to preserve cursor position.
if (flashText) if (!m_bPCMode)
m_win64TextBuffer = flashText; {
const wchar_t* flashText = m_KeyboardTextInput.getLabel();
if (flashText)
m_win64TextBuffer = flashText;
}
// Accumulate physical keyboard chars into our own buffer, then push to Flash via setLabel. // Accumulate physical keyboard chars into our own buffer, then push to Flash via setLabel.
// This bypasses Iggy's focus system (char events only route to the focused element). // This bypasses Iggy's focus system (char events only route to the focused element).
@ -178,7 +186,16 @@ void UIScene_Keyboard::tick()
{ {
if (ch == 0x08) // backspace if (ch == 0x08) // backspace
{ {
if (!m_win64TextBuffer.empty()) if (m_bPCMode)
{
if (m_iCursorPos > 0)
{
m_win64TextBuffer.erase(m_iCursorPos - 1, 1);
m_iCursorPos--;
changed = true;
}
}
else if (!m_win64TextBuffer.empty())
{ {
m_win64TextBuffer.pop_back(); m_win64TextBuffer.pop_back();
changed = true; changed = true;
@ -194,13 +211,45 @@ void UIScene_Keyboard::tick()
} }
else if ((int)m_win64TextBuffer.length() < m_win64MaxChars) else if ((int)m_win64TextBuffer.length() < m_win64MaxChars)
{ {
m_win64TextBuffer += ch; if (m_bPCMode)
{
m_win64TextBuffer.insert(m_iCursorPos, 1, ch);
m_iCursorPos++;
}
else
{
m_win64TextBuffer += ch;
}
changed = true;
}
}
if (m_bPCMode)
{
// Arrow keys, Home, End, Delete for cursor movement
if (g_KBMInput.IsKeyPressed(VK_LEFT) && m_iCursorPos > 0)
m_iCursorPos--;
if (g_KBMInput.IsKeyPressed(VK_RIGHT) && m_iCursorPos < (int)m_win64TextBuffer.length())
m_iCursorPos++;
if (g_KBMInput.IsKeyPressed(VK_HOME))
m_iCursorPos = 0;
if (g_KBMInput.IsKeyPressed(VK_END))
m_iCursorPos = (int)m_win64TextBuffer.length();
if (g_KBMInput.IsKeyPressed(VK_DELETE) && m_iCursorPos < (int)m_win64TextBuffer.length())
{
m_win64TextBuffer.erase(m_iCursorPos, 1);
changed = true; changed = true;
} }
} }
if (changed) if (changed)
m_KeyboardTextInput.setLabel(m_win64TextBuffer.c_str(), true /*instant*/); m_KeyboardTextInput.setLabel(m_win64TextBuffer.c_str(), true /*instant*/);
if (m_bPCMode)
{
m_KeyboardTextInput.setCaretVisible(true);
m_KeyboardTextInput.setCaretIndex(m_iCursorPos);
}
} }
#endif #endif
@ -229,27 +278,31 @@ void UIScene_Keyboard::handleInput(int iPad, int key, bool repeat, bool pressed,
handled = true; handled = true;
break; break;
case ACTION_MENU_X: // X case ACTION_MENU_X: // X
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcBackspaceButtonPressed, 0 , NULL );
handled = true;
break;
case ACTION_MENU_PAGEUP: // LT case ACTION_MENU_PAGEUP: // LT
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSymbolButtonPressed, 0 , NULL );
handled = true;
break;
case ACTION_MENU_Y: // Y case ACTION_MENU_Y: // Y
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSpaceButtonPressed, 0 , NULL );
handled = true;
break;
case ACTION_MENU_STICK_PRESS: // LS case ACTION_MENU_STICK_PRESS: // LS
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCapsButtonPressed, 0 , NULL );
handled = true;
break;
case ACTION_MENU_LEFT_SCROLL: // LB case ACTION_MENU_LEFT_SCROLL: // LB
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorLeftButtonPressed, 0 , NULL );
handled = true;
break;
case ACTION_MENU_RIGHT_SCROLL: // RB case ACTION_MENU_RIGHT_SCROLL: // RB
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorRightButtonPressed, 0 , NULL ); #ifdef _WINDOWS64
if (m_bPCMode)
{
handled = true;
break;
}
#endif
if (key == ACTION_MENU_X)
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcBackspaceButtonPressed, 0 , NULL );
else if (key == ACTION_MENU_PAGEUP)
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSymbolButtonPressed, 0 , NULL );
else if (key == ACTION_MENU_Y)
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSpaceButtonPressed, 0 , NULL );
else if (key == ACTION_MENU_STICK_PRESS)
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCapsButtonPressed, 0 , NULL );
else if (key == ACTION_MENU_LEFT_SCROLL)
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorLeftButtonPressed, 0 , NULL );
else if (key == ACTION_MENU_RIGHT_SCROLL)
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorRightButtonPressed, 0 , NULL );
handled = true; handled = true;
break; break;
case ACTION_MENU_PAUSEMENU: // Start case ACTION_MENU_PAUSEMENU: // Start
@ -269,11 +322,23 @@ void UIScene_Keyboard::handleInput(int iPad, int key, bool repeat, bool pressed,
switch(key) switch(key)
{ {
case ACTION_MENU_OK: case ACTION_MENU_OK:
#ifdef _WINDOWS64
if (m_bPCMode)
{
// pressing enter sometimes causes a "y" to be entered.
handled = true;
break;
}
#endif
// fall through for controller mode
case ACTION_MENU_LEFT: case ACTION_MENU_LEFT:
case ACTION_MENU_RIGHT: case ACTION_MENU_RIGHT:
case ACTION_MENU_UP: case ACTION_MENU_UP:
case ACTION_MENU_DOWN: case ACTION_MENU_DOWN:
sendInputToMovie(key, repeat, pressed, released); #ifdef _WINDOWS64
if (!m_bPCMode)
#endif
sendInputToMovie(key, repeat, pressed, released);
handled = true; handled = true;
break; break;
} }

View file

@ -13,6 +13,7 @@ private:
wstring m_win64TextBuffer; wstring m_win64TextBuffer;
int m_win64MaxChars; int m_win64MaxChars;
bool m_bPCMode; // Hides on-screen keyboard buttons; physical keyboard only bool m_bPCMode; // Hides on-screen keyboard buttons; physical keyboard only
int m_iCursorPos;
#endif #endif
protected: protected:

View file

@ -402,8 +402,13 @@ UIScene_LoadOrJoinMenu::~UIScene_LoadOrJoinMenu()
g_NetworkManager.SetSessionsUpdatedCallback( NULL, NULL ); g_NetworkManager.SetSessionsUpdatedCallback( NULL, NULL );
app.SetLiveLinkRequired( false ); app.SetLiveLinkRequired( false );
delete m_currentSessions; if (m_currentSessions)
m_currentSessions = NULL; {
for (auto& it : *m_currentSessions)
delete it;
delete m_currentSessions;
m_currentSessions = NULL;
}
#if TO_BE_IMPLEMENTED #if TO_BE_IMPLEMENTED
// Reset the background downloading, in case we changed it by attempting to download a texture pack // Reset the background downloading, in case we changed it by attempting to download a texture pack
@ -520,6 +525,9 @@ void UIScene_LoadOrJoinMenu::Initialise()
{ {
m_iSaveListIndex = 0; m_iSaveListIndex = 0;
m_iGameListIndex = 0; m_iGameListIndex = 0;
#ifdef _WINDOWS64
m_addServerPhase = eAddServer_Idle;
#endif
m_iDefaultButtonsC = 0; m_iDefaultButtonsC = 0;
m_iMashUpButtonsC=0; m_iMashUpButtonsC=0;
@ -1470,6 +1478,10 @@ void UIScene_LoadOrJoinMenu::handleFocusChange(F64 controlId, F64 childId)
{ {
case eControl_GamesList: case eControl_GamesList:
m_iGameListIndex = childId; m_iGameListIndex = childId;
#ifdef _WINDOWS64
// Offset past the "Add Server" button so m_iGameListIndex is a session index
m_iGameListIndex -= 1;
#endif
m_buttonListGames.updateChildFocus( (int) childId ); m_buttonListGames.updateChildFocus( (int) childId );
break; break;
case eControl_SavesList: case eControl_SavesList:
@ -1597,6 +1609,14 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
break; break;
case eControl_GamesList: case eControl_GamesList:
{ {
#ifdef _WINDOWS64
if ((int)childId == ADD_SERVER_BUTTON_INDEX)
{
ui.PlayUISFX(eSFX_Press);
BeginAddServer();
break;
}
#endif
m_bIgnoreInput=true; m_bIgnoreInput=true;
m_eAction = eAction_JoinGame; m_eAction = eAction_JoinGame;
@ -1606,6 +1626,10 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
{ {
int nIndex = (int)childId; int nIndex = (int)childId;
#ifdef _WINDOWS64
// Offset by 1 because the "Add Server" button is at index 0
nIndex -= 1;
#endif
m_iGameListIndex = nIndex; m_iGameListIndex = nIndex;
CheckAndJoinGame(nIndex); CheckAndJoinGame(nIndex);
} }
@ -1743,12 +1767,34 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
#endif #endif
#endif #endif
//CScene_MultiGameInfo::JoinMenuInitData *initData = new CScene_MultiGameInfo::JoinMenuInitData();
m_initData->iPad = 0;; m_initData->iPad = 0;;
m_initData->selectedSession = m_currentSessions->at( gameIndex ); m_initData->selectedSession = m_currentSessions->at( gameIndex );
#ifdef _WINDOWS64
{
int serverDbCount = 0;
FILE* dbFile = fopen("servers.db", "rb");
if (dbFile)
{
char magic[4] = {};
if (fread(magic, 1, 4, dbFile) == 4 && memcmp(magic, "MCSV", 4) == 0)
{
uint32_t version = 0, count = 0;
fread(&version, sizeof(uint32_t), 1, dbFile);
fread(&count, sizeof(uint32_t), 1, dbFile);
if (version == 1)
serverDbCount = (int)count;
}
fclose(dbFile);
}
int lanCount = (int)m_currentSessions->size() - serverDbCount;
if (gameIndex >= lanCount && lanCount >= 0)
m_initData->serverIndex = gameIndex - lanCount;
else
m_initData->serverIndex = -1;
}
#endif
// check that we have the texture pack available
// If it's not the default texture pack
if(m_initData->selectedSession->data.texturePackParentId!=0) if(m_initData->selectedSession->data.texturePackParentId!=0)
{ {
int texturePacksCount = Minecraft::GetInstance()->skins->getTexturePackCount(); int texturePacksCount = Minecraft::GetInstance()->skins->getTexturePackCount();
@ -1766,8 +1812,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
if(bHasTexturePackInstalled==false) if(bHasTexturePackInstalled==false)
{ {
// upsell the texture pack
// tell sentient about the upsell of the full version of the skin pack
#ifdef _XBOX #ifdef _XBOX
ULONGLONG ullOfferID_Full; ULONGLONG ullOfferID_Full;
app.GetDLCFullOfferIDForPackID(m_initData->selectedSession->data.texturePackParentId,&ullOfferID_Full); app.GetDLCFullOfferIDForPackID(m_initData->selectedSession->data.texturePackParentId,&ullOfferID_Full);
@ -1780,8 +1825,6 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
//uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION; //uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION;
uiIDA[1]=IDS_CONFIRM_CANCEL; uiIDA[1]=IDS_CONFIRM_CANCEL;
// Give the player a warning about the texture pack missing
ui.RequestAlertMessage(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, m_iPad,&UIScene_LoadOrJoinMenu::TexturePackDialogReturned,this); ui.RequestAlertMessage(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, m_iPad,&UIScene_LoadOrJoinMenu::TexturePackDialogReturned,this);
return; return;
@ -1799,7 +1842,6 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
m_controlJoinTimer.setVisible( false ); m_controlJoinTimer.setVisible( false );
#ifdef _XBOX #ifdef _XBOX
// Reset the background downloading, in case we changed it by attempting to download a texture pack
XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO);
#endif #endif
@ -1895,7 +1937,13 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
if(DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0) if(DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0)
{ {
unsigned int nIndex = m_buttonListGames.getCurrentSelection(); unsigned int nIndex = m_buttonListGames.getCurrentSelection();
#ifdef _WINDOWS64
// Offset past the "Add Server" button
if (nIndex > 0)
pSelectedSession = m_currentSessions->at( nIndex - 1 );
#else
pSelectedSession = m_currentSessions->at( nIndex ); pSelectedSession = m_currentSessions->at( nIndex );
#endif
} }
SessionID selectedSessionId; SessionID selectedSessionId;
@ -1911,8 +1959,37 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
int iY = -1; int iY = -1;
int iX=-1; int iX=-1;
delete m_currentSessions; vector<FriendSessionInfo*>* newSessions = g_NetworkManager.GetSessionList( m_iPad, 1, m_bShowingPartyGamesOnly );
m_currentSessions = g_NetworkManager.GetSessionList( m_iPad, 1, m_bShowingPartyGamesOnly );
if (m_currentSessions != NULL && m_currentSessions->size() == newSessions->size())
{
bool same = true;
for (size_t i = 0; i < newSessions->size(); i++)
{
if (memcmp(&(*m_currentSessions)[i]->sessionId, &(*newSessions)[i]->sessionId, sizeof(SessionID)) != 0 ||
wcscmp((*m_currentSessions)[i]->displayLabel ? (*m_currentSessions)[i]->displayLabel : L"",
(*newSessions)[i]->displayLabel ? (*newSessions)[i]->displayLabel : L"") != 0)
{
same = false;
break;
}
}
if (same)
{
for (auto& it : *newSessions)
delete it;
delete newSessions;
return;
}
}
if (m_currentSessions)
{
for (auto& it : *m_currentSessions)
delete it;
delete m_currentSessions;
}
m_currentSessions = newSessions;
// Update the xui list displayed // Update the xui list displayed
unsigned int xuiListSize = m_buttonListGames.getItemCount(); unsigned int xuiListSize = m_buttonListGames.getItemCount();
@ -1948,6 +2025,11 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
// clear out the games list and re-fill // clear out the games list and re-fill
m_buttonListGames.clearList(); m_buttonListGames.clearList();
#ifdef _WINDOWS64
// Always add the "Add Server" button as the first entry in the games list
m_buttonListGames.addItem(wstring(L"Add Server"));
#endif
if( filteredListSize > 0 ) if( filteredListSize > 0 )
{ {
// Reset the focus to the selected session if it still exists // Reset the focus to the selected session if it still exists
@ -2013,7 +2095,12 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
if(memcmp( &selectedSessionId, &sessionInfo->sessionId, sizeof(SessionID) ) == 0) if(memcmp( &selectedSessionId, &sessionInfo->sessionId, sizeof(SessionID) ) == 0)
{ {
#ifdef _WINDOWS64
// Offset past the "Add Server" button
m_buttonListGames.setCurrentSelection(sessionIndex + 1);
#else
m_buttonListGames.setCurrentSelection(sessionIndex); m_buttonListGames.setCurrentSelection(sessionIndex);
#endif
break; break;
} }
++sessionIndex; ++sessionIndex;
@ -4050,3 +4137,168 @@ int UIScene_LoadOrJoinMenu::CopySaveErrorDialogFinishedCallback(void *pParam,int
} }
#endif // _XBOX_ONE #endif // _XBOX_ONE
#ifdef _WINDOWS64
// adding servers bellow
void UIScene_LoadOrJoinMenu::BeginAddServer()
{
m_addServerPhase = eAddServer_IP;
m_addServerIP.clear();
m_addServerPort.clear();
UIKeyboardInitData kbData;
kbData.title = L"Server Address";
kbData.defaultText = L"";
kbData.maxChars = 128;
kbData.callback = &UIScene_LoadOrJoinMenu::AddServerKeyboardCallback;
kbData.lpParam = this;
kbData.pcMode = g_KBMInput.IsKBMActive();
ui.NavigateToScene(m_iPad, eUIScene_Keyboard, &kbData);
}
int UIScene_LoadOrJoinMenu::AddServerKeyboardCallback(LPVOID lpParam, bool bRes)
{
UIScene_LoadOrJoinMenu *pClass = (UIScene_LoadOrJoinMenu *)lpParam;
if (!bRes)
{
pClass->m_addServerPhase = eAddServer_Idle;
pClass->m_bIgnoreInput = false;
return 0;
}
uint16_t ui16Text[256];
ZeroMemory(ui16Text, sizeof(ui16Text));
Win64_GetKeyboardText(ui16Text, 256);
wchar_t wBuf[256] = {};
for (int k = 0; k < 255 && ui16Text[k]; k++)
wBuf[k] = (wchar_t)ui16Text[k];
if (wBuf[0] == 0)
{
pClass->m_addServerPhase = eAddServer_Idle;
pClass->m_bIgnoreInput = false;
return 0;
}
switch (pClass->m_addServerPhase)
{
case eAddServer_IP:
{
pClass->m_addServerIP = wBuf;
pClass->m_addServerPhase = eAddServer_Port;
UIKeyboardInitData kbData;
kbData.title = L"Server Port";
kbData.defaultText = L"25565";
kbData.maxChars = 6;
kbData.callback = &UIScene_LoadOrJoinMenu::AddServerKeyboardCallback;
kbData.lpParam = pClass;
kbData.pcMode = g_KBMInput.IsKBMActive();
ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData);
break;
}
case eAddServer_Port:
{
pClass->m_addServerPort = wBuf;
pClass->m_addServerPhase = eAddServer_Name;
UIKeyboardInitData kbData;
kbData.title = L"Server Name";
kbData.defaultText = L"Minecraft Server";
kbData.maxChars = 64;
kbData.callback = &UIScene_LoadOrJoinMenu::AddServerKeyboardCallback;
kbData.lpParam = pClass;
kbData.pcMode = g_KBMInput.IsKBMActive();
ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData);
break;
}
case eAddServer_Name:
{
wstring name = wBuf;
pClass->AppendServerToFile(pClass->m_addServerIP, pClass->m_addServerPort, name);
pClass->m_addServerPhase = eAddServer_Idle;
pClass->m_bIgnoreInput = false;
g_NetworkManager.ForceFriendsSessionRefresh();
break;
}
default:
pClass->m_addServerPhase = eAddServer_Idle;
pClass->m_bIgnoreInput = false;
break;
}
return 0;
}
void UIScene_LoadOrJoinMenu::AppendServerToFile(const wstring& ip, const wstring& port, const wstring& name)
{
char narrowIP[256] = {};
char narrowPort[16] = {};
char narrowName[256] = {};
wcstombs(narrowIP, ip.c_str(), sizeof(narrowIP) - 1);
wcstombs(narrowPort, port.c_str(), sizeof(narrowPort) - 1);
wcstombs(narrowName, name.c_str(), sizeof(narrowName) - 1);
uint16_t portNum = (uint16_t)atoi(narrowPort);
struct ServerEntry { std::string ip; uint16_t port; std::string name; };
std::vector<ServerEntry> entries;
FILE* file = fopen("servers.db", "rb");
if (file)
{
char magic[4] = {};
if (fread(magic, 1, 4, file) == 4 && memcmp(magic, "MCSV", 4) == 0)
{
uint32_t version = 0, count = 0;
fread(&version, sizeof(uint32_t), 1, file);
fread(&count, sizeof(uint32_t), 1, file);
if (version == 1)
{
for (uint32_t s = 0; s < count; s++)
{
uint16_t ipLen = 0, p = 0, nameLen = 0;
if (fread(&ipLen, sizeof(uint16_t), 1, file) != 1) break;
if (ipLen == 0 || ipLen > 256) break;
char ipBuf[257] = {};
if (fread(ipBuf, 1, ipLen, file) != ipLen) break;
if (fread(&p, sizeof(uint16_t), 1, file) != 1) break;
if (fread(&nameLen, sizeof(uint16_t), 1, file) != 1) break;
if (nameLen > 256) break;
char nameBuf[257] = {};
if (nameLen > 0 && fread(nameBuf, 1, nameLen, file) != nameLen) break;
entries.push_back({std::string(ipBuf), p, std::string(nameBuf)});
}
}
}
fclose(file);
}
entries.push_back({std::string(narrowIP), portNum, std::string(narrowName)});
file = fopen("servers.db", "wb");
if (file)
{
fwrite("MCSV", 1, 4, file);
uint32_t version = 1;
uint32_t count = (uint32_t)entries.size();
fwrite(&version, sizeof(uint32_t), 1, file);
fwrite(&count, sizeof(uint32_t), 1, file);
for (size_t i = 0; i < entries.size(); i++)
{
uint16_t ipLen = (uint16_t)entries[i].ip.length();
fwrite(&ipLen, sizeof(uint16_t), 1, file);
fwrite(entries[i].ip.c_str(), 1, ipLen, file);
fwrite(&entries[i].port, sizeof(uint16_t), 1, file);
uint16_t nameLen = (uint16_t)entries[i].name.length();
fwrite(&nameLen, sizeof(uint16_t), 1, file);
fwrite(entries[i].name.c_str(), 1, nameLen, file);
}
fclose(file);
}
}
#endif // _WINDOWS64

View file

@ -175,6 +175,18 @@ public:
private: private:
void CheckAndJoinGame(int gameIndex); void CheckAndJoinGame(int gameIndex);
#ifdef _WINDOWS64
static const int ADD_SERVER_BUTTON_INDEX = 0;
enum eAddServerPhase { eAddServer_Idle, eAddServer_IP, eAddServer_Port, eAddServer_Name };
eAddServerPhase m_addServerPhase;
wstring m_addServerIP;
wstring m_addServerPort;
void BeginAddServer();
void AppendServerToFile(const wstring& ip, const wstring& port, const wstring& name);
static int AddServerKeyboardCallback(LPVOID lpParam, bool bRes);
#endif
#if defined(__PS3__) || defined(__PSVITA__) || defined(__ORBIS__) #if defined(__PS3__) || defined(__PSVITA__) || defined(__ORBIS__)
static int MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::EMessageResult result); static int MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::EMessageResult result);
static int PSN_SignInReturned(void *pParam,bool bContinue, int iPad); static int PSN_SignInReturned(void *pParam,bool bContinue, int iPad);

View file

@ -13,7 +13,7 @@
//#define SKIN_SELECT_PACK_PLAYER_CUSTOM 1 //#define SKIN_SELECT_PACK_PLAYER_CUSTOM 1
#define SKIN_SELECT_MAX_DEFAULTS 2 #define SKIN_SELECT_MAX_DEFAULTS 2
WCHAR *UIScene_SkinSelectMenu::wchDefaultNamesA[]= const WCHAR *UIScene_SkinSelectMenu::wchDefaultNamesA[]=
{ {
L"USE LOCALISED VERSION", // Server selected L"USE LOCALISED VERSION", // Server selected
L"Steve", L"Steve",

View file

@ -6,7 +6,7 @@
class UIScene_SkinSelectMenu : public UIScene class UIScene_SkinSelectMenu : public UIScene
{ {
private: private:
static WCHAR *wchDefaultNamesA[eDefaultSkins_Count]; static const WCHAR *wchDefaultNamesA[eDefaultSkins_Count];
// 4J Stu - How many to show on each side of the main control // 4J Stu - How many to show on each side of the main control
static const BYTE sidePreviewControls = 4; static const BYTE sidePreviewControls = 4;

View file

@ -0,0 +1,114 @@
#pragma once
// Shared split-screen UI helpers to avoid duplicating viewport math
// across HUD, Chat, Tooltips, and container menus.
// Compute the raw viewport rectangle for a given viewport type.
inline void GetViewportRect(F32 screenW, F32 screenH, C4JRender::eViewportType viewport,
F32 &originX, F32 &originY, F32 &viewW, F32 &viewH)
{
originX = originY = 0;
viewW = screenW;
viewH = screenH;
switch(viewport)
{
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
viewH = screenH * 0.5f; break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
originY = screenH * 0.5f; viewH = screenH * 0.5f; break;
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
viewW = screenW * 0.5f; break;
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
originX = screenW * 0.5f; viewW = screenW * 0.5f; break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
viewW = screenW * 0.5f; viewH = screenH * 0.5f; break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
originX = screenW * 0.5f; viewW = screenW * 0.5f; viewH = screenH * 0.5f; break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
originY = screenH * 0.5f; viewW = screenW * 0.5f; viewH = screenH * 0.5f; break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
originX = screenW * 0.5f; originY = screenH * 0.5f;
viewW = screenW * 0.5f; viewH = screenH * 0.5f; break;
default: break;
}
}
// Fit a 16:9 rectangle inside the given dimensions.
inline void Fit16x9(F32 viewW, F32 viewH, S32 &fitW, S32 &fitH, S32 &offsetX, S32 &offsetY)
{
const F32 kAspect = 16.0f / 9.0f;
if(viewW / viewH > kAspect)
{
fitH = (S32)viewH;
fitW = (S32)(viewH * kAspect);
}
else
{
fitW = (S32)viewW;
fitH = (S32)(viewW / kAspect);
}
offsetX = (S32)((viewW - fitW) * 0.5f);
offsetY = (S32)((viewH - fitH) * 0.5f);
}
// Convenience: just fit 16:9 dimensions, ignore offsets.
inline void Fit16x9(S32 &width, S32 &height)
{
S32 offX, offY;
Fit16x9((F32)width, (F32)height, width, height, offX, offY);
}
// Compute the uniform scale and tileYStart for split-screen tile rendering.
// Used by HUD, Chat, and Tooltips to scale the SWF movie to cover the viewport tile.
inline void ComputeTileScale(S32 tileWidth, S32 tileHeight, S32 movieWidth, S32 movieHeight,
bool needsYTile, F32 &outScale, S32 &outTileYStart)
{
F32 scaleW = (F32)tileWidth / (F32)movieWidth;
F32 scaleH = (F32)tileHeight / (F32)movieHeight;
F32 scale = (scaleW > scaleH) ? scaleW : scaleH;
if(scale < 1.0f) scale = 1.0f;
outTileYStart = 0;
if(needsYTile)
{
S32 dispH = (S32)(movieHeight * scale);
outTileYStart = dispH - tileHeight;
if(outTileYStart < 0) outTileYStart = 0;
scaleH = (F32)(outTileYStart + tileHeight) / (F32)movieHeight;
scale = (scaleW > scaleH) ? scaleW : scaleH;
if(scale < 1.0f) scale = 1.0f;
}
outScale = scale;
}
// Compute the render offset to center split-screen SWF content in the viewport.
// Used by Chat and Tooltips (HUD uses repositionHud instead).
inline void ComputeSplitContentOffset(C4JRender::eViewportType viewport, S32 movieWidth, S32 movieHeight,
F32 scale, S32 tileWidth, S32 tileHeight, S32 tileYStart,
S32 &outXOffset, S32 &outYOffset)
{
S32 contentCenterX, contentCenterY;
if(viewport == C4JRender::VIEWPORT_TYPE_SPLIT_LEFT || viewport == C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT)
{
contentCenterX = (S32)(movieWidth * scale / 4);
contentCenterY = (S32)(movieHeight * scale / 2);
}
else if(viewport == C4JRender::VIEWPORT_TYPE_SPLIT_TOP || viewport == C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM)
{
contentCenterX = (S32)(movieWidth * scale / 2);
contentCenterY = (S32)(movieHeight * scale * 3 / 4);
}
else
{
contentCenterX = (S32)(movieWidth * scale / 4);
contentCenterY = (S32)(movieHeight * scale * 3 / 4);
}
outXOffset = 0;
outYOffset = 0;
if(viewport == C4JRender::VIEWPORT_TYPE_SPLIT_LEFT || viewport == C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT || viewport == C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT)
outXOffset = -(tileWidth / 2 - contentCenterX);
if(viewport == C4JRender::VIEWPORT_TYPE_SPLIT_TOP || viewport == C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT || viewport == C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT)
outYOffset = -(tileHeight / 2 - (contentCenterY - tileYStart));
}

View file

@ -280,6 +280,9 @@ typedef struct _JoinMenuInitData
{ {
FriendSessionInfo *selectedSession; FriendSessionInfo *selectedSession;
int iPad; int iPad;
#ifdef _WINDOWS64
int serverIndex; // Index of the server in servers.db, -1 if not a saved server
#endif
} JoinMenuInitData; } JoinMenuInitData;
// Native keyboard (Windows64 replacement for InputManager.RequestKeyboard WinAPI dialog) // Native keyboard (Windows64 replacement for InputManager.RequestKeyboard WinAPI dialog)

View file

@ -1,16 +1,13 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream /* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2011 Mark Adler * Copyright (C) 1995-2011, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
/* @(#) $Id$ */ /* @(#) $Id$ */
#include "zutil.h" #include "zutil.h"
#define local static #define BASE 65521U /* largest prime smaller than 65536 */
local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
#define BASE 65521 /* largest prime smaller than 65536 */
#define NMAX 5552 #define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
@ -61,11 +58,7 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
#endif #endif
/* ========================================================================= */ /* ========================================================================= */
uLong ZEXPORT adler32(adler, buf, len) uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) {
uLong adler;
const Bytef *buf;
uInt len;
{
unsigned long sum2; unsigned long sum2;
unsigned n; unsigned n;
@ -132,11 +125,12 @@ uLong ZEXPORT adler32(adler, buf, len)
} }
/* ========================================================================= */ /* ========================================================================= */
local uLong adler32_combine_(adler1, adler2, len2) uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) {
uLong adler1; return adler32_z(adler, buf, len);
uLong adler2; }
z_off64_t len2;
{ /* ========================================================================= */
local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) {
unsigned long sum1; unsigned long sum1;
unsigned long sum2; unsigned long sum2;
unsigned rem; unsigned rem;
@ -155,24 +149,16 @@ local uLong adler32_combine_(adler1, adler2, len2)
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE;
if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
if (sum2 >= BASE) sum2 -= BASE; if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16); return sum1 | (sum2 << 16);
} }
/* ========================================================================= */ /* ========================================================================= */
uLong ZEXPORT adler32_combine(adler1, adler2, len2) uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) {
uLong adler1;
uLong adler2;
z_off_t len2;
{
return adler32_combine_(adler1, adler2, len2); return adler32_combine_(adler1, adler2, len2);
} }
uLong ZEXPORT adler32_combine64(adler1, adler2, len2) uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) {
uLong adler1;
uLong adler2;
z_off64_t len2;
{
return adler32_combine_(adler1, adler2, len2); return adler32_combine_(adler1, adler2, len2);
} }

View file

@ -1,5 +1,5 @@
/* compress.c -- compress a memory buffer /* compress.c -- compress a memory buffer
* Copyright (C) 1995-2005 Jean-loup Gailly. * Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -18,26 +18,22 @@
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer, memory, Z_BUF_ERROR if there was not enough room in the output buffer,
Z_STREAM_ERROR if the level parameter is invalid. Z_STREAM_ERROR if the level parameter is invalid.
The _z versions of the functions take size_t length arguments.
*/ */
int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) int ZEXPORT compress2_z(Bytef *dest, z_size_t *destLen, const Bytef *source,
Bytef *dest; z_size_t sourceLen, int level) {
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
int level;
{
z_stream stream; z_stream stream;
int err; int err;
const uInt max = (uInt)-1;
z_size_t left;
stream.next_in = (z_const Bytef *)source; if ((sourceLen > 0 && source == NULL) ||
stream.avail_in = (uInt)sourceLen; destLen == NULL || (*destLen > 0 && dest == NULL))
#ifdef MAXSEG_64K return Z_STREAM_ERROR;
/* Check for source > 64K on 16-bit machine: */
if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; left = *destLen;
#endif *destLen = 0;
stream.next_out = dest;
stream.avail_out = (uInt)*destLen;
if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
stream.zalloc = (alloc_func)0; stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0; stream.zfree = (free_func)0;
@ -46,36 +42,58 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
err = deflateInit(&stream, level); err = deflateInit(&stream, level);
if (err != Z_OK) return err; if (err != Z_OK) return err;
err = deflate(&stream, Z_FINISH); stream.next_out = dest;
if (err != Z_STREAM_END) { stream.avail_out = 0;
deflateEnd(&stream); stream.next_in = (z_const Bytef *)source;
return err == Z_OK ? Z_BUF_ERROR : err; stream.avail_in = 0;
}
*destLen = stream.total_out;
err = deflateEnd(&stream); do {
return err; if (stream.avail_out == 0) {
stream.avail_out = left > (z_size_t)max ? max : (uInt)left;
left -= stream.avail_out;
}
if (stream.avail_in == 0) {
stream.avail_in = sourceLen > (z_size_t)max ? max :
(uInt)sourceLen;
sourceLen -= stream.avail_in;
}
err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);
} while (err == Z_OK);
*destLen = (z_size_t)(stream.next_out - dest);
deflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK : err;
}
int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen, int level) {
int ret;
z_size_t got = *destLen;
ret = compress2_z(dest, &got, source, sourceLen, level);
*destLen = (uLong)got;
return ret;
} }
/* =========================================================================== /* ===========================================================================
*/ */
int ZEXPORT compress (dest, destLen, source, sourceLen) int ZEXPORT compress_z(Bytef *dest, z_size_t *destLen, const Bytef *source,
Bytef *dest; z_size_t sourceLen) {
uLongf *destLen; return compress2_z(dest, destLen, source, sourceLen,
const Bytef *source; Z_DEFAULT_COMPRESSION);
uLong sourceLen; }
{ int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen) {
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
} }
/* =========================================================================== /* ===========================================================================
If the default memLevel or windowBits for deflateInit() is changed, then If the default memLevel or windowBits for deflateInit() is changed, then
this function needs to be updated. this function needs to be updated.
*/ */
uLong ZEXPORT compressBound (sourceLen) z_size_t ZEXPORT compressBound_z(z_size_t sourceLen) {
uLong sourceLen; z_size_t bound = sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
{ (sourceLen >> 25) + 13;
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + return bound < sourceLen ? (z_size_t)-1 : bound;
(sourceLen >> 25) + 13; }
uLong ZEXPORT compressBound(uLong sourceLen) {
z_size_t bound = compressBound_z(sourceLen);
return (uLong)bound != bound ? (uLong)-1 : (uLong)bound;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* deflate.h -- internal compression state /* deflate.h -- internal compression state
* Copyright (C) 1995-2012 Jean-loup Gailly * Copyright (C) 1995-2026 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -23,6 +23,10 @@
# define GZIP # define GZIP
#endif #endif
/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at
the cost of a larger memory footprint */
/* #define LIT_MEM */
/* =========================================================================== /* ===========================================================================
* Internal compression state. * Internal compression state.
*/ */
@ -51,13 +55,16 @@
#define Buf_size 16 #define Buf_size 16
/* size of bit buffer in bi_buf */ /* size of bit buffer in bi_buf */
#define INIT_STATE 42 #define INIT_STATE 42 /* zlib header -> BUSY_STATE */
#define EXTRA_STATE 69 #ifdef GZIP
#define NAME_STATE 73 # define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */
#define COMMENT_STATE 91 #endif
#define HCRC_STATE 103 #define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */
#define BUSY_STATE 113 #define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */
#define FINISH_STATE 666 #define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */
#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */
#define BUSY_STATE 113 /* deflate -> FINISH_STATE */
#define FINISH_STATE 666 /* stream complete */
/* Stream status */ /* Stream status */
@ -83,7 +90,7 @@ typedef struct static_tree_desc_s static_tree_desc;
typedef struct tree_desc_s { typedef struct tree_desc_s {
ct_data *dyn_tree; /* the dynamic tree */ ct_data *dyn_tree; /* the dynamic tree */
int max_code; /* largest code with non zero frequency */ int max_code; /* largest code with non zero frequency */
static_tree_desc *stat_desc; /* the corresponding static tree */ const static_tree_desc *stat_desc; /* the corresponding static tree */
} FAR tree_desc; } FAR tree_desc;
typedef ush Pos; typedef ush Pos;
@ -100,10 +107,10 @@ typedef struct internal_state {
Bytef *pending_buf; /* output still pending */ Bytef *pending_buf; /* output still pending */
ulg pending_buf_size; /* size of pending_buf */ ulg pending_buf_size; /* size of pending_buf */
Bytef *pending_out; /* next pending byte to output to the stream */ Bytef *pending_out; /* next pending byte to output to the stream */
uInt pending; /* nb of bytes in the pending buffer */ ulg pending; /* nb of bytes in the pending buffer */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
gz_headerp gzhead; /* gzip header information to write */ gz_headerp gzhead; /* gzip header information to write */
uInt gzindex; /* where in extra, name, or comment */ ulg gzindex; /* where in extra, name, or comment */
Byte method; /* can only be DEFLATED */ Byte method; /* can only be DEFLATED */
int last_flush; /* value of flush param for previous deflate call */ int last_flush; /* value of flush param for previous deflate call */
@ -214,7 +221,14 @@ typedef struct internal_state {
/* Depth of each subtree used as tie breaker for trees of equal frequency /* Depth of each subtree used as tie breaker for trees of equal frequency
*/ */
uchf *l_buf; /* buffer for literals or lengths */ #ifdef LIT_MEM
# define LIT_BUFS 5
ushf *d_buf; /* buffer for distances */
uchf *l_buf; /* buffer for literals/lengths */
#else
# define LIT_BUFS 4
uchf *sym_buf; /* buffer for distances and literals/lengths */
#endif
uInt lit_bufsize; uInt lit_bufsize;
/* Size of match buffer for literals/lengths. There are 4 reasons for /* Size of match buffer for literals/lengths. There are 4 reasons for
@ -236,20 +250,15 @@ typedef struct internal_state {
* - I can't count above 4 * - I can't count above 4
*/ */
uInt last_lit; /* running index in l_buf */ uInt sym_next; /* running index in symbol buffer */
uInt sym_end; /* symbol table full when sym_next reaches this */
ushf *d_buf;
/* Buffer for distances. To simplify the code, d_buf and l_buf have
* the same number of elements. To use different lengths, an extra flag
* array would be necessary.
*/
ulg opt_len; /* bit length of current block with optimal trees */ ulg opt_len; /* bit length of current block with optimal trees */
ulg static_len; /* bit length of current block with static trees */ ulg static_len; /* bit length of current block with static trees */
uInt matches; /* number of string matches in current block */ uInt matches; /* number of string matches in current block */
uInt insert; /* bytes at end of window left to insert */ uInt insert; /* bytes at end of window left to insert */
#ifdef DEBUG #ifdef ZLIB_DEBUG
ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
#endif #endif
@ -262,6 +271,9 @@ typedef struct internal_state {
/* Number of valid bits in bi_buf. All bits above the last valid bit /* Number of valid bits in bi_buf. All bits above the last valid bit
* are always zero. * are always zero.
*/ */
int bi_used;
/* Last number of used bits when going to a byte boundary.
*/
ulg high_water; ulg high_water;
/* High water mark offset in window for initialized bytes -- bytes above /* High water mark offset in window for initialized bytes -- bytes above
@ -270,12 +282,15 @@ typedef struct internal_state {
* updated to the new high water mark. * updated to the new high water mark.
*/ */
int slid;
/* True if the hash table has been slid since it was cleared. */
} FAR deflate_state; } FAR deflate_state;
/* Output a byte on the stream. /* Output a byte on the stream.
* IN assertion: there is enough room in pending_buf. * IN assertion: there is enough room in pending_buf.
*/ */
#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} #define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);}
#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
@ -293,14 +308,14 @@ typedef struct internal_state {
memory checker errors from longest match routines */ memory checker errors from longest match routines */
/* in trees.c */ /* in trees.c */
void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); void ZLIB_INTERNAL _tr_init(deflate_state *s);
int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc);
void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
ulg stored_len, int last)); ulg stored_len, int last);
void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s);
void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_align(deflate_state *s);
void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
ulg stored_len, int last)); ulg stored_len, int last);
#define d_code(dist) \ #define d_code(dist) \
((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
@ -309,7 +324,7 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
* used. * used.
*/ */
#ifndef DEBUG #ifndef ZLIB_DEBUG
/* Inline versions of _tr_tally for speed: */ /* Inline versions of _tr_tally for speed: */
#if defined(GEN_TREES_H) || !defined(STDC) #if defined(GEN_TREES_H) || !defined(STDC)
@ -320,24 +335,46 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
extern const uch ZLIB_INTERNAL _dist_code[]; extern const uch ZLIB_INTERNAL _dist_code[];
#endif #endif
#ifdef LIT_MEM
# define _tr_tally_lit(s, c, flush) \ # define _tr_tally_lit(s, c, flush) \
{ uch cc = (c); \ { uch cc = (c); \
s->d_buf[s->last_lit] = 0; \ s->d_buf[s->sym_next] = 0; \
s->l_buf[s->last_lit++] = cc; \ s->l_buf[s->sym_next++] = cc; \
s->dyn_ltree[cc].Freq++; \ s->dyn_ltree[cc].Freq++; \
flush = (s->last_lit == s->lit_bufsize-1); \ flush = (s->sym_next == s->sym_end); \
} }
# define _tr_tally_dist(s, distance, length, flush) \ # define _tr_tally_dist(s, distance, length, flush) \
{ uch len = (length); \ { uch len = (uch)(length); \
ush dist = (distance); \ ush dist = (ush)(distance); \
s->d_buf[s->last_lit] = dist; \ s->d_buf[s->sym_next] = dist; \
s->l_buf[s->last_lit++] = len; \ s->l_buf[s->sym_next++] = len; \
dist--; \ dist--; \
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
s->dyn_dtree[d_code(dist)].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \
flush = (s->last_lit == s->lit_bufsize-1); \ flush = (s->sym_next == s->sym_end); \
} }
#else #else
# define _tr_tally_lit(s, c, flush) \
{ uch cc = (c); \
s->sym_buf[s->sym_next++] = 0; \
s->sym_buf[s->sym_next++] = 0; \
s->sym_buf[s->sym_next++] = cc; \
s->dyn_ltree[cc].Freq++; \
flush = (s->sym_next == s->sym_end); \
}
# define _tr_tally_dist(s, distance, length, flush) \
{ uch len = (uch)(length); \
ush dist = (ush)(distance); \
s->sym_buf[s->sym_next++] = (uch)dist; \
s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \
s->sym_buf[s->sym_next++] = len; \
dist--; \
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
s->dyn_dtree[d_code(dist)].Freq++; \
flush = (s->sym_next == s->sym_end); \
}
#endif
#else
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
# define _tr_tally_dist(s, distance, length, flush) \ # define _tr_tally_dist(s, distance, length, flush) \
flush = _tr_tally(s, distance, length) flush = _tr_tally(s, distance, length)

View file

@ -8,9 +8,7 @@
/* gzclose() is in a separate file so that it is linked in only if it is used. /* gzclose() is in a separate file so that it is linked in only if it is used.
That way the other gzclose functions can be used instead to avoid linking in That way the other gzclose functions can be used instead to avoid linking in
unneeded compression or decompression routines. */ unneeded compression or decompression routines. */
int ZEXPORT gzclose(file) int ZEXPORT gzclose(gzFile file) {
gzFile file;
{
#ifndef NO_GZCOMPRESS #ifndef NO_GZCOMPRESS
gz_statep state; gz_statep state;

View file

@ -1,5 +1,5 @@
/* gzguts.h -- zlib internal header definitions for gz* operations /* gzguts.h -- zlib internal header definitions for gz* operations
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * Copyright (C) 2004-2026 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -7,9 +7,8 @@
# ifndef _LARGEFILE_SOURCE # ifndef _LARGEFILE_SOURCE
# define _LARGEFILE_SOURCE 1 # define _LARGEFILE_SOURCE 1
# endif # endif
# ifdef _FILE_OFFSET_BITS # undef _FILE_OFFSET_BITS
# undef _FILE_OFFSET_BITS # undef _TIME_BITS
# endif
#endif #endif
#ifdef HAVE_HIDDEN #ifdef HAVE_HIDDEN
@ -18,6 +17,18 @@
# define ZLIB_INTERNAL # define ZLIB_INTERNAL
#endif #endif
#if defined(_WIN32)
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
# endif
# ifndef _CRT_NONSTDC_NO_DEPRECATE
# define _CRT_NONSTDC_NO_DEPRECATE
# endif
#endif
#include <stdio.h> #include <stdio.h>
#include "zlib.h" #include "zlib.h"
#ifdef STDC #ifdef STDC
@ -25,6 +36,10 @@
# include <stdlib.h> # include <stdlib.h>
# include <limits.h> # include <limits.h>
#endif #endif
#ifndef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 200112L
#endif
#include <fcntl.h> #include <fcntl.h>
#ifdef _WIN32 #ifdef _WIN32
@ -33,13 +48,11 @@
#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
# include <io.h> # include <io.h>
# include <sys/stat.h>
#endif #endif
#ifdef WINAPI_FAMILY #if defined(_WIN32) && !defined(WIDECHAR)
# define open _open # define WIDECHAR
# define read _read
# define write _write
# define close _close
#endif #endif
#ifdef NO_DEFLATE /* for compatibility with old definition */ #ifdef NO_DEFLATE /* for compatibility with old definition */
@ -65,53 +78,49 @@
#endif #endif
#ifndef HAVE_VSNPRINTF #ifndef HAVE_VSNPRINTF
# ifdef MSDOS # if !defined(NO_vsnprintf) && \
(defined(MSDOS) || defined(__TURBOC__) || defined(__SASC) || \
defined(VMS) || defined(__OS400) || defined(__MVS__))
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
but for now we just assume it doesn't. */ but for now we just assume it doesn't. */
# define NO_vsnprintf # define NO_vsnprintf
# endif # endif
# ifdef __TURBOC__
# define NO_vsnprintf
# endif
# ifdef WIN32 # ifdef WIN32
/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
# if !defined(vsnprintf) && !defined(NO_vsnprintf) # if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) # ifndef vsnprintf
# define vsnprintf _vsnprintf # define vsnprintf _vsnprintf
# endif # endif
# endif # endif
# endif # elif !defined(__STDC_VERSION__) || __STDC_VERSION__-0 < 199901L
# ifdef __SASC /* Otherwise if C89/90, assume no C99 snprintf() or vsnprintf() */
# define NO_vsnprintf # ifndef NO_snprintf
# endif # define NO_snprintf
# ifdef VMS # endif
# define NO_vsnprintf # ifndef NO_vsnprintf
# endif # define NO_vsnprintf
# ifdef __OS400__ # endif
# define NO_vsnprintf
# endif
# ifdef __MVS__
# define NO_vsnprintf
# endif # endif
#endif #endif
/* unlike snprintf (which is required in C99, yet still not supported by /* unlike snprintf (which is required in C99), _snprintf does not guarantee
Microsoft more than a decade later!), _snprintf does not guarantee null null termination of the result -- however this is only used in gzlib.c where
termination of the result -- however this is only used in gzlib.c where
the result is assured to fit in the space provided */ the result is assured to fit in the space provided */
#ifdef _MSC_VER #if defined(_MSC_VER) && _MSC_VER < 1900
# define snprintf _snprintf # define snprintf _snprintf
#endif #endif
#ifndef local #ifndef local
# define local static # define local static
#endif #endif
/* compile with -Dlocal if your debugger can't find static symbols */ /* since "static" is used to mean two completely different things in C, we
define "local" for the non-static meaning of "static", for readability
(compile with -Dlocal if your debugger can't find static symbols) */
/* gz* functions always use library allocation functions */ /* gz* functions always use library allocation functions */
#ifndef STDC #ifndef STDC
extern voidp malloc OF((uInt size)); extern voidp malloc(uInt size);
extern void free OF((voidpf ptr)); extern void free(voidpf ptr);
#endif #endif
/* get errno and strerror definition */ /* get errno and strerror definition */
@ -129,10 +138,10 @@
/* provide prototypes for these when building zlib without LFS */ /* provide prototypes for these when building zlib without LFS */
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int);
ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gztell64(gzFile);
ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile);
#endif #endif
/* default memLevel */ /* default memLevel */
@ -170,20 +179,22 @@ typedef struct {
char *path; /* path or fd for error messages */ char *path; /* path or fd for error messages */
unsigned size; /* buffer size, zero if not allocated yet */ unsigned size; /* buffer size, zero if not allocated yet */
unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned want; /* requested buffer size, default is GZBUFSIZE */
unsigned char *in; /* input buffer */ unsigned char *in; /* input buffer (double-sized when writing) */
unsigned char *out; /* output buffer (double-sized when reading) */ unsigned char *out; /* output buffer (double-sized when reading) */
int direct; /* 0 if processing gzip, 1 if transparent */ int direct; /* 0 if processing gzip, 1 if transparent */
/* just for reading */ /* just for reading */
int junk; /* -1 = start, 1 = junk candidate, 0 = in gzip */
int how; /* 0: get header, 1: copy, 2: decompress */ int how; /* 0: get header, 1: copy, 2: decompress */
int again; /* true if EAGAIN or EWOULDBLOCK on last i/o */
z_off64_t start; /* where the gzip data started, for rewinding */ z_off64_t start; /* where the gzip data started, for rewinding */
int eof; /* true if end of input file reached */ int eof; /* true if end of input file reached */
int past; /* true if read requested past end */ int past; /* true if read requested past end */
/* just for writing */ /* just for writing */
int level; /* compression level */ int level; /* compression level */
int strategy; /* compression strategy */ int strategy; /* compression strategy */
int reset; /* true if a reset is pending after a Z_FINISH */
/* seek request */ /* seek request */
z_off64_t skip; /* amount to skip (already rewound if backwards) */ z_off64_t skip; /* amount to skip (already rewound if backwards) */
int seek; /* true if seek request pending */
/* error information */ /* error information */
int err; /* error code */ int err; /* error code */
char *msg; /* error message */ char *msg; /* error message */
@ -193,17 +204,13 @@ typedef struct {
typedef gz_state FAR *gz_statep; typedef gz_state FAR *gz_statep;
/* shared functions */ /* shared functions */
void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); void ZLIB_INTERNAL gz_error(gz_statep, int, const char *);
#if defined UNDER_CE #if defined UNDER_CE
char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); char ZLIB_INTERNAL *gz_strwinerror(DWORD error);
#endif #endif
/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
value -- needed when comparing unsigned to z_off64_t, which is signed value -- needed when comparing unsigned to z_off64_t, which is signed
(possible z_off64_t types off_t, off64_t, and long are all signed) */ (possible z_off64_t types off_t, off64_t, and long are all signed) */
#ifdef INT_MAX unsigned ZLIB_INTERNAL gz_intmax(void);
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
#else
unsigned ZLIB_INTERNAL gz_intmax OF((void));
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
#endif

View file

@ -1,23 +1,19 @@
/* gzlib.c -- zlib functions common to reading and writing gzip files /* gzlib.c -- zlib functions common to reading and writing gzip files
* Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler * Copyright (C) 2004-2026 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
#include "gzguts.h" #include "gzguts.h"
#if defined(_WIN32) && !defined(__BORLANDC__) #if defined(__DJGPP__)
# define LSEEK llseek
#elif defined(_WIN32) && !defined(__BORLANDC__) && !defined(UNDER_CE)
# define LSEEK _lseeki64 # define LSEEK _lseeki64
#else #elif defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
# define LSEEK lseek64 # define LSEEK lseek64
#else #else
# define LSEEK lseek # define LSEEK lseek
#endif #endif
#endif
/* Local functions */
local void gz_reset OF((gz_statep));
local gzFile gz_open OF((const void *, int, const char *));
#if defined UNDER_CE #if defined UNDER_CE
@ -30,9 +26,7 @@ local gzFile gz_open OF((const void *, int, const char *));
The gz_strwinerror function does not change the current setting of The gz_strwinerror function does not change the current setting of
GetLastError. */ GetLastError. */
char ZLIB_INTERNAL *gz_strwinerror (error) char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
DWORD error;
{
static char buf[1024]; static char buf[1024];
wchar_t *msgbuf; wchar_t *msgbuf;
@ -58,7 +52,7 @@ char ZLIB_INTERNAL *gz_strwinerror (error)
msgbuf[chars] = 0; msgbuf[chars] = 0;
} }
wcstombs(buf, msgbuf, chars + 1); wcstombs(buf, msgbuf, chars + 1); /* assumes buf is big enough */
LocalFree(msgbuf); LocalFree(msgbuf);
} }
else { else {
@ -72,39 +66,34 @@ char ZLIB_INTERNAL *gz_strwinerror (error)
#endif /* UNDER_CE */ #endif /* UNDER_CE */
/* Reset gzip file state */ /* Reset gzip file state */
local void gz_reset(state) local void gz_reset(gz_statep state) {
gz_statep state;
{
state->x.have = 0; /* no output data available */ state->x.have = 0; /* no output data available */
if (state->mode == GZ_READ) { /* for reading ... */ if (state->mode == GZ_READ) { /* for reading ... */
state->eof = 0; /* not at end of file */ state->eof = 0; /* not at end of file */
state->past = 0; /* have not read past end yet */ state->past = 0; /* have not read past end yet */
state->how = LOOK; /* look for gzip header */ state->how = LOOK; /* look for gzip header */
state->junk = -1; /* mark first member */
} }
state->seek = 0; /* no seek request pending */ else /* for writing ... */
state->reset = 0; /* no deflateReset pending */
state->again = 0; /* no stalled i/o yet */
state->skip = 0; /* no seek request pending */
gz_error(state, Z_OK, NULL); /* clear error */ gz_error(state, Z_OK, NULL); /* clear error */
state->x.pos = 0; /* no uncompressed data yet */ state->x.pos = 0; /* no uncompressed data yet */
state->strm.avail_in = 0; /* no input data yet */ state->strm.avail_in = 0; /* no input data yet */
} }
/* Open a gzip file either by name or file descriptor. */ /* Open a gzip file either by name or file descriptor. */
local gzFile gz_open(path, fd, mode) local gzFile gz_open(const void *path, int fd, const char *mode) {
const void *path;
int fd;
const char *mode;
{
gz_statep state; gz_statep state;
size_t len; z_size_t len;
int oflag; int oflag = 0;
#ifdef O_CLOEXEC
int cloexec = 0;
#endif
#ifdef O_EXCL #ifdef O_EXCL
int exclusive = 0; int exclusive = 0;
#endif #endif
/* check input */ /* check input */
if (path == NULL) if (path == NULL || mode == NULL)
return NULL; return NULL;
/* allocate gzFile structure to return */ /* allocate gzFile structure to return */
@ -113,6 +102,7 @@ local gzFile gz_open(path, fd, mode)
return NULL; return NULL;
state->size = 0; /* no buffers allocated yet */ state->size = 0; /* no buffers allocated yet */
state->want = GZBUFSIZE; /* requested buffer size */ state->want = GZBUFSIZE; /* requested buffer size */
state->err = Z_OK; /* no error yet */
state->msg = NULL; /* no error message yet */ state->msg = NULL; /* no error message yet */
/* interpret mode */ /* interpret mode */
@ -143,7 +133,7 @@ local gzFile gz_open(path, fd, mode)
break; break;
#ifdef O_CLOEXEC #ifdef O_CLOEXEC
case 'e': case 'e':
cloexec = 1; oflag |= O_CLOEXEC;
break; break;
#endif #endif
#ifdef O_EXCL #ifdef O_EXCL
@ -163,6 +153,14 @@ local gzFile gz_open(path, fd, mode)
case 'F': case 'F':
state->strategy = Z_FIXED; state->strategy = Z_FIXED;
break; break;
case 'G':
state->direct = -1;
break;
#ifdef O_NONBLOCK
case 'N':
oflag |= O_NONBLOCK;
break;
#endif
case 'T': case 'T':
state->direct = 1; state->direct = 1;
break; break;
@ -178,22 +176,30 @@ local gzFile gz_open(path, fd, mode)
return NULL; return NULL;
} }
/* can't force transparent read */ /* direct is 0, 1 if "T", or -1 if "G" (last "G" or "T" wins) */
if (state->mode == GZ_READ) { if (state->mode == GZ_READ) {
if (state->direct) { if (state->direct == 1) {
/* can't force a transparent read */
free(state); free(state);
return NULL; return NULL;
} }
state->direct = 1; /* for empty file */ if (state->direct == 0)
/* default when reading is auto-detect of gzip vs. transparent --
start with a transparent assumption in case of an empty file */
state->direct = 1;
} }
else if (state->direct == -1) {
/* "G" has no meaning when writing -- disallow it */
free(state);
return NULL;
}
/* if reading, direct == 1 for auto-detect, -1 for gzip only; if writing or
appending, direct == 0 for gzip, 1 for transparent (copy in to out) */
/* save the path name for error messages */ /* save the path name for error messages */
#ifdef _WIN32 #ifdef WIDECHAR
if (fd == -2) { if (fd == -2)
len = wcstombs(NULL, path, 0); len = wcstombs(NULL, path, 0);
if (len == (size_t)-1)
len = 0;
}
else else
#endif #endif
len = strlen((const char *)path); len = strlen((const char *)path);
@ -202,30 +208,30 @@ local gzFile gz_open(path, fd, mode)
free(state); free(state);
return NULL; return NULL;
} }
#ifdef _WIN32 #ifdef WIDECHAR
if (fd == -2) if (fd == -2) {
if (len) if (len)
wcstombs(state->path, path, len + 1); wcstombs(state->path, path, len + 1);
else else
*(state->path) = 0; *(state->path) = 0;
}
else else
#endif #endif
{
#if !defined(NO_snprintf) && !defined(NO_vsnprintf) #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
snprintf(state->path, len + 1, "%s", (const char *)path); (void)snprintf(state->path, len + 1, "%s", (const char *)path);
#else #else
strcpy(state->path, path); strcpy(state->path, path);
#endif #endif
}
/* compute the flags for open() */ /* compute the flags for open() */
oflag = oflag |=
#ifdef O_LARGEFILE #ifdef O_LARGEFILE
O_LARGEFILE | O_LARGEFILE |
#endif #endif
#ifdef O_BINARY #ifdef O_BINARY
O_BINARY | O_BINARY |
#endif
#ifdef O_CLOEXEC
(cloexec ? O_CLOEXEC : 0) |
#endif #endif
(state->mode == GZ_READ ? (state->mode == GZ_READ ?
O_RDONLY : O_RDONLY :
@ -238,18 +244,32 @@ local gzFile gz_open(path, fd, mode)
O_APPEND))); O_APPEND)));
/* open the file with the appropriate flags (or just use fd) */ /* open the file with the appropriate flags (or just use fd) */
state->fd = fd > -1 ? fd : ( if (fd == -1)
#ifdef _WIN32 state->fd = open((const char *)path, oflag, 0666);
fd == -2 ? _wopen(path, oflag, 0666) : #ifdef WIDECHAR
else if (fd == -2)
state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE);
#endif #endif
open((const char *)path, oflag, 0666)); else {
#ifdef O_NONBLOCK
if (oflag & O_NONBLOCK)
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
#endif
#ifdef O_CLOEXEC
if (oflag & O_CLOEXEC)
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | O_CLOEXEC);
#endif
state->fd = fd;
}
if (state->fd == -1) { if (state->fd == -1) {
free(state->path); free(state->path);
free(state); free(state);
return NULL; return NULL;
} }
if (state->mode == GZ_APPEND) if (state->mode == GZ_APPEND) {
LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */
state->mode = GZ_WRITE; /* simplify later checks */ state->mode = GZ_WRITE; /* simplify later checks */
}
/* save the current position for rewinding (only if reading) */ /* save the current position for rewinding (only if reading) */
if (state->mode == GZ_READ) { if (state->mode == GZ_READ) {
@ -265,33 +285,24 @@ local gzFile gz_open(path, fd, mode)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
gzFile ZEXPORT gzopen(path, mode) gzFile ZEXPORT gzopen(const char *path, const char *mode) {
const char *path;
const char *mode;
{
return gz_open(path, -1, mode); return gz_open(path, -1, mode);
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
gzFile ZEXPORT gzopen64(path, mode) gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
const char *path;
const char *mode;
{
return gz_open(path, -1, mode); return gz_open(path, -1, mode);
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
gzFile ZEXPORT gzdopen(fd, mode) gzFile ZEXPORT gzdopen(int fd, const char *mode) {
int fd;
const char *mode;
{
char *path; /* identifier for error messages */ char *path; /* identifier for error messages */
gzFile gz; gzFile gz;
if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
return NULL; return NULL;
#if !defined(NO_snprintf) && !defined(NO_vsnprintf) #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */ (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
#else #else
sprintf(path, "<fd:%d>", fd); /* for debugging */ sprintf(path, "<fd:%d>", fd); /* for debugging */
#endif #endif
@ -301,20 +312,14 @@ gzFile ZEXPORT gzdopen(fd, mode)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
#ifdef _WIN32 #ifdef WIDECHAR
gzFile ZEXPORT gzopen_w(path, mode) gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
const wchar_t *path;
const char *mode;
{
return gz_open(path, -2, mode); return gz_open(path, -2, mode);
} }
#endif #endif
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzbuffer(file, size) int ZEXPORT gzbuffer(gzFile file, unsigned size) {
gzFile file;
unsigned size;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* get internal structure and check integrity */
@ -329,16 +334,16 @@ int ZEXPORT gzbuffer(file, size)
return -1; return -1;
/* check and set requested size */ /* check and set requested size */
if (size < 2) if ((size << 1) < size)
size = 2; /* need two bytes to check magic header */ return -1; /* need to be able to double it */
if (size < 8)
size = 8; /* needed to behave well with flushing */
state->want = size; state->want = size;
return 0; return 0;
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzrewind(file) int ZEXPORT gzrewind(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure */
@ -359,11 +364,7 @@ int ZEXPORT gzrewind(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off64_t ZEXPORT gzseek64(file, offset, whence) z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
gzFile file;
z_off64_t offset;
int whence;
{
unsigned n; unsigned n;
z_off64_t ret; z_off64_t ret;
gz_statep state; gz_statep state;
@ -386,20 +387,21 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
/* normalize offset to a SEEK_CUR specification */ /* normalize offset to a SEEK_CUR specification */
if (whence == SEEK_SET) if (whence == SEEK_SET)
offset -= state->x.pos; offset -= state->x.pos;
else if (state->seek) else {
offset += state->skip; offset += state->past ? 0 : state->skip;
state->seek = 0; state->skip = 0;
}
/* if within raw area while reading, just go there */ /* if within raw area while reading, just go there */
if (state->mode == GZ_READ && state->how == COPY && if (state->mode == GZ_READ && state->how == COPY &&
state->x.pos + offset >= 0) { state->x.pos + offset >= 0) {
ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
if (ret == -1) if (ret == -1)
return -1; return -1;
state->x.have = 0; state->x.have = 0;
state->eof = 0; state->eof = 0;
state->past = 0; state->past = 0;
state->seek = 0; state->skip = 0;
gz_error(state, Z_OK, NULL); gz_error(state, Z_OK, NULL);
state->strm.avail_in = 0; state->strm.avail_in = 0;
state->x.pos += offset; state->x.pos += offset;
@ -428,19 +430,12 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
} }
/* request skip (if not zero) */ /* request skip (if not zero) */
if (offset) { state->skip = offset;
state->seek = 1;
state->skip = offset;
}
return state->x.pos + offset; return state->x.pos + offset;
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off_t ZEXPORT gzseek(file, offset, whence) z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
gzFile file;
z_off_t offset;
int whence;
{
z_off64_t ret; z_off64_t ret;
ret = gzseek64(file, (z_off64_t)offset, whence); ret = gzseek64(file, (z_off64_t)offset, whence);
@ -448,9 +443,7 @@ z_off_t ZEXPORT gzseek(file, offset, whence)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off64_t ZEXPORT gztell64(file) z_off64_t ZEXPORT gztell64(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* get internal structure and check integrity */
@ -461,13 +454,11 @@ z_off64_t ZEXPORT gztell64(file)
return -1; return -1;
/* return position */ /* return position */
return state->x.pos + (state->seek ? state->skip : 0); return state->x.pos + (state->past ? 0 : state->skip);
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off_t ZEXPORT gztell(file) z_off_t ZEXPORT gztell(gzFile file) {
gzFile file;
{
z_off64_t ret; z_off64_t ret;
ret = gztell64(file); ret = gztell64(file);
@ -475,9 +466,7 @@ z_off_t ZEXPORT gztell(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off64_t ZEXPORT gzoffset64(file) z_off64_t ZEXPORT gzoffset64(gzFile file) {
gzFile file;
{
z_off64_t offset; z_off64_t offset;
gz_statep state; gz_statep state;
@ -498,9 +487,7 @@ z_off64_t ZEXPORT gzoffset64(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
z_off_t ZEXPORT gzoffset(file) z_off_t ZEXPORT gzoffset(gzFile file) {
gzFile file;
{
z_off64_t ret; z_off64_t ret;
ret = gzoffset64(file); ret = gzoffset64(file);
@ -508,9 +495,7 @@ z_off_t ZEXPORT gzoffset(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzeof(file) int ZEXPORT gzeof(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* get internal structure and check integrity */
@ -525,10 +510,7 @@ int ZEXPORT gzeof(file)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
const char * ZEXPORT gzerror(file, errnum) const char * ZEXPORT gzerror(gzFile file, int *errnum) {
gzFile file;
int *errnum;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* get internal structure and check integrity */
@ -546,9 +528,7 @@ const char * ZEXPORT gzerror(file, errnum)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
void ZEXPORT gzclearerr(file) void ZEXPORT gzclearerr(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure and check integrity */ /* get internal structure and check integrity */
@ -572,11 +552,7 @@ void ZEXPORT gzclearerr(file)
memory). Simply save the error message as a static string. If there is an memory). Simply save the error message as a static string. If there is an
allocation failure constructing the error message, then convert the error to allocation failure constructing the error message, then convert the error to
out of memory. */ out of memory. */
void ZLIB_INTERNAL gz_error(state, err, msg) void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
gz_statep state;
int err;
const char *msg;
{
/* free previously allocated message and clear */ /* free previously allocated message and clear */
if (state->msg != NULL) { if (state->msg != NULL) {
if (state->err != Z_MEM_ERROR) if (state->err != Z_MEM_ERROR)
@ -585,7 +561,7 @@ void ZLIB_INTERNAL gz_error(state, err, msg)
} }
/* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
if (err != Z_OK && err != Z_BUF_ERROR) if (err != Z_OK && err != Z_BUF_ERROR && !state->again)
state->x.have = 0; state->x.have = 0;
/* set error code, and if no message, then done */ /* set error code, and if no message, then done */
@ -604,31 +580,30 @@ void ZLIB_INTERNAL gz_error(state, err, msg)
return; return;
} }
#if !defined(NO_snprintf) && !defined(NO_vsnprintf) #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
"%s%s%s", state->path, ": ", msg); "%s%s%s", state->path, ": ", msg);
#else #else
strcpy(state->msg, state->path); strcpy(state->msg, state->path);
strcat(state->msg, ": "); strcat(state->msg, ": ");
strcat(state->msg, msg); strcat(state->msg, msg);
#endif #endif
return;
} }
#ifndef INT_MAX
/* portably return maximum value for an int (when limits.h presumed not /* portably return maximum value for an int (when limits.h presumed not
available) -- we need to do this to cover cases where 2's complement not available) -- we need to do this to cover cases where 2's complement not
used, since C standard permits 1's complement and sign-bit representations, used, since C standard permits 1's complement and sign-bit representations,
otherwise we could just use ((unsigned)-1) >> 1 */ otherwise we could just use ((unsigned)-1) >> 1 */
unsigned ZLIB_INTERNAL gz_intmax() unsigned ZLIB_INTERNAL gz_intmax(void) {
{ #ifdef INT_MAX
unsigned p, q; return INT_MAX;
#else
unsigned p = 1, q;
p = 1;
do { do {
q = p; q = p;
p <<= 1; p <<= 1;
p++; p++;
} while (p > q); } while (p > q);
return q >> 1; return q >> 1;
}
#endif #endif
}

View file

@ -1,38 +1,43 @@
/* gzread.c -- zlib functions for reading gzip files /* gzread.c -- zlib functions for reading gzip files
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * Copyright (C) 2004-2026 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
#include "gzguts.h" #include "gzguts.h"
/* Local functions */
local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
local int gz_avail OF((gz_statep));
local int gz_look OF((gz_statep));
local int gz_decomp OF((gz_statep));
local int gz_fetch OF((gz_statep));
local int gz_skip OF((gz_statep, z_off64_t));
/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
state->fd, and update state->eof, state->err, and state->msg as appropriate. state->fd, and update state->eof, state->err, and state->msg as appropriate.
This function needs to loop on read(), since read() is not guaranteed to This function needs to loop on read(), since read() is not guaranteed to
read the number of bytes requested, depending on the type of descriptor. */ read the number of bytes requested, depending on the type of descriptor. It
local int gz_load(state, buf, len, have) also needs to loop to manage the fact that read() returns an int. If the
gz_statep state; descriptor is non-blocking and read() returns with no data in order to avoid
unsigned char *buf; blocking, then gz_load() will return 0 if some data has been read, or -1 if
unsigned len; no data has been read. Either way, state->again is set true to indicate a
unsigned *have; non-blocking event. If errno is non-zero on return, then there was an error
{ signaled from read(). *have is set to the number of bytes read. */
local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
unsigned *have) {
int ret; int ret;
unsigned get, max = ((unsigned)-1 >> 2) + 1;
state->again = 0;
errno = 0;
*have = 0; *have = 0;
do { do {
ret = read(state->fd, buf + *have, len - *have); get = len - *have;
if (get > max)
get = max;
ret = (int)read(state->fd, buf + *have, get);
if (ret <= 0) if (ret <= 0)
break; break;
*have += ret; *have += (unsigned)ret;
} while (*have < len); } while (*have < len);
if (ret < 0) { if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
state->again = 1;
if (*have != 0)
return 0;
}
gz_error(state, Z_ERRNO, zstrerror()); gz_error(state, Z_ERRNO, zstrerror());
return -1; return -1;
} }
@ -48,9 +53,7 @@ local int gz_load(state, buf, len, have)
If strm->avail_in != 0, then the current data is moved to the beginning of If strm->avail_in != 0, then the current data is moved to the beginning of
the input buffer, and then the remainder of the buffer is loaded with the the input buffer, and then the remainder of the buffer is loaded with the
available data from the input file. */ available data from the input file. */
local int gz_avail(state) local int gz_avail(gz_statep state) {
gz_statep state;
{
unsigned got; unsigned got;
z_streamp strm = &(state->strm); z_streamp strm = &(state->strm);
@ -60,10 +63,14 @@ local int gz_avail(state)
if (strm->avail_in) { /* copy what's there to the start */ if (strm->avail_in) { /* copy what's there to the start */
unsigned char *p = state->in; unsigned char *p = state->in;
unsigned const char *q = strm->next_in; unsigned const char *q = strm->next_in;
unsigned n = strm->avail_in;
do { if (q != p) {
*p++ = *q++; unsigned n = strm->avail_in;
} while (--n);
do {
*p++ = *q++;
} while (--n);
}
} }
if (gz_load(state, state->in + strm->avail_in, if (gz_load(state, state->in + strm->avail_in,
state->size - strm->avail_in, &got) == -1) state->size - strm->avail_in, &got) == -1)
@ -83,9 +90,7 @@ local int gz_avail(state)
case, all further file reads will be directly to either the output buffer or case, all further file reads will be directly to either the output buffer or
a user buffer. If decompressing, the inflate state will be initialized. a user buffer. If decompressing, the inflate state will be initialized.
gz_look() will return 0 on success or -1 on failure. */ gz_look() will return 0 on success or -1 on failure. */
local int gz_look(state) local int gz_look(gz_statep state) {
gz_statep state;
{
z_streamp strm = &(state->strm); z_streamp strm = &(state->strm);
/* allocate read buffers and inflate memory */ /* allocate read buffers and inflate memory */
@ -94,10 +99,8 @@ local int gz_look(state)
state->in = (unsigned char *)malloc(state->want); state->in = (unsigned char *)malloc(state->want);
state->out = (unsigned char *)malloc(state->want << 1); state->out = (unsigned char *)malloc(state->want << 1);
if (state->in == NULL || state->out == NULL) { if (state->in == NULL || state->out == NULL) {
if (state->out != NULL) free(state->out);
free(state->out); free(state->in);
if (state->in != NULL)
free(state->in);
gz_error(state, Z_MEM_ERROR, "out of memory"); gz_error(state, Z_MEM_ERROR, "out of memory");
return -1; return -1;
} }
@ -118,60 +121,63 @@ local int gz_look(state)
} }
} }
/* get at least the magic bytes in the input buffer */ /* if transparent reading is disabled, which would only be at the start, or
if (strm->avail_in < 2) { if we're looking for a gzip member after the first one, which is not at
if (gz_avail(state) == -1) the start, then proceed directly to look for a gzip member next */
return -1; if (state->direct == -1 || state->junk == 0) {
if (strm->avail_in == 0)
return 0;
}
/* look for gzip magic bytes -- if there, do gzip decoding (note: there is
a logical dilemma here when considering the case of a partially written
gzip file, to wit, if a single 31 byte is written, then we cannot tell
whether this is a single-byte file, or just a partially written gzip
file -- for here we assume that if a gzip file is being written, then
the header will be written in a single operation, so that reading a
single byte is sufficient indication that it is not a gzip file) */
if (strm->avail_in > 1 &&
strm->next_in[0] == 31 && strm->next_in[1] == 139) {
inflateReset(strm); inflateReset(strm);
state->how = GZIP; state->how = GZIP;
state->junk = state->junk != -1;
state->direct = 0; state->direct = 0;
return 0; return 0;
} }
/* no gzip header -- if we were decoding gzip before, then this is trailing /* otherwise we're at the start with auto-detect -- we check to see if the
garbage. Ignore the trailing garbage and finish. */ first four bytes could be gzip header in order to decide whether or not
if (state->direct == 0) { this will be a transparent read */
strm->avail_in = 0;
state->eof = 1; /* load any header bytes into the input buffer -- if the input is empty,
state->x.have = 0; then it's not an error as this is a transparent read of zero bytes */
if (gz_avail(state) == -1)
return -1;
if (strm->avail_in == 0 || (state->again && strm->avail_in < 4))
/* if non-blocking input stalled before getting four bytes, then
return and wait until a later call has accumulated enough */
return 0;
/* see if this is (likely) gzip input -- if the first four bytes are
consistent with a gzip header, then go look for the first gzip member,
otherwise proceed to copy the input transparently */
if (strm->avail_in > 3 &&
strm->next_in[0] == 31 && strm->next_in[1] == 139 &&
strm->next_in[2] == 8 && strm->next_in[3] < 32) {
inflateReset(strm);
state->how = GZIP;
state->junk = 1;
state->direct = 0;
return 0; return 0;
} }
/* doing raw i/o, copy any leftover input to output -- this assumes that /* doing raw i/o: copy any leftover input to output -- this assumes that
the output buffer is larger than the input buffer, which also assures the output buffer is larger than the input buffer, which also assures
space for gzungetc() */ space for gzungetc() */
state->x.next = state->out; state->x.next = state->out;
if (strm->avail_in) { memcpy(state->x.next, strm->next_in, strm->avail_in);
memcpy(state->x.next, strm->next_in, strm->avail_in); state->x.have = strm->avail_in;
state->x.have = strm->avail_in; strm->avail_in = 0;
strm->avail_in = 0;
}
state->how = COPY; state->how = COPY;
state->direct = 1;
return 0; return 0;
} }
/* Decompress from input to the provided next_out and avail_out in the state. /* Decompress from input to the provided next_out and avail_out in the state.
On return, state->x.have and state->x.next point to the just decompressed On return, state->x.have and state->x.next point to the just decompressed
data. If the gzip stream completes, state->how is reset to LOOK to look for data. If the gzip stream completes, state->how is reset to LOOK to look for
the next gzip stream or raw data, once state->x.have is depleted. Returns 0 the next gzip stream or raw data, once state->x.have is depleted. Returns 0
on success, -1 on failure. */ on success, -1 on failure. If EOF is reached when looking for more input to
local int gz_decomp(state) complete the gzip member, then an unexpected end of file error is raised.
gz_statep state; If there is no more input, but state->again is true, then EOF has not been
{ reached, and no error is raised. */
local int gz_decomp(gz_statep state) {
int ret = Z_OK; int ret = Z_OK;
unsigned had; unsigned had;
z_streamp strm = &(state->strm); z_streamp strm = &(state->strm);
@ -180,28 +186,41 @@ local int gz_decomp(state)
had = strm->avail_out; had = strm->avail_out;
do { do {
/* get more input for inflate() */ /* get more input for inflate() */
if (strm->avail_in == 0 && gz_avail(state) == -1) if (strm->avail_in == 0 && gz_avail(state) == -1) {
return -1; ret = state->err;
break;
}
if (strm->avail_in == 0) { if (strm->avail_in == 0) {
gz_error(state, Z_BUF_ERROR, "unexpected end of file"); if (!state->again)
gz_error(state, Z_BUF_ERROR, "unexpected end of file");
break; break;
} }
/* decompress and handle errors */ /* decompress and handle errors */
ret = inflate(strm, Z_NO_FLUSH); ret = inflate(strm, Z_NO_FLUSH);
if (strm->avail_out < had)
/* any decompressed data marks this as a real gzip stream */
state->junk = 0;
if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
gz_error(state, Z_STREAM_ERROR, gz_error(state, Z_STREAM_ERROR,
"internal error: inflate stream corrupt"); "internal error: inflate stream corrupt");
return -1; break;
} }
if (ret == Z_MEM_ERROR) { if (ret == Z_MEM_ERROR) {
gz_error(state, Z_MEM_ERROR, "out of memory"); gz_error(state, Z_MEM_ERROR, "out of memory");
return -1; break;
} }
if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ if (ret == Z_DATA_ERROR) { /* deflate stream invalid */
if (state->junk == 1) { /* trailing garbage is ok */
strm->avail_in = 0;
state->eof = 1;
state->how = LOOK;
ret = Z_OK;
break;
}
gz_error(state, Z_DATA_ERROR, gz_error(state, Z_DATA_ERROR,
strm->msg == NULL ? "compressed data error" : strm->msg); strm->msg == NULL ? "compressed data error" : strm->msg);
return -1; break;
} }
} while (strm->avail_out && ret != Z_STREAM_END); } while (strm->avail_out && ret != Z_STREAM_END);
@ -210,11 +229,14 @@ local int gz_decomp(state)
state->x.next = strm->next_out - state->x.have; state->x.next = strm->next_out - state->x.have;
/* if the gzip stream completed successfully, look for another */ /* if the gzip stream completed successfully, look for another */
if (ret == Z_STREAM_END) if (ret == Z_STREAM_END) {
state->junk = 0;
state->how = LOOK; state->how = LOOK;
return 0;
}
/* good decompression */ /* return decompression status */
return 0; return ret != Z_OK ? -1 : 0;
} }
/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. /* Fetch data and put it in the output buffer. Assumes state->x.have is 0.
@ -223,9 +245,7 @@ local int gz_decomp(state)
looked for to determine whether to copy or decompress. Returns -1 on error, looked for to determine whether to copy or decompress. Returns -1 on error,
otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the
end of the input file has been reached and all data has been processed. */ end of the input file has been reached and all data has been processed. */
local int gz_fetch(state) local int gz_fetch(gz_statep state) {
gz_statep state;
{
z_streamp strm = &(state->strm); z_streamp strm = &(state->strm);
do { do {
@ -247,28 +267,31 @@ local int gz_fetch(state)
strm->next_out = state->out; strm->next_out = state->out;
if (gz_decomp(state) == -1) if (gz_decomp(state) == -1)
return -1; return -1;
break;
default:
gz_error(state, Z_STREAM_ERROR, "state corrupt");
return -1;
} }
} while (state->x.have == 0 && (!state->eof || strm->avail_in)); } while (state->x.have == 0 && (!state->eof || strm->avail_in));
return 0; return 0;
} }
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ /* Skip state->skip (> 0) uncompressed bytes of output. Return -1 on error, 0
local int gz_skip(state, len) on success. */
gz_statep state; local int gz_skip(gz_statep state) {
z_off64_t len;
{
unsigned n; unsigned n;
/* skip over len bytes or reach end-of-file, whichever comes first */ /* skip over len bytes or reach end-of-file, whichever comes first */
while (len) do {
/* skip over whatever is in output buffer */ /* skip over whatever is in output buffer */
if (state->x.have) { if (state->x.have) {
n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? n = GT_OFF(state->x.have) ||
(unsigned)len : state->x.have; (z_off64_t)state->x.have > state->skip ?
(unsigned)state->skip : state->x.have;
state->x.have -= n; state->x.have -= n;
state->x.next += n; state->x.next += n;
state->x.pos += n; state->x.pos += n;
len -= n; state->skip -= n;
} }
/* output buffer empty -- return if we're at the end of the input */ /* output buffer empty -- return if we're at the end of the input */
@ -281,88 +304,75 @@ local int gz_skip(state, len)
if (gz_fetch(state) == -1) if (gz_fetch(state) == -1)
return -1; return -1;
} }
} while (state->skip);
return 0; return 0;
} }
/* -- see zlib.h -- */ /* Read len bytes into buf from file, or less than len up to the end of the
int ZEXPORT gzread(file, buf, len) input. Return the number of bytes read. If zero is returned, either the end
gzFile file; of file was reached, or there was an error. state->err must be consulted in
voidp buf; that case to determine which. If there was an error, but some uncompressed
unsigned len; bytes were read before the error, then that count is returned. The error is
{ still recorded, and so is deferred until the next call. */
unsigned got, n; local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
gz_statep state; z_size_t got;
z_streamp strm; unsigned n;
int err;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
strm = &(state->strm);
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return -1;
/* since an int is returned, make sure len fits in one, otherwise return
with an error (this avoids the flaw in the interface) */
if ((int)len < 0) {
gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
return -1;
}
/* if len is zero, avoid unnecessary operations */ /* if len is zero, avoid unnecessary operations */
if (len == 0) if (len == 0)
return 0; return 0;
/* process a skip request */ /* process a skip request */
if (state->seek) { if (state->skip && gz_skip(state) == -1)
state->seek = 0; return 0;
if (gz_skip(state, state->skip) == -1)
return -1;
}
/* get len bytes to buf, or less than len if at the end */ /* get len bytes to buf, or less than len if at the end */
got = 0; got = 0;
err = 0;
do { do {
/* set n to the maximum amount of len that fits in an unsigned int */
n = (unsigned)-1;
if (n > len)
n = (unsigned)len;
/* first just try copying data from the output buffer */ /* first just try copying data from the output buffer */
if (state->x.have) { if (state->x.have) {
n = state->x.have > len ? len : state->x.have; if (state->x.have < n)
n = state->x.have;
memcpy(buf, state->x.next, n); memcpy(buf, state->x.next, n);
state->x.next += n; state->x.next += n;
state->x.have -= n; state->x.have -= n;
if (state->err != Z_OK)
/* caught deferred error from gz_fetch() */
err = -1;
} }
/* output buffer empty -- return if we're at the end of the input */ /* output buffer empty -- return if we're at the end of the input */
else if (state->eof && strm->avail_in == 0) { else if (state->eof && state->strm.avail_in == 0)
state->past = 1; /* tried to read past end */
break; break;
}
/* need output data -- for small len or new stream load up our output /* need output data -- for small len or new stream load up our output
buffer */ buffer, so that gzgetc() can be fast */
else if (state->how == LOOK || len < (state->size << 1)) { else if (state->how == LOOK || n < (state->size << 1)) {
/* get more output, looking for header if required */ /* get more output, looking for header if required */
if (gz_fetch(state) == -1) if (gz_fetch(state) == -1 && state->x.have == 0)
return -1; /* if state->x.have != 0, error will be caught after copy */
err = -1;
continue; /* no progress yet -- go back to copy above */ continue; /* no progress yet -- go back to copy above */
/* the copy above assures that we will leave with space in the /* the copy above assures that we will leave with space in the
output buffer, allowing at least one gzungetc() to succeed */ output buffer, allowing at least one gzungetc() to succeed */
} }
/* large len -- read directly into user buffer */ /* large len -- read directly into user buffer */
else if (state->how == COPY) { /* read directly */ else if (state->how == COPY) /* read directly */
if (gz_load(state, (unsigned char *)buf, len, &n) == -1) err = gz_load(state, (unsigned char *)buf, n, &n);
return -1;
}
/* large len -- decompress directly into user buffer */ /* large len -- decompress directly into user buffer */
else { /* state->how == GZIP */ else { /* state->how == GZIP */
strm->avail_out = len; state->strm.avail_out = n;
strm->next_out = (unsigned char *)buf; state->strm.next_out = (unsigned char *)buf;
if (gz_decomp(state) == -1) err = gz_decomp(state);
return -1;
n = state->x.have; n = state->x.have;
state->x.have = 0; state->x.have = 0;
} }
@ -372,10 +382,86 @@ int ZEXPORT gzread(file, buf, len)
buf = (char *)buf + n; buf = (char *)buf + n;
got += n; got += n;
state->x.pos += n; state->x.pos += n;
} while (len); } while (len && !err);
/* return number of bytes read into user buffer (will fit in int) */ /* note read past eof */
return (int)got; if (len && state->eof)
state->past = 1;
/* return number of bytes read into user buffer */
return got;
}
/* -- see zlib.h -- */
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
gz_statep state;
/* get internal structure and check that it's for reading */
if (file == NULL)
return -1;
state = (gz_statep)file;
if (state->mode != GZ_READ)
return -1;
/* check that there was no (serious) error */
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
return -1;
gz_error(state, Z_OK, NULL);
/* since an int is returned, make sure len fits in one, otherwise return
with an error (this avoids a flaw in the interface) */
if ((int)len < 0) {
gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
return -1;
}
/* read len or fewer bytes to buf */
len = (unsigned)gz_read(state, buf, len);
/* check for an error */
if (len == 0) {
if (state->err != Z_OK && state->err != Z_BUF_ERROR)
return -1;
if (state->again) {
/* non-blocking input stalled after some input was read, but no
uncompressed bytes were produced -- let the application know
this isn't EOF */
gz_error(state, Z_ERRNO, zstrerror());
return -1;
}
}
/* return the number of bytes read */
return (int)len;
}
/* -- see zlib.h -- */
z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
gzFile file) {
z_size_t len;
gz_statep state;
/* get internal structure and check that it's for reading */
if (file == NULL)
return 0;
state = (gz_statep)file;
if (state->mode != GZ_READ)
return 0;
/* check that there was no (serious) error */
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
return 0;
gz_error(state, Z_OK, NULL);
/* compute bytes to read -- error on overflow */
len = nitems * size;
if (size && len / size != nitems) {
gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
return 0;
}
/* read len or fewer bytes to buf, return the number of full items read */
return len ? gz_read(state, buf, len) / size : 0;
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
@ -384,23 +470,22 @@ int ZEXPORT gzread(file, buf, len)
#else #else
# undef gzgetc # undef gzgetc
#endif #endif
int ZEXPORT gzgetc(file) int ZEXPORT gzgetc(gzFile file) {
gzFile file;
{
int ret;
unsigned char buf[1]; unsigned char buf[1];
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure and check that it's for reading */
if (file == NULL) if (file == NULL)
return -1; return -1;
state = (gz_statep)file; state = (gz_statep)file;
if (state->mode != GZ_READ)
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return -1; return -1;
/* check that there was no (serious) error */
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
return -1;
gz_error(state, Z_OK, NULL);
/* try output buffer (no need to check for skip request) */ /* try output buffer (no need to check for skip request) */
if (state->x.have) { if (state->x.have) {
state->x.have--; state->x.have--;
@ -408,40 +493,37 @@ int ZEXPORT gzgetc(file)
return *(state->x.next)++; return *(state->x.next)++;
} }
/* nothing there -- try gzread() */ /* nothing there -- try gz_read() */
ret = gzread(file, buf, 1); return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
return ret < 1 ? -1 : buf[0];
} }
int ZEXPORT gzgetc_(file) int ZEXPORT gzgetc_(gzFile file) {
gzFile file;
{
return gzgetc(file); return gzgetc(file);
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzungetc(c, file) int ZEXPORT gzungetc(int c, gzFile file) {
int c;
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure and check that it's for reading */
if (file == NULL) if (file == NULL)
return -1; return -1;
state = (gz_statep)file; state = (gz_statep)file;
if (state->mode != GZ_READ)
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return -1; return -1;
/* in case this was just opened, set up the input buffer */
if (state->how == LOOK && state->x.have == 0)
(void)gz_look(state);
/* check that there was no (serious) error */
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
return -1;
gz_error(state, Z_OK, NULL);
/* process a skip request */ /* process a skip request */
if (state->seek) { if (state->skip && gz_skip(state) == -1)
state->seek = 0; return -1;
if (gz_skip(state, state->skip) == -1)
return -1;
}
/* can't push EOF */ /* can't push EOF */
if (c < 0) if (c < 0)
@ -451,7 +533,7 @@ int ZEXPORT gzungetc(c, file)
if (state->x.have == 0) { if (state->x.have == 0) {
state->x.have = 1; state->x.have = 1;
state->x.next = state->out + (state->size << 1) - 1; state->x.next = state->out + (state->size << 1) - 1;
state->x.next[0] = c; state->x.next[0] = (unsigned char)c;
state->x.pos--; state->x.pos--;
state->past = 0; state->past = 0;
return c; return c;
@ -467,55 +549,51 @@ int ZEXPORT gzungetc(c, file)
if (state->x.next == state->out) { if (state->x.next == state->out) {
unsigned char *src = state->out + state->x.have; unsigned char *src = state->out + state->x.have;
unsigned char *dest = state->out + (state->size << 1); unsigned char *dest = state->out + (state->size << 1);
while (src > state->out) while (src > state->out)
*--dest = *--src; *--dest = *--src;
state->x.next = dest; state->x.next = dest;
} }
state->x.have++; state->x.have++;
state->x.next--; state->x.next--;
state->x.next[0] = c; state->x.next[0] = (unsigned char)c;
state->x.pos--; state->x.pos--;
state->past = 0; state->past = 0;
return c; return c;
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
char * ZEXPORT gzgets(file, buf, len) char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
gzFile file;
char *buf;
int len;
{
unsigned left, n; unsigned left, n;
char *str; char *str;
unsigned char *eol; unsigned char *eol;
gz_statep state; gz_statep state;
/* check parameters and get internal structure */ /* check parameters, get internal structure, and check that it's for
reading */
if (file == NULL || buf == NULL || len < 1) if (file == NULL || buf == NULL || len < 1)
return NULL; return NULL;
state = (gz_statep)file; state = (gz_statep)file;
if (state->mode != GZ_READ)
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return NULL; return NULL;
/* process a skip request */ /* check that there was no (serious) error */
if (state->seek) { if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
state->seek = 0; return NULL;
if (gz_skip(state, state->skip) == -1) gz_error(state, Z_OK, NULL);
return NULL;
}
/* copy output bytes up to new line or len - 1, whichever comes first -- /* process a skip request */
append a terminating zero to the string (we don't check for a zero in if (state->skip && gz_skip(state) == -1)
the contents, let the user worry about that) */ return NULL;
/* copy output up to a new line, len-1 bytes, or there is no more output,
whichever comes first */
str = buf; str = buf;
left = (unsigned)len - 1; left = (unsigned)len - 1;
if (left) do { if (left) do {
/* assure that something is in the output buffer */ /* assure that something is in the output buffer */
if (state->x.have == 0 && gz_fetch(state) == -1) if (state->x.have == 0 && gz_fetch(state) == -1)
return NULL; /* error */ break; /* error */
if (state->x.have == 0) { /* end of file */ if (state->x.have == 0) { /* end of file */
state->past = 1; /* read past end */ state->past = 1; /* read past end */
break; /* return what we have */ break; /* return what we have */
@ -536,7 +614,9 @@ char * ZEXPORT gzgets(file, buf, len)
buf += n; buf += n;
} while (left && eol == NULL); } while (left && eol == NULL);
/* return terminated string, or if nothing, end of file */ /* append a terminating zero to the string (we don't check for a zero in
the contents, let the user worry about that) -- return the terminated
string, or if nothing was read, NULL */
if (buf == str) if (buf == str)
return NULL; return NULL;
buf[0] = 0; buf[0] = 0;
@ -544,9 +624,7 @@ char * ZEXPORT gzgets(file, buf, len)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzdirect(file) int ZEXPORT gzdirect(gzFile file) {
gzFile file;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure */
@ -560,22 +638,18 @@ int ZEXPORT gzdirect(file)
(void)gz_look(state); (void)gz_look(state);
/* return 1 if transparent, 0 if processing a gzip stream */ /* return 1 if transparent, 0 if processing a gzip stream */
return state->direct; return state->direct == 1;
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzclose_r(file) int ZEXPORT gzclose_r(gzFile file) {
gzFile file;
{
int ret, err; int ret, err;
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure and check that it's for reading */
if (file == NULL) if (file == NULL)
return Z_STREAM_ERROR; return Z_STREAM_ERROR;
state = (gz_statep)file; state = (gz_statep)file;
/* check that we're reading */
if (state->mode != GZ_READ) if (state->mode != GZ_READ)
return Z_STREAM_ERROR; return Z_STREAM_ERROR;

View file

@ -1,25 +1,19 @@
/* gzwrite.c -- zlib functions for writing gzip files /* gzwrite.c -- zlib functions for writing gzip files
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * Copyright (C) 2004-2026 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
#include "gzguts.h" #include "gzguts.h"
/* Local functions */
local int gz_init OF((gz_statep));
local int gz_comp OF((gz_statep, int));
local int gz_zero OF((gz_statep, z_off64_t));
/* Initialize state for writing a gzip file. Mark initialization by setting /* Initialize state for writing a gzip file. Mark initialization by setting
state->size to non-zero. Return -1 on failure or 0 on success. */ state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
local int gz_init(state) success. */
gz_statep state; local int gz_init(gz_statep state) {
{
int ret; int ret;
z_streamp strm = &(state->strm); z_streamp strm = &(state->strm);
/* allocate input buffer */ /* allocate input buffer (double size for gzprintf) */
state->in = (unsigned char *)malloc(state->want); state->in = (unsigned char *)malloc(state->want << 1);
if (state->in == NULL) { if (state->in == NULL) {
gz_error(state, Z_MEM_ERROR, "out of memory"); gz_error(state, Z_MEM_ERROR, "out of memory");
return -1; return -1;
@ -47,6 +41,7 @@ local int gz_init(state)
gz_error(state, Z_MEM_ERROR, "out of memory"); gz_error(state, Z_MEM_ERROR, "out of memory");
return -1; return -1;
} }
strm->next_in = NULL;
} }
/* mark state as initialized */ /* mark state as initialized */
@ -62,17 +57,14 @@ local int gz_init(state)
} }
/* Compress whatever is at avail_in and next_in and write to the output file. /* Compress whatever is at avail_in and next_in and write to the output file.
Return -1 if there is an error writing to the output file, otherwise 0. Return -1 if there is an error writing to the output file or if gz_init()
flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, fails to allocate memory, otherwise 0. flush is assumed to be a valid
then the deflate() state is reset to start a new gzip stream. If gz->direct deflate() flush value. If flush is Z_FINISH, then the deflate() state is
is true, then simply write to the output file without compressing, and reset to start a new gzip stream. If gz->direct is true, then simply write
ignore flush. */ to the output file without compressing, and ignore flush. */
local int gz_comp(state, flush) local int gz_comp(gz_statep state, int flush) {
gz_statep state; int ret, writ;
int flush; unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
{
int ret, got;
unsigned have;
z_streamp strm = &(state->strm); z_streamp strm = &(state->strm);
/* allocate memory if this is the first time through */ /* allocate memory if this is the first time through */
@ -81,15 +73,33 @@ local int gz_comp(state, flush)
/* write directly if requested */ /* write directly if requested */
if (state->direct) { if (state->direct) {
got = write(state->fd, strm->next_in, strm->avail_in); while (strm->avail_in) {
if (got < 0 || (unsigned)got != strm->avail_in) { errno = 0;
gz_error(state, Z_ERRNO, zstrerror()); state->again = 0;
return -1; put = strm->avail_in > max ? max : strm->avail_in;
writ = (int)write(state->fd, strm->next_in, put);
if (writ < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
state->again = 1;
gz_error(state, Z_ERRNO, zstrerror());
return -1;
}
strm->avail_in -= (unsigned)writ;
strm->next_in += writ;
} }
strm->avail_in = 0;
return 0; return 0;
} }
/* check for a pending reset */
if (state->reset) {
/* don't start a new gzip member unless there is data to write and
we're not flushing */
if (strm->avail_in == 0 && flush == Z_NO_FLUSH)
return 0;
deflateReset(strm);
state->reset = 0;
}
/* run deflate() on provided input until it produces no more output */ /* run deflate() on provided input until it produces no more output */
ret = Z_OK; ret = Z_OK;
do { do {
@ -97,17 +107,25 @@ local int gz_comp(state, flush)
doing Z_FINISH then don't write until we get to Z_STREAM_END */ doing Z_FINISH then don't write until we get to Z_STREAM_END */
if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
(flush != Z_FINISH || ret == Z_STREAM_END))) { (flush != Z_FINISH || ret == Z_STREAM_END))) {
have = (unsigned)(strm->next_out - state->x.next); while (strm->next_out > state->x.next) {
if (have && ((got = write(state->fd, state->x.next, have)) < 0 || errno = 0;
(unsigned)got != have)) { state->again = 0;
gz_error(state, Z_ERRNO, zstrerror()); put = strm->next_out - state->x.next > (int)max ? max :
return -1; (unsigned)(strm->next_out - state->x.next);
writ = (int)write(state->fd, state->x.next, put);
if (writ < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
state->again = 1;
gz_error(state, Z_ERRNO, zstrerror());
return -1;
}
state->x.next += writ;
} }
if (strm->avail_out == 0) { if (strm->avail_out == 0) {
strm->avail_out = state->size; strm->avail_out = state->size;
strm->next_out = state->out; strm->next_out = state->out;
state->x.next = state->out;
} }
state->x.next = strm->next_out;
} }
/* compress */ /* compress */
@ -123,18 +141,18 @@ local int gz_comp(state, flush)
/* if that completed a deflate stream, allow another to start */ /* if that completed a deflate stream, allow another to start */
if (flush == Z_FINISH) if (flush == Z_FINISH)
deflateReset(strm); state->reset = 1;
/* all done, no errors */ /* all done, no errors */
return 0; return 0;
} }
/* Compress len zeros to output. Return -1 on error, 0 on success. */ /* Compress state->skip (> 0) zeros to output. Return -1 on a write error or
local int gz_zero(state, len) memory allocation failure by gz_comp(), or 0 on success. state->skip is
gz_statep state; updated with the number of successfully written zeros, in case there is a
z_off64_t len; stall on a non-blocking write destination. */
{ local int gz_zero(gz_statep state) {
int first; int first, ret;
unsigned n; unsigned n;
z_streamp strm = &(state->strm); z_streamp strm = &(state->strm);
@ -142,51 +160,34 @@ local int gz_zero(state, len)
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
return -1; return -1;
/* compress len zeros (len guaranteed > 0) */ /* compress state->skip zeros */
first = 1; first = 1;
while (len) { do {
n = GT_OFF(state->size) || (z_off64_t)state->size > len ? n = GT_OFF(state->size) || (z_off64_t)state->size > state->skip ?
(unsigned)len : state->size; (unsigned)state->skip : state->size;
if (first) { if (first) {
memset(state->in, 0, n); memset(state->in, 0, n);
first = 0; first = 0;
} }
strm->avail_in = n; strm->avail_in = n;
strm->next_in = state->in; strm->next_in = state->in;
ret = gz_comp(state, Z_NO_FLUSH);
n -= strm->avail_in;
state->x.pos += n; state->x.pos += n;
if (gz_comp(state, Z_NO_FLUSH) == -1) state->skip -= n;
if (ret == -1)
return -1; return -1;
len -= n; } while (state->skip);
}
return 0; return 0;
} }
/* -- see zlib.h -- */ /* Write len bytes from buf to file. Return the number of bytes written. If
int ZEXPORT gzwrite(file, buf, len) the returned value is less than len, then there was an error. If the error
gzFile file; was a non-blocking stall, then the number of bytes consumed is returned.
voidpc buf; For any other error, 0 is returned. */
unsigned len; local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
{ z_size_t put = len;
unsigned put = len; int ret;
gz_statep state;
z_streamp strm;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
strm = &(state->strm);
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK)
return 0;
/* since an int is returned, make sure len fits in one, otherwise return
with an error (this avoids the flaw in the interface) */
if ((int)len < 0) {
gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
return 0;
}
/* if len is zero, avoid unnecessary operations */ /* if len is zero, avoid unnecessary operations */
if (len == 0) if (len == 0)
@ -197,55 +198,113 @@ int ZEXPORT gzwrite(file, buf, len)
return 0; return 0;
/* check for seek request */ /* check for seek request */
if (state->seek) { if (state->skip && gz_zero(state) == -1)
state->seek = 0; return 0;
if (gz_zero(state, state->skip) == -1)
return 0;
}
/* for small len, copy to input buffer, otherwise compress directly */ /* for small len, copy to input buffer, otherwise compress directly */
if (len < state->size) { if (len < state->size) {
/* copy to input buffer, compress when full */ /* copy to input buffer, compress when full */
do { for (;;) {
unsigned have, copy; unsigned have, copy;
if (strm->avail_in == 0) if (state->strm.avail_in == 0)
strm->next_in = state->in; state->strm.next_in = state->in;
have = (unsigned)((strm->next_in + strm->avail_in) - state->in); have = (unsigned)((state->strm.next_in + state->strm.avail_in) -
state->in);
copy = state->size - have; copy = state->size - have;
if (copy > len) if (copy > len)
copy = len; copy = (unsigned)len;
memcpy(state->in + have, buf, copy); memcpy(state->in + have, buf, copy);
strm->avail_in += copy; state->strm.avail_in += copy;
state->x.pos += copy; state->x.pos += copy;
buf = (const char *)buf + copy; buf = (const char *)buf + copy;
len -= copy; len -= copy;
if (len && gz_comp(state, Z_NO_FLUSH) == -1) if (len == 0)
return 0; break;
} while (len); if (gz_comp(state, Z_NO_FLUSH) == -1)
return state->again ? put - len : 0;
}
} }
else { else {
/* consume whatever's left in the input buffer */ /* consume whatever's left in the input buffer */
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
return 0; return 0;
/* directly compress user buffer to file */ /* directly compress user buffer to file */
strm->avail_in = len; state->strm.next_in = (z_const Bytef *)buf;
strm->next_in = (z_const Bytef *)buf; do {
state->x.pos += len; unsigned n = (unsigned)-1;
if (gz_comp(state, Z_NO_FLUSH) == -1)
return 0; if (n > len)
n = (unsigned)len;
state->strm.avail_in = n;
ret = gz_comp(state, Z_NO_FLUSH);
n -= state->strm.avail_in;
state->x.pos += n;
len -= n;
if (ret == -1)
return state->again ? put - len : 0;
} while (len);
} }
/* input was all buffered or compressed (put will fit in int) */ /* input was all buffered or compressed */
return (int)put; return put;
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzputc(file, c) int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
gzFile file; gz_statep state;
int c;
{ /* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
/* check that we're writing and that there's no (serious) error */
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
return 0;
gz_error(state, Z_OK, NULL);
/* since an int is returned, make sure len fits in one, otherwise return
with an error (this avoids a flaw in the interface) */
if ((int)len < 0) {
gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
return 0;
}
/* write len bytes from buf (the return value will fit in an int) */
return (int)gz_write(state, buf, len);
}
/* -- see zlib.h -- */
z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
gzFile file) {
z_size_t len;
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
/* check that we're writing and that there's no (serious) error */
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
return 0;
gz_error(state, Z_OK, NULL);
/* compute bytes to read -- error on overflow */
len = nitems * size;
if (size && len / size != nitems) {
gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
return 0;
}
/* write len bytes to buf, return the number of full items written */
return len ? gz_write(state, buf, len) / size : 0;
}
/* -- see zlib.h -- */
int ZEXPORT gzputc(gzFile file, int c) {
unsigned have; unsigned have;
unsigned char buf[1]; unsigned char buf[1];
gz_statep state; gz_statep state;
@ -257,16 +316,14 @@ int ZEXPORT gzputc(file, c)
state = (gz_statep)file; state = (gz_statep)file;
strm = &(state->strm); strm = &(state->strm);
/* check that we're writing and that there's no error */ /* check that we're writing and that there's no (serious) error */
if (state->mode != GZ_WRITE || state->err != Z_OK) if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
return -1; return -1;
gz_error(state, Z_OK, NULL);
/* check for seek request */ /* check for seek request */
if (state->seek) { if (state->skip && gz_zero(state) == -1)
state->seek = 0; return -1;
if (gz_zero(state, state->skip) == -1)
return -1;
}
/* try writing to input buffer for speed (state->size == 0 if buffer not /* try writing to input buffer for speed (state->size == 0 if buffer not
initialized) */ initialized) */
@ -275,7 +332,7 @@ int ZEXPORT gzputc(file, c)
strm->next_in = state->in; strm->next_in = state->in;
have = (unsigned)((strm->next_in + strm->avail_in) - state->in); have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
if (have < state->size) { if (have < state->size) {
state->in[have] = c; state->in[have] = (unsigned char)c;
strm->avail_in++; strm->avail_in++;
state->x.pos++; state->x.pos++;
return c & 0xff; return c & 0xff;
@ -283,94 +340,151 @@ int ZEXPORT gzputc(file, c)
} }
/* no room in buffer or not initialized, use gz_write() */ /* no room in buffer or not initialized, use gz_write() */
buf[0] = c; buf[0] = (unsigned char)c;
if (gzwrite(file, buf, 1) != 1) if (gz_write(state, buf, 1) != 1)
return -1; return -1;
return c & 0xff; return c & 0xff;
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzputs(file, str) int ZEXPORT gzputs(gzFile file, const char *s) {
gzFile file; z_size_t len, put;
const char *str;
{
int ret;
unsigned len;
/* write string */
len = (unsigned)strlen(str);
ret = gzwrite(file, str, len);
return ret == 0 && len != 0 ? -1 : ret;
}
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#include <stdarg.h>
/* -- see zlib.h -- */
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
{
int size, len;
gz_statep state; gz_statep state;
z_streamp strm;
/* get internal structure */ /* get internal structure */
if (file == NULL) if (file == NULL)
return -1; return -1;
state = (gz_statep)file; state = (gz_statep)file;
/* check that we're writing and that there's no (serious) error */
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
return -1;
gz_error(state, Z_OK, NULL);
/* write string */
len = strlen(s);
if ((int)len < 0 || (unsigned)len != len) {
gz_error(state, Z_STREAM_ERROR, "string length does not fit in int");
return -1;
}
put = gz_write(state, s, len);
return len && put == 0 ? -1 : (int)put;
}
#if (((!defined(STDC) && !defined(Z_HAVE_STDARG_H)) || !defined(NO_vsnprintf)) && \
(defined(STDC) || defined(Z_HAVE_STDARG_H) || !defined(NO_snprintf))) || \
defined(ZLIB_INSECURE)
/* If the second half of the input buffer is occupied, write out the contents.
If there is any input remaining due to a non-blocking stall on write, move
it to the start of the buffer. Return true if this did not open up the
second half of the buffer. state->err should be checked after this to
handle a gz_comp() error. */
local int gz_vacate(gz_statep state) {
z_streamp strm;
strm = &(state->strm);
if (strm->next_in + strm->avail_in <= state->in + state->size)
return 0;
(void)gz_comp(state, Z_NO_FLUSH);
if (strm->avail_in == 0) {
strm->next_in = state->in;
return 0;
}
memmove(state->in, strm->next_in, strm->avail_in);
strm->next_in = state->in;
return strm->avail_in > state->size;
}
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#include <stdarg.h>
/* -- see zlib.h -- */
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
#if defined(NO_vsnprintf) && !defined(ZLIB_INSECURE)
#warning "vsnprintf() not available -- gzprintf() stub returns Z_STREAM_ERROR"
#warning "you can recompile with ZLIB_INSECURE defined to use vsprintf()"
/* prevent use of insecure vsprintf(), unless purposefully requested */
(void)file, (void)format, (void)va;
return Z_STREAM_ERROR;
#else
int len, ret;
char *next;
gz_statep state;
z_streamp strm;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
strm = &(state->strm); strm = &(state->strm);
/* check that we're writing and that there's no error */ /* check that we're writing and that there's no (serious) error */
if (state->mode != GZ_WRITE || state->err != Z_OK) if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
return 0; return Z_STREAM_ERROR;
gz_error(state, Z_OK, NULL);
/* make sure we have some buffer space */ /* make sure we have some buffer space */
if (state->size == 0 && gz_init(state) == -1) if (state->size == 0 && gz_init(state) == -1)
return 0; return state->err;
/* check for seek request */ /* check for seek request */
if (state->seek) { if (state->skip && gz_zero(state) == -1)
state->seek = 0; return state->err;
if (gz_zero(state, state->skip) == -1)
return 0; /* do the printf() into the input buffer, put length in len -- the input
buffer is double-sized just for this function, so there should be
state->size bytes available after the current contents */
ret = gz_vacate(state);
if (state->err) {
if (ret && state->again) {
/* There was a non-blocking stall on write, resulting in the part
of the second half of the output buffer being occupied. Return
a Z_BUF_ERROR to let the application know that this gzprintf()
needs to be retried. */
gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
}
if (!state->again)
return state->err;
} }
if (strm->avail_in == 0)
/* consume whatever's left in the input buffer */ strm->next_in = state->in;
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
return 0; next[state->size - 1] = 0;
/* do the printf() into the input buffer, put length in len */
size = (int)(state->size);
state->in[size - 1] = 0;
#ifdef NO_vsnprintf #ifdef NO_vsnprintf
# ifdef HAS_vsprintf_void # ifdef HAS_vsprintf_void
(void)vsprintf((char *)(state->in), format, va); (void)vsprintf(next, format, va);
for (len = 0; len < size; len++) for (len = 0; len < state->size; len++)
if (state->in[len] == 0) break; if (next[len] == 0) break;
# else # else
len = vsprintf((char *)(state->in), format, va); len = vsprintf(next, format, va);
# endif # endif
#else #else
# ifdef HAS_vsnprintf_void # ifdef HAS_vsnprintf_void
(void)vsnprintf((char *)(state->in), size, format, va); (void)vsnprintf(next, state->size, format, va);
len = strlen((char *)(state->in)); len = strlen(next);
# else # else
len = vsnprintf((char *)(state->in), size, format, va); len = vsnprintf(next, state->size, format, va);
# endif # endif
#endif #endif
/* check that printf() results fit in buffer */ /* check that printf() results fit in buffer */
if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
return 0; return 0;
/* update buffer and position, defer compression until needed */ /* update buffer and position */
strm->avail_in = (unsigned)len; strm->avail_in += (unsigned)len;
strm->next_in = state->in;
state->x.pos += len; state->x.pos += len;
/* write out buffer if more than half is occupied */
ret = gz_vacate(state);
if (state->err && !state->again)
return state->err;
return len; return len;
#endif
} }
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
{
va_list va; va_list va;
int ret; int ret;
@ -383,122 +497,137 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
#else /* !STDC && !Z_HAVE_STDARG_H */ #else /* !STDC && !Z_HAVE_STDARG_H */
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) int a4, int a5, int a6, int a7, int a8, int a9, int a10,
gzFile file; int a11, int a12, int a13, int a14, int a15, int a16,
const char *format; int a17, int a18, int a19, int a20) {
int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, #if defined(NO_snprintf) && !defined(ZLIB_INSECURE)
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; #warning "snprintf() not available -- gzprintf() stub returns Z_STREAM_ERROR"
{ #warning "you can recompile with ZLIB_INSECURE defined to use sprintf()"
int size, len; /* prevent use of insecure sprintf(), unless purposefully requested */
(void)file, (void)format, (void)a1, (void)a2, (void)a3, (void)a4, (void)a5,
(void)a6, (void)a7, (void)a8, (void)a9, (void)a10, (void)a11, (void)a12,
(void)a13, (void)a14, (void)a15, (void)a16, (void)a17, (void)a18,
(void)a19, (void)a20;
return Z_STREAM_ERROR;
#else
int ret;
unsigned len, left;
char *next;
gz_statep state; gz_statep state;
z_streamp strm; z_streamp strm;
/* get internal structure */ /* get internal structure */
if (file == NULL) if (file == NULL)
return -1; return Z_STREAM_ERROR;
state = (gz_statep)file; state = (gz_statep)file;
strm = &(state->strm); strm = &(state->strm);
/* check that can really pass pointer in ints */ /* check that can really pass pointer in ints */
if (sizeof(int) != sizeof(void *)) if (sizeof(int) != sizeof(void *))
return 0; return Z_STREAM_ERROR;
/* check that we're writing and that there's no error */ /* check that we're writing and that there's no (serious) error */
if (state->mode != GZ_WRITE || state->err != Z_OK) if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
return 0; return Z_STREAM_ERROR;
gz_error(state, Z_OK, NULL);
/* make sure we have some buffer space */ /* make sure we have some buffer space */
if (state->size == 0 && gz_init(state) == -1) if (state->size == 0 && gz_init(state) == -1)
return 0; return state->err;
/* check for seek request */ /* check for seek request */
if (state->seek) { if (state->skip && gz_zero(state) == -1)
state->seek = 0; return state->err;
if (gz_zero(state, state->skip) == -1)
return 0; /* do the printf() into the input buffer, put length in len -- the input
buffer is double-sized just for this function, so there is guaranteed to
be state->size bytes available after the current contents */
ret = gz_vacate(state);
if (state->err) {
if (ret && state->again) {
/* There was a non-blocking stall on write, resulting in the part
of the second half of the output buffer being occupied. Return
a Z_BUF_ERROR to let the application know that this gzprintf()
needs to be retried. */
gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
}
if (!state->again)
return state->err;
} }
if (strm->avail_in == 0)
/* consume whatever's left in the input buffer */ strm->next_in = state->in;
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) next = (char *)(strm->next_in + strm->avail_in);
return 0; next[state->size - 1] = 0;
/* do the printf() into the input buffer, put length in len */
size = (int)(state->size);
state->in[size - 1] = 0;
#ifdef NO_snprintf #ifdef NO_snprintf
# ifdef HAS_sprintf_void # ifdef HAS_sprintf_void
sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); a13, a14, a15, a16, a17, a18, a19, a20);
for (len = 0; len < size; len++) for (len = 0; len < size; len++)
if (state->in[len] == 0) break; if (next[len] == 0)
break;
# else # else
len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); a12, a13, a14, a15, a16, a17, a18, a19, a20);
# endif # endif
#else #else
# ifdef HAS_snprintf_void # ifdef HAS_snprintf_void
snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,
a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
len = strlen((char *)(state->in)); len = strlen(next);
# else # else
len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,
a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
a19, a20);
# endif # endif
#endif #endif
/* check that printf() results fit in buffer */ /* check that printf() results fit in buffer */
if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) if (len == 0 || len >= state->size || next[state->size - 1] != 0)
return 0; return 0;
/* update buffer and position, defer compression until needed */ /* update buffer and position, compress first half if past that */
strm->avail_in = (unsigned)len; strm->avail_in += len;
strm->next_in = state->in;
state->x.pos += len; state->x.pos += len;
return len;
/* write out buffer if more than half is occupied */
ret = gz_vacate(state);
if (state->err && !state->again)
return state->err;
return (int)len;
#endif
} }
#endif #endif
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzflush(file, flush) int ZEXPORT gzflush(gzFile file, int flush) {
gzFile file;
int flush;
{
gz_statep state; gz_statep state;
/* get internal structure */ /* get internal structure */
if (file == NULL) if (file == NULL)
return -1; return Z_STREAM_ERROR;
state = (gz_statep)file; state = (gz_statep)file;
/* check that we're writing and that there's no error */ /* check that we're writing and that there's no (serious) error */
if (state->mode != GZ_WRITE || state->err != Z_OK) if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
return Z_STREAM_ERROR; return Z_STREAM_ERROR;
gz_error(state, Z_OK, NULL);
/* check flush parameter */ /* check flush parameter */
if (flush < 0 || flush > Z_FINISH) if (flush < 0 || flush > Z_FINISH)
return Z_STREAM_ERROR; return Z_STREAM_ERROR;
/* check for seek request */ /* check for seek request */
if (state->seek) { if (state->skip && gz_zero(state) == -1)
state->seek = 0; return state->err;
if (gz_zero(state, state->skip) == -1)
return -1;
}
/* compress remaining data with requested flush */ /* compress remaining data with requested flush */
gz_comp(state, flush); (void)gz_comp(state, flush);
return state->err; return state->err;
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzsetparams(file, level, strategy) int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
gzFile file;
int level;
int strategy;
{
gz_statep state; gz_statep state;
z_streamp strm; z_streamp strm;
@ -508,25 +637,24 @@ int ZEXPORT gzsetparams(file, level, strategy)
state = (gz_statep)file; state = (gz_statep)file;
strm = &(state->strm); strm = &(state->strm);
/* check that we're writing and that there's no error */ /* check that we're compressing and that there's no (serious) error */
if (state->mode != GZ_WRITE || state->err != Z_OK) if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again) ||
state->direct)
return Z_STREAM_ERROR; return Z_STREAM_ERROR;
gz_error(state, Z_OK, NULL);
/* if no change is requested, then do nothing */ /* if no change is requested, then do nothing */
if (level == state->level && strategy == state->strategy) if (level == state->level && strategy == state->strategy)
return Z_OK; return Z_OK;
/* check for seek request */ /* check for seek request */
if (state->seek) { if (state->skip && gz_zero(state) == -1)
state->seek = 0; return state->err;
if (gz_zero(state, state->skip) == -1)
return -1;
}
/* change compression parameters for subsequent input */ /* change compression parameters for subsequent input */
if (state->size) { if (state->size) {
/* flush previous input with previous parameters before changing */ /* flush previous input with previous parameters before changing */
if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
return state->err; return state->err;
deflateParams(strm, level, strategy); deflateParams(strm, level, strategy);
} }
@ -536,9 +664,7 @@ int ZEXPORT gzsetparams(file, level, strategy)
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
int ZEXPORT gzclose_w(file) int ZEXPORT gzclose_w(gzFile file) {
gzFile file;
{
int ret = Z_OK; int ret = Z_OK;
gz_statep state; gz_statep state;
@ -552,11 +678,8 @@ int ZEXPORT gzclose_w(file)
return Z_STREAM_ERROR; return Z_STREAM_ERROR;
/* check for seek request */ /* check for seek request */
if (state->seek) { if (state->skip && gz_zero(state) == -1)
state->seek = 0; ret = state->err;
if (gz_zero(state, state->skip) == -1)
ret = state->err;
}
/* flush, free memory, and close file */ /* flush, free memory, and close file */
if (gz_comp(state, Z_FINISH) == -1) if (gz_comp(state, Z_FINISH) == -1)

View file

@ -1,5 +1,5 @@
/* infback.c -- inflate using a call-back interface /* infback.c -- inflate using a call-back interface
* Copyright (C) 1995-2011 Mark Adler * Copyright (C) 1995-2026 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -15,9 +15,6 @@
#include "inflate.h" #include "inflate.h"
#include "inffast.h" #include "inffast.h"
/* function prototypes */
local void fixedtables OF((struct inflate_state FAR *state));
/* /*
strm provides memory allocation functions in zalloc and zfree, or strm provides memory allocation functions in zalloc and zfree, or
Z_NULL to use the library memory allocation functions. Z_NULL to use the library memory allocation functions.
@ -25,13 +22,9 @@ local void fixedtables OF((struct inflate_state FAR *state));
windowBits is in the range 8..15, and window is a user-supplied windowBits is in the range 8..15, and window is a user-supplied
window and output buffer that is 2**windowBits bytes. window and output buffer that is 2**windowBits bytes.
*/ */
int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,
z_streamp strm; unsigned char FAR *window, const char *version,
int windowBits; int stream_size) {
unsigned char FAR *window;
const char *version;
int stream_size;
{
struct inflate_state FAR *state; struct inflate_state FAR *state;
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
@ -53,7 +46,7 @@ int stream_size;
#ifdef Z_SOLO #ifdef Z_SOLO
return Z_STREAM_ERROR; return Z_STREAM_ERROR;
#else #else
strm->zfree = zcfree; strm->zfree = zcfree;
#endif #endif
state = (struct inflate_state FAR *)ZALLOC(strm, 1, state = (struct inflate_state FAR *)ZALLOC(strm, 1,
sizeof(struct inflate_state)); sizeof(struct inflate_state));
@ -61,67 +54,15 @@ int stream_size;
Tracev((stderr, "inflate: allocated\n")); Tracev((stderr, "inflate: allocated\n"));
strm->state = (struct internal_state FAR *)state; strm->state = (struct internal_state FAR *)state;
state->dmax = 32768U; state->dmax = 32768U;
state->wbits = windowBits; state->wbits = (uInt)windowBits;
state->wsize = 1U << windowBits; state->wsize = 1U << windowBits;
state->window = window; state->window = window;
state->wnext = 0; state->wnext = 0;
state->whave = 0; state->whave = 0;
state->sane = 1;
return Z_OK; return Z_OK;
} }
/*
Return state with length and distance decoding tables and index sizes set to
fixed code decoding. Normally this returns fixed tables from inffixed.h.
If BUILDFIXED is defined, then instead this routine builds the tables the
first time it's called, and returns those tables the first time and
thereafter. This reduces the size of the code by about 2K bytes, in
exchange for a little execution time. However, BUILDFIXED should not be
used for threaded applications, since the rewriting of the tables and virgin
may not be thread-safe.
*/
local void fixedtables(state)
struct inflate_state FAR *state;
{
#ifdef BUILDFIXED
static int virgin = 1;
static code *lenfix, *distfix;
static code fixed[544];
/* build fixed huffman tables if first call (may not be thread safe) */
if (virgin) {
unsigned sym, bits;
static code *next;
/* literal/length table */
sym = 0;
while (sym < 144) state->lens[sym++] = 8;
while (sym < 256) state->lens[sym++] = 9;
while (sym < 280) state->lens[sym++] = 7;
while (sym < 288) state->lens[sym++] = 8;
next = fixed;
lenfix = next;
bits = 9;
inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
/* distance table */
sym = 0;
while (sym < 32) state->lens[sym++] = 5;
distfix = next;
bits = 5;
inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
/* do this just once */
virgin = 0;
}
#else /* !BUILDFIXED */
# include "inffixed.h"
#endif /* BUILDFIXED */
state->lencode = lenfix;
state->lenbits = 9;
state->distcode = distfix;
state->distbits = 5;
}
/* Macros for inflateBack(): */ /* Macros for inflateBack(): */
/* Load returned state from inflate_fast() */ /* Load returned state from inflate_fast() */
@ -247,13 +188,8 @@ struct inflate_state FAR *state;
inflateBack() can also return Z_STREAM_ERROR if the input parameters inflateBack() can also return Z_STREAM_ERROR if the input parameters
are not correct, i.e. strm is Z_NULL or the state was not initialized. are not correct, i.e. strm is Z_NULL or the state was not initialized.
*/ */
int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
z_streamp strm; out_func out, void FAR *out_desc) {
in_func in;
void FAR *in_desc;
out_func out;
void FAR *out_desc;
{
struct inflate_state FAR *state; struct inflate_state FAR *state;
z_const unsigned char FAR *next; /* next input */ z_const unsigned char FAR *next; /* next input */
unsigned char FAR *put; /* next output */ unsigned char FAR *put; /* next output */
@ -306,7 +242,7 @@ void FAR *out_desc;
state->mode = STORED; state->mode = STORED;
break; break;
case 1: /* fixed block */ case 1: /* fixed block */
fixedtables(state); inflate_fixed(state);
Tracev((stderr, "inflate: fixed codes block%s\n", Tracev((stderr, "inflate: fixed codes block%s\n",
state->last ? " (last)" : "")); state->last ? " (last)" : ""));
state->mode = LEN; /* decode codes */ state->mode = LEN; /* decode codes */
@ -316,8 +252,8 @@ void FAR *out_desc;
state->last ? " (last)" : "")); state->last ? " (last)" : ""));
state->mode = TABLE; state->mode = TABLE;
break; break;
case 3: default:
strm->msg = (char *)"invalid block type"; strm->msg = (z_const char *)"invalid block type";
state->mode = BAD; state->mode = BAD;
} }
DROPBITS(2); DROPBITS(2);
@ -328,7 +264,7 @@ void FAR *out_desc;
BYTEBITS(); /* go to byte boundary */ BYTEBITS(); /* go to byte boundary */
NEEDBITS(32); NEEDBITS(32);
if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
strm->msg = (char *)"invalid stored block lengths"; strm->msg = (z_const char *)"invalid stored block lengths";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -366,7 +302,8 @@ void FAR *out_desc;
DROPBITS(4); DROPBITS(4);
#ifndef PKZIP_BUG_WORKAROUND #ifndef PKZIP_BUG_WORKAROUND
if (state->nlen > 286 || state->ndist > 30) { if (state->nlen > 286 || state->ndist > 30) {
strm->msg = (char *)"too many length or distance symbols"; strm->msg = (z_const char *)
"too many length or distance symbols";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -388,7 +325,7 @@ void FAR *out_desc;
ret = inflate_table(CODES, state->lens, 19, &(state->next), ret = inflate_table(CODES, state->lens, 19, &(state->next),
&(state->lenbits), state->work); &(state->lenbits), state->work);
if (ret) { if (ret) {
strm->msg = (char *)"invalid code lengths set"; strm->msg = (z_const char *)"invalid code lengths set";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -411,7 +348,8 @@ void FAR *out_desc;
NEEDBITS(here.bits + 2); NEEDBITS(here.bits + 2);
DROPBITS(here.bits); DROPBITS(here.bits);
if (state->have == 0) { if (state->have == 0) {
strm->msg = (char *)"invalid bit length repeat"; strm->msg = (z_const char *)
"invalid bit length repeat";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -434,7 +372,8 @@ void FAR *out_desc;
DROPBITS(7); DROPBITS(7);
} }
if (state->have + copy > state->nlen + state->ndist) { if (state->have + copy > state->nlen + state->ndist) {
strm->msg = (char *)"invalid bit length repeat"; strm->msg = (z_const char *)
"invalid bit length repeat";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -448,7 +387,8 @@ void FAR *out_desc;
/* check for end-of-block code (better have one) */ /* check for end-of-block code (better have one) */
if (state->lens[256] == 0) { if (state->lens[256] == 0) {
strm->msg = (char *)"invalid code -- missing end-of-block"; strm->msg = (z_const char *)
"invalid code -- missing end-of-block";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -462,7 +402,7 @@ void FAR *out_desc;
ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
&(state->lenbits), state->work); &(state->lenbits), state->work);
if (ret) { if (ret) {
strm->msg = (char *)"invalid literal/lengths set"; strm->msg = (z_const char *)"invalid literal/lengths set";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -471,19 +411,18 @@ void FAR *out_desc;
ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
&(state->next), &(state->distbits), state->work); &(state->next), &(state->distbits), state->work);
if (ret) { if (ret) {
strm->msg = (char *)"invalid distances set"; strm->msg = (z_const char *)"invalid distances set";
state->mode = BAD; state->mode = BAD;
break; break;
} }
Tracev((stderr, "inflate: codes ok\n")); Tracev((stderr, "inflate: codes ok\n"));
state->mode = LEN; state->mode = LEN;
/* fallthrough */
case LEN: case LEN:
/* use inflate_fast() if we have enough input and output */ /* use inflate_fast() if we have enough input and output */
if (have >= 6 && left >= 258) { if (have >= 6 && left >= 258) {
RESTORE(); RESTORE();
if (state->whave < state->wsize)
state->whave = state->wsize - left;
inflate_fast(strm, state->wsize); inflate_fast(strm, state->wsize);
LOAD(); LOAD();
break; break;
@ -529,7 +468,7 @@ void FAR *out_desc;
/* invalid code */ /* invalid code */
if (here.op & 64) { if (here.op & 64) {
strm->msg = (char *)"invalid literal/length code"; strm->msg = (z_const char *)"invalid literal/length code";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -561,7 +500,7 @@ void FAR *out_desc;
} }
DROPBITS(here.bits); DROPBITS(here.bits);
if (here.op & 64) { if (here.op & 64) {
strm->msg = (char *)"invalid distance code"; strm->msg = (z_const char *)"invalid distance code";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -576,7 +515,7 @@ void FAR *out_desc;
} }
if (state->offset > state->wsize - (state->whave < state->wsize ? if (state->offset > state->wsize - (state->whave < state->wsize ?
left : 0)) { left : 0)) {
strm->msg = (char *)"invalid distance too far back"; strm->msg = (z_const char *)"invalid distance too far back";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -604,33 +543,33 @@ void FAR *out_desc;
break; break;
case DONE: case DONE:
/* inflate stream terminated properly -- write leftover output */ /* inflate stream terminated properly */
ret = Z_STREAM_END; ret = Z_STREAM_END;
if (left < state->wsize) {
if (out(out_desc, state->window, state->wsize - left))
ret = Z_BUF_ERROR;
}
goto inf_leave; goto inf_leave;
case BAD: case BAD:
ret = Z_DATA_ERROR; ret = Z_DATA_ERROR;
goto inf_leave; goto inf_leave;
default: /* can't happen, but makes compilers happy */ default:
/* can't happen, but makes compilers happy */
ret = Z_STREAM_ERROR; ret = Z_STREAM_ERROR;
goto inf_leave; goto inf_leave;
} }
/* Return unused input */ /* Write leftover output and return unused input */
inf_leave: inf_leave:
if (left < state->wsize) {
if (out(out_desc, state->window, state->wsize - left) &&
ret == Z_STREAM_END)
ret = Z_BUF_ERROR;
}
strm->next_in = next; strm->next_in = next;
strm->avail_in = have; strm->avail_in = have;
return ret; return ret;
} }
int ZEXPORT inflateBackEnd(strm) int ZEXPORT inflateBackEnd(z_streamp strm) {
z_streamp strm;
{
if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
return Z_STREAM_ERROR; return Z_STREAM_ERROR;
ZFREE(strm, strm->state); ZFREE(strm, strm->state);

View file

@ -1,5 +1,5 @@
/* inffast.c -- fast decoding /* inffast.c -- fast decoding
* Copyright (C) 1995-2008, 2010, 2013 Mark Adler * Copyright (C) 1995-2026 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -8,26 +8,9 @@
#include "inflate.h" #include "inflate.h"
#include "inffast.h" #include "inffast.h"
#ifndef ASMINF #ifdef ASMINF
# pragma message("Assembler code may have bugs -- use at your own risk")
/* Allow machine dependent optimization for post-increment or pre-increment.
Based on testing to date,
Pre-increment preferred for:
- PowerPC G3 (Adler)
- MIPS R5000 (Randers-Pehrson)
Post-increment preferred for:
- none
No measurable difference:
- Pentium III (Anderson)
- M68060 (Nikl)
*/
#ifdef POSTINC
# define OFF 0
# define PUP(a) *(a)++
#else #else
# define OFF 1
# define PUP(a) *++(a)
#endif
/* /*
Decode literal, length, and distance codes and write out the resulting Decode literal, length, and distance codes and write out the resulting
@ -64,10 +47,7 @@
requires strm->avail_out >= 258 for each loop to avoid checking for requires strm->avail_out >= 258 for each loop to avoid checking for
output space. output space.
*/ */
void ZLIB_INTERNAL inflate_fast(strm, start) void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
z_streamp strm;
unsigned start; /* inflate()'s starting value for strm->avail_out */
{
struct inflate_state FAR *state; struct inflate_state FAR *state;
z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *in; /* local strm->next_in */
z_const unsigned char FAR *last; /* have enough input while in < last */ z_const unsigned char FAR *last; /* have enough input while in < last */
@ -87,7 +67,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
code const FAR *dcode; /* local strm->distcode */ code const FAR *dcode; /* local strm->distcode */
unsigned lmask; /* mask for first level of length codes */ unsigned lmask; /* mask for first level of length codes */
unsigned dmask; /* mask for first level of distance codes */ unsigned dmask; /* mask for first level of distance codes */
code here; /* retrieved table entry */ code const *here; /* retrieved table entry */
unsigned op; /* code bits, operation, extra bits, or */ unsigned op; /* code bits, operation, extra bits, or */
/* window position, window bytes to copy */ /* window position, window bytes to copy */
unsigned len; /* match length, unused bytes */ unsigned len; /* match length, unused bytes */
@ -96,9 +76,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
/* copy state to local variables */ /* copy state to local variables */
state = (struct inflate_state FAR *)strm->state; state = (struct inflate_state FAR *)strm->state;
in = strm->next_in - OFF; in = strm->next_in;
last = in + (strm->avail_in - 5); last = in + (strm->avail_in - 5);
out = strm->next_out - OFF; out = strm->next_out;
beg = out - (start - strm->avail_out); beg = out - (start - strm->avail_out);
end = out + (strm->avail_out - 257); end = out + (strm->avail_out - 257);
#ifdef INFLATE_STRICT #ifdef INFLATE_STRICT
@ -119,29 +99,29 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
input data or output space */ input data or output space */
do { do {
if (bits < 15) { if (bits < 15) {
hold += (unsigned long)(PUP(in)) << bits; hold += (unsigned long)(*in++) << bits;
bits += 8; bits += 8;
hold += (unsigned long)(PUP(in)) << bits; hold += (unsigned long)(*in++) << bits;
bits += 8; bits += 8;
} }
here = lcode[hold & lmask]; here = lcode + (hold & lmask);
dolen: dolen:
op = (unsigned)(here.bits); op = (unsigned)(here->bits);
hold >>= op; hold >>= op;
bits -= op; bits -= op;
op = (unsigned)(here.op); op = (unsigned)(here->op);
if (op == 0) { /* literal */ if (op == 0) { /* literal */
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
"inflate: literal '%c'\n" : "inflate: literal '%c'\n" :
"inflate: literal 0x%02x\n", here.val)); "inflate: literal 0x%02x\n", here->val));
PUP(out) = (unsigned char)(here.val); *out++ = (unsigned char)(here->val);
} }
else if (op & 16) { /* length base */ else if (op & 16) { /* length base */
len = (unsigned)(here.val); len = (unsigned)(here->val);
op &= 15; /* number of extra bits */ op &= 15; /* number of extra bits */
if (op) { if (op) {
if (bits < op) { if (bits < op) {
hold += (unsigned long)(PUP(in)) << bits; hold += (unsigned long)(*in++) << bits;
bits += 8; bits += 8;
} }
len += (unsigned)hold & ((1U << op) - 1); len += (unsigned)hold & ((1U << op) - 1);
@ -150,32 +130,33 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
} }
Tracevv((stderr, "inflate: length %u\n", len)); Tracevv((stderr, "inflate: length %u\n", len));
if (bits < 15) { if (bits < 15) {
hold += (unsigned long)(PUP(in)) << bits; hold += (unsigned long)(*in++) << bits;
bits += 8; bits += 8;
hold += (unsigned long)(PUP(in)) << bits; hold += (unsigned long)(*in++) << bits;
bits += 8; bits += 8;
} }
here = dcode[hold & dmask]; here = dcode + (hold & dmask);
dodist: dodist:
op = (unsigned)(here.bits); op = (unsigned)(here->bits);
hold >>= op; hold >>= op;
bits -= op; bits -= op;
op = (unsigned)(here.op); op = (unsigned)(here->op);
if (op & 16) { /* distance base */ if (op & 16) { /* distance base */
dist = (unsigned)(here.val); dist = (unsigned)(here->val);
op &= 15; /* number of extra bits */ op &= 15; /* number of extra bits */
if (bits < op) { if (bits < op) {
hold += (unsigned long)(PUP(in)) << bits; hold += (unsigned long)(*in++) << bits;
bits += 8; bits += 8;
if (bits < op) { if (bits < op) {
hold += (unsigned long)(PUP(in)) << bits; hold += (unsigned long)(*in++) << bits;
bits += 8; bits += 8;
} }
} }
dist += (unsigned)hold & ((1U << op) - 1); dist += (unsigned)hold & ((1U << op) - 1);
#ifdef INFLATE_STRICT #ifdef INFLATE_STRICT
if (dist > dmax) { if (dist > dmax) {
strm->msg = (char *)"invalid distance too far back"; strm->msg = (z_const char *)
"invalid distance too far back";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -188,38 +169,38 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
op = dist - op; /* distance back in window */ op = dist - op; /* distance back in window */
if (op > whave) { if (op > whave) {
if (state->sane) { if (state->sane) {
strm->msg = strm->msg = (z_const char *)
(char *)"invalid distance too far back"; "invalid distance too far back";
state->mode = BAD; state->mode = BAD;
break; break;
} }
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
if (len <= op - whave) { if (len <= op - whave) {
do { do {
PUP(out) = 0; *out++ = 0;
} while (--len); } while (--len);
continue; continue;
} }
len -= op - whave; len -= op - whave;
do { do {
PUP(out) = 0; *out++ = 0;
} while (--op > whave); } while (--op > whave);
if (op == 0) { if (op == 0) {
from = out - dist; from = out - dist;
do { do {
PUP(out) = PUP(from); *out++ = *from++;
} while (--len); } while (--len);
continue; continue;
} }
#endif #endif
} }
from = window - OFF; from = window;
if (wnext == 0) { /* very common case */ if (wnext == 0) { /* very common case */
from += wsize - op; from += wsize - op;
if (op < len) { /* some from window */ if (op < len) { /* some from window */
len -= op; len -= op;
do { do {
PUP(out) = PUP(from); *out++ = *from++;
} while (--op); } while (--op);
from = out - dist; /* rest from output */ from = out - dist; /* rest from output */
} }
@ -230,14 +211,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
if (op < len) { /* some from end of window */ if (op < len) { /* some from end of window */
len -= op; len -= op;
do { do {
PUP(out) = PUP(from); *out++ = *from++;
} while (--op); } while (--op);
from = window - OFF; from = window;
if (wnext < len) { /* some from start of window */ if (wnext < len) { /* some from start of window */
op = wnext; op = wnext;
len -= op; len -= op;
do { do {
PUP(out) = PUP(from); *out++ = *from++;
} while (--op); } while (--op);
from = out - dist; /* rest from output */ from = out - dist; /* rest from output */
} }
@ -248,50 +229,50 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
if (op < len) { /* some from window */ if (op < len) { /* some from window */
len -= op; len -= op;
do { do {
PUP(out) = PUP(from); *out++ = *from++;
} while (--op); } while (--op);
from = out - dist; /* rest from output */ from = out - dist; /* rest from output */
} }
} }
while (len > 2) { while (len > 2) {
PUP(out) = PUP(from); *out++ = *from++;
PUP(out) = PUP(from); *out++ = *from++;
PUP(out) = PUP(from); *out++ = *from++;
len -= 3; len -= 3;
} }
if (len) { if (len) {
PUP(out) = PUP(from); *out++ = *from++;
if (len > 1) if (len > 1)
PUP(out) = PUP(from); *out++ = *from++;
} }
} }
else { else {
from = out - dist; /* copy direct from output */ from = out - dist; /* copy direct from output */
do { /* minimum length is three */ do { /* minimum length is three */
PUP(out) = PUP(from); *out++ = *from++;
PUP(out) = PUP(from); *out++ = *from++;
PUP(out) = PUP(from); *out++ = *from++;
len -= 3; len -= 3;
} while (len > 2); } while (len > 2);
if (len) { if (len) {
PUP(out) = PUP(from); *out++ = *from++;
if (len > 1) if (len > 1)
PUP(out) = PUP(from); *out++ = *from++;
} }
} }
} }
else if ((op & 64) == 0) { /* 2nd level distance code */ else if ((op & 64) == 0) { /* 2nd level distance code */
here = dcode[here.val + (hold & ((1U << op) - 1))]; here = dcode + here->val + (hold & ((1U << op) - 1));
goto dodist; goto dodist;
} }
else { else {
strm->msg = (char *)"invalid distance code"; strm->msg = (z_const char *)"invalid distance code";
state->mode = BAD; state->mode = BAD;
break; break;
} }
} }
else if ((op & 64) == 0) { /* 2nd level length code */ else if ((op & 64) == 0) { /* 2nd level length code */
here = lcode[here.val + (hold & ((1U << op) - 1))]; here = lcode + here->val + (hold & ((1U << op) - 1));
goto dolen; goto dolen;
} }
else if (op & 32) { /* end-of-block */ else if (op & 32) { /* end-of-block */
@ -300,7 +281,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
break; break;
} }
else { else {
strm->msg = (char *)"invalid literal/length code"; strm->msg = (z_const char *)"invalid literal/length code";
state->mode = BAD; state->mode = BAD;
break; break;
} }
@ -313,8 +294,8 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
hold &= (1U << bits) - 1; hold &= (1U << bits) - 1;
/* update state and return */ /* update state and return */
strm->next_in = in + OFF; strm->next_in = in;
strm->next_out = out + OFF; strm->next_out = out;
strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
strm->avail_out = (unsigned)(out < end ? strm->avail_out = (unsigned)(out < end ?
257 + (end - out) : 257 - (out - end)); 257 + (end - out) : 257 - (out - end));

View file

@ -8,4 +8,4 @@
subject to change. Applications should only use zlib.h. subject to change. Applications should only use zlib.h.
*/ */
void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start);

View file

@ -1,94 +1,94 @@
/* inffixed.h -- table for decoding fixed codes /* inffixed.h -- table for decoding fixed codes
* Generated automatically by makefixed(). * Generated automatically by makefixed().
*/ */
/* WARNING: this file should *not* be used by applications. /* WARNING: this file should *not* be used by applications.
It is part of the implementation of this library and is It is part of the implementation of this library and is
subject to change. Applications should only use zlib.h. subject to change. Applications should only use zlib.h.
*/ */
static const code lenfix[512] = { static const code lenfix[512] = {
{96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
{0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
{0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
{0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
{0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
{21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
{0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
{0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
{18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
{0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
{0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
{0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
{20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
{0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
{0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
{16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
{0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
{0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
{0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
{0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
{0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
{0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
{0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
{17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
{0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
{0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
{0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
{19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
{0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
{0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
{16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
{0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
{0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
{0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
{0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
{20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
{0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
{0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
{17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
{0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
{0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
{0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
{20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
{0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
{0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
{0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
{16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
{0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
{0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
{0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
{0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
{0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
{0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
{0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
{16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
{0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
{0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
{0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
{19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
{0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
{0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
{16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
{0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
{0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
{0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
{0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
{64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
{0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
{0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
{18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
{0,9,255} {0,9,255}
}; };
static const code distfix[32] = { static const code distfix[32] = {
{16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
{21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
{18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
{19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
{16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
{22,5,193},{64,5,0} {22,5,193},{64,5,0}
}; };

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* inflate.h -- internal inflate state definition /* inflate.h -- internal inflate state definition
* Copyright (C) 1995-2009 Mark Adler * Copyright (C) 1995-2019 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -18,7 +18,7 @@
/* Possible inflate modes between inflate() calls */ /* Possible inflate modes between inflate() calls */
typedef enum { typedef enum {
HEAD, /* i: waiting for magic header */ HEAD = 16180, /* i: waiting for magic header */
FLAGS, /* i: waiting for method and flags (gzip) */ FLAGS, /* i: waiting for method and flags (gzip) */
TIME, /* i: waiting for modification time (gzip) */ TIME, /* i: waiting for modification time (gzip) */
OS, /* i: waiting for extra flags and operating system (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */
@ -77,13 +77,17 @@ typedef enum {
CHECK -> LENGTH -> DONE CHECK -> LENGTH -> DONE
*/ */
/* state maintained between inflate() calls. Approximately 10K bytes. */ /* State maintained between inflate() calls -- approximately 7K bytes, not
including the allocated sliding window, which is up to 32K bytes. */
struct inflate_state { struct inflate_state {
z_streamp strm; /* pointer back to this zlib stream */
inflate_mode mode; /* current inflate mode */ inflate_mode mode; /* current inflate mode */
int last; /* true if processing last block */ int last; /* true if processing last block */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip,
bit 2 true to validate check value */
int havedict; /* true if dictionary provided */ int havedict; /* true if dictionary provided */
int flags; /* gzip header method and flags (0 if zlib) */ int flags; /* gzip header method and flags, 0 if zlib, or
-1 if raw or no header yet */
unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
unsigned long check; /* protected copy of check value */ unsigned long check; /* protected copy of check value */
unsigned long total; /* protected copy of output count */ unsigned long total; /* protected copy of output count */
@ -96,7 +100,7 @@ struct inflate_state {
unsigned char FAR *window; /* allocated sliding window, if needed */ unsigned char FAR *window; /* allocated sliding window, if needed */
/* bit accumulator */ /* bit accumulator */
unsigned long hold; /* input bit accumulator */ unsigned long hold; /* input bit accumulator */
unsigned bits; /* number of bits in "in" */ unsigned bits; /* number of bits in hold */
/* for string and stored block copying */ /* for string and stored block copying */
unsigned length; /* literal or length of data to copy */ unsigned length; /* literal or length of data to copy */
unsigned offset; /* distance back to copy string from */ unsigned offset; /* distance back to copy string from */

View file

@ -1,15 +1,29 @@
/* inftrees.c -- generate Huffman trees for efficient decoding /* inftrees.c -- generate Huffman trees for efficient decoding
* Copyright (C) 1995-2013 Mark Adler * Copyright (C) 1995-2026 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
#ifdef MAKEFIXED
# ifndef BUILDFIXED
# define BUILDFIXED
# endif
#endif
#ifdef BUILDFIXED
# define Z_ONCE
#endif
#include "zutil.h" #include "zutil.h"
#include "inftrees.h" #include "inftrees.h"
#include "inflate.h"
#ifndef NULL
# define NULL 0
#endif
#define MAXBITS 15 #define MAXBITS 15
const char inflate_copyright[] = const char inflate_copyright[] =
" inflate 1.2.8 Copyright 1995-2013 Mark Adler "; " inflate 1.3.2.1 Copyright 1995-2026 Mark Adler ";
/* /*
If you use the zlib library in a product, an acknowledgment is welcome If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot in the documentation of your product. If for some reason you cannot
@ -29,14 +43,9 @@ const char inflate_copyright[] =
table index bits. It will differ if the request is greater than the table index bits. It will differ if the request is greater than the
longest code or if it is less than the shortest code. longest code or if it is less than the shortest code.
*/ */
int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
codetype type; unsigned codes, code FAR * FAR *table,
unsigned short FAR *lens; unsigned FAR *bits, unsigned short FAR *work) {
unsigned codes;
code FAR * FAR *table;
unsigned FAR *bits;
unsigned short FAR *work;
{
unsigned len; /* a code's length in bits */ unsigned len; /* a code's length in bits */
unsigned sym; /* index of code symbols */ unsigned sym; /* index of code symbols */
unsigned min, max; /* minimum and maximum code lengths */ unsigned min, max; /* minimum and maximum code lengths */
@ -52,9 +61,9 @@ unsigned short FAR *work;
unsigned mask; /* mask for low root bits */ unsigned mask; /* mask for low root bits */
code here; /* table entry for duplication */ code here; /* table entry for duplication */
code FAR *next; /* next available space in table */ code FAR *next; /* next available space in table */
const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *base = NULL; /* base value table to use */
const unsigned short FAR *extra; /* extra bits table to use */ const unsigned short FAR *extra = NULL; /* extra bits table to use */
int end; /* use base and extra for symbol > end */ unsigned match = 0; /* use base and extra for symbol >= match */
unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short count[MAXBITS+1]; /* number of codes of each length */
unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
static const unsigned short lbase[31] = { /* Length codes 257..285 base */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
@ -62,7 +71,7 @@ unsigned short FAR *work;
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
static const unsigned short lext[31] = { /* Length codes 257..285 extra */ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 68, 193};
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
@ -180,20 +189,16 @@ unsigned short FAR *work;
/* set up for code type */ /* set up for code type */
switch (type) { switch (type) {
case CODES: case CODES:
base = extra = work; /* dummy value--not used */ match = 20;
end = 19;
break; break;
case LENS: case LENS:
base = lbase; base = lbase;
base -= 257;
extra = lext; extra = lext;
extra -= 257; match = 257;
end = 256;
break; break;
default: /* DISTS */ case DISTS:
base = dbase; base = dbase;
extra = dext; extra = dext;
end = -1;
} }
/* initialize state for loop */ /* initialize state for loop */
@ -216,13 +221,13 @@ unsigned short FAR *work;
for (;;) { for (;;) {
/* create table entry */ /* create table entry */
here.bits = (unsigned char)(len - drop); here.bits = (unsigned char)(len - drop);
if ((int)(work[sym]) < end) { if (work[sym] + 1U < match) {
here.op = (unsigned char)0; here.op = (unsigned char)0;
here.val = work[sym]; here.val = work[sym];
} }
else if ((int)(work[sym]) > end) { else if (work[sym] >= match) {
here.op = (unsigned char)(extra[work[sym]]); here.op = (unsigned char)(extra[work[sym] - match]);
here.val = base[work[sym]]; here.val = base[work[sym] - match];
} }
else { else {
here.op = (unsigned char)(32 + 64); /* end of block */ here.op = (unsigned char)(32 + 64); /* end of block */
@ -304,3 +309,116 @@ unsigned short FAR *work;
*bits = root; *bits = root;
return 0; return 0;
} }
#ifdef BUILDFIXED
/*
If this is compiled with BUILDFIXED defined, and if inflate will be used in
multiple threads, and if atomics are not available, then inflate() must be
called with a fixed block (e.g. 0x03 0x00) to initialize the tables and must
return before any other threads are allowed to call inflate.
*/
static code *lenfix, *distfix;
static code fixed[544];
/* State for z_once(). */
local z_once_t built = Z_ONCE_INIT;
local void buildtables(void) {
unsigned sym, bits;
static code *next;
unsigned short lens[288], work[288];
/* literal/length table */
sym = 0;
while (sym < 144) lens[sym++] = 8;
while (sym < 256) lens[sym++] = 9;
while (sym < 280) lens[sym++] = 7;
while (sym < 288) lens[sym++] = 8;
next = fixed;
lenfix = next;
bits = 9;
inflate_table(LENS, lens, 288, &(next), &(bits), work);
/* distance table */
sym = 0;
while (sym < 32) lens[sym++] = 5;
distfix = next;
bits = 5;
inflate_table(DISTS, lens, 32, &(next), &(bits), work);
}
#else /* !BUILDFIXED */
# include "inffixed.h"
#endif /* BUILDFIXED */
/*
Return state with length and distance decoding tables and index sizes set to
fixed code decoding. Normally this returns fixed tables from inffixed.h.
If BUILDFIXED is defined, then instead this routine builds the tables the
first time it's called, and returns those tables the first time and
thereafter. This reduces the size of the code by about 2K bytes, in
exchange for a little execution time. However, BUILDFIXED should not be
used for threaded applications if atomics are not available, as it will
not be thread-safe.
*/
void inflate_fixed(struct inflate_state FAR *state) {
#ifdef BUILDFIXED
z_once(&built, buildtables);
#endif /* BUILDFIXED */
state->lencode = lenfix;
state->lenbits = 9;
state->distcode = distfix;
state->distbits = 5;
}
#ifdef MAKEFIXED
#include <stdio.h>
/*
Write out the inffixed.h that will be #include'd above. Defining MAKEFIXED
also defines BUILDFIXED, so the tables are built on the fly. main() writes
those tables to stdout, which would directed to inffixed.h. Compile this
along with zutil.c:
cc -DMAKEFIXED -o fix inftrees.c zutil.c
./fix > inffixed.h
*/
int main(void) {
unsigned low, size;
struct inflate_state state;
inflate_fixed(&state);
puts("/* inffixed.h -- table for decoding fixed codes");
puts(" * Generated automatically by makefixed().");
puts(" */");
puts("");
puts("/* WARNING: this file should *not* be used by applications.");
puts(" It is part of the implementation of this library and is");
puts(" subject to change. Applications should only use zlib.h.");
puts(" */");
puts("");
size = 1U << 9;
printf("static const code lenfix[%u] = {", size);
low = 0;
for (;;) {
if ((low % 7) == 0) printf("\n ");
printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
state.lencode[low].bits, state.lencode[low].val);
if (++low == size) break;
putchar(',');
}
puts("\n};");
size = 1U << 5;
printf("\nstatic const code distfix[%u] = {", size);
low = 0;
for (;;) {
if ((low % 6) == 0) printf("\n ");
printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
state.distcode[low].val);
if (++low == size) break;
putchar(',');
}
puts("\n};");
return 0;
}
#endif /* MAKEFIXED */

View file

@ -1,5 +1,5 @@
/* inftrees.h -- header to use inftrees.c /* inftrees.h -- header to use inftrees.c
* Copyright (C) 1995-2005, 2010 Mark Adler * Copyright (C) 1995-2026 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -38,11 +38,11 @@ typedef struct {
/* Maximum size of the dynamic table. The maximum number of code structures is /* Maximum size of the dynamic table. The maximum number of code structures is
1444, which is the sum of 852 for literal/length codes and 592 for distance 1444, which is the sum of 852 for literal/length codes and 592 for distance
codes. These values were found by exhaustive searches using the program codes. These values were found by exhaustive searches using the program
examples/enough.c found in the zlib distribtution. The arguments to that examples/enough.c found in the zlib distribution. The arguments to that
program are the number of symbols, the initial root table size, and the program are the number of symbols, the initial root table size, and the
maximum bit length of a code. "enough 286 9 15" for literal/length codes maximum bit length of a code. "enough 286 9 15" for literal/length codes
returns returns 852, and "enough 30 6 15" for distance codes returns 592. returns 852, and "enough 30 6 15" for distance codes returns 592. The
The initial root table size (9 or 6) is found in the fifth argument of the initial root table size (9 or 6) is found in the fifth argument of the
inflate_table() calls in inflate.c and infback.c. If the root table size is inflate_table() calls in inflate.c and infback.c. If the root table size is
changed, then these maximum sizes would be need to be recalculated and changed, then these maximum sizes would be need to be recalculated and
updated. */ updated. */
@ -57,6 +57,8 @@ typedef enum {
DISTS DISTS
} codetype; } codetype;
int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
unsigned codes, code FAR * FAR *table, unsigned codes, code FAR * FAR *table,
unsigned FAR *bits, unsigned short FAR *work)); unsigned FAR *bits, unsigned short FAR *work);
struct inflate_state;
void ZLIB_INTERNAL inflate_fixed(struct inflate_state FAR *state);

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* uncompr.c -- decompress a memory buffer /* uncompr.c -- decompress a memory buffer
* Copyright (C) 1995-2003, 2010 Jean-loup Gailly. * Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -9,51 +9,93 @@
#include "zlib.h" #include "zlib.h"
/* =========================================================================== /* ===========================================================================
Decompresses the source buffer into the destination buffer. sourceLen is Decompresses the source buffer into the destination buffer. *sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total the byte length of the source buffer. Upon entry, *destLen is the total size
size of the destination buffer, which must be large enough to hold the of the destination buffer, which must be large enough to hold the entire
entire uncompressed data. (The size of the uncompressed data must have uncompressed data. (The size of the uncompressed data must have been saved
been saved previously by the compressor and transmitted to the decompressor previously by the compressor and transmitted to the decompressor by some
by some mechanism outside the scope of this compression library.) mechanism outside the scope of this compression library.) Upon exit,
Upon exit, destLen is the actual size of the compressed buffer. *destLen is the size of the decompressed data and *sourceLen is the number
of source bytes consumed. Upon return, source + *sourceLen points to the
first unused input byte.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough
enough memory, Z_BUF_ERROR if there was not enough room in the output memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
buffer, or Z_DATA_ERROR if the input data was corrupted. Z_DATA_ERROR if the input data was corrupted, including if the input data is
an incomplete zlib stream.
The _z versions of the functions take size_t length arguments.
*/ */
int ZEXPORT uncompress (dest, destLen, source, sourceLen) int ZEXPORT uncompress2_z(Bytef *dest, z_size_t *destLen, const Bytef *source,
Bytef *dest; z_size_t *sourceLen) {
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
{
z_stream stream; z_stream stream;
int err; int err;
const uInt max = (uInt)-1;
z_size_t len, left;
if (sourceLen == NULL || (*sourceLen > 0 && source == NULL) ||
destLen == NULL || (*destLen > 0 && dest == NULL))
return Z_STREAM_ERROR;
len = *sourceLen;
left = *destLen;
if (left == 0 && dest == Z_NULL)
dest = (Bytef *)&stream.reserved; /* next_out cannot be NULL */
stream.next_in = (z_const Bytef *)source; stream.next_in = (z_const Bytef *)source;
stream.avail_in = (uInt)sourceLen; stream.avail_in = 0;
/* Check for source > 64K on 16-bit machine: */
if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
stream.next_out = dest;
stream.avail_out = (uInt)*destLen;
if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
stream.zalloc = (alloc_func)0; stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0; stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = inflateInit(&stream); err = inflateInit(&stream);
if (err != Z_OK) return err; if (err != Z_OK) return err;
err = inflate(&stream, Z_FINISH); stream.next_out = dest;
if (err != Z_STREAM_END) { stream.avail_out = 0;
inflateEnd(&stream);
if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
return Z_DATA_ERROR;
return err;
}
*destLen = stream.total_out;
err = inflateEnd(&stream); do {
return err; if (stream.avail_out == 0) {
stream.avail_out = left > (z_size_t)max ? max : (uInt)left;
left -= stream.avail_out;
}
if (stream.avail_in == 0) {
stream.avail_in = len > (z_size_t)max ? max : (uInt)len;
len -= stream.avail_in;
}
err = inflate(&stream, Z_NO_FLUSH);
} while (err == Z_OK);
/* Set len and left to the unused input data and unused output space. Set
*sourceLen to the amount of input consumed. Set *destLen to the amount
of data produced. */
len += stream.avail_in;
left += stream.avail_out;
*sourceLen -= len;
*destLen -= left;
inflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK :
err == Z_NEED_DICT ? Z_DATA_ERROR :
err == Z_BUF_ERROR && len == 0 ? Z_DATA_ERROR :
err;
}
int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong *sourceLen) {
int ret;
z_size_t got = *destLen, used = *sourceLen;
ret = uncompress2_z(dest, &got, source, &used);
*sourceLen = (uLong)used;
*destLen = (uLong)got;
return ret;
}
int ZEXPORT uncompress_z(Bytef *dest, z_size_t *destLen, const Bytef *source,
z_size_t sourceLen) {
z_size_t used = sourceLen;
return uncompress2_z(dest, destLen, source, &used);
}
int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen) {
uLong used = sourceLen;
return uncompress2(dest, destLen, source, &used);
} }

View file

@ -1,5 +1,5 @@
/* zconf.h -- configuration of the zlib compression library /* zconf.h -- configuration of the zlib compression library
* Copyright (C) 1995-2013 Jean-loup Gailly. * Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -17,7 +17,7 @@
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
# define Z_PREFIX_SET # define Z_PREFIX_SET
/* all linked symbols */ /* all linked symbols and init macros */
# define _dist_code z__dist_code # define _dist_code z__dist_code
# define _length_code z__length_code # define _length_code z__length_code
# define _tr_align z__tr_align # define _tr_align z__tr_align
@ -29,18 +29,30 @@
# define adler32 z_adler32 # define adler32 z_adler32
# define adler32_combine z_adler32_combine # define adler32_combine z_adler32_combine
# define adler32_combine64 z_adler32_combine64 # define adler32_combine64 z_adler32_combine64
# define adler32_z z_adler32_z
# ifndef Z_SOLO # ifndef Z_SOLO
# define compress z_compress # define compress z_compress
# define compress2 z_compress2 # define compress2 z_compress2
# define compress_z z_compress_z
# define compress2_z z_compress2_z
# define compressBound z_compressBound # define compressBound z_compressBound
# define compressBound_z z_compressBound_z
# endif # endif
# define crc32 z_crc32 # define crc32 z_crc32
# define crc32_combine z_crc32_combine # define crc32_combine z_crc32_combine
# define crc32_combine64 z_crc32_combine64 # define crc32_combine64 z_crc32_combine64
# define crc32_combine_gen z_crc32_combine_gen
# define crc32_combine_gen64 z_crc32_combine_gen64
# define crc32_combine_op z_crc32_combine_op
# define crc32_z z_crc32_z
# define deflate z_deflate # define deflate z_deflate
# define deflateBound z_deflateBound # define deflateBound z_deflateBound
# define deflateBound_z z_deflateBound_z
# define deflateCopy z_deflateCopy # define deflateCopy z_deflateCopy
# define deflateEnd z_deflateEnd # define deflateEnd z_deflateEnd
# define deflateGetDictionary z_deflateGetDictionary
# define deflateInit z_deflateInit
# define deflateInit2 z_deflateInit2
# define deflateInit2_ z_deflateInit2_ # define deflateInit2_ z_deflateInit2_
# define deflateInit_ z_deflateInit_ # define deflateInit_ z_deflateInit_
# define deflateParams z_deflateParams # define deflateParams z_deflateParams
@ -51,6 +63,7 @@
# define deflateSetDictionary z_deflateSetDictionary # define deflateSetDictionary z_deflateSetDictionary
# define deflateSetHeader z_deflateSetHeader # define deflateSetHeader z_deflateSetHeader
# define deflateTune z_deflateTune # define deflateTune z_deflateTune
# define deflateUsed z_deflateUsed
# define deflate_copyright z_deflate_copyright # define deflate_copyright z_deflate_copyright
# define get_crc_table z_get_crc_table # define get_crc_table z_get_crc_table
# ifndef Z_SOLO # ifndef Z_SOLO
@ -67,6 +80,8 @@
# define gzeof z_gzeof # define gzeof z_gzeof
# define gzerror z_gzerror # define gzerror z_gzerror
# define gzflush z_gzflush # define gzflush z_gzflush
# define gzfread z_gzfread
# define gzfwrite z_gzfwrite
# define gzgetc z_gzgetc # define gzgetc z_gzgetc
# define gzgetc_ z_gzgetc_ # define gzgetc_ z_gzgetc_
# define gzgets z_gzgets # define gzgets z_gzgets
@ -78,7 +93,6 @@
# define gzopen_w z_gzopen_w # define gzopen_w z_gzopen_w
# endif # endif
# define gzprintf z_gzprintf # define gzprintf z_gzprintf
# define gzvprintf z_gzvprintf
# define gzputc z_gzputc # define gzputc z_gzputc
# define gzputs z_gzputs # define gzputs z_gzputs
# define gzread z_gzread # define gzread z_gzread
@ -89,32 +103,42 @@
# define gztell z_gztell # define gztell z_gztell
# define gztell64 z_gztell64 # define gztell64 z_gztell64
# define gzungetc z_gzungetc # define gzungetc z_gzungetc
# define gzvprintf z_gzvprintf
# define gzwrite z_gzwrite # define gzwrite z_gzwrite
# endif # endif
# define inflate z_inflate # define inflate z_inflate
# define inflateBack z_inflateBack # define inflateBack z_inflateBack
# define inflateBackEnd z_inflateBackEnd # define inflateBackEnd z_inflateBackEnd
# define inflateBackInit z_inflateBackInit
# define inflateBackInit_ z_inflateBackInit_ # define inflateBackInit_ z_inflateBackInit_
# define inflateCodesUsed z_inflateCodesUsed
# define inflateCopy z_inflateCopy # define inflateCopy z_inflateCopy
# define inflateEnd z_inflateEnd # define inflateEnd z_inflateEnd
# define inflateGetDictionary z_inflateGetDictionary
# define inflateGetHeader z_inflateGetHeader # define inflateGetHeader z_inflateGetHeader
# define inflateInit z_inflateInit
# define inflateInit2 z_inflateInit2
# define inflateInit2_ z_inflateInit2_ # define inflateInit2_ z_inflateInit2_
# define inflateInit_ z_inflateInit_ # define inflateInit_ z_inflateInit_
# define inflateMark z_inflateMark # define inflateMark z_inflateMark
# define inflatePrime z_inflatePrime # define inflatePrime z_inflatePrime
# define inflateReset z_inflateReset # define inflateReset z_inflateReset
# define inflateReset2 z_inflateReset2 # define inflateReset2 z_inflateReset2
# define inflateResetKeep z_inflateResetKeep
# define inflateSetDictionary z_inflateSetDictionary # define inflateSetDictionary z_inflateSetDictionary
# define inflateGetDictionary z_inflateGetDictionary
# define inflateSync z_inflateSync # define inflateSync z_inflateSync
# define inflateSyncPoint z_inflateSyncPoint # define inflateSyncPoint z_inflateSyncPoint
# define inflateUndermine z_inflateUndermine # define inflateUndermine z_inflateUndermine
# define inflateResetKeep z_inflateResetKeep # define inflateValidate z_inflateValidate
# define inflate_copyright z_inflate_copyright # define inflate_copyright z_inflate_copyright
# define inflate_fast z_inflate_fast # define inflate_fast z_inflate_fast
# define inflate_table z_inflate_table # define inflate_table z_inflate_table
# define inflate_fixed z_inflate_fixed
# ifndef Z_SOLO # ifndef Z_SOLO
# define uncompress z_uncompress # define uncompress z_uncompress
# define uncompress2 z_uncompress2
# define uncompress_z z_uncompress_z
# define uncompress2_z z_uncompress2_z
# endif # endif
# define zError z_zError # define zError z_zError
# ifndef Z_SOLO # ifndef Z_SOLO
@ -218,15 +242,31 @@
# endif # endif
#endif #endif
#if defined(ZLIB_CONST) && !defined(z_const) #ifndef z_const
# define z_const const # ifdef ZLIB_CONST
#else # define z_const const
# define z_const # else
# define z_const
# endif
#endif #endif
/* Some Mac compilers merge all .h files incorrectly: */ #ifdef Z_SOLO
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) # ifdef _WIN64
# define NO_DUMMY_DECL typedef unsigned long long z_size_t;
# else
typedef unsigned long z_size_t;
# endif
#else
# define z_longlong long long
# if defined(NO_SIZE_T)
typedef unsigned NO_SIZE_T z_size_t;
# elif defined(STDC)
# include <stddef.h>
typedef size_t z_size_t;
# else
typedef unsigned long z_size_t;
# endif
# undef z_longlong
#endif #endif
/* Maximum value for memLevel in deflateInit2 */ /* Maximum value for memLevel in deflateInit2 */
@ -256,7 +296,7 @@
Of course this will generally degrade compression (there's no free lunch). Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits The memory requirements for inflate are (in bytes) 1 << windowBits
that is, 32K for windowBits=15 (default value) plus a few kilobytes that is, 32K for windowBits=15 (default value) plus about 7 kilobytes
for small objects. for small objects.
*/ */
@ -270,14 +310,6 @@
# endif # endif
#endif #endif
#ifndef Z_ARG /* function prototypes for stdarg */
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
# define Z_ARG(args) args
# else
# define Z_ARG(args) ()
# endif
#endif
/* The following definitions for FAR are needed only for MSDOS mixed /* The following definitions for FAR are needed only for MSDOS mixed
* model programming (small or medium model with some far allocations). * model programming (small or medium model with some far allocations).
* This was tested only with MSC; for other MSDOS compilers you may have * This was tested only with MSC; for other MSDOS compilers you may have
@ -326,6 +358,9 @@
# ifdef FAR # ifdef FAR
# undef FAR # undef FAR
# endif # endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h> # include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */ /* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
@ -408,11 +443,11 @@ typedef uLong FAR uLongf;
typedef unsigned long z_crc_t; typedef unsigned long z_crc_t;
#endif #endif
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ #if HAVE_UNISTD_H-0 /* may be set to #if 1 by ./configure */
# define Z_HAVE_UNISTD_H # define Z_HAVE_UNISTD_H
#endif #endif
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ #if HAVE_STDARG_H-0 /* may be set to #if 1 by ./configure */
# define Z_HAVE_STDARG_H # define Z_HAVE_STDARG_H
#endif #endif
@ -444,11 +479,14 @@ typedef uLong FAR uLongf;
# undef _LARGEFILE64_SOURCE # undef _LARGEFILE64_SOURCE
#endif #endif
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) #ifndef Z_HAVE_UNISTD_H
# define Z_HAVE_UNISTD_H # if defined(__WATCOMC__) || defined(__GO32__) || \
(defined(_LARGEFILE64_SOURCE) && !defined(_WIN32))
# define Z_HAVE_UNISTD_H
# endif
#endif #endif
#ifndef Z_SOLO #ifndef Z_SOLO
# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # if defined(Z_HAVE_UNISTD_H)
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
# ifdef VMS # ifdef VMS
# include <unixio.h> /* for off_t */ # include <unixio.h> /* for off_t */
@ -478,17 +516,19 @@ typedef uLong FAR uLongf;
#endif #endif
#ifndef z_off_t #ifndef z_off_t
# define z_off_t long # define z_off_t long long
#endif #endif
#if !defined(_WIN32) && defined(Z_LARGE64) #if !defined(_WIN32) && defined(Z_LARGE64)
# define z_off64_t off64_t # define z_off64_t off64_t
#elif defined(__MINGW32__)
# define z_off64_t long long
#elif defined(_WIN32) && !defined(__GNUC__)
# define z_off64_t __int64
#elif defined(__GO32__)
# define z_off64_t offset_t
#else #else
# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) # define z_off64_t z_off_t
# define z_off64_t long long
# else
# define z_off64_t z_off_t
# endif
#endif #endif
/* MVS linker does not support external names larger than 8 bytes */ /* MVS linker does not support external names larger than 8 bytes */

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* zutil.c -- target dependent utility functions for the compression library /* zutil.c -- target dependent utility functions for the compression library
* Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. * Copyright (C) 1995-2026 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -10,30 +10,25 @@
# include "gzguts.h" # include "gzguts.h"
#endif #endif
#ifndef NO_DUMMY_DECL
struct internal_state {int dummy;}; /* for buggy compilers */
#endif
z_const char * const z_errmsg[10] = { z_const char * const z_errmsg[10] = {
"need dictionary", /* Z_NEED_DICT 2 */ (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */
"stream end", /* Z_STREAM_END 1 */ (z_const char *)"stream end", /* Z_STREAM_END 1 */
"", /* Z_OK 0 */ (z_const char *)"", /* Z_OK 0 */
"file error", /* Z_ERRNO (-1) */ (z_const char *)"file error", /* Z_ERRNO (-1) */
"stream error", /* Z_STREAM_ERROR (-2) */ (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */
"data error", /* Z_DATA_ERROR (-3) */ (z_const char *)"data error", /* Z_DATA_ERROR (-3) */
"insufficient memory", /* Z_MEM_ERROR (-4) */ (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */
"buffer error", /* Z_BUF_ERROR (-5) */ (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */
"incompatible version",/* Z_VERSION_ERROR (-6) */ (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */
""}; (z_const char *)""
};
const char * ZEXPORT zlibVersion() const char * ZEXPORT zlibVersion(void) {
{
return ZLIB_VERSION; return ZLIB_VERSION;
} }
uLong ZEXPORT zlibCompileFlags() uLong ZEXPORT zlibCompileFlags(void) {
{
uLong flags; uLong flags;
flags = 0; flags = 0;
@ -61,12 +56,14 @@ uLong ZEXPORT zlibCompileFlags()
case 8: flags += 2 << 6; break; case 8: flags += 2 << 6; break;
default: flags += 3 << 6; default: flags += 3 << 6;
} }
#ifdef DEBUG #ifdef ZLIB_DEBUG
flags += 1 << 8; flags += 1 << 8;
#endif #endif
/*
#if defined(ASMV) || defined(ASMINF) #if defined(ASMV) || defined(ASMINF)
flags += 1 << 9; flags += 1 << 9;
#endif #endif
*/
#ifdef ZLIB_WINAPI #ifdef ZLIB_WINAPI
flags += 1 << 10; flags += 1 << 10;
#endif #endif
@ -89,42 +86,48 @@ uLong ZEXPORT zlibCompileFlags()
flags += 1L << 21; flags += 1L << 21;
#endif #endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H) #if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifdef NO_vsnprintf # ifdef NO_vsnprintf
flags += 1L << 25; # ifdef ZLIB_INSECURE
# ifdef HAS_vsprintf_void flags += 1L << 25;
flags += 1L << 26; # else
# endif flags += 1L << 27;
# else # endif
# ifdef HAS_vsnprintf_void # ifdef HAS_vsprintf_void
flags += 1L << 26; flags += 1L << 26;
# endif # endif
# endif # else
# ifdef HAS_vsnprintf_void
flags += 1L << 26;
# endif
# endif
#else #else
flags += 1L << 24; flags += 1L << 24;
# ifdef NO_snprintf # ifdef NO_snprintf
flags += 1L << 25; # ifdef ZLIB_INSECURE
# ifdef HAS_sprintf_void flags += 1L << 25;
flags += 1L << 26; # else
# endif flags += 1L << 27;
# else # endif
# ifdef HAS_snprintf_void # ifdef HAS_sprintf_void
flags += 1L << 26; flags += 1L << 26;
# endif # endif
# endif # else
# ifdef HAS_snprintf_void
flags += 1L << 26;
# endif
# endif
#endif #endif
return flags; return flags;
} }
#ifdef DEBUG #ifdef ZLIB_DEBUG
#include <stdlib.h>
# ifndef verbose # ifndef verbose
# define verbose 0 # define verbose 0
# endif # endif
int ZLIB_INTERNAL z_verbose = verbose; int ZLIB_INTERNAL z_verbose = verbose;
void ZLIB_INTERNAL z_error (m) void ZLIB_INTERNAL z_error(char *m) {
char *m;
{
fprintf(stderr, "%s\n", m); fprintf(stderr, "%s\n", m);
exit(1); exit(1);
} }
@ -133,14 +136,12 @@ void ZLIB_INTERNAL z_error (m)
/* exported to allow conversion of error code to string for compress() and /* exported to allow conversion of error code to string for compress() and
* uncompress() * uncompress()
*/ */
const char * ZEXPORT zError(err) const char * ZEXPORT zError(int err) {
int err;
{
return ERR_MSG(err); return ERR_MSG(err);
} }
#if defined(_WIN32_WCE) #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800
/* The Microsoft C Run-Time Library for Windows CE doesn't have /* The older Microsoft C Run-Time Library for Windows CE doesn't have
* errno. We define it as a global variable to simplify porting. * errno. We define it as a global variable to simplify porting.
* Its value is always 0 and should not be used. * Its value is always 0 and should not be used.
*/ */
@ -149,39 +150,33 @@ const char * ZEXPORT zError(err)
#ifndef HAVE_MEMCPY #ifndef HAVE_MEMCPY
void ZLIB_INTERNAL zmemcpy(dest, source, len) void ZLIB_INTERNAL zmemcpy(void FAR *dst, const void FAR *src, z_size_t n) {
Bytef* dest; uchf *p = dst;
const Bytef* source; const uchf *q = src;
uInt len; while (n) {
{ *p++ = *q++;
if (len == 0) return; n--;
do { }
*dest++ = *source++; /* ??? to be unrolled */
} while (--len != 0);
} }
int ZLIB_INTERNAL zmemcmp(s1, s2, len) int ZLIB_INTERNAL zmemcmp(const void FAR *s1, const void FAR *s2, z_size_t n) {
const Bytef* s1; const uchf *p = s1, *q = s2;
const Bytef* s2; while (n) {
uInt len; if (*p++ != *q++)
{ return (int)p[-1] - (int)q[-1];
uInt j; n--;
for (j = 0; j < len; j++) {
if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
} }
return 0; return 0;
} }
void ZLIB_INTERNAL zmemzero(dest, len) void ZLIB_INTERNAL zmemzero(void FAR *b, z_size_t len) {
Bytef* dest; uchf *p = b;
uInt len; while (len) {
{ *p++ = 0;
if (len == 0) return; len--;
do { }
*dest++ = 0; /* ??? to be unrolled */
} while (--len != 0);
} }
#endif #endif
#ifndef Z_SOLO #ifndef Z_SOLO
@ -217,11 +212,12 @@ local ptr_table table[MAX_PTR];
* a protected system like OS/2. Use Microsoft C instead. * a protected system like OS/2. Use Microsoft C instead.
*/ */
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
{ voidpf buf;
voidpf buf = opaque; /* just to make some compilers happy */
ulg bsize = (ulg)items*size; ulg bsize = (ulg)items*size;
(void)opaque;
/* If we allocate less than 65520 bytes, we assume that farmalloc /* If we allocate less than 65520 bytes, we assume that farmalloc
* will return a usable pointer which doesn't have to be normalized. * will return a usable pointer which doesn't have to be normalized.
*/ */
@ -241,9 +237,11 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
return buf; return buf;
} }
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
{
int n; int n;
(void)opaque;
if (*(ush*)&ptr != 0) { /* object < 64K */ if (*(ush*)&ptr != 0) { /* object < 64K */
farfree(ptr); farfree(ptr);
return; return;
@ -259,7 +257,6 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
next_ptr--; next_ptr--;
return; return;
} }
ptr = opaque; /* just to make some compilers happy */
Assert(0, "zcfree: ptr not found"); Assert(0, "zcfree: ptr not found");
} }
@ -276,15 +273,13 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
# define _hfree hfree # define _hfree hfree
#endif #endif
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) {
{ (void)opaque;
if (opaque) opaque = 0; /* to make compiler happy */
return _halloc((long)items, size); return _halloc((long)items, size);
} }
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
{ (void)opaque;
if (opaque) opaque = 0; /* to make compiler happy */
_hfree(ptr); _hfree(ptr);
} }
@ -296,27 +291,20 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
#ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */
#ifndef STDC #ifndef STDC
extern voidp malloc OF((uInt size)); extern voidp malloc(uInt size);
extern voidp calloc OF((uInt items, uInt size)); extern voidp calloc(uInt items, uInt size);
extern void free OF((voidpf ptr)); extern void free(voidpf ptr);
#endif #endif
voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
voidpf opaque; (void)opaque;
unsigned items;
unsigned size;
{
if (opaque) items += size - size; /* make compiler happy */
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
(voidpf)calloc(items, size); (voidpf)calloc(items, size);
} }
void ZLIB_INTERNAL zcfree (opaque, ptr) void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
voidpf opaque; (void)opaque;
voidpf ptr;
{
free(ptr); free(ptr);
if (opaque) return; /* make compiler happy */
} }
#endif /* MY_ZCALLOC */ #endif /* MY_ZCALLOC */

View file

@ -1,5 +1,5 @@
/* zutil.h -- internal interface and configuration of the compression library /* zutil.h -- internal interface and configuration of the compression library
* Copyright (C) 1995-2013 Jean-loup Gailly. * Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
@ -29,14 +29,16 @@
# include <stdlib.h> # include <stdlib.h>
#endif #endif
#ifdef Z_SOLO
typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */
#endif
#ifndef local #ifndef local
# define local static # define local static
#endif #endif
/* compile with -Dlocal if your debugger can't find static symbols */ /* since "static" is used to mean two completely different things in C, we
define "local" for the non-static meaning of "static", for readability
(compile with -Dlocal if your debugger can't find static symbols) */
extern const char deflate_copyright[];
extern const char inflate_copyright[];
extern const char inflate9_copyright[];
typedef unsigned char uch; typedef unsigned char uch;
typedef uch FAR uchf; typedef uch FAR uchf;
@ -44,17 +46,32 @@ typedef unsigned short ush;
typedef ush FAR ushf; typedef ush FAR ushf;
typedef unsigned long ulg; typedef unsigned long ulg;
#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC)
# include <limits.h>
# if (ULONG_MAX == 0xffffffffffffffff)
# define Z_U8 unsigned long
# elif (ULLONG_MAX == 0xffffffffffffffff)
# define Z_U8 unsigned long long
# elif (ULONG_LONG_MAX == 0xffffffffffffffff)
# define Z_U8 unsigned long long
# elif (UINT_MAX == 0xffffffffffffffff)
# define Z_U8 unsigned
# endif
#endif
extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* (size given to avoid silly warnings with Visual C++) */ /* (size given to avoid silly warnings with Visual C++) */
#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)]
#define ERR_RETURN(strm,err) \ #define ERR_RETURN(strm,err) \
return (strm->msg = ERR_MSG(err), (err)) return (strm->msg = ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */ /* To be used only when the state is known to be valid */
/* common constants */ /* common constants */
#if MAX_WBITS < 9 || MAX_WBITS > 15
# error MAX_WBITS must be in 9..15
#endif
#ifndef DEF_WBITS #ifndef DEF_WBITS
# define DEF_WBITS MAX_WBITS # define DEF_WBITS MAX_WBITS
#endif #endif
@ -98,67 +115,58 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#endif #endif
#ifdef AMIGA #ifdef AMIGA
# define OS_CODE 0x01 # define OS_CODE 1
#endif #endif
#if defined(VAXC) || defined(VMS) #if defined(VAXC) || defined(VMS)
# define OS_CODE 0x02 # define OS_CODE 2
# define F_OPEN(name, mode) \ # define F_OPEN(name, mode) \
fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif #endif
#ifdef __370__
# if __TARGET_LIB__ < 0x20000000
# define OS_CODE 4
# elif __TARGET_LIB__ < 0x40000000
# define OS_CODE 11
# else
# define OS_CODE 8
# endif
#endif
#if defined(ATARI) || defined(atarist) #if defined(ATARI) || defined(atarist)
# define OS_CODE 0x05 # define OS_CODE 5
#endif #endif
#ifdef OS2 #ifdef OS2
# define OS_CODE 0x06 # define OS_CODE 6
# if defined(M_I86) && !defined(Z_SOLO) # if defined(M_I86) && !defined(Z_SOLO)
# include <malloc.h> # include <malloc.h>
# endif # endif
#endif #endif
#if defined(MACOS) || defined(TARGET_OS_MAC) #if defined(MACOS)
# define OS_CODE 0x07 # define OS_CODE 7
# ifndef Z_SOLO
# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
# include <unix.h> /* for fdopen */
# else
# ifndef fdopen
# define fdopen(fd,mode) NULL /* No fdopen() */
# endif
# endif
# endif
#endif #endif
#ifdef TOPS20 #if defined(__acorn) || defined(__riscos)
# define OS_CODE 0x0a # define OS_CODE 13
#endif #endif
#ifdef WIN32 #if defined(WIN32) && !defined(__CYGWIN__)
# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ # define OS_CODE 10
# define OS_CODE 0x0b
# endif
#endif #endif
#ifdef __50SERIES /* Prime/PRIMOS */ #ifdef _BEOS_
# define OS_CODE 0x0f # define OS_CODE 16
#endif #endif
#if defined(_BEOS_) || defined(RISCOS) #ifdef __TOS_OS400__
# define fdopen(fd,mode) NULL /* No fdopen() */ # define OS_CODE 18
#endif #endif
#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX #ifdef __APPLE__
# if defined(_WIN32_WCE) # define OS_CODE 19
# define fdopen(fd,mode) NULL /* No fdopen() */
# ifndef _PTRDIFF_T_DEFINED
typedef int ptrdiff_t;
# define _PTRDIFF_T_DEFINED
# endif
# else
# define fdopen(fd,type) _fdopen(fd,type)
# endif
#endif #endif
#if defined(__BORLANDC__) && !defined(MSDOS) #if defined(__BORLANDC__) && !defined(MSDOS)
@ -168,16 +176,16 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#endif #endif
/* provide prototypes for these when building zlib without LFS */ /* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) && \ #ifndef Z_LARGE64
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
#endif #endif
/* common defaults */ /* common defaults */
#ifndef OS_CODE #ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */ # define OS_CODE 3 /* assume Unix */
#endif #endif
#ifndef F_OPEN #ifndef F_OPEN
@ -210,16 +218,16 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# define zmemzero(dest, len) memset(dest, 0, len) # define zmemzero(dest, len) memset(dest, 0, len)
# endif # endif
#else #else
void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); void ZLIB_INTERNAL zmemcpy(void FAR *, const void FAR *, z_size_t);
int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); int ZLIB_INTERNAL zmemcmp(const void FAR *, const void FAR *, z_size_t);
void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); void ZLIB_INTERNAL zmemzero(void FAR *, z_size_t);
#endif #endif
/* Diagnostic functions */ /* Diagnostic functions */
#ifdef DEBUG #ifdef ZLIB_DEBUG
# include <stdio.h> # include <stdio.h>
extern int ZLIB_INTERNAL z_verbose; extern int ZLIB_INTERNAL z_verbose;
extern void ZLIB_INTERNAL z_error OF((char *m)); extern void ZLIB_INTERNAL z_error(char *m);
# define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Assert(cond,msg) {if(!(cond)) z_error(msg);}
# define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Trace(x) {if (z_verbose>=0) fprintf x ;}
# define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;}
@ -236,9 +244,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#endif #endif
#ifndef Z_SOLO #ifndef Z_SOLO
voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items,
unsigned size)); unsigned size);
void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr);
#endif #endif
#define ZALLOC(strm, items, size) \ #define ZALLOC(strm, items, size) \
@ -250,4 +258,74 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
(((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
#ifdef Z_ONCE
/*
Create a local z_once() function depending on the availability of atomics.
*/
/* Check for the availability of atomics. */
#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \
!defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
typedef struct {
atomic_flag begun;
atomic_int done;
} z_once_t;
#define Z_ONCE_INIT {ATOMIC_FLAG_INIT, 0}
/*
Run the provided init() function exactly once, even if multiple threads
invoke once() at the same time. The state must be a once_t initialized with
Z_ONCE_INIT.
*/
local void z_once(z_once_t *state, void (*init)(void)) {
if (!atomic_load(&state->done)) {
if (atomic_flag_test_and_set(&state->begun))
while (!atomic_load(&state->done))
;
else {
init();
atomic_store(&state->done, 1);
}
}
}
#else /* no atomics */
#warning zlib not thread-safe
typedef struct z_once_s {
volatile int begun;
volatile int done;
} z_once_t;
#define Z_ONCE_INIT {0, 0}
/* Test and set. Alas, not atomic, but tries to limit the period of
vulnerability. */
local int test_and_set(int volatile *flag) {
int was;
was = *flag;
*flag = 1;
return was;
}
/* Run the provided init() function once. This is not thread-safe. */
local void z_once(z_once_t *state, void (*init)(void)) {
if (!state->done) {
if (test_and_set(&state->begun))
while (!state->done)
;
else {
init();
state->done = 1;
}
}
}
#endif /* ?atomics */
#endif /* Z_ONCE */
#endif /* ZUTIL_H */ #endif /* ZUTIL_H */

View file

@ -2,7 +2,7 @@
class Chunk; class Chunk;
class Mob; class Mob;
class DirtyChunkSorter : public std::binary_function<const Chunk *,const Chunk *,bool> class DirtyChunkSorter
{ {
private: private:
shared_ptr<LivingEntity> cameraEntity; shared_ptr<LivingEntity> cameraEntity;

View file

@ -2,7 +2,7 @@
class Entity; class Entity;
class Chunk; class Chunk;
class DistanceChunkSorter : public std::binary_function<const Chunk *,const Chunk *,bool> class DistanceChunkSorter
{ {
private: private:
double ix, iy, iz; double ix, iy, iz;

View file

@ -27,6 +27,7 @@
#include "Leaderboards\DurangoLeaderboardManager.h" #include "Leaderboards\DurangoLeaderboardManager.h"
#include "..\..\Minecraft.Client\Tesselator.h" #include "..\..\Minecraft.Client\Tesselator.h"
#include "..\..\Minecraft.Client\Options.h" #include "..\..\Minecraft.Client\Options.h"
#include "..\GameRenderer.h"
#include "Sentient\SentientManager.h" #include "Sentient\SentientManager.h"
#include "..\..\Minecraft.World\IntCache.h" #include "..\..\Minecraft.World\IntCache.h"
#include "..\Textures.h" #include "..\Textures.h"
@ -832,6 +833,9 @@ void oldWinMainTick()
#endif #endif
ui.tick(); ui.tick();
ui.render(); ui.render();
pMinecraft->gameRenderer->ApplyGammaPostProcess();
#if 0 #if 0
app.HandleButtonPresses(); app.HandleButtonPresses();

View file

@ -234,6 +234,7 @@ void EntityRenderDispatcher::prepare(Level *level, Textures *textures, Font *fon
if (pl->ThirdPersonView() == 2) if (pl->ThirdPersonView() == 2)
{ {
playerRotY += 180; playerRotY += 180;
playerRotX = -playerRotX;
} }
xPlayer = player->xOld + (player->x - player->xOld) * a; xPlayer = player->xOld + (player->x - player->xOld) * a;

View file

@ -69,10 +69,10 @@ void XShowAchievementsUI(int i) {}
DWORD XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE Mode) { return 0; } DWORD XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE Mode) { return 0; }
#ifndef _DURANGO #ifndef _DURANGO
void PIXAddNamedCounter(int a, char* b, ...) {} void PIXAddNamedCounter(int a, const char* b, ...) {}
//#define PS3_USE_PIX_EVENTS //#define PS3_USE_PIX_EVENTS
//#define PS4_USE_PIX_EVENTS //#define PS4_USE_PIX_EVENTS
void PIXBeginNamedEvent(int a, char* b, ...) void PIXBeginNamedEvent(int a, const char* b, ...)
{ {
#ifdef PS4_USE_PIX_EVENTS #ifdef PS4_USE_PIX_EVENTS
char buf[512]; char buf[512];
@ -125,7 +125,7 @@ void PIXEndNamedEvent()
PixDepth -= 1; PixDepth -= 1;
#endif #endif
} }
void PIXSetMarkerDeprecated(int a, char* b, ...) {} void PIXSetMarkerDeprecated(int a, const char* b, ...) {}
#else #else
// 4J Stu - Removed this implementation in favour of a macro that will convert our string format // 4J Stu - Removed this implementation in favour of a macro that will convert our string format
// conversion at compile time rather than at runtime // conversion at compile time rather than at runtime
@ -192,7 +192,16 @@ void IQNetPlayer::SendData(IQNetPlayer * player, const void* pvData, DWORD dwDat
{ {
if (WinsockNetLayer::IsActive()) if (WinsockNetLayer::IsActive())
{ {
WinsockNetLayer::SendToSmallId(player->m_smallId, pvData, dwDataSize); if (!WinsockNetLayer::IsHosting() && !m_isRemote)
{
SOCKET sock = WinsockNetLayer::GetLocalSocket(m_smallId);
if (sock != INVALID_SOCKET)
WinsockNetLayer::SendOnSocket(sock, pvData, dwDataSize);
}
else
{
WinsockNetLayer::SendToSmallId(player->m_smallId, pvData, dwDataSize);
}
} }
} }
bool IQNetPlayer::IsSameSystem(IQNetPlayer * player) { return (this == player) || (!m_isRemote && !player->m_isRemote); } bool IQNetPlayer::IsSameSystem(IQNetPlayer * player) { return (this == player) || (!m_isRemote && !player->m_isRemote); }
@ -243,7 +252,20 @@ void Win64_SetupRemoteQNetPlayer(IQNetPlayer * player, BYTE smallId, bool isHost
static bool Win64_IsActivePlayer(IQNetPlayer* p, DWORD index); static bool Win64_IsActivePlayer(IQNetPlayer* p, DWORD index);
HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex) { return S_OK; } HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex) {
if (dwUserIndex >= MINECRAFT_NET_MAX_PLAYERS) return E_FAIL;
m_player[dwUserIndex].m_isRemote = false;
m_player[dwUserIndex].m_isHostPlayer = false;
// Give the joining player a distinct gamertag
extern wchar_t g_Win64UsernameW[17];
if (dwUserIndex == 0)
wcscpy_s(m_player[0].m_gamertag, 32, g_Win64UsernameW);
else
swprintf_s(m_player[dwUserIndex].m_gamertag, 32, L"%s(%d)", g_Win64UsernameW, dwUserIndex + 1);
if (dwUserIndex >= s_playerCount)
s_playerCount = dwUserIndex + 1;
return S_OK;
}
IQNetPlayer* IQNet::GetHostPlayer() { return &m_player[0]; } IQNetPlayer* IQNet::GetHostPlayer() { return &m_player[0]; }
IQNetPlayer* IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex) IQNetPlayer* IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
{ {
@ -255,13 +277,31 @@ IQNetPlayer* IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
return &m_player[dwUserIndex]; return &m_player[dwUserIndex];
return NULL; return NULL;
} }
if (dwUserIndex != 0) if (dwUserIndex == 0)
return NULL;
for (DWORD i = 0; i < s_playerCount; i++)
{ {
if (!m_player[i].m_isRemote && Win64_IsActivePlayer(&m_player[i], i)) // Primary pad: use direct index when networking is active (smallId may not be 0)
return &m_player[i]; if (WinsockNetLayer::IsActive())
{
DWORD idx = WinsockNetLayer::GetLocalSmallId();
if (idx < MINECRAFT_NET_MAX_PLAYERS &&
!m_player[idx].m_isRemote &&
Win64_IsActivePlayer(&m_player[idx], idx))
return &m_player[idx];
return NULL;
}
// Offline: scan for first local player
for (DWORD i = 0; i < s_playerCount; i++)
{
if (!m_player[i].m_isRemote && Win64_IsActivePlayer(&m_player[i], i))
return &m_player[i];
}
return NULL;
} }
// Split-screen pads 1-3: the player is at m_player[dwUserIndex] with isRemote=false
if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS &&
!m_player[dwUserIndex].m_isRemote &&
Win64_IsActivePlayer(&m_player[dwUserIndex], dwUserIndex))
return &m_player[dwUserIndex];
return NULL; return NULL;
} }
static bool Win64_IsActivePlayer(IQNetPlayer * p, DWORD index) static bool Win64_IsActivePlayer(IQNetPlayer * p, DWORD index)
@ -582,7 +622,7 @@ void C_4JProfile::SetTrialTextStringTable(CXuiStringTable * pStringTable, int
void C_4JProfile::SetTrialAwardText(eAwardType AwardType, int iTitle, int iText) {} void C_4JProfile::SetTrialAwardText(eAwardType AwardType, int iTitle, int iText) {}
int C_4JProfile::GetLockedProfile() { return 0; } int C_4JProfile::GetLockedProfile() { return 0; }
void C_4JProfile::SetLockedProfile(int iProf) {} void C_4JProfile::SetLockedProfile(int iProf) {}
bool C_4JProfile::IsSignedIn(int iQuadrant) { return (iQuadrant == 0); } bool C_4JProfile::IsSignedIn(int iQuadrant) { return (iQuadrant == 0) || InputManager.IsPadConnected(iQuadrant); }
bool C_4JProfile::IsSignedInLive(int iProf) { return true; } bool C_4JProfile::IsSignedInLive(int iProf) { return true; }
bool C_4JProfile::IsGuest(int iQuadrant) { return false; } bool C_4JProfile::IsGuest(int iQuadrant) { return false; }
UINT C_4JProfile::RequestSignInUI(bool bFromInvite, bool bLocalGame, bool bNoGuestsAllowed, bool bMultiplayerSignIn, bool bAddUser, int(*Func)(LPVOID, const bool, const int iPad), LPVOID lpParam, int iQuadrant) { return 0; } UINT C_4JProfile::RequestSignInUI(bool bFromInvite, bool bLocalGame, bool bNoGuestsAllowed, bool bMultiplayerSignIn, bool bAddUser, int(*Func)(LPVOID, const bool, const int iPad), LPVOID lpParam, int iQuadrant) { return 0; }
@ -593,18 +633,10 @@ bool C_4JProfile::QuerySigninStatus(void) { return true; }
void C_4JProfile::GetXUID(int iPad, PlayerUID * pXuid, bool bOnlineXuid) void C_4JProfile::GetXUID(int iPad, PlayerUID * pXuid, bool bOnlineXuid)
{ {
#ifdef _WINDOWS64 #ifdef _WINDOWS64
if (iPad != 0) // Each pad gets a unique XUID derived from the persistent uid.dat value.
{ // Pad 0 uses the base XUID directly. Pads 1-3 get a deterministic hash
*pXuid = INVALID_XUID; // of (base + pad) to produce fully independent IDs with no overlap risk.
return; *pXuid = Win64Xuid::DeriveXuidForPad(Win64Xuid::ResolvePersistentXuid(), iPad);
}
// LoginPacket reads this value as client identity:
// - host keeps legacy host XUID for world compatibility
// - non-host uses persistent uid.dat-backed XUID
if (IQNet::s_isHosting)
*pXuid = Win64Xuid::GetLegacyEmbeddedHostXuid();
else
*pXuid = Win64Xuid::ResolvePersistentXuid();
#else #else
* pXuid = 0xe000d45248242f2e + iPad; * pXuid = 0xe000d45248242f2e + iPad;
#endif #endif
@ -634,8 +666,24 @@ void C_4JProfile::SetPrimaryPad(int iPad) {}
char fakeGamerTag[32] = "PlayerName"; char fakeGamerTag[32] = "PlayerName";
void SetFakeGamertag(char* name) { strcpy_s(fakeGamerTag, name); } void SetFakeGamertag(char* name) { strcpy_s(fakeGamerTag, name); }
#else #else
char* C_4JProfile::GetGamertag(int iPad) { extern char g_Win64Username[17]; return g_Win64Username; } char* C_4JProfile::GetGamertag(int iPad) {
wstring C_4JProfile::GetDisplayName(int iPad) { extern wchar_t g_Win64UsernameW[17]; return g_Win64UsernameW; } extern char g_Win64Username[17];
if (iPad > 0 && iPad < XUSER_MAX_COUNT && IQNet::m_player[iPad].m_gamertag[0] != 0 &&
!IQNet::m_player[iPad].m_isRemote)
{
static char s_padGamertag[XUSER_MAX_COUNT][17];
WideCharToMultiByte(CP_ACP, 0, IQNet::m_player[iPad].m_gamertag, -1, s_padGamertag[iPad], 17, NULL, NULL);
return s_padGamertag[iPad];
}
return g_Win64Username;
}
wstring C_4JProfile::GetDisplayName(int iPad) {
extern wchar_t g_Win64UsernameW[17];
if (iPad > 0 && iPad < XUSER_MAX_COUNT && IQNet::m_player[iPad].m_gamertag[0] != 0 &&
!IQNet::m_player[iPad].m_isRemote)
return IQNet::m_player[iPad].m_gamertag;
return g_Win64UsernameW;
}
#endif #endif
bool C_4JProfile::IsFullVersion() { return s_bProfileIsFullVersion; } bool C_4JProfile::IsFullVersion() { return s_bProfileIsFullVersion; }
void C_4JProfile::SetSignInChangeCallback(void (*Func)(LPVOID, bool, unsigned int), LPVOID lpParam) {} void C_4JProfile::SetSignInChangeCallback(void (*Func)(LPVOID, bool, unsigned int), LPVOID lpParam) {}

View file

@ -149,7 +149,7 @@ void Font::renderStyleLine(float x0, float y0, float x1, float y1)
void Font::addCharacterQuad(wchar_t c) void Font::addCharacterQuad(wchar_t c)
{ {
float xOff = c % m_cols * m_charWidth; float xOff = c % m_cols * m_charWidth;
float yOff = c / m_cols * m_charWidth; float yOff = c / m_cols * m_charHeight; // was m_charWidth — wrong when glyphs aren't square
float width = charWidths[c] - .01f; float width = charWidths[c] - .01f;
float height = m_charHeight - .01f; float height = m_charHeight - .01f;
float fontWidth = m_cols * m_charWidth; float fontWidth = m_cols * m_charWidth;
@ -187,7 +187,7 @@ void Font::addCharacterQuad(wchar_t c)
void Font::renderCharacter(wchar_t c) void Font::renderCharacter(wchar_t c)
{ {
float xOff = c % m_cols * m_charWidth; float xOff = c % m_cols * m_charWidth;
float yOff = c / m_cols * m_charWidth; float yOff = c / m_cols * m_charHeight; // was m_charWidth — wrong when glyphs aren't square
float width = charWidths[c] - .01f; float width = charWidths[c] - .01f;
float height = m_charHeight - .01f; float height = m_charHeight - .01f;

View file

@ -595,9 +595,10 @@ void GameRenderer::unZoomRegion()
// 4J added as we have more complex adjustments to make for fov & aspect on account of viewports // 4J added as we have more complex adjustments to make for fov & aspect on account of viewports
void GameRenderer::getFovAndAspect(float& fov, float& aspect, float a, bool applyEffects) void GameRenderer::getFovAndAspect(float& fov, float& aspect, float a, bool applyEffects)
{ {
// 4J - split out aspect ratio and fov here so we can adjust for viewports - we might need to revisit these as // Use the real window dimensions so the perspective updates on resize.
// they are maybe be too generous for performance. extern int g_rScreenWidth;
aspect = mc->width / (float) mc->height; extern int g_rScreenHeight;
aspect = g_rScreenWidth / static_cast<float>(g_rScreenHeight);
fov = getFov(a, applyEffects); fov = getFov(a, applyEffects);
if( ( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_TOP ) || if( ( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_TOP ) ||
@ -947,9 +948,9 @@ float GameRenderer::ComputeGammaFromSlider(float slider0to100)
slider = min(slider, 100.0f); slider = min(slider, 100.0f);
if (slider > 50.0f) if (slider > 50.0f)
return 1.0f + (slider - 50.0f) / 50.0f * 3.0f; // 1.0 -> 4.0 return 1.0f + (slider - 50.0f) / 50.0f * 1.2f; // 1.0 -> 1.5
else else
return 1.0f - (50.0f - slider) / 50.0f * 0.85f; // 1.0 -> 0.15 return 1.0f - (50.0f - slider) / 50.0f * 0.4f; // 1.0 -> 0.5
} }
void GameRenderer::CachePlayerGammas() void GameRenderer::CachePlayerGammas()
@ -970,6 +971,10 @@ void GameRenderer::CachePlayerGammas()
bool GameRenderer::ComputeViewportForPlayer(int j, D3D11_VIEWPORT &outViewport) const bool GameRenderer::ComputeViewportForPlayer(int j, D3D11_VIEWPORT &outViewport) const
{ {
// Use the actual backbuffer dimensions so viewports adapt to window resize.
extern int g_rScreenWidth;
extern int g_rScreenHeight;
int active = 0; int active = 0;
int indexMap[NUM_LIGHT_TEXTURES] = {-1, -1, -1, -1}; int indexMap[NUM_LIGHT_TEXTURES] = {-1, -1, -1, -1};
for (int i = 0; i < XUSER_MAX_COUNT && i < NUM_LIGHT_TEXTURES; ++i) for (int i = 0; i < XUSER_MAX_COUNT && i < NUM_LIGHT_TEXTURES; ++i)
@ -982,8 +987,8 @@ bool GameRenderer::ComputeViewportForPlayer(int j, D3D11_VIEWPORT &outViewport)
{ {
outViewport.TopLeftX = 0.0f; outViewport.TopLeftX = 0.0f;
outViewport.TopLeftY = 0.0f; outViewport.TopLeftY = 0.0f;
outViewport.Width = static_cast<FLOAT>(mc->width); outViewport.Width = static_cast<FLOAT>(g_rScreenWidth);
outViewport.Height = static_cast<FLOAT>(mc->height); outViewport.Height = static_cast<FLOAT>(g_rScreenHeight);
outViewport.MinDepth = 0.0f; outViewport.MinDepth = 0.0f;
outViewport.MaxDepth = 1.0f; outViewport.MaxDepth = 1.0f;
return true; return true;
@ -999,8 +1004,8 @@ bool GameRenderer::ComputeViewportForPlayer(int j, D3D11_VIEWPORT &outViewport)
if (k < 0) if (k < 0)
return false; return false;
const float width = static_cast<float>(mc->width); const float width = static_cast<float>(g_rScreenWidth);
const float height = static_cast<float>(mc->height); const float height = static_cast<float>(g_rScreenHeight);
if (active == 2) if (active == 2)
{ {
@ -1059,20 +1064,36 @@ void GameRenderer::ApplyGammaPostProcess() const
D3D11_VIEWPORT vps[NUM_LIGHT_TEXTURES]; D3D11_VIEWPORT vps[NUM_LIGHT_TEXTURES];
float gammas[NUM_LIGHT_TEXTURES]; float gammas[NUM_LIGHT_TEXTURES];
const UINT n = BuildPlayerViewports(vps, gammas, NUM_LIGHT_TEXTURES); const UINT n = BuildPlayerViewports(vps, gammas, NUM_LIGHT_TEXTURES);
if (n == 0)
return;
bool anyEffect = false; float gamma = 1.0f;
for (UINT i = 0; i < n; ++i) bool hasPlayers = n > 0;
if (hasPlayers)
{ {
if (gammas[i] < 0.99f || gammas[i] > 1.01f) bool anyEffect = false;
for (UINT i = 0; i < n; ++i)
{ {
anyEffect = true; if (gammas[i] < 0.99f || gammas[i] > 1.01f)
break; {
anyEffect = true;
break;
}
} }
if (!anyEffect)
return;
} }
if (!anyEffect) else
{
const float slider = app.GetGameSettings(0, eGameSetting_Gamma);
gamma = ComputeGammaFromSlider(slider);
if (gamma < 0.99f || gamma > 1.01f)
{
PostProcesser::GetInstance().SetGamma(gamma);
PostProcesser::GetInstance().Apply();
return;
}
return; return;
}
if (n == 1) if (n == 1)
{ {
@ -1157,7 +1178,7 @@ void GameRenderer::render(float a, bool bFirst)
if (mc->noRender) return; if (mc->noRender) return;
GameRenderer::anaglyph3d = mc->options->anaglyph3d; GameRenderer::anaglyph3d = mc->options->anaglyph3d;
glViewport(0, 0, mc->width, mc->height); // 4J - added glViewport(0, 0, mc->width, mc->height); // 4J - added (no-op on Win64, viewport set by StateSetViewport)
ScreenSizeCalculator ssc(mc->options, mc->width, mc->height); ScreenSizeCalculator ssc(mc->options, mc->width, mc->height);
int screenWidth = ssc.getWidth(); int screenWidth = ssc.getWidth();
int screenHeight = ssc.getHeight(); int screenHeight = ssc.getHeight();
@ -1177,35 +1198,33 @@ void GameRenderer::render(float a, bool bFirst)
renderLevel(a, lastNsTime + 1000000000 / maxFps); renderLevel(a, lastNsTime + 1000000000 / maxFps);
} }
lastNsTime = System::nanoTime(); lastNsTime = System::nanoTime();
if (!mc->options->hideGui || mc->screen != NULL) if (!mc->options->hideGui || mc->screen != NULL)
{ {
mc->gui->render(a, mc->screen != NULL, xMouse, yMouse); mc->gui->render(a, mc->screen != NULL, xMouse, yMouse);
}
} }
} else
else {
{ glViewport(0, 0, mc->width, mc->height);
glViewport(0, 0, mc->width, mc->height); glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glLoadIdentity(); glMatrixMode(GL_MODELVIEW);
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glLoadIdentity(); setupGuiScreen();
setupGuiScreen();
lastNsTime = System::nanoTime(); lastNsTime = System::nanoTime();
} }
if (mc->screen != NULL) if (mc->screen != NULL)
{ {
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
mc->screen->render(xMouse, yMouse, a); mc->screen->render(xMouse, yMouse, a);
if (mc->screen != NULL && mc->screen->particles != NULL) mc->screen->particles->render(a); if (mc->screen != NULL && mc->screen->particles != NULL) mc->screen->particles->render(a);
} }
}
ApplyGammaPostProcess();
}
void GameRenderer::renderLevel(float a) void GameRenderer::renderLevel(float a)
{ {

View file

@ -81,7 +81,9 @@ private:
float m_cachedGammaPerPlayer[NUM_LIGHT_TEXTURES]; float m_cachedGammaPerPlayer[NUM_LIGHT_TEXTURES];
static float ComputeGammaFromSlider(float slider0to100); static float ComputeGammaFromSlider(float slider0to100);
void CachePlayerGammas(); void CachePlayerGammas();
public:
void ApplyGammaPostProcess() const; void ApplyGammaPostProcess() const;
private:
bool ComputeViewportForPlayer(int j, D3D11_VIEWPORT& outViewport) const; bool ComputeViewportForPlayer(int j, D3D11_VIEWPORT& outViewport) const;
uint32_t BuildPlayerViewports(D3D11_VIEWPORT* outViewports, float* outGammas, UINT maxCount) const; uint32_t BuildPlayerViewports(D3D11_VIEWPORT* outViewports, float* outGammas, UINT maxCount) const;

View file

@ -859,89 +859,179 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
glTranslatef((float)debugLeft, (float)debugTop, 0.f); glTranslatef((float)debugLeft, (float)debugTop, 0.f);
glScalef(scale, scale, 1.f); glScalef(scale, scale, 1.f);
glTranslatef((float)-debugLeft, (float)-debugTop, 0.f); glTranslatef((float)-debugLeft, (float)-debugTop, 0.f);
if (Minecraft::warezTime > 0) glTranslatef(0, 32, 0);
font->drawShadow(ClientConstants::VERSION_STRING + L" (" + minecraft->fpsString + L")", debugLeft, debugTop, 0xffffff);
font->drawShadow(L"Seed: " + std::to_wstring(minecraft->level->getLevelData()->getSeed() ), debugLeft, debugTop + 12, 0xffffff);
font->drawShadow(minecraft->gatherStats1(), debugLeft, debugTop + 22, 0xffffff);
font->drawShadow(minecraft->gatherStats2(), debugLeft, debugTop + 32, 0xffffff);
font->drawShadow(minecraft->gatherStats3(), debugLeft, debugTop + 42, 0xffffff);
font->drawShadow(minecraft->gatherStats4(), debugLeft, debugTop + 52, 0xffffff);
// TERRAIN FEATURES vector<wstring> lines;
int iYPos = debugTop + 62;
if(minecraft->level->dimension->id==0) lines.push_back(ClientConstants::VERSION_STRING);
{ lines.push_back(minecraft->fpsString);
wstring wfeature[eTerrainFeature_Count]; lines.push_back(L"E: " + std::to_wstring(minecraft->level->getAllEntities().size())); // Could maybe use entity::shouldRender to work out how many are rendered but thats like expensive
// TODO Add server information with packet counts - once multiplayer is more stable
int renderDistance = app.GetGameSettings(iPad, eGameSetting_RenderDistance);
// Calculate the chunk sections using 16 * (2n + 1)^2
lines.push_back(L"C: " + std::to_wstring(16 * (2 * renderDistance + 1) * (2 * renderDistance + 1)) + L" D: " + std::to_wstring(renderDistance));
lines.push_back(minecraft->gatherStats4()); // Chunk Cache
wfeature[eTerrainFeature_Stronghold] = L"Stronghold: "; // Dimension
wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: "; wstring dimension = L"unknown";
wfeature[eTerrainFeature_Village] = L"Village: "; switch (minecraft->player->dimension)
wfeature[eTerrainFeature_Ravine] = L"Ravine: "; {
case -1:
float maxW = (float)(screenWidth - debugLeft - 8) / scale; dimension = L"minecraft:the_nether";
float maxWForContent = maxW - (float)font->width(L"..."); break;
bool truncated[eTerrainFeature_Count] = {}; case 0:
dimension = L"minecraft:overworld";
for (int i = 0; i < (int)app.m_vTerrainFeatures.size(); i++) break;
{ case 1:
FEATURE_DATA *pFeatureData=app.m_vTerrainFeatures[i]; dimension = L"minecraft:the_end";
int type = pFeatureData->eTerrainFeature; break;
if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine) continue;
if (truncated[type]) continue;
wstring itemInfo = L"[" + std::to_wstring( pFeatureData->x*16 ) + L", " + std::to_wstring( pFeatureData->z*16 ) + L"] ";
if (font->width(wfeature[type] + itemInfo) <= maxWForContent)
wfeature[type] += itemInfo;
else
{
wfeature[type] += L"...";
truncated[type] = true;
}
}
for( int i = eTerrainFeature_Stronghold; i < (int) eTerrainFeature_Count; i++ )
{
iYPos+=10;
font->drawShadow(wfeature[i], debugLeft, iYPos, 0xffffff);
}
} }
lines.push_back(dimension);
//font->drawShadow(minecraft->gatherStats5(), iSafezoneXHalf+2, 32 + 10, 0xffffff); lines.push_back(L""); // Spacer
{
/* 4J - removed // Players block pos
long max = Runtime.getRuntime().maxMemory(); int xBlockPos = Mth::floor(minecraft->player->x);
long total = Runtime.getRuntime().totalMemory(); int yBlockPos = Mth::floor(minecraft->player->y);
long free = Runtime.getRuntime().freeMemory(); int zBlockPos = Mth::floor(minecraft->player->z);
long used = total - free;
String msg = "Used memory: " + (used * 100 / max) + "% (" + (used / 1024 / 1024) + "MB) of " + (max / 1024 / 1024) + "MB"; // Chunk player is in
drawString(font, msg, screenWidth - font.width(msg) - 2, 2, 0xe0e0e0); int xChunkPos = xBlockPos >> 4;
msg = "Allocated memory: " + (total * 100 / max) + "% (" + (total / 1024 / 1024) + "MB)"; int yChunkPos = yBlockPos >> 4;
drawString(font, msg, screenWidth - font.width(msg) - 2, 12, 0xe0e0e0); int zChunkPos = zBlockPos >> 4;
*/
// Players offset within the chunk
int xChunkOffset = xBlockPos & 15;
int yChunkOffset = yBlockPos & 15;
int zChunkOffset = zBlockPos & 15;
// Format the position like java with limited decumal places
WCHAR posString[44]; // Allows upto 7 digit positions (+-9_999_999)
swprintf(posString, 44, L"%.3f / %.5f / %.3f", minecraft->player->x, minecraft->player->y, minecraft->player->z);
lines.push_back(L"XYZ: " + std::wstring(posString));
lines.push_back(L"Block: " + std::to_wstring(static_cast<int>(xBlockPos)) + L" " + std::to_wstring(static_cast<int>(yBlockPos)) + L" " + std::to_wstring(static_cast<int>(zBlockPos)));
lines.push_back(L"Chunk: " + std::to_wstring(xChunkOffset) + L" " + std::to_wstring(yChunkOffset) + L" " + std::to_wstring(zChunkOffset) + L" in " + std::to_wstring(xChunkPos) + L" " + std::to_wstring(yChunkPos) + L" " + std::to_wstring(zChunkPos));
// Wrap the yRot to 360 then adjust to (-180 to 180) range to match java
float yRotDisplay = fmod(minecraft->player->yRot, 360.0f);
if (yRotDisplay > 180.0f)
{
yRotDisplay -= 360.0f;
} }
// 4J Stu - Moved these so that they don't overlap if (yRotDisplay < -180.0f)
double xBlockPos = floor(minecraft->player->x); {
double yBlockPos = floor(minecraft->player->y); yRotDisplay += 360.0f;
double zBlockPos = floor(minecraft->player->z); }
drawString(font, L"x: " + std::to_wstring(minecraft->player->x) + L"/ Head: " + std::to_wstring(static_cast<int>(xBlockPos)) + L"/ Chunk: " + std::to_wstring(minecraft->player->xChunk), debugLeft, iYPos + 8 * 0, 0xe0e0e0); // Generate the angle string in the format "yRot / xRot" with one decimal place, similar to java edition
drawString(font, L"y: " + std::to_wstring(minecraft->player->y) + L"/ Head: " + std::to_wstring(static_cast<int>(yBlockPos)), debugLeft, iYPos + 8 * 1, 0xe0e0e0); WCHAR angleString[16];
drawString(font, L"z: " + std::to_wstring(minecraft->player->z) + L"/ Head: " + std::to_wstring(static_cast<int>(zBlockPos)) + L"/ Chunk: " + std::to_wstring(minecraft->player->zChunk), debugLeft, iYPos + 8 * 2, 0xe0e0e0); swprintf(angleString, 16, L"%.1f / %.1f", yRotDisplay, minecraft->player->xRot);
drawString(font, L"f: " + std::to_wstring(Mth::floor(minecraft->player->yRot * 4.0f / 360.0f + 0.5) & 0x3) + L"/ yRot: " + std::to_wstring(minecraft->player->yRot), debugLeft, iYPos + 8 * 3, 0xe0e0e0);
iYPos += 8*4;
int px = Mth::floor(minecraft->player->x); // Work out the named direction
int py = Mth::floor(minecraft->player->y); int direction = Mth::floor(minecraft->player->yRot * 4.0f / 360.0f + 0.5) & 0x3;
int pz = Mth::floor(minecraft->player->z); wstring cardinalDirection;
if (minecraft->level != NULL && minecraft->level->hasChunkAt(px, py, pz)) switch (direction)
{
case 0:
cardinalDirection = L"south";
break;
case 1:
cardinalDirection = L"west";
break;
case 2:
cardinalDirection = L"north";
break;
case 3:
cardinalDirection = L"east";
break;
}
lines.push_back(L"Facing: " + cardinalDirection + L" (" + angleString + L")");
// We have to limit y to 256 as we don't get any information past that
if (minecraft->level != NULL && minecraft->level->hasChunkAt(xBlockPos, fmod(yBlockPos, 256), zBlockPos))
{ {
LevelChunk *chunkAt = minecraft->level->getChunkAt(px, pz); LevelChunk *chunkAt = minecraft->level->getChunkAt(xBlockPos, zBlockPos);
Biome *biome = chunkAt->getBiome(px & 15, pz & 15, minecraft->level->getBiomeSource()); if (chunkAt != NULL)
drawString( {
font, int skyLight = chunkAt->getBrightness(LightLayer::Sky, xChunkOffset, yChunkOffset, zChunkOffset);
L"b: " + biome->m_name + L" (" + std::to_wstring(biome->id) + L")", debugLeft, iYPos, 0xe0e0e0); int blockLight = chunkAt->getBrightness(LightLayer::Block, xChunkOffset, yChunkOffset, zChunkOffset);
int maxLight = fmax(skyLight, blockLight);
lines.push_back(L"Light: " + std::to_wstring(maxLight) + L" (" + std::to_wstring(skyLight) + L" sky, " + std::to_wstring(blockLight) + L" block)");
lines.push_back(L"CH S: " + std::to_wstring(chunkAt->getHeightmap(xChunkOffset, zChunkOffset)));
Biome *biome = chunkAt->getBiome(xChunkOffset, zChunkOffset, minecraft->level->getBiomeSource());
lines.push_back(L"Biome: " + biome->m_name + L" (" + std::to_wstring(biome->id) + L")");
lines.push_back(L"Difficulty: " + std::to_wstring(minecraft->level->difficulty) + L" (Day " + std::to_wstring(minecraft->level->getGameTime() / Level::TICKS_PER_DAY) + L")");
}
} }
// This is all LCE only stuff, it was never on java
lines.push_back(L""); // Spacer
lines.push_back(L"Seed: " + std::to_wstring(minecraft->level->getLevelData()->getSeed()));
lines.push_back(minecraft->gatherStats1()); // Time to autosave
lines.push_back(minecraft->gatherStats2()); // Empty currently - CPlatformNetworkManagerStub::GatherStats()
lines.push_back(minecraft->gatherStats3()); // RTT
#ifdef _DEBUG // Only show terrain features in debug builds not release
// TERRAIN FEATURES
if (minecraft->level->dimension->id == 0)
{
wstring wfeature[eTerrainFeature_Count];
wfeature[eTerrainFeature_Stronghold] = L"Stronghold: ";
wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: ";
wfeature[eTerrainFeature_Village] = L"Village: ";
wfeature[eTerrainFeature_Ravine] = L"Ravine: ";
float maxW = (float)(screenWidth - debugLeft - 8) / scale;
float maxWForContent = maxW - (float)font->width(L"...");
bool truncated[eTerrainFeature_Count] = {};
for (int i = 0; i < (int)app.m_vTerrainFeatures.size(); i++)
{
FEATURE_DATA *pFeatureData = app.m_vTerrainFeatures[i];
int type = pFeatureData->eTerrainFeature;
if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine)
{
continue;
}
if (truncated[type])
{
continue;
}
wstring itemInfo = L"[" + std::to_wstring(pFeatureData->x * 16) + L", " + std::to_wstring(pFeatureData->z * 16) + L"] ";
if (font->width(wfeature[type] + itemInfo) <= maxWForContent)
{
wfeature[type] += itemInfo;
}
else
{
wfeature[type] += L"...";
truncated[type] = true;
}
}
lines.push_back(L""); // Add a spacer line
for (int i = eTerrainFeature_Stronghold; i <= (int)eTerrainFeature_Ravine; i++)
{
lines.push_back(wfeature[i]);
}
lines.push_back(L"");
}
#endif
// Loop through the lines and draw them all on screen
int yPos = debugTop;
for (const auto &line : lines)
{
drawString(font, line, debugLeft, yPos, 0xffffff);
yPos += 10;
}
glPopMatrix(); glPopMatrix();
} }
MemSect(0); MemSect(0);

View file

@ -55,8 +55,15 @@ void HorseRenderer::renderModel(shared_ptr<LivingEntity> mob, float wp, float ws
void HorseRenderer::bindTexture(ResourceLocation *location) void HorseRenderer::bindTexture(ResourceLocation *location)
{ {
// Set up (potentially) multiple texture layers for the horse if (location->getTextureCount() > 1)
entityRenderDispatcher->textures->bindTextureLayers(location); {
// Set up multiple texture layers for the horse
entityRenderDispatcher->textures->bindTextureLayers(location);
}
else
{
EntityRenderer::bindTexture(location);
}
} }
ResourceLocation *HorseRenderer::getTextureLocation(shared_ptr<Entity> entity) ResourceLocation *HorseRenderer::getTextureLocation(shared_ptr<Entity> entity)

View file

@ -930,6 +930,14 @@ void ItemInHandRenderer::tick()
} }
void ItemInHandRenderer::reset()
{
selectedItem = nullptr;
lastSlot = -1;
height = 0.0f;
oHeight = 0.0f;
}
void ItemInHandRenderer::itemPlaced() void ItemInHandRenderer::itemPlaced()
{ {
height = 0; height = 0;

View file

@ -41,6 +41,7 @@ private:
int lastSlot; int lastSlot;
public: public:
void tick(); void tick();
void reset();
void itemPlaced(); void itemPlaced();
void itemUsed(); void itemUsed();
}; };

View file

@ -545,7 +545,8 @@ void LevelRenderer::renderEntities(Vec3 *cam, Culler *culler, float a)
for (auto& entity : entities) for (auto& entity : entities)
{ {
bool shouldRender = (entity->shouldRender(cam) && (entity->noCulling || culler->isVisible(entity->bb))); bool isPlayerVehicle = (entity == mc->cameraTargetPlayer->riding);
bool shouldRender = (entity->shouldRender(cam) && (entity->noCulling || isPlayerVehicle || culler->isVisible(entity->bb)));
// Render the mob if the mob's leash holder is within the culler // Render the mob if the mob's leash holder is within the culler
if ( !shouldRender && entity->instanceof(eTYPE_MOB) ) if ( !shouldRender && entity->instanceof(eTYPE_MOB) )

View file

@ -278,7 +278,7 @@ void LocalPlayer::aiStep()
} }
if (isSneaking()) sprintTriggerTime = 0; if (isSneaking()) sprintTriggerTime = 0;
#ifdef _WINDOWS64 #ifdef _WINDOWS64
if (input->sprinting && onGround && enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness) && !isSneaking()) if (input->sprinting && !isSprinting() && onGround && enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness) && !isSneaking())
{ {
setSprinting(true); setSprinting(true);
} }

View file

@ -1551,7 +1551,7 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata"</Command>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
@ -1561,12 +1561,13 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata"</Command>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PreprocessorDefinitions>_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_DEBUG;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_DEBUG;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CallAttributedProfiling>Disabled</CallAttributedProfiling> <CallAttributedProfiling>Disabled</CallAttributedProfiling>
<AdditionalIncludeDirectories>Windows64\Iggy\include;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>Windows64\Iggy\include;$(ProjectDir);$(ProjectDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>Default</BasicRuntimeChecks> <BasicRuntimeChecks>Default</BasicRuntimeChecks>
<ShowIncludes>false</ShowIncludes> <ShowIncludes>false</ShowIncludes>
<AdditionalOptions>/FS %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/FS %(AdditionalOptions)</AdditionalOptions>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -1595,6 +1596,12 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata"</Command>
<PostBuildEvent> <PostBuildEvent>
<Message>Run post-build script</Message> <Message>Run post-build script</Message>
</PostBuildEvent> </PostBuildEvent>
<PreBuildEvent>
<Command>powershell -ExecutionPolicy Bypass -File "$(ProjectDir)prebuild.ps1"</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Run pre-build script</Message>
</PreBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'">
<ClCompile> <ClCompile>
@ -1786,7 +1793,7 @@ xcopy /q /y /i /s /e $(ProjectDir)DurangoMedia\CU $(LayoutDir)Image\Loose\CU</C
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PreprocessorDefinitions>_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CallAttributedProfiling>Disabled</CallAttributedProfiling> <CallAttributedProfiling>Disabled</CallAttributedProfiling>
<AdditionalIncludeDirectories>Windows64\Iggy\include;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>Windows64\Iggy\include;$(ProjectDir);$(ProjectDir)..\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>Default</BasicRuntimeChecks> <BasicRuntimeChecks>Default</BasicRuntimeChecks>
@ -1796,6 +1803,7 @@ xcopy /q /y /i /s /e $(ProjectDir)DurangoMedia\CU $(LayoutDir)Image\Loose\CU</C
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations> <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<StringPooling>true</StringPooling> <StringPooling>true</StringPooling>
<AdditionalOptions>/FS /Ob3 %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/FS /Ob3 %(AdditionalOptions)</AdditionalOptions>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -1823,6 +1831,12 @@ xcopy /q /y /i /s /e $(ProjectDir)DurangoMedia\CU $(LayoutDir)Image\Loose\CU</C
<DeploymentType>CopyToHardDrive</DeploymentType> <DeploymentType>CopyToHardDrive</DeploymentType>
<DeploymentFiles>$(RemoteRoot)=$(ImagePath);$(RemoteRoot)\res=Xbox\res;$(RemoteRoot)=Xbox\AvatarAwards;$(RemoteRoot)\Tutorial=Xbox\Tutorial\Tutorial;$(RemoteRoot)=Xbox\584111F70AAAAAAA;$(RemoteRoot)=Xbox\kinect\speech;$(RemoteRoot)=Xbox\XZP\TMSFiles.xzp</DeploymentFiles> <DeploymentFiles>$(RemoteRoot)=$(ImagePath);$(RemoteRoot)\res=Xbox\res;$(RemoteRoot)=Xbox\AvatarAwards;$(RemoteRoot)\Tutorial=Xbox\Tutorial\Tutorial;$(RemoteRoot)=Xbox\584111F70AAAAAAA;$(RemoteRoot)=Xbox\kinect\speech;$(RemoteRoot)=Xbox\XZP\TMSFiles.xzp</DeploymentFiles>
</Deploy> </Deploy>
<PreBuildEvent>
<Command>powershell -ExecutionPolicy Bypass -File "$(ProjectDir)prebuild.ps1"</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Run pre-build script</Message>
</PreBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'">
<ClCompile> <ClCompile>
@ -1928,6 +1942,7 @@ xcopy /q /y /i /s /e $(ProjectDir)DurangoMedia\CU $(LayoutDir)Image\Loose\CU</C
<BasicRuntimeChecks>Default</BasicRuntimeChecks> <BasicRuntimeChecks>Default</BasicRuntimeChecks>
<ShowIncludes>false</ShowIncludes> <ShowIncludes>false</ShowIncludes>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -2775,6 +2790,7 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata"</Command>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
<CallAttributedProfiling>Disabled</CallAttributedProfiling> <CallAttributedProfiling>Disabled</CallAttributedProfiling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks> <BasicRuntimeChecks>Default</BasicRuntimeChecks>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -2895,6 +2911,7 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata"</Command>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
<CallAttributedProfiling>Disabled</CallAttributedProfiling> <CallAttributedProfiling>Disabled</CallAttributedProfiling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks> <BasicRuntimeChecks>Default</BasicRuntimeChecks>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -3015,6 +3032,7 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata"</Command>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
<CallAttributedProfiling>Disabled</CallAttributedProfiling> <CallAttributedProfiling>Disabled</CallAttributedProfiling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks> <BasicRuntimeChecks>Default</BasicRuntimeChecks>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -3135,6 +3153,7 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata"</Command>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
<CallAttributedProfiling>Disabled</CallAttributedProfiling> <CallAttributedProfiling>Disabled</CallAttributedProfiling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks> <BasicRuntimeChecks>Default</BasicRuntimeChecks>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -5585,6 +5604,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\include\lce_filesystem\lce_filesystem.h" />
<ClInclude Include="AbstractContainerScreen.h"> <ClInclude Include="AbstractContainerScreen.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Durango'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Durango'">true</ExcludedFromBuild>
@ -5717,7 +5737,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ClInclude Include="Common\DLC\DLCSkinFile.h" /> <ClInclude Include="Common\DLC\DLCSkinFile.h" />
<ClInclude Include="Common\DLC\DLCTextureFile.h" /> <ClInclude Include="Common\DLC\DLCTextureFile.h" />
<ClInclude Include="Common\DLC\DLCUIDataFile.h" /> <ClInclude Include="Common\DLC\DLCUIDataFile.h" />
<ClInclude Include="Common\Filesystem\Filesystem.h" />
<ClInclude Include="Common\GameRules\AddEnchantmentRuleDefinition.h" /> <ClInclude Include="Common\GameRules\AddEnchantmentRuleDefinition.h" />
<ClInclude Include="Common\GameRules\AddItemRuleDefinition.h" /> <ClInclude Include="Common\GameRules\AddItemRuleDefinition.h" />
<ClInclude Include="Common\GameRules\ApplySchematicRuleDefinition.h" /> <ClInclude Include="Common\GameRules\ApplySchematicRuleDefinition.h" />
@ -28322,6 +28341,9 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ClInclude Include="ZombieRenderer.h" /> <ClInclude Include="ZombieRenderer.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\include\lce_filesystem\lce_filesystem.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)../include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<ClCompile Include="AbstractContainerScreen.cpp"> <ClCompile Include="AbstractContainerScreen.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Durango'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Durango'">true</ExcludedFromBuild>
@ -28473,7 +28495,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ClCompile Include="Common\DLC\DLCSkinFile.cpp" /> <ClCompile Include="Common\DLC\DLCSkinFile.cpp" />
<ClCompile Include="Common\DLC\DLCTextureFile.cpp" /> <ClCompile Include="Common\DLC\DLCTextureFile.cpp" />
<ClCompile Include="Common\DLC\DLCUIDataFile.cpp" /> <ClCompile Include="Common\DLC\DLCUIDataFile.cpp" />
<ClCompile Include="Common\Filesystem\Filesystem.cpp" />
<ClCompile Include="Common\GameRules\AddEnchantmentRuleDefinition.cpp" /> <ClCompile Include="Common\GameRules\AddEnchantmentRuleDefinition.cpp" />
<ClCompile Include="Common\GameRules\AddItemRuleDefinition.cpp" /> <ClCompile Include="Common\GameRules\AddItemRuleDefinition.cpp" />
<ClCompile Include="Common\GameRules\ApplySchematicRuleDefinition.cpp" /> <ClCompile Include="Common\GameRules\ApplySchematicRuleDefinition.cpp" />

View file

@ -729,8 +729,11 @@
<Filter Include="Windows64\Source Files\Network"> <Filter Include="Windows64\Source Files\Network">
<UniqueIdentifier>{e5d7fb24-25b8-413c-84ec-974bf0d4a3d1}</UniqueIdentifier> <UniqueIdentifier>{e5d7fb24-25b8-413c-84ec-974bf0d4a3d1}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Common\Source Files\Filesystem"> <Filter Include="include">
<UniqueIdentifier>{c79fd64d-7529-4da4-b5f3-2541e084932b}</UniqueIdentifier> <UniqueIdentifier>{d8cdea16-28f5-4993-baf8-26a129e50c84}</UniqueIdentifier>
</Filter>
<Filter Include="include\lce_filesystem">
<UniqueIdentifier>{70b1f1aa-fe50-4aab-9a6c-14df8cb1f231}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -3781,15 +3784,15 @@
<ClInclude Include="Windows64\Network\WinsockNetLayer.h"> <ClInclude Include="Windows64\Network\WinsockNetLayer.h">
<Filter>Windows64\Source Files\Network</Filter> <Filter>Windows64\Source Files\Network</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Common\Filesystem\Filesystem.h">
<Filter>Common\Source Files\Filesystem</Filter>
</ClInclude>
<ClInclude Include="Common\Audio\miniaudio.h"> <ClInclude Include="Common\Audio\miniaudio.h">
<Filter>Common\Source Files\Audio</Filter> <Filter>Common\Source Files\Audio</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Common\Audio\stb_vorbis.h"> <ClInclude Include="Common\Audio\stb_vorbis.h">
<Filter>Common\Source Files\Audio</Filter> <Filter>Common\Source Files\Audio</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\include\lce_filesystem\lce_filesystem.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
@ -5943,8 +5946,8 @@
<ClCompile Include="Windows64\Network\WinsockNetLayer.cpp"> <ClCompile Include="Windows64\Network\WinsockNetLayer.cpp">
<Filter>Windows64\Source Files\Network</Filter> <Filter>Windows64\Source Files\Network</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Common\Filesystem\Filesystem.cpp"> <ClCompile Include="..\include\lce_filesystem\lce_filesystem.cpp">
<Filter>Common\Source Files\Filesystem</Filter> <Filter>include\lce_filesystem</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,5 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Minecraft.h" #include "Minecraft.h"
#include "Common/UI/UIScene.h"
#include "GameMode.h" #include "GameMode.h"
#include "Timer.h" #include "Timer.h"
#include "ProgressRenderer.h" #include "ProgressRenderer.h"
@ -9,6 +10,7 @@
#include "User.h" #include "User.h"
#include "Textures.h" #include "Textures.h"
#include "GameRenderer.h" #include "GameRenderer.h"
#include "ItemInHandRenderer.h"
#include "HumanoidModel.h" #include "HumanoidModel.h"
#include "Options.h" #include "Options.h"
#include "TexturePackRepository.h" #include "TexturePackRepository.h"
@ -216,6 +218,7 @@ Minecraft::Minecraft(Component *mouseComponent, Canvas *parent, MinecraftApplet
m_pendingLocalConnections[i] = NULL; m_pendingLocalConnections[i] = NULL;
m_connectionFailed[i] = false; m_connectionFailed[i] = false;
localgameModes[i]=NULL; localgameModes[i]=NULL;
localitemInHandRenderers[i] = NULL;
} }
animateTickLevel = NULL; // 4J added animateTickLevel = NULL; // 4J added
@ -742,7 +745,7 @@ void Minecraft::run()
while (System::currentTimeMillis() >= lastTime + 1000) while (System::currentTimeMillis() >= lastTime + 1000)
{ {
fpsString = std::to_wstring(frames) + L" fps, " + std::to_wstring(Chunk::updates) + L" chunk updates"; fpsString = std::to_wstring(frames) + L" fps (" + std::to_wstring(Chunk::updates) + L" chunk updates)";
Chunk::updates = 0; Chunk::updates = 0;
lastTime += 1000; lastTime += 1000;
frames = 0; frames = 0;
@ -1479,9 +1482,22 @@ void Minecraft::run_middle()
if(g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT)) if(g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT))
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_USE; localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_USE;
bool isClosableByEitherKey = ui.IsSceneInStack(i, eUIScene_FurnaceMenu) ||
ui.IsSceneInStack(i, eUIScene_ContainerMenu) ||
ui.IsSceneInStack(i, eUIScene_DispenserMenu) ||
ui.IsSceneInStack(i, eUIScene_EnchantingMenu) ||
ui.IsSceneInStack(i, eUIScene_BrewingStandMenu) ||
ui.IsSceneInStack(i, eUIScene_TradingMenu) ||
ui.IsSceneInStack(i, eUIScene_AnvilMenu) ||
ui.IsSceneInStack(i, eUIScene_HopperMenu) ||
ui.IsSceneInStack(i, eUIScene_BeaconMenu) ||
ui.IsSceneInStack(i, eUIScene_InventoryMenu) ||
ui.IsSceneInStack(i, eUIScene_HorseMenu);
bool isEditing = ui.GetTopScene(i) && ui.GetTopScene(i)->isDirectEditBlocking();
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_INVENTORY)) if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_INVENTORY))
{ {
if(ui.IsSceneInStack(i, eUIScene_InventoryMenu)) if(isClosableByEitherKey && !isEditing)
{ {
ui.CloseUIScenes(i); ui.CloseUIScenes(i);
} }
@ -1496,7 +1512,7 @@ void Minecraft::run_middle()
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING) || g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING_ALT)) if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING) || g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING_ALT))
{ {
if(ui.IsSceneInStack(i, eUIScene_Crafting2x2Menu) || ui.IsSceneInStack(i, eUIScene_Crafting3x3Menu) || ui.IsSceneInStack(i, eUIScene_CreativeMenu)) if((ui.IsSceneInStack(i, eUIScene_Crafting2x2Menu) || ui.IsSceneInStack(i, eUIScene_Crafting3x3Menu) || ui.IsSceneInStack(i, eUIScene_CreativeMenu) || isClosableByEitherKey) && !isEditing)
{ {
ui.CloseUIScenes(i); ui.CloseUIScenes(i);
} }
@ -2066,7 +2082,7 @@ void Minecraft::run_middle()
while (System::nanoTime() >= lastTime + 1000000000) while (System::nanoTime() >= lastTime + 1000000000)
{ {
MemSect(31); MemSect(31);
fpsString = std::to_wstring(frames) + L" fps, " + std::to_wstring(Chunk::updates) + L" chunk updates"; fpsString = std::to_wstring(frames) + L" fps (" + std::to_wstring(Chunk::updates) + L" chunk updates)";
MemSect(0); MemSect(0);
Chunk::updates = 0; Chunk::updates = 0;
lastTime += 1000000000; lastTime += 1000000000;
@ -2357,16 +2373,21 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
} }
#ifdef _WINDOWS64 #ifdef _WINDOWS64
if ((screen != NULL || ui.GetMenuDisplayed(iPad)) && g_KBMInput.IsMouseGrabbed()) // Mouse grab/release only for the primary (KBM) player — splitscreen
// players use controllers and must never fight over the cursor state.
if (iPad == ProfileManager.GetPrimaryPad())
{ {
g_KBMInput.SetMouseGrabbed(false); if ((screen != NULL || ui.GetMenuDisplayed(iPad)) && g_KBMInput.IsMouseGrabbed())
{
g_KBMInput.SetMouseGrabbed(false);
}
} }
#endif #endif
if (screen == NULL && !ui.GetMenuDisplayed(iPad) ) if (screen == NULL && !ui.GetMenuDisplayed(iPad) )
{ {
#ifdef _WINDOWS64 #ifdef _WINDOWS64
if (!g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsWindowFocused()) if (iPad == ProfileManager.GetPrimaryPad() && !g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsWindowFocused())
{ {
g_KBMInput.SetMouseGrabbed(true); g_KBMInput.SetMouseGrabbed(true);
} }
@ -4226,6 +4247,17 @@ void Minecraft::setLevel(MultiPlayerLevel *level, int message /*=-1*/, shared_pt
// 4J - stop update thread from processing this level, which blocks until it is safe to move on - will be re-enabled if we set the level to be non-NULL // 4J - stop update thread from processing this level, which blocks until it is safe to move on - will be re-enabled if we set the level to be non-NULL
gameRenderer->DisableUpdateThread(); gameRenderer->DisableUpdateThread();
if (level == NULL || player == NULL)
{
for (int i = 0; i < XUSER_MAX_COUNT; ++i)
{
if (localitemInHandRenderers[i] != NULL)
{
localitemInHandRenderers[i]->reset();
}
}
}
for(unsigned int i = 0; i < levels.length; ++i) for(unsigned int i = 0; i < levels.length; ++i)
{ {
// 4J We only need to save out in multiplayer is we are setting the level to NULL // 4J We only need to save out in multiplayer is we are setting the level to NULL
@ -4642,8 +4674,14 @@ void Minecraft::startAndConnectTo(const wstring& name, const wstring& sid, const
Minecraft *minecraft; Minecraft *minecraft;
// 4J - was new Minecraft(frame, canvas, NULL, 854, 480, fullScreen); // 4J - was new Minecraft(frame, canvas, NULL, 854, 480, fullScreen);
// Logical width is proportional to the real screen aspect ratio so that
// the ortho projection and HUD layout match the viewport without stretching.
extern int g_iScreenWidth;
extern int g_iScreenHeight;
int logicalH = 720;
int logicalW = logicalH * g_iScreenWidth / g_iScreenHeight;
minecraft = new Minecraft(NULL, NULL, NULL, 1280, 720, fullScreen); minecraft = new Minecraft(NULL, NULL, NULL, logicalW, logicalH, fullScreen);
/* - 4J - removed /* - 4J - removed
{ {

View file

@ -2169,12 +2169,16 @@ void MinecraftServer::tick()
} }
Entity::tickExtraWandering(); // 4J added Entity::tickExtraWandering(); // 4J added
PIXBeginNamedEvent(0,"Connection tick"); // Process player disconnect/kick queue BEFORE ticking connections.
connection->tick(); // PendingConnection::handleLogin rejects duplicate XUIDs, so the old
PIXEndNamedEvent(); // player must be removed from PlayerList before a reconnecting client's
// LoginPacket is processed.
PIXBeginNamedEvent(0,"Players tick"); PIXBeginNamedEvent(0,"Players tick");
players->tick(); players->tick();
PIXEndNamedEvent(); PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Connection tick");
connection->tick();
PIXEndNamedEvent();
// 4J - removed // 4J - removed
#if 0 #if 0

View file

@ -32,6 +32,7 @@
//#include "NetworkManager.h" //#include "NetworkManager.h"
#include "..\..\Minecraft.Client\Tesselator.h" #include "..\..\Minecraft.Client\Tesselator.h"
#include "..\..\Minecraft.Client\Options.h" #include "..\..\Minecraft.Client\Options.h"
#include "..\GameRenderer.h"
#include "Sentient\SentientManager.h" #include "Sentient\SentientManager.h"
#include "..\..\Minecraft.World\IntCache.h" #include "..\..\Minecraft.World\IntCache.h"
#include "..\Textures.h" #include "..\Textures.h"
@ -1302,6 +1303,9 @@ int main(int argc, const char *argv[] )
#endif #endif
ui.tick(); ui.tick();
ui.render(); ui.render();
pMinecraft->gameRenderer->ApplyGammaPostProcess();
#if 0 #if 0
app.HandleButtonPresses(); app.HandleButtonPresses();

View file

@ -43,7 +43,7 @@ Dungeon!
Exclusive! Exclusive!
The bee's knees! The bee's knees!
Down with O.P.P.! Down with O.P.P.!
Closed source! Closed source xD!
Classy! Classy!
Wow! Wow!
Not on steam! Not on steam!

View file

@ -86,6 +86,7 @@ char secureFileId[CELL_SAVEDATA_SECUREFILEID_SIZE] =
#include "..\..\Minecraft.Client\Tesselator.h" #include "..\..\Minecraft.Client\Tesselator.h"
#include "..\Common\Console_Awards_enum.h" #include "..\Common\Console_Awards_enum.h"
#include "..\..\Minecraft.Client\Options.h" #include "..\..\Minecraft.Client\Options.h"
#include "..\GameRenderer.h"
#include "Sentient\SentientManager.h" #include "Sentient\SentientManager.h"
#include "..\..\Minecraft.World\IntCache.h" #include "..\..\Minecraft.World\IntCache.h"
#include "..\Textures.h" #include "..\Textures.h"
@ -1245,6 +1246,8 @@ int main()
ui.tick(); ui.tick();
ui.render(); ui.render();
pMinecraft->gameRenderer->ApplyGammaPostProcess();
// Present the frame. // Present the frame.
PIXBeginNamedEvent(0,"Frame present"); PIXBeginNamedEvent(0,"Frame present");
RenderManager.Present(); RenderManager.Present();

View file

@ -46,6 +46,7 @@
#include "..\..\Minecraft.Client\Tesselator.h" #include "..\..\Minecraft.Client\Tesselator.h"
#include "..\Common\Console_Awards_enum.h" #include "..\Common\Console_Awards_enum.h"
#include "..\..\Minecraft.Client\Options.h" #include "..\..\Minecraft.Client\Options.h"
#include "..\GameRenderer.h"
#include "Sentient\SentientManager.h" #include "Sentient\SentientManager.h"
#include "..\..\Minecraft.World\IntCache.h" #include "..\..\Minecraft.World\IntCache.h"
#include "..\Textures.h" #include "..\Textures.h"
@ -904,6 +905,9 @@ int main()
#endif #endif
ui.tick(); ui.tick();
ui.render(); ui.render();
pMinecraft->gameRenderer->ApplyGammaPostProcess();
#if 0 #if 0
app.HandleButtonPresses(); app.HandleButtonPresses();

View file

@ -190,9 +190,34 @@ void PendingConnection::handleLogin(shared_ptr<LoginPacket> packet)
} }
else if (duplicateXuid) else if (duplicateXuid)
{ {
// if same XUID already in use by another player so disconnect this one. // The old player is still in PlayerList (disconnect hasn't been
app.DebugPrintf("Rejecting duplicate xuid for name: %ls\n", name.c_str()); // processed yet). Force-close the stale connection so the
disconnect(DisconnectPacket::eDisconnect_Banned); // reconnecting client isn't rejected.
app.DebugPrintf("RECONNECT: Duplicate xuid for name: %ls, forcing old connection closed\n", name.c_str());
shared_ptr<ServerPlayer> stalePlayer = server->getPlayers()->getPlayer(loginXuid);
if (stalePlayer == nullptr && packet->m_onlineXuid != INVALID_XUID)
stalePlayer = server->getPlayers()->getPlayer(packet->m_onlineXuid);
if (stalePlayer != nullptr && stalePlayer->connection != nullptr)
{
BYTE oldSmallId = 0;
if (stalePlayer->connection->connection != nullptr && stalePlayer->connection->connection->getSocket() != nullptr)
oldSmallId = stalePlayer->connection->connection->getSocket()->getSmallId();
app.DebugPrintf("RECONNECT: Force-disconnecting old player smallId=%d\n", oldSmallId);
stalePlayer->connection->disconnect(DisconnectPacket::eDisconnect_Closed);
// Queue the old SmallId for recycling so it's not permanently leaked.
// PlayerList::tick() will call PushFreeSmallId/ClearSocketForSmallId.
if (oldSmallId != 0)
server->getPlayers()->queueSmallIdForRecycle(oldSmallId);
app.DebugPrintf("RECONNECT: Old player force-disconnect complete\n");
}
// Accept the login now that the old entry is removed.
app.DebugPrintf("RECONNECT: Calling handleAcceptedLogin for new connection\n");
handleAcceptedLogin(packet);
app.DebugPrintf("RECONNECT: handleAcceptedLogin complete\n");
} }
#ifdef _WINDOWS64 #ifdef _WINDOWS64
else if (g_bRejectDuplicateNames) else if (g_bRejectDuplicateNames)

View file

@ -19,6 +19,9 @@
#include "..\Minecraft.World\net.minecraft.network.packet.h" #include "..\Minecraft.World\net.minecraft.network.packet.h"
#include "..\Minecraft.World\net.minecraft.network.h" #include "..\Minecraft.World\net.minecraft.network.h"
#include "Windows64\Windows64_Xuid.h" #include "Windows64\Windows64_Xuid.h"
#ifdef _WINDOWS64
#include "Windows64\Network\WinsockNetLayer.h"
#endif
#include "..\Minecraft.World\Pos.h" #include "..\Minecraft.World\Pos.h"
#include "..\Minecraft.World\ProgressListener.h" #include "..\Minecraft.World\ProgressListener.h"
#include "..\Minecraft.World\HellRandomLevelSource.h" #include "..\Minecraft.World\HellRandomLevelSource.h"
@ -237,6 +240,14 @@ bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer>
addPlayerToReceiving( player ); addPlayerToReceiving( player );
int maxPlayersForPacket = getMaxPlayers() > 255 ? 255 : getMaxPlayers(); int maxPlayersForPacket = getMaxPlayers() > 255 ? 255 : getMaxPlayers();
BYTE newSmallId = 0;
Socket *sock = connection->getSocket();
INetworkPlayer *np = sock ? sock->getPlayer() : nullptr;
if (np) newSmallId = np->GetSmallId();
app.DebugPrintf("RECONNECT: placeNewPlayer smallId=%d entityId=%d dim=%d\n",
newSmallId, player->entityId, level->dimension->id);
playerConnection->send( shared_ptr<LoginPacket>( new LoginPacket(L"", player->entityId, level->getLevelData()->getGenerator(), level->getSeed(), player->gameMode->getGameModeForPlayer()->getId(), playerConnection->send( shared_ptr<LoginPacket>( new LoginPacket(L"", player->entityId, level->getLevelData()->getGenerator(), level->getSeed(), player->gameMode->getGameModeForPlayer()->getId(),
(byte) level->dimension->id, (byte) level->getMaxBuildHeight(), (byte) maxPlayersForPacket, (byte) level->dimension->id, (byte) level->getMaxBuildHeight(), (byte) maxPlayersForPacket,
level->difficulty, TelemetryManager->GetMultiplayerInstanceID(), (BYTE)playerIndex, level->useNewSeaLevel(), player->getAllPlayerGamePrivileges(), level->difficulty, TelemetryManager->GetMultiplayerInstanceID(), (BYTE)playerIndex, level->useNewSeaLevel(), player->getAllPlayerGamePrivileges(),
@ -979,6 +990,14 @@ void PlayerList::tick()
{ {
player->connection->disconnect( DisconnectPacket::eDisconnect_Closed ); player->connection->disconnect( DisconnectPacket::eDisconnect_Closed );
} }
#ifdef _WINDOWS64
// The old Connection's read/write threads are now dead (disconnect waits
// for them). Safe to recycle the smallId — no stale write thread can
// resolve getPlayer() to a new connection that reuses this slot.
WinsockNetLayer::PushFreeSmallId(smallId);
WinsockNetLayer::ClearSocketForSmallId(smallId);
#endif
} }
LeaveCriticalSection(&m_closePlayersCS); LeaveCriticalSection(&m_closePlayersCS);
@ -1618,6 +1637,13 @@ void PlayerList::closePlayerConnectionBySmallId(BYTE networkSmallId)
LeaveCriticalSection(&m_closePlayersCS); LeaveCriticalSection(&m_closePlayersCS);
} }
void PlayerList::queueSmallIdForRecycle(BYTE smallId)
{
EnterCriticalSection(&m_closePlayersCS);
m_smallIdsToClose.push_back(smallId);
LeaveCriticalSection(&m_closePlayersCS);
}
bool PlayerList::isXuidBanned(PlayerUID xuid) bool PlayerList::isXuidBanned(PlayerUID xuid)
{ {
if( xuid == INVALID_XUID ) return false; if( xuid == INVALID_XUID ) return false;

View file

@ -133,6 +133,7 @@ public:
// 4J Added // 4J Added
void kickPlayerByShortId(BYTE networkSmallId); void kickPlayerByShortId(BYTE networkSmallId);
void closePlayerConnectionBySmallId(BYTE networkSmallId); void closePlayerConnectionBySmallId(BYTE networkSmallId);
void queueSmallIdForRecycle(BYTE smallId);
bool isXuidBanned(PlayerUID xuid); bool isXuidBanned(PlayerUID xuid);
// AP added for Vita so the range can be increased once the level starts // AP added for Vita so the range can be increased once the level starts
void setViewDistance(int newViewDistance); void setViewDistance(int newViewDistance);

View file

@ -46,19 +46,30 @@ void ServerConnection::handleConnection(shared_ptr<PendingConnection> uc)
void ServerConnection::stop() void ServerConnection::stop()
{ {
std::vector<shared_ptr<PendingConnection> > pendingSnapshot;
EnterCriticalSection(&pending_cs); EnterCriticalSection(&pending_cs);
for (unsigned int i = 0; i < pending.size(); i++) pendingSnapshot = pending;
{
shared_ptr<PendingConnection> uc = pending[i];
uc->connection->close(DisconnectPacket::eDisconnect_Closed);
}
LeaveCriticalSection(&pending_cs); LeaveCriticalSection(&pending_cs);
for (unsigned int i = 0; i < players.size(); i++) for (unsigned int i = 0; i < pendingSnapshot.size(); i++)
{ {
shared_ptr<PlayerConnection> player = players[i]; shared_ptr<PendingConnection> uc = pendingSnapshot[i];
player->connection->close(DisconnectPacket::eDisconnect_Closed); if (uc != NULL && !uc->done)
} {
uc->disconnect(DisconnectPacket::eDisconnect_Closed);
}
}
// Snapshot to avoid iterator invalidation if disconnect modifies the vector.
std::vector<shared_ptr<PlayerConnection> > playerSnapshot = players;
for (unsigned int i = 0; i < playerSnapshot.size(); i++)
{
shared_ptr<PlayerConnection> player = playerSnapshot[i];
if (player != NULL && !player->done)
{
player->disconnect(DisconnectPacket::eDisconnect_Quitting);
}
}
} }
void ServerConnection::tick() void ServerConnection::tick()
@ -107,7 +118,10 @@ void ServerConnection::tick()
players.erase(players.begin()+i); players.erase(players.begin()+i);
i--; i--;
} }
player->connection->flush(); else
{
player->connection->flush();
}
} }
} }

View file

@ -256,7 +256,6 @@ void ServerLevel::tick()
if (time % (saveInterval) == (dimension->id * dimension->id * (saveInterval/2))) if (time % (saveInterval) == (dimension->id * dimension->id * (saveInterval/2)))
#endif #endif
{ {
//app.DebugPrintf("Incremental save\n");
PIXBeginNamedEvent(0,"Incremental save"); PIXBeginNamedEvent(0,"Incremental save");
save(false, NULL); save(false, NULL);
PIXEndNamedEvent(); PIXEndNamedEvent();

View file

@ -426,7 +426,6 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
// unloaded on the client and so just gradually build up more and more of the finite set of chunks as the player moves // unloaded on the client and so just gradually build up more and more of the finite set of chunks as the player moves
if( !g_NetworkManager.SystemFlagGet(connection->getNetworkPlayer(),flagIndex) ) if( !g_NetworkManager.SystemFlagGet(connection->getNetworkPlayer(),flagIndex) )
{ {
// app.DebugPrintf("Creating BRUP for %d %d\n",nearest.x, nearest.z);
PIXBeginNamedEvent(0,"Creation BRUP for sending\n"); PIXBeginNamedEvent(0,"Creation BRUP for sending\n");
int64_t before = System::currentTimeMillis(); int64_t before = System::currentTimeMillis();
shared_ptr<BlockRegionUpdatePacket> packet = shared_ptr<BlockRegionUpdatePacket>( new BlockRegionUpdatePacket(nearest.x * 16, 0, nearest.z * 16, 16, Level::maxBuildHeight, 16, level) ); shared_ptr<BlockRegionUpdatePacket> packet = shared_ptr<BlockRegionUpdatePacket>( new BlockRegionUpdatePacket(nearest.x * 16, 0, nearest.z * 16, 16, Level::maxBuildHeight, 16, level) );

Some files were not shown because too many files have changed in this diff Show more