initial commit

This commit is contained in:
2026-08-27 17:15:05 -07:00
commit 80e222fa04
71 changed files with 54456 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
build/
out/
*.obj
*.exe
*.lib
*.pdb
*.ilk
*.exp
.vs/
*.sdf
*.suo
*.user
*.log
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
Makefile
Thumbs.db
Desktop.ini
+130
View File
@@ -0,0 +1,130 @@
cmake_minimum_required(VERSION 3.14)
project(ImXui VERSION 0.1.0 LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(IMXUI_CORE_SOURCES
src/Element.cpp
src/Canvas.cpp
src/XurParser.cpp
src/XuiClasses.cpp
src/XurXml.cpp
src/Application.cpp
src/RenderCommands.cpp
src/XuiControls.cpp
src/XzpPackage.cpp
src/XuiXmlWriter.cpp
src/XurWriter.cpp
)
if(WIN32)
list(APPEND IMXUI_CORE_SOURCES src/XuiCompat.cpp src/X360Backend.cpp)
endif()
set(IMXUI_BACKEND_SOURCES
src/Renderer.cpp
src/TextureManager.cpp
src/Skin.cpp
)
set(IMXUI_HEADERS
include/ImXui/ImXui.h
include/ImXui/RenderCommands.h
include/ImXui/XurFormat.h
include/ImXui/Renderer.h
include/ImXui/TextureManager.h
include/ImXui/Skin.h
include/ImXui/XurWriter.h
include/ImXui/XuiXmlWriter.h
)
add_library(ImXuiCore STATIC ${IMXUI_CORE_SOURCES} ${IMXUI_HEADERS})
target_include_directories(ImXuiCore PUBLIC include compat/include)
target_include_directories(ImXuiCore PRIVATE src)
set(IMXUI_HEADERS ${IMXUI_HEADERS} compat/include/xui.h compat/include/xuiapp.h
compat/include/xuirender.h compat/include/xuiresource.h)
add_library(ImXuiSoft STATIC
src/FontEngine.cpp
src/ImageManager.cpp
src/SoftwareRenderer.cpp
)
target_include_directories(ImXuiSoft PUBLIC include)
target_include_directories(ImXuiSoft PRIVATE src third_party)
target_link_libraries(ImXuiSoft PUBLIC ImXuiCore)
if(WIN32)
add_library(ImXui STATIC ${IMXUI_BACKEND_SOURCES} ${IMXUI_HEADERS})
target_include_directories(ImXui PUBLIC include)
target_include_directories(ImXui PRIVATE src)
target_link_libraries(ImXui PUBLIC ImXuiCore d3d11.lib dxgi.lib d3dcompiler.lib d2d1.lib dwrite.lib)
endif()
if(WIN32)
add_executable(NotepadDemo WIN32 examples/NotepadDemo.cpp)
target_link_libraries(NotepadDemo PRIVATE ImXui comdlg32.lib)
target_include_directories(NotepadDemo PRIVATE include)
add_custom_command(TARGET NotepadDemo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_SOURCE_DIR}/examples/assets/notepad.xui"
"$<TARGET_FILE_DIR:NotepadDemo>"
COMMENT "Copying notepad.xui"
VERBATIM)
endif()
if(UNIX AND NOT APPLE)
add_executable(NotepadDemo examples/NotepadDemo.cpp)
target_link_libraries(NotepadDemo PRIVATE ImXuiSoft ImXuiCore X11)
target_include_directories(NotepadDemo PRIVATE include)
add_custom_command(TARGET NotepadDemo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_SOURCE_DIR}/examples/assets/notepad.xui"
"$<TARGET_FILE_DIR:NotepadDemo>"
COMMENT "Copying notepad.xui"
VERBATIM)
endif()
if(WIN32)
find_file(D3DCOMPILER_DLL d3dcompiler_46.dll
PATHS
"C:/Program Files (x86)/Windows Kits/8.0/Redist/D3D/x86"
"C:/Program Files (x86)/Windows Kits/8.1/Redist/D3D/x86"
"C:/Program Files (x86)/Windows Kits/10/Redist/D3D/x86"
NO_DEFAULT_PATH
)
mark_as_advanced(D3DCOMPILER_DLL)
if(D3DCOMPILER_DLL)
add_custom_command(TARGET NotepadDemo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${D3DCOMPILER_DLL}"
"$<TARGET_FILE_DIR:NotepadDemo>"
COMMENT "Copying d3dcompiler_46.dll")
endif()
endif()
add_executable(XUITool tools/xuitool.cpp
third_party/zlib/adler32.c
third_party/zlib/compress.c
third_party/zlib/crc32.c
third_party/zlib/deflate.c
third_party/zlib/infback.c
third_party/zlib/inffast.c
third_party/zlib/inflate.c
third_party/zlib/inftrees.c
third_party/zlib/trees.c
third_party/zlib/uncompr.c
third_party/zlib/zutil.c
)
target_link_libraries(XUITool PRIVATE ImXuiCore)
target_include_directories(XUITool PRIVATE include third_party/zlib)
if(WIN32)
install(TARGETS ImXui LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
endif()
install(DIRECTORY include/ DESTINATION include)
+41
View File
@@ -0,0 +1,41 @@
{
"version": 4,
"configurePresets": [
{
"name": "windows",
"displayName": "Windows (Visual Studio)",
"generator": "Visual Studio 17 2022",
"binaryDir": "${sourceDir}/build/windows",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "linux",
"displayName": "Linux (gcc makefiles)",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build/linux",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
}
],
"buildPresets": [
{
"name": "windows",
"configurePreset": "windows",
"configuration": "Debug"
},
{
"name": "linux",
"configurePreset": "linux"
}
]
}
+1339
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
#include "xui.h"
+1
View File
@@ -0,0 +1 @@
#include "xui.h"
+1
View File
@@ -0,0 +1 @@
#include "xui.h"
+194
View File
@@ -0,0 +1,194 @@
#include "xui.h"
#include "XUI/SlotProgressControl.h"
#include "XUI/XUI_BasePlayer.h"
#include "XUI/XUI_Chat.h"
#include "XUI/XUI_ConnectingProgress.h"
#include "XUI/XUI_Control_ComboBox.h"
#include "XUI/XUI_Ctrl_4JEdit.h"
#include "XUI/XUI_Ctrl_4JIcon.h"
#include "XUI/XUI_Ctrl_4JList.h"
#include "XUI/XUI_Ctrl_BeaconButton.h"
#include "XUI/XUI_Ctrl_BrewProgress.h"
#include "XUI/XUI_Ctrl_BubblesProgress.h"
#include "XUI/XUI_Ctrl_BurnProgress.h"
#include "XUI/XUI_Ctrl_CraftIngredientSlot.h"
#include "XUI/XUI_Ctrl_EnchantButton.h"
#include "XUI/XUI_Ctrl_EnchantmentBook.h"
#include "XUI/XUI_Ctrl_EnchantmentButtonText.h"
#include "XUI/XUI_Ctrl_FireProgress.h"
#include "XUI/XUI_Ctrl_LoadingProgress.h"
#include "XUI/XUI_Ctrl_MinecraftHorse.h"
#include "XUI/XUI_Ctrl_MinecraftPlayer.h"
#include "XUI/XUI_Ctrl_MinecraftSkinPreview.h"
#include "XUI/XUI_Ctrl_MinecraftSlot.h"
#include "XUI/XUI_Ctrl_MobEffect.h"
#include "XUI/XUI_Ctrl_PassthroughList.h"
#include "XUI/XUI_Ctrl_SliderWrapper.h"
#include "XUI/XUI_Ctrl_SlotItem.h"
#include "XUI/XUI_Ctrl_SlotItemListItem.h"
#include "XUI/XUI_Ctrl_SlotList.h"
#include "XUI/XUI_Ctrl_SplashPulser.h"
#include "XUI/XUI_DLCOffers.h"
#include "XUI/XUI_Death.h"
#include "XUI/XUI_Debug.h"
#include "XUI/XUI_DebugItemEditor.h"
#include "XUI/XUI_DebugOverlay.h"
#include "XUI/XUI_DebugSchematicCreator.h"
#include "XUI/XUI_DebugSetCamera.h"
#include "XUI/XUI_DebugTips.h"
#include "XUI/XUI_FullscreenProgress.h"
#include "XUI/XUI_HUD.h"
#include "XUI/XUI_HelpAndOptions.h"
#include "XUI/XUI_HelpControls.h"
#include "XUI/XUI_HelpCredits.h"
#include "XUI/XUI_HelpHowToPlay.h"
#include "XUI/XUI_HowToPlayMenu.h"
#include "XUI/XUI_InGameHostOptions.h"
#include "XUI/XUI_InGameInfo.h"
#include "XUI/XUI_InGamePlayerOptions.h"
#include "XUI/XUI_Intro.h"
#include "XUI/XUI_Leaderboards.h"
#include "XUI/XUI_LoadSettings.h"
#include "XUI/XUI_MainMenu.h"
#include "XUI/XUI_MultiGameCreate.h"
#include "XUI/XUI_MultiGameInfo.h"
#include "XUI/XUI_MultiGameJoinLoad.h"
#include "XUI/XUI_MultiGameLaunchMoreOptions.h"
#include "XUI/XUI_NewUpdateMessage.h"
#include "XUI/XUI_PartnernetPassword.h"
#include "XUI/XUI_PauseMenu.h"
#include "XUI/XUI_Reinstall.h"
#include "XUI/XUI_SaveMessage.h"
#include "XUI/XUI_Scene_Anvil.h"
#include "XUI/XUI_Scene_Base.h"
#include "XUI/XUI_Scene_Beacon.h"
#include "XUI/XUI_Scene_BrewingStand.h"
#include "XUI/XUI_Scene_Container.h"
#include "XUI/XUI_Scene_CraftingPanel.h"
#include "XUI/XUI_Scene_Enchant.h"
#include "XUI/XUI_Scene_Fireworks.h"
#include "XUI/XUI_Scene_Furnace.h"
#include "XUI/XUI_Scene_Hopper.h"
#include "XUI/XUI_Scene_HorseInventory.h"
#include "XUI/XUI_Scene_Inventory.h"
#include "XUI/XUI_Scene_Inventory_Creative.h"
#include "XUI/XUI_Scene_Trading.h"
#include "XUI/XUI_Scene_Trap.h"
#include "XUI/XUI_Scene_Win.h"
#include "XUI/XUI_SettingsAll.h"
#include "XUI/XUI_SettingsAudio.h"
#include "XUI/XUI_SettingsControl.h"
#include "XUI/XUI_SettingsGraphics.h"
#include "XUI/XUI_SettingsOptions.h"
#include "XUI/XUI_SettingsUI.h"
#include "XUI/XUI_SignEntry.h"
#include "XUI/XUI_SkinSelect.h"
#include "XUI/XUI_SocialPost.h"
#include "XUI/XUI_Teleport.h"
#include "XUI/XUI_TextEntry.h"
#include "XUI/XUI_TransferToXboxOne.h"
#include "XUI/XUI_TrialExitUpsell.h"
#include "XUI/XUI_TutorialPopup.h"
void XuiEnsureTitleClassesRegistered() {
CScene_Chat::Register();
CScene_ConnectingProgress::Register();
CScene_Controls::Register();
CScene_Credits::Register();
CScene_DLCMain::Register();
CScene_DLCOffers::Register();
CScene_Death::Register();
CScene_Debug::Register();
CScene_DebugItemEditor::Register();
CScene_DebugOverlay::Register();
CScene_DebugSchematicCreator::Register();
CScene_DebugSetCamera::Register();
CScene_DebugTips::Register();
CScene_FullscreenProgress::Register();
CScene_HelpAndOptions::Register();
CScene_HowToPlay::Register();
CScene_HowToPlayMenu::Register();
CScene_InGameHostOptions::Register();
CScene_InGameInfo::Register();
CScene_InGamePlayerOptions::Register();
CScene_Intro::Register();
CScene_Leaderboards::Register();
CScene_LoadGameSettings::Register();
CScene_Main::Register();
CScene_MultiGameCreate::Register();
CScene_MultiGameInfo::Register();
CScene_MultiGameJoinLoad::Register();
CScene_MultiGameLaunchMoreOptions::Register();
CScene_NewUpdateMessage::Register();
CScene_PartnernetPassword::Register();
CScene_Reinstall::Register();
CScene_SaveMessage::Register();
CScene_SettingsAll::Register();
CScene_SettingsAudio::Register();
CScene_SettingsControl::Register();
CScene_SettingsGraphics::Register();
CScene_SettingsOptions::Register();
CScene_SettingsUI::Register();
CScene_SignEntry::Register();
CScene_SkinSelect::Register();
CScene_SocialPost::Register();
CScene_Teleport::Register();
CScene_TextEntry::Register();
CScene_TransferToXboxOne::Register();
CScene_TrialExitUpsell::Register();
CScene_TutorialPopup::Register();
CScene_Win::Register();
CXuiControl4JComboBox::Register();
CXuiCtrl4JEdit::Register();
CXuiCtrl4JIcon::Register();
CXuiCtrl4JList::Register();
CXuiCtrlBeaconButton::Register();
CXuiCtrlBrewProgress::Register();
CXuiCtrlBubblesProgress::Register();
CXuiCtrlBurnProgress::Register();
CXuiCtrlCraftIngredientSlot::Register();
CXuiCtrlEnchantmentBook::Register();
CXuiCtrlEnchantmentButton::Register();
CXuiCtrlEnchantmentButtonText::Register();
CXuiCtrlFireProgress::Register();
CXuiCtrlLoadingProgress::Register();
CXuiCtrlMinecraftHorse::Register();
CXuiCtrlMinecraftPlayer::Register();
CXuiCtrlMinecraftSkinPreview::Register();
CXuiCtrlMinecraftSlot::Register();
CXuiCtrlMobEffect::Register();
CXuiCtrlPassThroughList::Register();
CXuiCtrlSliderWrapper::Register();
CXuiCtrlSlotItem::Register();
CXuiCtrlSlotItemListItem::Register();
CXuiCtrlSlotList::Register();
CXuiCtrlSplashPulser::Register();
CXuiSceneAnvil::Register();
CXuiSceneBase::Register();
CXuiSceneBasePlayer::Register();
CXuiSceneBeacon::Register();
CXuiSceneBrewingStand::Register();
CXuiSceneContainer::Register();
CXuiSceneCraftingPanel::Register();
CXuiSceneEnchant::Register();
CXuiSceneFireworks::Register();
CXuiSceneFurnace::Register();
CXuiSceneHopper::Register();
CXuiSceneHorseInventory::Register();
CXuiSceneHud::Register();
CXuiSceneInventory::Register();
CXuiSceneInventoryCreative::Register();
CXuiSceneTrading::Register();
CXuiSceneTrap::Register();
SlotProgressControl::Register();
UIScene_PauseMenu::Register();
}
namespace {
struct ImXuiTitleSeedInitializer {
ImXuiTitleSeedInitializer() { XuiEnsureTitleClassesRegistered(); }
} s_titleSeed;
}
File diff suppressed because it is too large Load Diff
+116
View File
@@ -0,0 +1,116 @@
<XuiCanvas version="000c">
<Properties>
<Width>1280.000000</Width>
<Height>720.000000</Height>
</Properties>
<XuiFigure>
<Properties>
<Id>chrome</Id>
<Width>1280.000000</Width>
<Height>720.000000</Height>
<Position>0.000000,0.000000,0.000000</Position>
<Anchor>15</Anchor>
<Fill>
<Properties>
<FillType>1</FillType>
<FillColor>0xff20242c</FillColor>
</Properties>
</Fill>
<Closed>true</Closed>
<Points>4,0.000000,0.000000,0.000000,0.000000,1280.000000,0.000000,0,1280.000000,0.000000,1280.000000,0.000000,1280.000000,720.000000,0,1280.000000,720.000000,1280.000000,720.000000,0.000000,720.000000,0,0.000000,720.000000,0.000000,720.000000,0.000000,0.000000,0,</Points>
</Properties>
<XuiFigure>
<Properties>
<Id>titleBar</Id>
<Width>1280.000000</Width>
<Height>30.000000</Height>
<Position>0.000000,0.000000,0.000000</Position>
<Anchor>7</Anchor>
<Fill>
<Properties>
<FillType>1</FillType>
<FillColor>0xff20242c</FillColor>
</Properties>
</Fill>
<Closed>true</Closed>
<Points>4,0.000000,0.000000,0.000000,0.000000,1280.000000,0.000000,0,1280.000000,0.000000,1280.000000,0.000000,1280.000000,30.000000,0,1280.000000,30.000000,1280.000000,30.000000,0.000000,30.000000,0,0.000000,30.000000,0.000000,30.000000,0.000000,0.000000,0,</Points>
</Properties>
</XuiFigure>
<XuiFigure>
<Properties>
<Id>menuBar</Id>
<Width>1280.000000</Width>
<Height>28.000000</Height>
<Position>0.000000,30.000000,0.000000</Position>
<Anchor>7</Anchor>
<Fill>
<Properties>
<FillType>1</FillType>
<FillColor>0xff2b303b</FillColor>
</Properties>
</Fill>
<Closed>true</Closed>
<Points>4,0.000000,0.000000,0.000000,0.000000,1280.000000,0.000000,0,1280.000000,0.000000,1280.000000,0.000000,1280.000000,28.000000,0,1280.000000,28.000000,1280.000000,28.000000,0.000000,28.000000,0,0.000000,28.000000,0.000000,28.000000,0.000000,0.000000,0,</Points>
</Properties>
</XuiFigure>
<XuiFigure>
<Properties>
<Id>textArea</Id>
<Width>1280.000000</Width>
<Height>638.000000</Height>
<Position>0.000000,58.000000,0.000000</Position>
<Anchor>15</Anchor>
<Fill>
<Properties>
<FillType>1</FillType>
<FillColor>0xff1c1f26</FillColor>
</Properties>
</Fill>
<Closed>true</Closed>
<Points>4,0.000000,0.000000,0.000000,0.000000,1280.000000,0.000000,0,1280.000000,0.000000,1280.000000,0.000000,1280.000000,638.000000,0,1280.000000,638.000000,1280.000000,638.000000,0.000000,638.000000,0,0.000000,638.000000,0.000000,638.000000,0.000000,0.000000,0,</Points>
</Properties>
</XuiFigure>
<XuiFigure>
<Properties>
<Id>statusBar</Id>
<Width>1280.000000</Width>
<Height>24.000000</Height>
<Position>0.000000,696.000000,0.000000</Position>
<Anchor>13</Anchor>
<Fill>
<Properties>
<FillType>1</FillType>
<FillColor>0xff2b303b</FillColor>
</Properties>
</Fill>
<Closed>true</Closed>
<Points>4,0.000000,0.000000,0.000000,0.000000,1280.000000,0.000000,0,1280.000000,0.000000,1280.000000,0.000000,1280.000000,24.000000,0,1280.000000,24.000000,1280.000000,24.000000,0.000000,24.000000,0,0.000000,24.000000,0.000000,24.000000,0.000000,0.000000,0,</Points>
</Properties>
</XuiFigure>
<XuiFigure>
<Properties>
<Id>findBar</Id>
<Width>1280.000000</Width>
<Height>40.000000</Height>
<Position>0.000000,58.000000,0.000000</Position>
<Anchor>7</Anchor>
<Show>false</Show>
<Fill>
<Properties>
<FillType>1</FillType>
<FillColor>0xff262b34</FillColor>
</Properties>
</Fill>
<Closed>true</Closed>
<Points>4,0.000000,0.000000,0.000000,0.000000,1280.000000,0.000000,0,1280.000000,0.000000,1280.000000,0.000000,1280.000000,40.000000,0,1280.000000,40.000000,1280.000000,40.000000,0.000000,40.000000,0,0.000000,40.000000,0.000000,40.000000,0.000000,0.000000,0,</Points>
</Properties>
</XuiFigure>
</XuiFigure>
</XuiCanvas>
+47
View File
@@ -0,0 +1,47 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
namespace ImXui {
class FontEngine {
public:
FontEngine();
~FontEngine();
bool loadFontFile(const std::string& path);
bool loadFontMemory(const void* data, size_t size);
bool loadSystemFont(const std::string& requestedName);
bool isLoaded() const { return m_font != nullptr; }
float measureText(const std::wstring& text, float sizePx) const;
float lineHeight(float sizePx) const;
bool renderText(const std::wstring& text, float sizePx,
std::vector<uint8_t>& outRgba, int& outW, int& outH) const;
const std::string& getLoadedPath() const { return m_path; }
private:
struct FontData;
FontData* m_font;
std::vector<uint8_t> m_blob;
const void* m_blobPtr;
size_t m_blobSize;
std::string m_path;
};
}
File diff suppressed because it is too large Load Diff
+833
View File
@@ -0,0 +1,833 @@
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <functional>
#include <unordered_map>
#include <cstdint>
#include "XurFormat.h"
namespace ImXui {
const float BASE_SCENE_WIDTH = 1280.0f;
const float BASE_SCENE_HEIGHT = 720.0f;
enum AnchorStyle : uint32_t {
AnchorNone = 0,
AnchorLeft = 0x01,
AnchorTop = 0x02,
AnchorRight = 0x04,
AnchorBottom = 0x08,
AnchorCenterX = 0x10,
AnchorCenterY = 0x20,
};
enum class Result {
Success = 0,
Error_General = -1,
Error_NotFound = -2,
Error_InvalidParam = -3,
Error_OutOfMemory = -4,
Error_InvalidFile = -5,
Error_NotImplemented = -6,
};
struct Vec2 {
Vec2() : x(0), y(0) {}
Vec2(float x_, float y_) : x(x_), y(y_) {}
float x, y;
};
struct Vec3 {
Vec3() : x(0), y(0), z(0) {}
Vec3(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
float x, y, z;
};
struct Rect {
Rect() : x(0), y(0), w(0), h(0) {}
Rect(float x_, float y_, float w_, float h_) : x(x_), y(y_), w(w_), h(h_) {}
float x, y, w, h;
float left() const { return x; }
float top() const { return y; }
float right() const { return x + w; }
float bottom() const { return y + h; }
Vec2 center() const { return Vec2(x + w * 0.5f, y + h * 0.5f); }
};
struct Color {
Color() : r(1.0f), g(1.0f), b(1.0f), a(1.0f) {}
Color(float r_, float g_, float b_, float a_) : r(r_), g(g_), b(b_), a(a_) {}
float r, g, b, a;
};
class Value {
public:
enum Type {
Null, Boolean, Number, StringUTF8, StringUTF16,
};
Value() : m_type(Null), m_number(0.0), m_bool(false) {}
explicit Value(bool v) : m_type(Boolean), m_number(0.0), m_bool(v) {}
explicit Value(double v) : m_type(Number), m_number(v), m_bool(false) {}
explicit Value(float v) : m_type(Number), m_number((double)v), m_bool(false) {}
explicit Value(int v) : m_type(Number), m_number((double)v), m_bool(false) {}
explicit Value(const char* utf8) : m_type(StringUTF8), m_number(0.0), m_bool(false), m_string8(utf8 ? utf8 : "") {}
explicit Value(const std::string& utf8) : m_type(StringUTF8), m_number(0.0), m_bool(false), m_string8(utf8) {}
explicit Value(const wchar_t* utf16) : m_type(StringUTF16), m_number(0.0), m_bool(false), m_string16(utf16 ? utf16 : L"") {}
explicit Value(const std::wstring& utf16) : m_type(StringUTF16), m_number(0.0), m_bool(false), m_string16(utf16) {}
Type type() const { return m_type; }
bool isNull() const { return m_type == Null; }
bool isBool() const { return m_type == Boolean; }
bool isNumber() const { return m_type == Number; }
bool isString() const { return m_type == StringUTF8 || m_type == StringUTF16; }
bool toBool() const { return m_type == Boolean ? m_bool : false; }
double toNumber() const { return m_type == Number ? m_number : 0.0; }
float toFloat() const { return (float)toNumber(); }
int toInt() const { return (int)toNumber(); }
const std::string& toString8() const { return m_string8; }
const std::wstring& toString16() const { return m_string16; }
private:
Type m_type;
double m_number;
bool m_bool;
std::string m_string8;
std::wstring m_string16;
};
enum class EventType {
None, Press, Release, FocusGained, FocusLost,
ValueChanged, SelectionChanged, SliderMove,
MouseEnter, MouseLeave, AnimationEnd,
};
class Element;
class Control;
class Scene;
class Canvas;
class Application;
typedef std::function<Result(Scene*, void*)> InitCallback;
typedef std::function<Result(Scene*, uint32_t)> TimerCallback;
typedef std::function<Result(Scene*, uint32_t key, bool down)> InputCallback;
typedef std::function<void(Scene*, void* region)> DrawCallback;
typedef std::function<Value(const std::vector<Value>&)> MethodCallback;
class Element {
public:
Element();
virtual ~Element();
void setId(const std::wstring& id) { m_id = id; }
const std::wstring& getId() const { return m_id; }
void setClassName(const std::wstring& name) { m_className = name; }
const std::wstring& getClassName() const { return m_className; }
void setParent(Element* parent) { m_parent = parent; }
Element* getParent() const { return m_parent; }
Element* getChildById(const std::wstring& id);
Element* findFirstChild(const std::wstring& id);
void setPosition(const Vec3& pos) { m_position = pos; markLayoutDirty(); }
Vec3 getPosition() const { return m_position; }
void setBounds(float w, float h) { m_bounds.w = w; m_bounds.h = h; markLayoutDirty(); }
Vec2 getBounds() const { return Vec2(m_bounds.w, m_bounds.h); }
void setAnchor(uint32_t anchor) { m_anchor = anchor; markLayoutDirty(); }
uint32_t getAnchor() const { return m_anchor; }
Rect getComputedRect() const { return m_computedRect; }
void markLayoutDirty() { m_layoutDirty = true; }
bool isLayoutDirty() const { return m_layoutDirty; }
void computeLayout(Rect parentRect);
void computeLayout() { computeLayout(Rect(0, 0, 1280, 720)); }
void setShow(bool show) { m_visible = show; }
bool isShown() const { return m_visible; }
void setOpacity(float opacity) { m_opacity = opacity; }
float getOpacity() const { return m_opacity; }
void setScale(const Vec3& scale) { m_scale = scale; }
Vec3 getScale() const { return m_scale; }
void setPivot(const Vec3& pivot) { m_pivot = pivot; }
Vec3 getPivot() const { return m_pivot; }
void setRotation(const Vec3& rotation) { m_rotation = rotation; }
Vec3 getRotation() const { return m_rotation; }
void setBlendMode(uint32_t mode) { m_blendMode = mode; }
uint32_t getBlendMode() const { return m_blendMode; }
void setClipChildren(bool clip) { m_clipChildren = clip; }
bool getClipChildren() const { return m_clipChildren; }
void setHittable(bool hittable) { m_hittable = hittable; }
bool isHittable() const { return m_hittable; }
void setLayoutLineBreak(bool lb) { m_layoutLineBreak = lb; markLayoutDirty(); }
bool getLayoutLineBreak() const { return m_layoutLineBreak; }
void setLayoutFloat(bool lf) { m_layoutFloat = lf; markLayoutDirty(); }
bool getLayoutFloat() const { return m_layoutFloat; }
void setColumn(uint32_t col) { m_column = col; markLayoutDirty(); }
uint32_t getColumn() const { return m_column; }
void setRow(uint32_t row) { m_row = row; markLayoutDirty(); }
uint32_t getRow() const { return m_row; }
void setColumnSpan(uint32_t span) { m_columnSpan = span; markLayoutDirty(); }
uint32_t getColumnSpan() const { return m_columnSpan; }
void setRowSpan(uint32_t span) { m_rowSpan = span; markLayoutDirty(); }
uint32_t getRowSpan() const { return m_rowSpan; }
void setColorFactor(const Color& c) { m_colorFactor = c; }
Color getColorFactor() const { return m_colorFactor; }
void setImagePath(const std::wstring& path) { m_imagePath = path; }
const std::wstring& getImagePath() const { return m_imagePath; }
void addChild(std::unique_ptr<Element> child);
bool removeChildById(const std::wstring& id);
const std::vector<std::unique_ptr<Element>>& getChildren() const { return m_children; }
virtual void onEvent(EventType type, const std::vector<Value>& args);
virtual bool isControl() const { return false; }
protected:
std::wstring m_id;
std::wstring m_className;
Element* m_parent;
std::vector<std::unique_ptr<Element>> m_children;
Vec3 m_position;
Rect m_bounds;
Vec3 m_scale;
Vec3 m_pivot;
Vec3 m_rotation;
float m_opacity;
bool m_visible;
Color m_colorFactor;
std::wstring m_imagePath;
uint32_t m_anchor;
uint32_t m_blendMode;
bool m_clipChildren;
bool m_hittable;
bool m_layoutLineBreak;
bool m_layoutFloat;
uint32_t m_column;
uint32_t m_row;
uint32_t m_columnSpan;
uint32_t m_rowSpan;
Rect m_computedRect;
bool m_layoutDirty;
bool m_isNineGrid;
uint32_t m_nineGridLeft;
uint32_t m_nineGridTop;
uint32_t m_nineGridRight;
uint32_t m_nineGridBottom;
bool m_nineGridNoCenter;
std::wstring m_nineGridTexture;
bool m_isFigure;
bool m_figureClosed;
uint32_t m_figureFillType;
Color m_figureFillColor;
std::wstring m_figureFillTexture;
float m_figureFillRotation;
Vec2 m_figureFillTranslation;
Vec2 m_figureFillScale;
uint32_t m_figureFillWrapX;
uint32_t m_figureFillWrapY;
float m_figureStrokeWidth;
Color m_figureStrokeColor;
std::vector<Vec2> m_figurePoints;
public:
void setIsNineGrid(bool v) { m_isNineGrid = v; }
bool getIsNineGrid() const { return m_isNineGrid; }
void setNineGridLeft(uint32_t v) { m_nineGridLeft = v; }
uint32_t getNineGridLeft() const { return m_nineGridLeft; }
void setNineGridTop(uint32_t v) { m_nineGridTop = v; }
uint32_t getNineGridTop() const { return m_nineGridTop; }
void setNineGridRight(uint32_t v) { m_nineGridRight = v; }
uint32_t getNineGridRight() const { return m_nineGridRight; }
void setNineGridBottom(uint32_t v) { m_nineGridBottom = v; }
uint32_t getNineGridBottom() const { return m_nineGridBottom; }
void setNineGridNoCenter(bool v) { m_nineGridNoCenter = v; }
bool getNineGridNoCenter() const { return m_nineGridNoCenter; }
void setNineGridTexture(const std::wstring& v) { m_nineGridTexture = v; }
const std::wstring& getNineGridTexture() const { return m_nineGridTexture; }
void setIsFigure(bool v) { m_isFigure = v; }
bool getIsFigure() const { return m_isFigure; }
void setFigureClosed(bool v) { m_figureClosed = v; }
bool getFigureClosed() const { return m_figureClosed; }
void setFigureFillType(uint32_t v) { m_figureFillType = v; }
uint32_t getFigureFillType() const { return m_figureFillType; }
void setFigureFillColor(const Color& c) { m_figureFillColor = c; }
Color getFigureFillColor() const { return m_figureFillColor; }
void setFigureFillTexture(const std::wstring& v) { m_figureFillTexture = v; }
const std::wstring& getFigureFillTexture() const { return m_figureFillTexture; }
void setFigureFillRotation(float v) { m_figureFillRotation = v; }
float getFigureFillRotation() const { return m_figureFillRotation; }
void setFigureFillTranslation(const Vec2& v) { m_figureFillTranslation = v; }
Vec2 getFigureFillTranslation() const { return m_figureFillTranslation; }
void setFigureFillScale(const Vec2& v) { m_figureFillScale = v; }
Vec2 getFigureFillScale() const { return m_figureFillScale; }
void setFigureFillWrapX(uint32_t v) { m_figureFillWrapX = v; }
uint32_t getFigureFillWrapX() const { return m_figureFillWrapX; }
void setFigureFillWrapY(uint32_t v) { m_figureFillWrapY = v; }
uint32_t getFigureFillWrapY() const { return m_figureFillWrapY; }
void setFigureStrokeWidth(float v) { m_figureStrokeWidth = v; }
float getFigureStrokeWidth() const { return m_figureStrokeWidth; }
void setFigureStrokeColor(const Color& c) { m_figureStrokeColor = c; }
Color getFigureStrokeColor() const { return m_figureStrokeColor; }
void setFigurePoints(const std::vector<Vec2>& pts) { m_figurePoints = pts; }
const std::vector<Vec2>& getFigurePoints() const { return m_figurePoints; }
};
class Control : public Element {
public:
Control();
explicit Control(const std::wstring& id);
~Control();
bool isControl() const override { return true; }
void setText(const std::wstring& text) { m_text = text; }
const std::wstring& getText() const { return m_text; }
void setFontName(const std::wstring& name) { m_fontName = name; }
const std::wstring& getFontName() const { return m_fontName; }
void setFontSize(float size) { m_fontSize = size; }
float getFontSize() const { return m_fontSize; }
void setEnable(bool enable) { m_enabled = enable; }
bool isEnabled() const { return m_enabled; }
void setFocused(bool focused);
bool isFocused() const { return m_focused; }
virtual void press();
void setOnPressCallback(const std::function<void()>& cb) { m_onPress = cb; }
virtual void onFocusGained();
virtual void onFocusLost();
void setOnFocusCallback(const std::function<void(bool)>& cb) { m_onFocus = cb; }
virtual void onValueChanged(const Value& newValue);
void setOnValueChangedCallback(const std::function<void(const Value&)>& cb) { m_onValueChanged = cb; }
virtual void onSelectionChanged(int newSelection);
void setOnSelectionChangedCallback(const std::function<void(int)>& cb) { m_onSelectionChanged = cb; }
void setVisual(const std::wstring& visual) { m_visual = visual; }
const std::wstring& getVisual() const { return m_visual; }
void setProgressValue(int value) { m_progressValue = value; }
int getProgressValue() const { return m_progressValue; }
void setProgressRange(int min, int max) { m_progressMin = min; m_progressMax = max; }
int getProgressMin() const { return m_progressMin; }
int getProgressMax() const { return m_progressMax; }
float getProgress() const {
if (m_progressMax <= m_progressMin) return 0;
return (float)(m_progressValue - m_progressMin) / (float)(m_progressMax - m_progressMin);
}
void setNavUp(const std::wstring& id) { m_navUp = id; }
const std::wstring& getNavUp() const { return m_navUp; }
void setNavDown(const std::wstring& id) { m_navDown = id; }
const std::wstring& getNavDown() const { return m_navDown; }
void setNavLeft(const std::wstring& id) { m_navLeft = id; }
const std::wstring& getNavLeft() const { return m_navLeft; }
void setNavRight(const std::wstring& id) { m_navRight = id; }
const std::wstring& getNavRight() const { return m_navRight; }
void setNavTabForward(const std::wstring& id) { m_navTabForward = id; }
const std::wstring& getNavTabForward() const { return m_navTabForward; }
void setNavTabBackward(const std::wstring& id) { m_navTabBackward = id; }
const std::wstring& getNavTabBackward() const { return m_navTabBackward; }
void setPressKey(uint32_t key) { m_pressKey = key; }
uint32_t getPressKey() const { return m_pressKey; }
void setPressAnimObject(const std::wstring& name) { m_pressAnimObject = name; }
const std::wstring& getPressAnimObject() const { return m_pressAnimObject; }
void setFocusAnimObject(const std::wstring& name) { m_focusAnimObject = name; }
const std::wstring& getFocusAnimObject() const { return m_focusAnimObject; }
void setStep(int step) { m_step = step; }
int getStep() const { return m_step; }
void setVertical(bool vert) { m_vertical = vert; }
bool isVertical() const { return m_vertical; }
void setAccelInc(int inc) { m_accelInc = inc; }
int getAccelInc() const { return m_accelInc; }
void setAccelTime(uint32_t time) { m_accelTime = time; }
uint32_t getAccelTime() const { return m_accelTime; }
virtual Value getProperty(const std::wstring& name);
virtual bool setProperty(const std::wstring& name, const Value& value);
void setUserData(void* data) { m_userData = data; }
void* getUserData() const { return m_userData; }
void onEvent(EventType type, const std::vector<Value>& args) override;
void setCustomDrawId(const std::wstring& id) { m_customDrawId = id; }
const std::wstring& getCustomDrawId() const { return m_customDrawId; }
Control* getNavTarget(int direction) const;
protected:
std::wstring m_text;
std::wstring m_fontName;
float m_fontSize;
std::wstring m_visual;
std::wstring m_customDrawId;
bool m_enabled;
bool m_focused;
int m_progressValue;
int m_progressMin;
int m_progressMax;
void* m_userData;
std::wstring m_navUp;
std::wstring m_navDown;
std::wstring m_navLeft;
std::wstring m_navRight;
std::wstring m_navTabForward;
std::wstring m_navTabBackward;
uint32_t m_pressKey;
std::wstring m_pressAnimObject;
std::wstring m_focusAnimObject;
int m_step;
bool m_vertical;
int m_accelInc;
uint32_t m_accelTime;
std::function<void()> m_onPress;
std::function<void(bool)> m_onFocus;
std::function<void(const Value&)> m_onValueChanged;
std::function<void(int)> m_onSelectionChanged;
};
class Scene {
public:
Scene();
virtual ~Scene();
virtual Result onCreate(void* initData = nullptr);
virtual Result onDestroy();
virtual Result onTick(float deltaTime);
virtual Result onKeyDown(uint32_t key);
virtual Result onKeyUp(uint32_t key);
virtual Result onTimer(uint32_t timerId);
virtual Result onTransitionStart(uint32_t transAction, uint32_t transType);
virtual Result onGetSourceText(int dataIndex, std::wstring& outText);
virtual Result onGetSourceImage(int dataIndex, std::wstring& outImagePath);
virtual Result onGetItemCount(int& outCount);
virtual Result onGetItemEnable(int itemIndex, bool& outEnabled);
Element* getRootElement() const { return m_root.get(); }
Control* findControl(const std::wstring& id);
Element* findElement(const std::wstring& id);
Element* findElementRecursive(Element* root, const std::wstring& id);
void setClassOverride(const std::wstring& className) { m_className = className; }
const std::wstring& getClassOverride() const { return m_className; }
void addSubScene(std::unique_ptr<Scene> subScene);
Scene* findSubScene(const std::wstring& id);
void setDisplaySize(float width, float height);
float getDisplayWidth() const { return m_displayWidth; }
float getDisplayHeight() const { return m_displayHeight; }
void setMovieWidth(float w) { m_movieWidth = w; }
float getMovieWidth() const { return m_movieWidth; }
void setMovieHeight(float h) { m_movieHeight = h; }
float getMovieHeight() const { return m_movieHeight; }
void setFrameRate(float fps) { m_frameRate = fps; }
float getFrameRate() const { return m_frameRate; }
void setUserData(void* data) { m_userData = data; }
void* getUserData() const { return m_userData; }
void setDefaultFocus(const std::wstring& id) { m_defaultFocus = id; }
const std::wstring& getDefaultFocus() const { return m_defaultFocus; }
void addTimer(uint32_t id, int intervalMs);
void killTimer(uint32_t id);
void updateTimers(float deltaTime);
void sendMessage(uint32_t msgId, void* data, Element* source = nullptr);
void broadcastMessage(uint32_t msgId, void* data, Element* source = nullptr);
void setOnMessageCallback(const std::function<bool(uint32_t, void*, Element*)>& cb) { m_messageCallback = cb; }
void playTimeline(const std::wstring& elementName, int startFrame, int endFrame, bool loop, bool pause);
void stopTimeline(const std::wstring& elementName, bool gotoEnd);
int findNamedFrame(const std::wstring& elementName, const std::wstring& frameName);
void loadTimelines(const std::vector<XurFormat::XurTimeline>& timelines,
const std::vector<XurFormat::XurNamedFrame>& namedFrames);
void startTimeline(const std::wstring& elementName);
void updateAnimations(float deltaTime);
void setFocusedControl(Control* ctrl);
Control* getFocusedControl() const { return m_focusedControl; }
void navigateFocus(int direction);
virtual Value callMethod(const std::wstring& methodName, const std::vector<Value>& args);
void registerMethod(const std::wstring& name, const MethodCallback& cb);
virtual void dispatchEvent(const std::wstring& targetId, EventType type, const std::vector<Value>& args);
typedef std::function<bool(const std::wstring& funcName, const std::vector<Value>& args)> ExternalCallback;
void setExternalCallback(const ExternalCallback& cb) { m_externalCallback = cb; }
protected:
std::unique_ptr<Element> m_root;
std::wstring m_className;
std::vector<std::unique_ptr<Scene>> m_subScenes;
struct TimerEntry {
uint32_t id;
int intervalMs;
float accumulated;
};
std::vector<TimerEntry> m_timers;
float m_displayWidth;
float m_displayHeight;
float m_movieWidth;
float m_movieHeight;
float m_frameRate;
void* m_userData;
std::wstring m_defaultFocus;
std::wstring m_transTo;
std::wstring m_transFrom;
std::wstring m_transBackTo;
std::wstring m_transBackFrom;
bool m_ignorePresses;
Control* m_focusedControl;
std::unordered_map<std::wstring, MethodCallback> m_methods;
ExternalCallback m_externalCallback;
std::function<bool(uint32_t, void*, Element*)> m_messageCallback;
struct AnimationState {
std::wstring elementName;
int currentFrame;
int startFrame;
int endFrame;
bool loop;
bool paused;
float timeAccum;
struct KFProp {
std::string name;
XurFormat::XurPropertyValue value;
};
struct Keyframe {
int time;
uint8_t interpolation;
uint8_t easeIn;
uint8_t easeOut;
std::vector<KFProp> properties;
};
std::vector<Keyframe> keyframes;
};
std::vector<AnimationState> m_animations;
struct NamedFrame {
std::wstring name;
int keyframe;
uint32_t command;
std::wstring targetParameter;
};
std::vector<NamedFrame> m_namedFrames;
struct TimelineData {
std::wstring elementName;
struct KFProperty {
std::string name;
XurFormat::XurPropertyValue value;
};
struct KeyframeData {
int time;
uint8_t interpolation;
uint8_t easeIn;
uint8_t easeOut;
std::vector<KFProperty> properties;
};
std::vector<KeyframeData> keyframes;
};
std::vector<TimelineData> m_timelines;
struct TransitionState {
bool active;
float elapsed;
float duration;
std::wstring transType;
std::wstring transScenePath;
std::unique_ptr<Scene> transScene;
};
TransitionState m_transition;
void applyKeyframeProperty(Element* target, const AnimationState::KFProp& prop);
void interpolateKeyframeProperty(Element* target,
const AnimationState::KFProp& propA,
const AnimationState::KFProp& propB,
float t);
public:
void setTransitionTo(const std::wstring& path) { m_transTo = path; }
const std::wstring& getTransitionTo() const { return m_transTo; }
void setTransitionFrom(const std::wstring& path) { m_transFrom = path; }
const std::wstring& getTransitionFrom() const { return m_transFrom; }
void setTransitionBackTo(const std::wstring& path) { m_transBackTo = path; }
const std::wstring& getTransitionBackTo() const { return m_transBackTo; }
void setTransitionBackFrom(const std::wstring& path) { m_transBackFrom = path; }
const std::wstring& getTransitionBackFrom() const { return m_transBackFrom; }
void setIgnorePresses(bool v) { m_ignorePresses = v; }
bool getIgnorePresses() const { return m_ignorePresses; }
void startTransition(const std::wstring& type, float duration = 0.5f);
void updateTransition(float deltaTime);
bool isTransitioning() const { return m_transition.active; }
float getTransitionProgress() const;
Scene* getTransitionScene() const { return m_transition.transScene.get(); }
Value builtinSetAlpha(const std::vector<Value>& args);
Value builtinSetFocus(const std::vector<Value>& args);
Value builtinSetSafeZone(const std::vector<Value>& args);
Value builtinRemoveObject(const std::vector<Value>& args);
Value builtinSlideLeft(const std::vector<Value>& args);
Value builtinSlideRight(const std::vector<Value>& args);
Value builtinDoHorizontalResizeCheck(const std::vector<Value>& args);
};
class Canvas {
public:
Canvas();
~Canvas();
Result loadFromXui(const std::string& path);
Result loadFromXuiString(const std::wstring& xmlContent);
Result loadFromXur(const std::string& path);
Result loadFromXurMemory(const void* data, size_t size);
float getWidth() const { return m_width; }
float getHeight() const { return m_height; }
Scene* getScene() const { return m_scene.get(); }
void setScene(std::unique_ptr<Scene> scene) { m_scene = std::move(scene); }
Result parseXuiXml(const std::wstring& xml);
private:
float m_width;
float m_height;
std::unique_ptr<Scene> m_scene;
std::unique_ptr<Element> parseElementNode(const std::wstring& xml, size_t& pos);
std::wstring readProperty(const std::wstring& xml, size_t& pos);
};
typedef void* HXUIBRUSH;
class Brush {
public:
Brush();
~Brush();
void setImagePath(const std::wstring& path) { m_imagePath = path; }
const std::wstring& getImagePath() const { return m_imagePath; }
void setColor(const Color& c) { m_color = c; }
Color getColor() const { return m_color; }
void setOpacity(float opacity) { m_opacity = opacity; }
float getOpacity() const { return m_opacity; }
private:
std::wstring m_imagePath;
Color m_color;
float m_opacity;
};
class ProgressBar : public Control {
public:
ProgressBar();
explicit ProgressBar(const std::wstring& id);
~ProgressBar();
void setRange(int min, int max) { setProgressRange(min, max); }
void setValue(int value) { setProgressValue(value); }
int getValue() const { return getProgressValue(); }
void getRange(int* min, int* max) const { *min = getProgressMin(); *max = getProgressMax(); }
};
class Slider : public Control {
public:
Slider();
explicit Slider(const std::wstring& id);
~Slider();
void setRange(int min, int max) { setProgressRange(min, max); }
void setValue(int value) { setProgressValue(value); }
int getValue() const { return getProgressValue(); }
void getRange(int* min, int* max) const { *min = getProgressMin(); *max = getProgressMax(); }
void setStep(int step) { Control::setStep(step); }
int getStep() const { return Control::getStep(); }
void setVertical(bool vert) { Control::setVertical(vert); }
bool isVertical() const { return Control::isVertical(); }
};
struct ListItemInfo {
std::wstring text;
std::wstring imagePath;
HXUIBRUSH brush;
bool checked;
bool enabled;
int userData;
int index;
int sortIndex;
ListItemInfo() : brush(0), checked(false), enabled(true), userData(0), index(0), sortIndex(0) {}
};
class List : public Control {
public:
List();
explicit List(const std::wstring& id);
~List();
void addItem(const ListItemInfo& item);
void removeAllItems();
void updateItemText(int item, const std::wstring& text);
void updateItemGraphic(int item, HXUIBRUSH brush);
void selectByUserData(int userData);
int getIndexByUserData(int userData) const;
ListItemInfo& getData(int index);
ListItemInfo& getDataByUserData(int userData);
int getItemCount() const { return (int)m_items.size(); }
void setSelectionChangedHandler(Control* handler) { m_selectionChangedHandler = handler; }
void setWrap(bool wrap) { m_wrap = wrap; }
bool getWrap() const { return m_wrap; }
void setOnGetSourceText(const std::function<std::wstring(int)>& cb) { m_onGetSourceText = cb; }
void setOnGetSourceImage(const std::function<std::wstring(int)>& cb) { m_onGetSourceImage = cb; }
void setOnGetItemCount(const std::function<int()>& cb) { m_onGetItemCount = cb; }
void setOnGetItemEnable(const std::function<bool(int)>& cb) { m_onGetItemEnable = cb; }
void setOnSelectionChanged(const std::function<void(int)>& cb) { m_onSelectionChangedIdx = cb; }
std::wstring getSourceText(int index);
std::wstring getSourceImage(int index);
bool getItemEnable(int index);
private:
std::vector<ListItemInfo> m_items;
Control* m_selectionChangedHandler;
bool m_wrap;
std::function<std::wstring(int)> m_onGetSourceText;
std::function<std::wstring(int)> m_onGetSourceImage;
std::function<int()> m_onGetItemCount;
std::function<bool(int)> m_onGetItemEnable;
std::function<void(int)> m_onSelectionChangedIdx;
};
class Sound : public Element {
public:
Sound();
~Sound();
void play();
void stop();
void setCue(const std::wstring& cue) { m_cue = cue; }
const std::wstring& getCue() const { return m_cue; }
void setSoundBank(const std::wstring& bank) { m_soundBank = bank; }
const std::wstring& getSoundBank() const { return m_soundBank; }
void setWaveBank(const std::wstring& bank) { m_waveBank = bank; }
const std::wstring& getWaveBank() const { return m_waveBank; }
void setVolume(float vol) { m_volume = vol; }
float getVolume() const { return m_volume; }
void setLoop(bool loop) { m_loop = loop; }
bool getLoop() const { return m_loop; }
private:
std::wstring m_cue;
std::wstring m_soundBank;
std::wstring m_waveBank;
float m_volume;
bool m_loop;
};
class ElementImplBase {
public:
virtual ~ElementImplBase() {}
virtual Result OnInit(void* initData) { (void)initData; return Result_Success; }
virtual Result OnDestroy() { return Result_Success; }
};
class ControlImplBase {
public:
virtual ~ControlImplBase() {}
virtual Result OnInit(void* hObj, void* initData) { (void)hObj; (void)initData; return Result_Success; }
virtual Result OnDestroy(void* hObj) { (void)hObj; return Result_Success; }
virtual Result OnControlNavigate(void* hObj, void* navData) { (void)hObj; (void)navData; return Result_Success; }
virtual Result OnKeyDown(void* hObj, void* inputData) { (void)hObj; (void)inputData; return Result_Success; }
virtual Result OnCustomMessage_GetSlotItem(void* hObj, void* pData) { (void)hObj; (void)pData; return Result_Success; }
};
class ListImpl : public Control {
public:
ListImpl();
~ListImpl();
};
class ProgressBarImpl : public ProgressBar {
public:
ProgressBarImpl();
~ProgressBarImpl();
};
class Application {
public:
Application();
~Application();
Result init();
Result shutdown();
Result navigateToScene(int pad, Scene* scene, void* initData = nullptr);
Result navigateBack(int pad);
Result closeScene(int pad, Scene* scene);
void tick(float deltaTime);
void render();
Result sendKeyEvent(int pad, uint32_t key, bool down);
void loadStringTable(const std::wstring& path);
const wchar_t* getString(int id) const;
static Application* getInstance() { return s_instance; }
private:
static Application* s_instance;
struct Impl;
std::unique_ptr<Impl> m_impl;
};
}
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>
namespace ImXui {
struct ImageData {
ImageData() : w(0), h(0) {}
int w;
int h;
std::vector<uint8_t> rgba;
bool valid() const { return w > 0 && h > 0 && !rgba.empty(); }
};
struct MemoryTexture {
int w;
int h;
std::vector<uint8_t> rgba;
MemoryTexture() : w(0), h(0) {}
};
void registerMemoryTexture(const std::string& name, const void* rgba,
int w, int h);
const MemoryTexture* findMemoryTexture(const std::string& name);
void clearMemoryTextures();
struct MemoryTextureRaw {
std::vector<uint8_t> encoded;
};
void registerMemoryTextureRaw(const std::string& name, const void* data, size_t size);
const MemoryTextureRaw* findMemoryTextureRaw(const std::string& name);
bool unregisterMemoryTexture(const std::string& name);
class ImageManager {
public:
ImageManager();
~ImageManager();
void setBasePath(const std::string& path) { m_basePath = path; }
const std::string& getBasePath() const { return m_basePath; }
const ImageData* load(const std::string& path);
static bool decodeFile(const std::string& path, ImageData& out);
void clear();
private:
std::string m_basePath;
std::unordered_map<std::string, ImageData> m_cache;
};
}
+151
View File
@@ -0,0 +1,151 @@
#pragma once
#include "ImXui.h"
#include <cstdint>
#include <string>
#include <vector>
namespace ImXui {
enum RenderCommandType {
RenderCommandType_BeginScene,
RenderCommandType_PushTransform,
RenderCommandType_PopTransform,
RenderCommandType_PushClip,
RenderCommandType_PopClip,
RenderCommandType_ColoredQuad,
RenderCommandType_TexturedQuad,
RenderCommandType_NineGrid,
RenderCommandType_Figure,
RenderCommandType_Text,
RenderCommandType_CustomDraw,
RenderCommandType_SetBlendMode,
RenderCommandType_EndScene,
};
struct Transform2D {
float m00, m01, m10, m11, tx, ty;
Transform2D()
: m00(1.0f), m01(0.0f), m10(0.0f), m11(1.0f), tx(0.0f), ty(0.0f) {}
};
struct RenderCommand {
RenderCommandType type;
Rect rect;
Color color;
Color strokeColor;
float opacity;
float strokeWidth;
uint32_t blendMode;
uint32_t leftInset;
uint32_t topInset;
uint32_t rightInset;
uint32_t bottomInset;
bool noCenter;
bool closed;
Transform2D transform;
std::wstring resource;
std::wstring text;
std::wstring fontName;
float fontSize;
bool centered;
std::vector<Vec2> points;
RenderCommand()
: type(RenderCommandType_BeginScene)
, rect()
, color()
, strokeColor()
, opacity(1.0f)
, strokeWidth(0.0f)
, blendMode(0)
, leftInset(0)
, topInset(0)
, rightInset(0)
, bottomInset(0)
, noCenter(false)
, closed(false)
, transform()
, fontSize(0.0f)
, centered(false)
{
}
};
class IRenderCommandSink {
public:
virtual ~IRenderCommandSink() {}
virtual void beginScene(float width, float height) = 0;
virtual void drawColoredQuad(const Rect& rect, const Color& color, float opacity) = 0;
virtual void drawTexturedQuad(const Rect& rect, const std::wstring& resource,
const Color& color, float opacity) = 0;
virtual void drawText(const Rect& rect, const std::wstring& text,
const std::wstring& fontName, float fontSize,
const Color& color, float opacity, bool centered) = 0;
virtual void endScene() = 0;
virtual void pushTransform(const Transform2D&) {}
virtual void popTransform() {}
virtual void pushClip(const Rect&) {}
virtual void popClip() {}
virtual void drawNineGrid(const Rect&, const std::wstring&, const Color&, float,
uint32_t, uint32_t, uint32_t, uint32_t, bool) {}
virtual void drawFigure(const Rect&, const std::vector<Vec2>&, bool,
const Color&, const Color&, float, float, uint32_t) {}
virtual void setBlendMode(uint32_t) {}
virtual void drawCustom(const std::wstring& drawId, const Rect&, float opacity) {
(void)drawId; (void)opacity;
}
};
class RenderCommandBuffer : public IRenderCommandSink {
public:
RenderCommandBuffer() : m_width(0.0f), m_height(0.0f) {}
void clear();
const std::vector<RenderCommand>& getCommands() const { return m_commands; }
std::vector<RenderCommand>& getCommands() { return m_commands; }
float getWidth() const { return m_width; }
float getHeight() const { return m_height; }
void beginScene(float width, float height);
void drawColoredQuad(const Rect& rect, const Color& color, float opacity);
void drawTexturedQuad(const Rect& rect, const std::wstring& resource,
const Color& color, float opacity);
void drawText(const Rect& rect, const std::wstring& text,
const std::wstring& fontName, float fontSize,
const Color& color, float opacity, bool centered);
void endScene();
void pushTransform(const Transform2D& transform);
void popTransform();
void pushClip(const Rect& rect);
void popClip();
void drawNineGrid(const Rect& rect, const std::wstring& resource,
const Color& color, float opacity,
uint32_t leftInset, uint32_t topInset,
uint32_t rightInset, uint32_t bottomInset,
bool noCenter);
void drawFigure(const Rect& rect, const std::vector<Vec2>& points, bool closed,
const Color& fillColor, const Color& strokeColor,
float opacity, float strokeWidth, uint32_t blendMode);
void setBlendMode(uint32_t blendMode);
void drawCustom(const std::wstring& drawId, const Rect& rect, float opacity);
private:
float m_width;
float m_height;
std::vector<RenderCommand> m_commands;
};
void emitRenderCommands(const Scene* scene, IRenderCommandSink* sink);
}
+183
View File
@@ -0,0 +1,183 @@
#pragma once
#include "ImXui.h"
#include "TextureManager.h"
#include "Skin.h"
#include <cstdint>
#include <string>
#include <map>
#include <list>
#include <vector>
#include <stack>
struct ID3D11Device;
struct ID3D11DeviceContext;
struct ID3D11Buffer;
struct ID3D11VertexShader;
struct ID3D11PixelShader;
struct ID3D11InputLayout;
struct ID3D11BlendState;
struct ID3D11SamplerState;
struct ID3D11RasterizerState;
struct ID3D11ShaderResourceView;
struct IDWriteFactory;
struct ID2D1Factory;
struct IDXGIDevice;
struct IDXGIFactory2;
struct IDXGISwapChain1;
struct IDCompositionDevice;
struct IDCompositionTarget;
struct IDCompositionVisual;
namespace ImXui {
struct RendererVertex2D { float x, y, u, v, r, g, b, a; };
class Renderer {
public:
virtual ~Renderer() {}
virtual bool init(void* nativeWindow, int width, int height) = 0;
virtual void shutdown() = 0;
virtual bool resize(int width, int height) = 0;
virtual bool beginFrame(float clearR = 0, float clearG = 0, float clearB = 0, float clearA = 1) = 0;
virtual void endFrame(bool vsync = true) = 0;
virtual void renderScene(const Scene* scene) = 0;
virtual void setTextureManager(TextureManager* mgr) = 0;
virtual void setSkin(const Skin* skin) = 0;
virtual const Skin* getSkin() const = 0;
virtual bool loadFont(const wchar_t* path) = 0;
virtual bool initTextRendering() = 0;
virtual void shutdownTextRendering() = 0;
virtual void drawTexturedQuad(float x, float y, float w, float h, const wchar_t* texturePath,
float r = 1, float g = 1, float b = 1, float a = 1) = 0;
virtual void drawFigure(float x, float y, float w, float h,
const std::vector<Vec2>& points, bool closed,
float fillR, float fillG, float fillB, float fillA,
float strokeR, float strokeG, float strokeB, float strokeA,
float strokeWidth) = 0;
virtual void drawColoredQuad(float x, float y, float w, float h,
float r, float g, float b, float a) = 0;
virtual void drawTextString(float x, float y, float w, float h,
const std::wstring& text, const std::wstring& fontName, float fontSize,
float r = 1, float g = 1, float b = 1, float a = 1,
bool centered = false) = 0;
virtual int getWidth() const = 0;
virtual int getHeight() const = 0;
};
class D3D11Renderer : public Renderer {
public:
D3D11Renderer();
~D3D11Renderer();
bool init(void* hwnd, int width, int height) override;
bool initExternal(ID3D11Device* device, ID3D11DeviceContext* context);
void shutdown() override;
bool resize(int width, int height) override;
bool beginFrame(float clearR = 0, float clearG = 0, float clearB = 0, float clearA = 1) override;
void endFrame(bool vsync = true) override;
void renderScene(const Scene* scene) override;
void setTextureManager(TextureManager* mgr) override { m_textureMgr = mgr; }
void setSkin(const Skin* skin) override { m_skin = skin; }
const Skin* getSkin() const override { return m_skin; }
ID3D11Device* getDevice() const { return m_device; }
ID3D11DeviceContext* getContext() const { return m_context; }
bool loadFont(const wchar_t* path) override;
bool initTextRendering() override;
void shutdownTextRendering() override;
void drawTexturedQuad(float x, float y, float w, float h, const wchar_t* texturePath,
float r = 1, float g = 1, float b = 1, float a = 1) override;
void drawTexturedQuadSRV(float x, float y, float w, float h, ID3D11ShaderResourceView* srv,
float r = 1, float g = 1, float b = 1, float a = 1);
void drawNineGrid(float x, float y, float w, float h, ID3D11ShaderResourceView* srv,
uint32_t leftInset, uint32_t topInset, uint32_t rightInset, uint32_t bottomInset,
bool noCenter, float r = 1, float g = 1, float b = 1, float a = 1);
void drawFigure(float x, float y, float w, float h,
const std::vector<Vec2>& points, bool closed,
float fillR, float fillG, float fillB, float fillA,
float strokeR, float strokeG, float strokeB, float strokeA,
float strokeWidth) override;
void drawColoredQuad(float x, float y, float w, float h,
float r, float g, float b, float a) override;
void drawTextString(float x, float y, float w, float h,
const std::wstring& text, const std::wstring& fontName, float fontSize,
float r = 1, float g = 1, float b = 1, float a = 1,
bool centered = false) override;
int getWidth() const override { return m_width; }
int getHeight() const override { return m_height; }
private:
bool createShadersAndStates();
bool createQuadBuffer();
bool createWhiteTexture();
void drawElement(const Element* el);
void drawTexturedElement(const Element* el);
void drawVisualImages(const std::vector<VisualImage>& images, const Rect& elementRect, float offsetX, float offsetY, float alpha);
Rect computeImageRect(const VisualImage& img, const Rect& visualBounds, const Rect& elementRect);
ID3D11ShaderResourceView* getOrCreateTextTexture(const std::wstring& text, const std::wstring& fontName, float fontSize, uint32_t textStyle, float maxWidth, int& outW, int& outH);
void drawText(const Control* ctrl, const Rect& rect, float alpha, const std::wstring& fontName, float fontSize, float textR = 1, float textG = 1, float textB = 1, float textA = 1, uint32_t textStyle = 0);
ID3D11Device* m_device;
ID3D11DeviceContext* m_context;
bool m_ownsDevice;
void* m_swapChain;
IDCompositionDevice* m_dcompDevice;
IDCompositionTarget* m_dcompTarget;
IDCompositionVisual* m_dcompVisual;
ID3D11VertexShader* m_vs;
ID3D11PixelShader* m_psTex;
ID3D11InputLayout* m_inputLayout;
ID3D11BlendState* m_blendState;
ID3D11BlendState* m_textBlendState;
ID3D11SamplerState* m_sampler;
ID3D11ShaderResourceView* m_whiteSRV;
ID3D11RasterizerState* m_scissorRS;
ID3D11RasterizerState* m_normalRS;
std::stack<Rect> m_clipStack;
ID3D11Buffer* m_quadVB;
RendererVertex2D* m_batchPtr;
int m_batchCount;
int m_width;
int m_height;
TextureManager* m_textureMgr;
const Skin* m_skin;
IDWriteFactory* m_dwriteFactory;
ID2D1Factory* m_d2dFactory;
struct TextCacheEntry { ID3D11ShaderResourceView* srv; int w; int h; TextCacheEntry() : srv(nullptr), w(0), h(0) {} };
std::map<std::wstring, TextCacheEntry> m_textCache;
std::list<std::wstring> m_textLru;
static const size_t TEXT_CACHE_MAX = 128;
};
}
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <cstdint>
namespace ImXui {
struct VisualImage {
std::string imagePath;
float x, y, z, w, h;
uint32_t anchor;
VisualImage() : x(0), y(0), z(0), w(0), h(0), anchor(0) {}
};
struct TextProperties {
bool hasColor;
uint8_t textColorA, textColorR, textColorG, textColorB;
float pointSize;
bool hasPointSize;
std::string font;
bool hasFont;
uint32_t textStyle;
bool hasTextStyle;
TextProperties()
: hasColor(false), textColorA(255), textColorR(255), textColorG(255), textColorB(255)
, pointSize(12.0f), hasPointSize(false), hasFont(false), textStyle(0), hasTextStyle(false) {}
};
struct VisualEntry {
std::string id;
float templateWidth, templateHeight;
float posX, posY;
std::vector<VisualImage> images;
TextProperties textProps;
VisualEntry() : templateWidth(0), templateHeight(0), posX(0), posY(0) {}
};
class Skin {
public:
bool loadFromXui(const std::string& path);
bool loadFromString(const std::string& xml);
const std::vector<VisualImage>* getImages(const std::string& visualName) const;
const VisualEntry* getEntry(const std::string& visualName) const;
const std::vector<VisualEntry>& getAllEntries() const { return m_entries; }
int count() const { return (int)m_entryMap.size(); }
private:
void parseVisualBlock(const std::string& xml, size_t start, size_t end);
std::string readProp(const std::string& xml, const std::string& propName, size_t from, size_t to);
std::vector<VisualEntry> m_entries;
std::unordered_map<std::string, int> m_entryMap;
};
}
+92
View File
@@ -0,0 +1,92 @@
#pragma once
#include "Renderer.h"
#include "FontEngine.h"
#include "ImageManager.h"
#include <cstdint>
#include <string>
#include <vector>
#include <stack>
namespace ImXui {
class SoftwareRenderer : public Renderer {
public:
SoftwareRenderer();
~SoftwareRenderer();
bool init(void* nativeWindow, int width, int height) override;
void shutdown() override;
bool resize(int width, int height) override;
bool beginFrame(float clearR = 0, float clearG = 0, float clearB = 0, float clearA = 1) override;
void endFrame(bool vsync = true) override;
void renderScene(const Scene* scene) override;
void setTextureManager(TextureManager* mgr) override { (void)mgr; }
void setSkin(const Skin* skin) override { m_skin = skin; }
const Skin* getSkin() const override { return m_skin; }
bool loadFont(const wchar_t* path) override;
bool loadSystemFont(const std::string& name);
bool initTextRendering() override;
void shutdownTextRendering() override;
float measureText(const std::wstring& text, float sizePx) const;
float lineHeight(float sizePx) const;
void drawTexturedQuad(float x, float y, float w, float h, const wchar_t* texturePath,
float r = 1, float g = 1, float b = 1, float a = 1) override;
void drawFigure(float x, float y, float w, float h,
const std::vector<Vec2>& points, bool closed,
float fillR, float fillG, float fillB, float fillA,
float strokeR, float strokeG, float strokeB, float strokeA,
float strokeWidth) override;
void drawColoredQuad(float x, float y, float w, float h,
float r, float g, float b, float a) override;
void drawTextString(float x, float y, float w, float h,
const std::wstring& text, const std::wstring& fontName, float fontSize,
float r = 1, float g = 1, float b = 1, float a = 1,
bool centered = false) override;
int getWidth() const override { return m_width; }
int getHeight() const override { return m_height; }
const uint8_t* getFramebuffer() const { return m_fb.empty() ? nullptr : m_fb.data(); }
size_t getFramebufferSize() const { return m_fb.size(); }
uint32_t pixel(int x, int y) const;
bool savePng(const char* path) const;
bool saveBmp(const char* path) const;
private:
void drawElement(const Element* el);
void drawTexturedElement(const Element* el);
void drawNineGridRect(float x, float y, float w, float h, const ImageData& img,
uint32_t leftInset, uint32_t topInset, uint32_t rightInset, uint32_t bottomInset,
bool noCenter, float r, float g, float b, float a);
void fillRect(float x, float y, float w, float h, float r, float g, float b, float a);
void fillTriangle(float x0, float y0, float x1, float y1, float x2, float y2,
float r, float g, float b, float a);
void blitImage(int dx, int dy, int dw, int dh, const ImageData& img,
float tintR, float tintG, float tintB, float alpha);
void strokeSegment(float x0, float y0, float x1, float y1, float width,
float r, float g, float b, float a);
void pushClip(const Rect& r);
void popClip();
bool clipRect(Rect& r) const;
std::vector<uint8_t> m_fb;
int m_width;
int m_height;
FontEngine m_font;
ImageManager m_images;
const Skin* m_skin;
std::stack<Rect> m_clipStack;
};
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include <string>
#include <unordered_map>
#include <cstdint>
struct ID3D11Device;
struct ID3D11ShaderResourceView;
namespace ImXui {
class TextureManager {
public:
TextureManager() : m_device(nullptr) {}
~TextureManager() { shutdown(); }
bool init(ID3D11Device* device);
void shutdown();
void setBasePath(const std::string& path) { m_basePath = path; }
const std::string& getBasePath() const { return m_basePath; }
ID3D11ShaderResourceView* load(const std::string& relativePath);
bool getSize(const std::string& relativePath, int& w, int& h) const;
private:
ID3D11Device* m_device;
std::string m_basePath;
std::unordered_map<std::string, ID3D11ShaderResourceView*> m_cache;
std::unordered_map<std::string, int> m_widths;
std::unordered_map<std::string, int> m_heights;
};
}
+63
View File
@@ -0,0 +1,63 @@
#pragma once
#include "ImXui/RenderCommands.h"
#include "xui.h"
namespace ImXui {
class X360RenderSink : public IRenderCommandSink {
public:
X360RenderSink();
void setDevice(void* d3dDevice);
void setDelegateSink(IRenderCommandSink* sink);
void setFontRenderer(class IXuiFontRenderer* renderer);
void setFontTypeface(const wchar_t* typeface);
HXUIDC getDeviceContext() const { return m_hDC; }
void beginFrame(float width, float height);
void endFrame();
void beginScene(float width, float height);
void drawColoredQuad(const Rect& rect, const Color& color, float opacity);
void drawTexturedQuad(const Rect& rect, const std::wstring& resource,
const Color& color, float opacity);
void drawText(const Rect& rect, const std::wstring& text,
const std::wstring& fontName, float fontSize,
const Color& color, float opacity, bool centered);
void pushTransform(const Transform2D& t);
void popTransform();
void pushClip(const Rect& r);
void popClip();
void drawNineGrid(const Rect&, const std::wstring&, const Color&, float,
uint32_t, uint32_t, uint32_t, uint32_t, bool);
void drawFigure(const Rect&, const std::vector<Vec2>&, bool,
const Color&, const Color&, float, float, uint32_t);
void setBlendMode(uint32_t mode);
void drawCustom(const std::wstring& drawId, const Rect&, float opacity);
void endScene();
private:
bool drawQuadD3D(const Rect& rect, uint32_t abgr);
void flushText(const Rect& rect, const std::wstring& text,
const Color& color, float fontSize, bool centered);
void* m_device;
IRenderCommandSink* m_delegate;
class IXuiFontRenderer* m_fontRenderer;
HFONTOBJ m_font;
std::wstring m_typeface;
HXUIDC m_hDC;
Transform2D m_transform;
Rect m_clip;
uint32_t m_blendMode;
float m_width;
float m_height;
int m_clipDepth;
};
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <string>
#include <fstream>
#include <sstream>
namespace ImXui {
class Element;
class Control;
class Scene;
class XuiXmlWriter {
public:
static bool writeFile(const std::string& path, const Scene* scene);
static std::string serialize(const Scene* scene);
private:
static void writeElement(std::ostringstream& out, const Element* el, int indent);
static void writeControlProps(std::ostringstream& out, const Control* ctrl, int indent);
static void writeSceneProps(std::ostringstream& out, const Scene* scene, int indent);
static void indentLine(std::ostringstream& out, int level);
};
}
+237
View File
@@ -0,0 +1,237 @@
#pragma once
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
namespace ImXui {
namespace XurFormat {
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
# include <stdlib.h>
# define BSWAP16(x) _byteswap_ushort((unsigned short)(x))
# define BSWAP32(x) _byteswap_ulong((unsigned long)(x))
#else
# define BSWAP16(x) (((x) >> 8) | ((x) << 8))
# define BSWAP32(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) << 8) & 0xFF0000) | (((x) << 24) & 0xFF000000))
#endif
inline uint16_t swap16(uint16_t v) { return BSWAP16(v); }
inline uint32_t swap32(uint32_t v) { return BSWAP32(v); }
inline float swapFloat(uint32_t v) {
uint32_t swapped = swap32(v);
float result;
memcpy(&result, &swapped, 4);
return result;
}
const uint32_t MAGIC_XUIB = 0x58554942;
const uint32_t MAGIC_STRN = 0x5354524E;
const uint32_t MAGIC_VECT = 0x56454354;
const uint32_t MAGIC_QUAT = 0x51554154;
const uint32_t MAGIC_CUST = 0x43555354;
const uint32_t MAGIC_DATA = 0x44415441;
#pragma pack(push, 1)
struct XurHeader {
char magic[4];
uint32_t version;
uint32_t flags;
uint16_t toolVersion;
uint32_t fileSize;
uint16_t sectionsCount;
bool isValid() const {
return memcmp(magic, "XUIB", 4) == 0 && swap32(version) == 5;
}
uint32_t getFlags() const { return swap32(flags); }
uint32_t getFileSize() const { return swap32(fileSize); }
uint16_t getSectionsCount() const { return swap16(sectionsCount); }
};
struct XurCountHeader {
uint32_t totalObjectsCount;
uint32_t totalPropertiesCount;
uint32_t totalPropertiesArrayCount;
uint32_t keyframePropertiesCount;
uint32_t totalKeyframePropertyClassDepth;
uint32_t keyframePropertyDefinitionsCount;
uint32_t keyframesCount;
uint32_t timelinesCount;
uint32_t namedFramesCount;
uint32_t objectsWithChildrenCount;
void fromBE() {
totalObjectsCount = swap32(totalObjectsCount);
totalPropertiesCount = swap32(totalPropertiesCount);
totalPropertiesArrayCount = swap32(totalPropertiesArrayCount);
keyframePropertiesCount = swap32(keyframePropertiesCount);
totalKeyframePropertyClassDepth = swap32(totalKeyframePropertyClassDepth);
keyframePropertyDefinitionsCount = swap32(keyframePropertyDefinitionsCount);
keyframesCount = swap32(keyframesCount);
timelinesCount = swap32(timelinesCount);
namedFramesCount = swap32(namedFramesCount);
objectsWithChildrenCount = swap32(objectsWithChildrenCount);
}
};
struct XurSectionEntry {
uint32_t magic;
uint32_t offset;
uint32_t length;
void fromBE() {
magic = swap32(magic);
offset = swap32(offset);
length = swap32(length);
}
};
#pragma pack(pop)
struct XurVector { float x, y, z; };
struct XurQuaternion { float x, y, z, w; };
struct XurPoint { float x, y; };
struct XurBezierPoint { XurPoint point; XurPoint controlOne; XurPoint controlTwo; };
struct XurFigure { XurPoint boundingBox; std::vector<XurBezierPoint> points; };
struct XurColor { uint8_t a, r, g, b; };
enum XurPropertyType {
XurPropertyType_Bool = 0,
XurPropertyType_Integer = 1,
XurPropertyType_Unsigned = 2,
XurPropertyType_Float = 3,
XurPropertyType_String = 4,
XurPropertyType_Vector = 5,
XurPropertyType_Object = 6,
XurPropertyType_Colour = 7,
XurPropertyType_Custom = 8,
XurPropertyType_Quaternion = 9,
};
struct XurProperty;
class XurPropertyValue {
public:
XurPropertyType type;
bool boolVal;
int32_t intVal;
uint32_t uintVal;
float floatVal;
std::wstring stringVal;
XurVector vectorVal;
XurQuaternion quatVal;
XurColor colorVal;
XurFigure figureVal;
std::vector<XurProperty> compoundVal;
XurPropertyValue();
explicit XurPropertyValue(bool v);
explicit XurPropertyValue(int32_t v);
explicit XurPropertyValue(uint32_t v);
explicit XurPropertyValue(float v);
explicit XurPropertyValue(const std::wstring& v);
explicit XurPropertyValue(const XurVector& v);
explicit XurPropertyValue(const XurQuaternion& v);
explicit XurPropertyValue(const XurColor& v);
explicit XurPropertyValue(const XurFigure& v);
explicit XurPropertyValue(const std::vector<XurProperty>& v);
XurPropertyValue(const XurPropertyValue& other);
XurPropertyValue& operator=(const XurPropertyValue& other);
~XurPropertyValue();
};
struct XurProperty {
std::string name;
XurPropertyType type;
XurPropertyValue value;
};
enum XurNamedFrameCommand {
XurNamedFrameCommand_None = 0,
XurNamedFrameCommand_Stop = 1,
XurNamedFrameCommand_GotoAndStop = 2,
XurNamedFrameCommand_GotoAndPlay = 3,
XurNamedFrameCommand_Play = 4,
};
struct XurNamedFrame {
std::wstring name;
int32_t keyframe;
XurNamedFrameCommand command;
std::wstring targetParameter;
};
enum XurInterpolationType {
XurInterpolationType_None = 0,
XurInterpolationType_Linear = 1,
XurInterpolationType_EaseIn = 2,
XurInterpolationType_EaseOut = 3,
XurInterpolationType_EaseInOut = 4,
};
struct XurKeyframe {
int32_t time;
XurInterpolationType interpolation;
uint8_t easeIn;
uint8_t easeOut;
uint8_t easeScale;
std::vector<XurProperty> properties;
};
struct XurTimeline {
std::wstring elementName;
std::vector<XurKeyframe> keyframes;
};
struct XurObject {
std::string className;
std::vector<XurProperty> properties;
std::vector<XurObject> children;
std::vector<XurNamedFrame> namedFrames;
std::vector<XurTimeline> timelines;
};
struct XurDocument {
XurHeader header;
std::vector<std::wstring> strings;
std::vector<XurVector> vectors;
std::vector<XurQuaternion> quaternions;
std::vector<XurFigure> figures;
XurObject rootObject;
std::vector<uint8_t> rawData;
};
struct XuiPropDef {
std::string name;
XurPropertyType type;
bool indexed;
};
struct XuiClassInfo {
std::string name;
std::string baseClass;
std::vector<XuiPropDef> props;
};
class XuiClassRegistry {
public:
static const XuiClassInfo* findClass(const std::string& name);
static std::vector<const XuiClassInfo*> getHierarchy(const std::string& className);
static void initialize();
};
class XurParser {
public:
static std::unique_ptr<XurDocument> parse(const void* data, size_t size);
static std::unique_ptr<XurDocument> parseFromFile(const std::string& path);
static bool validate(const XurDocument* doc);
};
}
}
+60
View File
@@ -0,0 +1,60 @@
#pragma once
#include "XurFormat.h"
#include <string>
#include <vector>
#include <cstdint>
namespace ImXui {
class Element;
class Scene;
namespace XurFormat {
struct MemBuf {
std::vector<uint8_t> data;
void write(const void* d, size_t sz);
template<typename T> void writeBE(T v);
void writeU8(uint8_t v);
void writeU16BE(uint16_t v);
void writeU32BE(uint32_t v);
void writeS16BE(int16_t v);
void writeS32BE(int32_t v);
void writeFloatBE(float v);
uint32_t tell() const;
};
struct WriteContext {
std::vector<std::wstring> strings;
std::vector<XurVector> vectors;
std::vector<XurQuaternion> quaternions;
std::vector<XurFigure> figures;
int addString(const std::wstring& s);
int addVector(const XurVector& v);
int addQuaternion(const XurQuaternion& q);
int addFigure(const XurFigure& f);
};
class XurWriter {
public:
static bool writeToFile(const std::string& path, const XurObject& root);
static std::vector<uint8_t> serialize(const XurObject& root);
private:
static void writePropValue(MemBuf& buf, WriteContext& ctx, const XurPropertyValue& val);
static void writeProperties(MemBuf& buf, WriteContext& ctx, const XurObject& obj);
static void writeObject(MemBuf& buf, WriteContext& ctx, const XurObject& obj);
static void writeStrnSection(MemBuf& out, WriteContext& ctx);
static void writeVectSection(MemBuf& out, WriteContext& ctx);
static void writeQuatSection(MemBuf& out, WriteContext& ctx);
static void writeCustSection(MemBuf& out, WriteContext& ctx);
static void writeDataSection(MemBuf& out, WriteContext& ctx, const XurObject& root);
};
XurObject elementToXurObject(const Element* el);
XurObject sceneToXurObject(const Scene* scene);
}
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include "XurFormat.h"
#include <string>
namespace ImXui {
namespace XurFormat {
XurObject xuiXmlToObject(const std::string& xml);
std::string xurObjectToXuiXml(const XurObject& root);
bool xurObjectToXuiXml(const XurObject& root, const std::string& path);
XurObject xuiFileToObject(const std::string& path);
}
}
+66
View File
@@ -0,0 +1,66 @@
#pragma once
#include <cstdint>
#include <map>
#include <string>
#include <vector>
namespace ImXui {
class XzpPackage {
public:
struct Entry {
std::string name;
uint32_t offset;
uint32_t size;
Entry() : offset(0), size(0) {}
};
XzpPackage();
~XzpPackage();
bool openMemory(const void* data, size_t size);
bool openFile(const std::string& path);
bool isOpen() const { return m_open; }
int getVersion() const { return m_version; }
size_t getEntryCount() const { return m_entries.size(); }
const std::vector<Entry>& getEntries() const { return m_entries; }
const Entry* findEntry(const std::string& name) const;
bool readEntry(const Entry& entry, std::vector<uint8_t>& out) const;
bool readEntryByName(const std::string& name, std::vector<uint8_t>& out) const;
const uint8_t* entryData(const Entry& entry) const;
private:
void reset();
bool m_open;
int m_version;
std::vector<uint8_t> m_buffer;
std::vector<Entry> m_entries;
std::map<std::string, size_t> m_byName;
};
class XzpWriter {
public:
void addFile(const std::string& name, const void* data, size_t size);
bool build(std::vector<uint8_t>& out) const;
private:
struct Item {
std::string name;
std::vector<uint8_t> data;
};
std::vector<Item> m_items;
};
}
+195
View File
@@ -0,0 +1,195 @@
#include "ImXui/ImXui.h"
#include "ImXui/RenderCommands.h"
#include <map>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <sstream>
namespace ImXui {
Application* Application::s_instance = nullptr;
struct Application::Impl {
Impl() : deltaTime(0.0f) {}
std::vector<std::unique_ptr<Scene>> sceneStack[4];
std::map<uint32_t, std::unordered_map<int, std::wstring> > localeTables;
float deltaTime;
};
Application::Application() {
s_instance = this;
m_soundSink = nullptr;
m_renderSink = nullptr;
m_locale = 0x0409;
m_impl.reset(new Impl());
}
Application::~Application() {
shutdown();
s_instance = nullptr;
}
Result Application::init() {
return Result_Success;
}
Result Application::shutdown() {
for (int i = 0; i < 4; i++) {
m_impl->sceneStack[i].clear();
}
m_impl->localeTables.clear();
return Result_Success;
}
Result Application::navigateToScene(int pad, Scene* scene, void* initData) {
if (pad < 0 || pad >= 4 || !scene) return Result_Error_InvalidParam;
if (scene->onCreate(initData) == Result_Success) {
m_impl->sceneStack[pad].push_back(std::unique_ptr<Scene>(scene));
return Result_Success;
}
return Result_Error_General;
}
Result Application::navigateBack(int pad) {
if (pad < 0 || pad >= 4) return Result_Error_InvalidParam;
if (!m_impl->sceneStack[pad].empty()) {
auto& top = m_impl->sceneStack[pad].back();
top->onDestroy();
m_impl->sceneStack[pad].pop_back();
return Result_Success;
}
return Result_Error_NotFound;
}
Result Application::closeScene(int pad, Scene* scene) {
if (pad < 0 || pad >= 4 || !scene) return Result_Error_InvalidParam;
auto& stack = m_impl->sceneStack[pad];
for (auto it = stack.begin(); it != stack.end(); ++it) {
if (it->get() == scene) {
(*it)->onDestroy();
stack.erase(it);
return Result_Success;
}
}
return Result_Error_NotFound;
}
void Application::tick(float deltaTime) {
m_impl->deltaTime = deltaTime;
for (int i = 0; i < 4; i++) {
for (size_t si = 0; si < m_impl->sceneStack[i].size(); ++si) {
m_impl->sceneStack[i][si]->updateTimers(deltaTime);
m_impl->sceneStack[i][si]->updateAnimations(deltaTime);
m_impl->sceneStack[i][si]->updateTransition(deltaTime);
m_impl->sceneStack[i][si]->onTick(deltaTime);
}
}
}
void Application::render() {
if (!m_renderSink) return;
for (int i = 0; i < 4; i++) {
auto& stack = m_impl->sceneStack[i];
if (stack.empty()) continue;
emitRenderCommands(stack.back().get(), m_renderSink);
}
}
void Application::forEachScene(const std::function<void(Scene*, int)>& fn) {
for (int i = 0; i < 4; i++) {
for (size_t si = 0; si < m_impl->sceneStack[i].size(); ++si) fn(m_impl->sceneStack[i][si].get(), i);
}
}
void Application::setLocale(uint32_t localeId) {
if (localeId == m_locale) return;
m_locale = localeId;
forEachScene([](Scene* scene, int) { scene->onLocaleChanged(); });
}
void Application::setSkinPath(const std::wstring& path) {
if (path == m_skinPath) return;
m_skinPath = path;
notifySkinChanged();
}
void Application::notifySkinChanged() {
const uint32_t kSkinChangedMsg = 9;
for (int i = 0; i < 4; i++) {
for (size_t si = 0; si < m_impl->sceneStack[i].size(); ++si) {
m_impl->sceneStack[i][si]->broadcastMessage(kSkinChangedMsg, nullptr);
}
}
}
Result Application::sendKeyEvent(int pad, uint32_t key, bool down) {
if (pad < 0 || pad >= 4) return Result_Error_InvalidParam;
auto& stack = m_impl->sceneStack[pad];
if (stack.empty()) return Result_Error_NotFound;
auto* scene = stack.back().get();
if (down) return scene->onKeyDown(key);
else return scene->onKeyUp(key);
}
Result Application::sendCharEvent(int pad, wchar_t ch) {
if (pad < 0 || pad >= 4) return Result_Error_InvalidParam;
auto& stack = m_impl->sceneStack[pad];
if (stack.empty()) return Result_Error_NotFound;
Scene* scene = stack.back().get();
Edit* edit = dynamic_cast<Edit*>(scene->getUserFocus(0));
if (!edit || !edit->isEnabled()) return Result_Error_NotFound;
return edit->insertChar(ch) ? Result_Success : Result_Error_General;
}
void Application::loadStringTable(const std::wstring& path) {
std::string narrowPath(path.begin(), path.end());
std::ifstream ifs(narrowPath);
if (!ifs) return;
std::unordered_map<int, std::wstring>& table = m_impl->localeTables[m_locale];
std::string line;
while (std::getline(ifs, line)) {
auto eqPos = line.find('=');
if (eqPos == std::string::npos) continue;
int id = std::stoi(line.substr(0, eqPos));
std::string val = line.substr(eqPos + 1);
std::wstring wval;
wval.assign(val.begin(), val.end());
table[id] = wval;
}
}
const wchar_t* Application::getString(int id) const {
auto locIt = m_impl->localeTables.find(m_locale);
if (locIt != m_impl->localeTables.end()) {
auto it = locIt->second.find(id);
if (it != locIt->second.end()) return it->second.c_str();
}
auto defIt = m_impl->localeTables.find(0x0409);
if (defIt != m_impl->localeTables.end()) {
auto it = defIt->second.find(id);
if (it != defIt->second.end()) return it->second.c_str();
}
for (std::map<uint32_t, std::unordered_map<int, std::wstring> >::const_iterator tbi = m_impl->localeTables.begin();
tbi != m_impl->localeTables.end(); ++tbi) {
auto it = tbi->second.find(id);
if (it != tbi->second.end()) return it->second.c_str();
}
return L"";
}
}
+963
View File
@@ -0,0 +1,963 @@
#include "ImXui/ImXui.h"
#include "ImXui/XurFormat.h"
#include <fstream>
#include <sstream>
#include <vector>
#include <functional>
#include <cstring>
#include <cwctype>
#include <cwchar>
#include <climits>
#include <cstdlib>
#include <cerrno>
namespace ImXui {
namespace {
static bool appendUtf8CodePoint(std::wstring& output, unsigned long codePoint) {
#if WCHAR_MAX <= 0xffff
if (codePoint <= 0xffffu) {
output.push_back((wchar_t)codePoint);
} else if (codePoint <= 0x10ffffu) {
codePoint -= 0x10000u;
output.push_back((wchar_t)(0xd800u + (codePoint >> 10)));
output.push_back((wchar_t)(0xdc00u + (codePoint & 0x3ffu)));
} else {
return false;
}
#else
if (codePoint > 0x10ffffu) return false;
output.push_back((wchar_t)codePoint);
#endif
return true;
}
}
Canvas::Canvas() : m_width(1280.0f), m_height(720.0f) {}
Canvas::~Canvas() {}
Result Canvas::loadFromXui(const std::string& path) {
std::ifstream ifs(path, std::ios::binary | std::ios::ate);
if (!ifs) return Result_Error_NotFound;
std::streamsize size = ifs.tellg();
if (size < 0) return Result_Error_NotFound;
ifs.seekg(0, std::ios::beg);
std::vector<char> buf(size);
if (!ifs.read(buf.data(), size)) return Result_Error_InvalidFile;
std::wstring xml;
size_t offset = 0;
if (buf.size() >= 3 && (unsigned char)buf[0] == 0xef &&
(unsigned char)buf[1] == 0xbb && (unsigned char)buf[2] == 0xbf) {
offset = 3;
}
while (offset < buf.size()) {
unsigned char first = (unsigned char)buf[offset++];
unsigned long codePoint = 0;
size_t continuationCount = 0;
if (first < 0x80) {
codePoint = first;
} else if ((first & 0xe0) == 0xc0) {
codePoint = first & 0x1f;
continuationCount = 1;
} else if ((first & 0xf0) == 0xe0) {
codePoint = first & 0x0f;
continuationCount = 2;
} else if ((first & 0xf8) == 0xf0) {
codePoint = first & 0x07;
continuationCount = 3;
} else {
return Result_Error_InvalidFile;
}
for (size_t i = 0; i < continuationCount; ++i) {
if (offset >= buf.size()) return Result_Error_InvalidFile;
unsigned char next = (unsigned char)buf[offset++];
if ((next & 0xc0) != 0x80) return Result_Error_InvalidFile;
codePoint = (codePoint << 6) | (next & 0x3f);
}
if ((continuationCount == 1 && codePoint < 0x80) ||
(continuationCount == 2 && codePoint < 0x800) ||
(continuationCount == 3 && codePoint < 0x10000) ||
codePoint > 0x10ffffu || (codePoint >= 0xd800u && codePoint <= 0xdfffu)) {
return Result_Error_InvalidFile;
}
if (!appendUtf8CodePoint(xml, codePoint)) return Result_Error_InvalidFile;
}
return parseXuiXml(xml);
}
Result Canvas::loadFromXuiString(const std::wstring& xmlContent) {
return parseXuiXml(xmlContent);
}
Result Canvas::loadFromXur(const std::string& path) {
std::ifstream ifs(path, std::ios::binary | std::ios::ate);
if (!ifs) return Result_Error_NotFound;
std::streamsize size = ifs.tellg();
if (size < 0) return Result_Error_NotFound;
ifs.seekg(0, std::ios::beg);
std::vector<char> buf(size);
if (!ifs.read(buf.data(), size)) return Result_Error_InvalidFile;
return loadFromXurMemory(buf.data(), buf.size());
}
static void applyXurProperties(const XurFormat::XurObject& obj, Element* el) {
Control* ctrl = dynamic_cast<Control*>(el);
bool sawStroke = false;
for (size_t pi = 0; pi < obj.properties.size(); pi++) {
const XurFormat::XurProperty& prop = obj.properties[pi];
const XurFormat::XurPropertyValue& v = prop.value;
if (prop.name == "Id") {
if (v.type == XurFormat::XurPropertyType_String)
el->setId(v.stringVal);
} else if (prop.name == "Width") {
if (v.type == XurFormat::XurPropertyType_Float)
el->setBounds(v.floatVal, el->getBounds().y);
} else if (prop.name == "Height") {
if (v.type == XurFormat::XurPropertyType_Float)
el->setBounds(el->getBounds().x, v.floatVal);
} else if (prop.name == "Position") {
if (v.type == XurFormat::XurPropertyType_Vector)
el->setPosition(Vec3(v.vectorVal.x, v.vectorVal.y, v.vectorVal.z));
} else if (prop.name == "Anchor") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setAnchor(v.uintVal);
} else if (prop.name == "Scale") {
if (v.type == XurFormat::XurPropertyType_Vector)
el->setScale(Vec3(v.vectorVal.x, v.vectorVal.y, v.vectorVal.z));
} else if (prop.name == "Pivot") {
if (v.type == XurFormat::XurPropertyType_Vector)
el->setPivot(Vec3(v.vectorVal.x, v.vectorVal.y, v.vectorVal.z));
} else if (prop.name == "Rotation") {
if (v.type == XurFormat::XurPropertyType_Vector)
el->setRotation(Vec3(v.vectorVal.x, v.vectorVal.y, v.vectorVal.z));
} else if (prop.name == "Opacity") {
if (v.type == XurFormat::XurPropertyType_Float)
el->setOpacity(v.floatVal);
} else if (prop.name == "Show") {
if (v.type == XurFormat::XurPropertyType_Bool)
el->setShow(v.boolVal);
} else if (prop.name == "BlendMode") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setBlendMode(v.uintVal);
} else if (prop.name == "ClipChildren") {
if (v.type == XurFormat::XurPropertyType_Bool)
el->setClipChildren(v.boolVal);
} else if (prop.name == "Hittable") {
if (v.type == XurFormat::XurPropertyType_Bool)
el->setHittable(v.boolVal);
} else if (prop.name == "LayoutLineBreak") {
if (v.type == XurFormat::XurPropertyType_Bool)
el->setLayoutLineBreak(v.boolVal);
} else if (prop.name == "LayoutFloat") {
if (v.type == XurFormat::XurPropertyType_Bool)
el->setLayoutFloat(v.boolVal);
} else if (prop.name == "Column") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setColumn(v.uintVal);
} else if (prop.name == "Row") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setRow(v.uintVal);
} else if (prop.name == "ColumnSpan") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setColumnSpan(v.uintVal);
} else if (prop.name == "RowSpan") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setRowSpan(v.uintVal);
} else if (prop.name == "ColorFactor") {
if (v.type == XurFormat::XurPropertyType_Colour)
el->setColorFactor(Color(v.colorVal.r / 255.0f, v.colorVal.g / 255.0f, v.colorVal.b / 255.0f, v.colorVal.a / 255.0f));
} else if (prop.name == "Visual") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setVisual(v.stringVal);
} else if (prop.name == "ClassOverride") {
if (v.type == XurFormat::XurPropertyType_String)
el->setClassName(v.stringVal);
} else if (prop.name == "ImagePath" || prop.name == "Source") {
if (v.type == XurFormat::XurPropertyType_String)
el->setImagePath(v.stringVal);
} else if (prop.name == "Text") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setText(v.stringVal);
} else if (prop.name == "Font") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setFontName(v.stringVal);
} else if (prop.name == "PointSize") {
if (ctrl && v.type == XurFormat::XurPropertyType_Float)
ctrl->setFontSize(v.floatVal);
} else if (prop.name == "Enabled") {
if (ctrl && v.type == XurFormat::XurPropertyType_Bool)
ctrl->setEnable(v.boolVal);
} else if (prop.name == "Value") {
if (ctrl && v.type == XurFormat::XurPropertyType_Integer)
ctrl->setProgressValue(v.intVal);
} else if (prop.name == "RangeMin") {
if (ctrl && v.type == XurFormat::XurPropertyType_Integer)
ctrl->setProgressRange(v.intVal, ctrl->getProgressMax());
} else if (prop.name == "RangeMax") {
if (ctrl && v.type == XurFormat::XurPropertyType_Integer)
ctrl->setProgressRange(ctrl->getProgressMin(), v.intVal);
} else if (prop.name == "NavLeft") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setNavLeft(v.stringVal);
} else if (prop.name == "NavRight") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setNavRight(v.stringVal);
} else if (prop.name == "NavUp") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setNavUp(v.stringVal);
} else if (prop.name == "NavDown") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setNavDown(v.stringVal);
} else if (prop.name == "NavTabForward") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setNavTabForward(v.stringVal);
} else if (prop.name == "NavTabBackward") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setNavTabBackward(v.stringVal);
} else if (prop.name == "Step") {
if (ctrl && v.type == XurFormat::XurPropertyType_Integer)
ctrl->setStep(v.intVal);
} else if (prop.name == "Vertical") {
if (ctrl && v.type == XurFormat::XurPropertyType_Bool)
ctrl->setVertical(v.boolVal);
} else if (prop.name == "PressKey") {
if (ctrl && v.type == XurFormat::XurPropertyType_Unsigned)
ctrl->setPressKey(v.uintVal);
} else if (prop.name == "PressAnimObject") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setPressAnimObject(v.stringVal);
} else if (prop.name == "FocusAnimObject") {
if (ctrl && v.type == XurFormat::XurPropertyType_String)
ctrl->setFocusAnimObject(v.stringVal);
} else if (prop.name == "DefaultFocus") {
Scene* scene = dynamic_cast<Scene*>(el);
if (scene && v.type == XurFormat::XurPropertyType_String)
scene->setDefaultFocus(v.stringVal);
} else if (prop.name == "TransTo") {
Scene* scene = dynamic_cast<Scene*>(el);
if (scene && v.type == XurFormat::XurPropertyType_String)
scene->setTransitionTo(v.stringVal);
} else if (prop.name == "TransFrom") {
Scene* scene = dynamic_cast<Scene*>(el);
if (scene && v.type == XurFormat::XurPropertyType_String)
scene->setTransitionFrom(v.stringVal);
} else if (prop.name == "TransBackTo") {
Scene* scene = dynamic_cast<Scene*>(el);
if (scene && v.type == XurFormat::XurPropertyType_String)
scene->setTransitionBackTo(v.stringVal);
} else if (prop.name == "TransBackFrom") {
Scene* scene = dynamic_cast<Scene*>(el);
if (scene && v.type == XurFormat::XurPropertyType_String)
scene->setTransitionBackFrom(v.stringVal);
} else if (prop.name == "IgnorePresses") {
Scene* scene = dynamic_cast<Scene*>(el);
if (scene && v.type == XurFormat::XurPropertyType_Bool)
scene->setIgnorePresses(v.boolVal);
} else if (prop.name == "UnfocusedInput") {
} else if (prop.name == "Wrap") {
} else if (prop.name == "TextureFileName") {
if (v.type == XurFormat::XurPropertyType_String)
el->setNineGridTexture(v.stringVal);
} else if (prop.name == "LeftOffset") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setNineGridLeft(v.uintVal);
} else if (prop.name == "TopOffset") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setNineGridTop(v.uintVal);
} else if (prop.name == "RightOffset") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setNineGridRight(v.uintVal);
} else if (prop.name == "BottomOffset") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setNineGridBottom(v.uintVal);
} else if (prop.name == "NoCenter") {
if (v.type == XurFormat::XurPropertyType_Bool)
el->setNineGridNoCenter(v.boolVal);
} else if (prop.name == "FillType") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setFigureFillType(v.uintVal);
} else if (prop.name == "FillColor") {
if (v.type == XurFormat::XurPropertyType_Colour)
el->setFigureFillColor(Color(v.colorVal.r / 255.0f, v.colorVal.g / 255.0f, v.colorVal.b / 255.0f, v.colorVal.a / 255.0f));
} else if (prop.name == "Closed") {
if (v.type == XurFormat::XurPropertyType_Bool)
el->setFigureClosed(v.boolVal);
} else if (prop.name == "StrokeWidth") {
sawStroke = true;
if (v.type == XurFormat::XurPropertyType_Float)
el->setFigureStrokeWidth(v.floatVal);
} else if (prop.name == "StrokeColor") {
sawStroke = true;
if (v.type == XurFormat::XurPropertyType_Colour)
el->setFigureStrokeColor(Color(v.colorVal.r / 255.0f, v.colorVal.g / 255.0f, v.colorVal.b / 255.0f, v.colorVal.a / 255.0f));
} else if (prop.name == "Rotation") {
if (v.type == XurFormat::XurPropertyType_Float)
el->setFigureFillRotation(v.floatVal);
} else if (prop.name == "Translation") {
if (v.type == XurFormat::XurPropertyType_Vector)
el->setFigureFillTranslation(Vec2(v.vectorVal.x, v.vectorVal.y));
} else if (prop.name == "BrushFlags") {
if (v.type == XurFormat::XurPropertyType_Unsigned) {
}
} else if (prop.name == "WrapX") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setFigureFillWrapX(v.uintVal);
} else if (prop.name == "WrapY") {
if (v.type == XurFormat::XurPropertyType_Unsigned)
el->setFigureFillWrapY(v.uintVal);
} else if (prop.name == "Fill") {
if (v.type == XurFormat::XurPropertyType_Object) {
for (size_t cvi = 0; cvi < v.compoundVal.size(); ++cvi) {
const XurFormat::XurProperty& sp = v.compoundVal[cvi];
if (sp.name == "FillType" &&
(sp.value.type == XurFormat::XurPropertyType_Unsigned ||
sp.value.type == XurFormat::XurPropertyType_Integer)) {
uint32_t ft = (sp.value.type == XurFormat::XurPropertyType_Integer)
? (uint32_t)sp.value.intVal : sp.value.uintVal;
el->setFigureFillType(ft);
}
else if (sp.name == "FillColor" && sp.value.type == XurFormat::XurPropertyType_Colour)
el->setFigureFillColor(Color(sp.value.colorVal.r / 255.0f,
sp.value.colorVal.g / 255.0f,
sp.value.colorVal.b / 255.0f,
sp.value.colorVal.a / 255.0f));
}
}
} else if (prop.name == "Points") {
if (v.type == XurFormat::XurPropertyType_Custom && !v.figureVal.points.empty()) {
float bw = el->getBounds().x > 0.0f ? el->getBounds().x : 1.0f;
float bh = el->getBounds().y > 0.0f ? el->getBounds().y : 1.0f;
std::vector<Vec2> pts;
pts.reserve(v.figureVal.points.size());
for (size_t fpi = 0; fpi < v.figureVal.points.size(); ++fpi) {
pts.push_back(Vec2(v.figureVal.points[fpi].point.x / bw, v.figureVal.points[fpi].point.y / bh));
}
el->setFigurePoints(pts);
el->setIsFigure(true);
if (!sawStroke) el->setFigureStrokeWidth(0.0f);
}
}
}
}
Result Canvas::loadFromXurMemory(const void* data, size_t size) {
auto doc = XurFormat::XurParser::parse(data, size);
if (!doc || !XurFormat::XurParser::validate(doc.get())) {
return Result_Error_InvalidFile;
}
m_width = 1280.0f;
m_height = 720.0f;
std::unique_ptr<Scene> scene(new Scene());
std::function<Element*(const XurFormat::XurObject&, Element*)> buildTree;
buildTree = [&](const XurFormat::XurObject& obj, Element* parent) -> Element* {
std::unique_ptr<Control> el(new Control());
std::wstring cls(obj.className.begin(), obj.className.end());
el->setClassName(cls);
if (cls == L"XuiNineGrid") el->setIsNineGrid(true);
if (cls == L"XuiFigure") el->setIsFigure(true);
applyXurProperties(obj, el.get());
Element* raw = el.get();
if (parent) {
parent->addChild(std::unique_ptr<Element>(el.release()));
}
if (!obj.timelines.empty() || !obj.namedFrames.empty()) {
scene->loadElementTimelines(cls, obj.timelines, obj.namedFrames);
}
for (size_t cdi = 0; cdi < obj.children.size(); ++cdi) {
buildTree(obj.children[cdi], raw);
}
return raw;
};
Element* rootEl = buildTree(doc->rootObject, scene->getRootElement());
if (rootEl) {
std::wstring cls(doc->rootObject.className.begin(), doc->rootObject.className.end());
scene->setClassOverride(cls);
rootEl->computeLayout(Rect(0, 0, m_width, m_height));
}
scene->loadElementTimelines(std::wstring(doc->rootObject.className.begin(),
doc->rootObject.className.end()),
doc->rootObject.timelines, doc->rootObject.namedFrames);
m_scene = std::move(scene);
return Result_Success;
}
namespace {
struct XmlNode {
std::wstring name;
std::wstring text;
std::vector<std::pair<std::wstring, std::wstring> > attributes;
std::vector<XmlNode> children;
bool selfClosing;
XmlNode() : selfClosing(false) {}
};
static bool isXmlNameChar(wchar_t c) {
return std::iswalnum(c) || c == L'_' || c == L'-' || c == L':' || c == L'.';
}
static void trimXmlWhitespace(std::wstring& value) {
size_t first = 0;
while (first < value.size() && std::iswspace(value[first])) ++first;
size_t last = value.size();
while (last > first && std::iswspace(value[last - 1])) --last;
value = value.substr(first, last - first);
}
static int hexDigit(wchar_t c) {
if (c >= L'0' && c <= L'9') return (int)(c - L'0');
if (c >= L'a' && c <= L'f') return (int)(c - L'a' + 10);
if (c >= L'A' && c <= L'F') return (int)(c - L'A' + 10);
return -1;
}
static bool decodeXmlEntities(const std::wstring& input, std::wstring& output) {
output.clear();
for (size_t i = 0; i < input.size(); ++i) {
if (input[i] != L'&') {
output.push_back(input[i]);
continue;
}
size_t semi = input.find(L';', i + 1);
if (semi == std::wstring::npos) return false;
std::wstring entity = input.substr(i + 1, semi - i - 1);
if (entity == L"amp") output.push_back(L'&');
else if (entity == L"lt") output.push_back(L'<');
else if (entity == L"gt") output.push_back(L'>');
else if (entity == L"quot") output.push_back(L'\"');
else if (entity == L"apos") output.push_back(L'\'');
else if (!entity.empty() && entity[0] == L'#') {
unsigned long codePoint = 0;
if (entity.size() > 2 && (entity[1] == L'x' || entity[1] == L'X')) {
for (size_t j = 2; j < entity.size(); ++j) {
int digit = hexDigit(entity[j]);
if (digit < 0) return false;
codePoint = codePoint * 16u + (unsigned long)digit;
}
} else {
for (size_t j = 1; j < entity.size(); ++j) {
if (entity[j] < L'0' || entity[j] > L'9') return false;
codePoint = codePoint * 10u + (unsigned long)(entity[j] - L'0');
}
}
if (!appendUtf8CodePoint(output, codePoint)) return false;
} else {
return false;
}
i = semi;
}
return true;
}
class XmlParser {
public:
explicit XmlParser(const std::wstring& source) : m_source(source), m_pos(0) {}
bool parseDocument(XmlNode& root) {
skipWhitespace();
if (m_pos < m_source.size() && m_source[m_pos] == 0xfeff) ++m_pos;
skipWhitespace();
while (skipMisc()) skipWhitespace();
if (!parseElement(root)) return false;
skipWhitespace();
while (skipMisc()) skipWhitespace();
return m_pos == m_source.size();
}
bool parseElementAt(XmlNode& node, size_t& position) {
m_pos = position;
if (!parseElement(node)) return false;
position = m_pos;
return true;
}
private:
const std::wstring& m_source;
size_t m_pos;
void skipWhitespace() {
while (m_pos < m_source.size() && std::iswspace(m_source[m_pos])) ++m_pos;
}
bool skipMisc() {
if (m_source.compare(m_pos, 4, L"<!--") == 0) {
size_t end = m_source.find(L"-->", m_pos + 4);
if (end == std::wstring::npos) return false;
m_pos = end + 3;
return true;
}
if (m_source.compare(m_pos, 2, L"<?") == 0) {
size_t end = m_source.find(L"?>", m_pos + 2);
if (end == std::wstring::npos) return false;
m_pos = end + 2;
return true;
}
if (m_source.compare(m_pos, 2, L"<!") == 0) {
size_t end = m_source.find(L'>', m_pos + 2);
if (end == std::wstring::npos) return false;
m_pos = end + 1;
return true;
}
return false;
}
bool parseName(std::wstring& name) {
size_t start = m_pos;
while (m_pos < m_source.size() && isXmlNameChar(m_source[m_pos])) ++m_pos;
if (start == m_pos) return false;
name = m_source.substr(start, m_pos - start);
return true;
}
bool parseQuoted(std::wstring& value) {
if (m_pos >= m_source.size() ||
(m_source[m_pos] != L'\'' && m_source[m_pos] != L'\"')) return false;
wchar_t quote = m_source[m_pos++];
size_t start = m_pos;
while (m_pos < m_source.size() && m_source[m_pos] != quote) ++m_pos;
if (m_pos >= m_source.size()) return false;
std::wstring raw = m_source.substr(start, m_pos - start);
++m_pos;
return decodeXmlEntities(raw, value);
}
bool parseElement(XmlNode& node) {
if (m_pos >= m_source.size() || m_source[m_pos] != L'<') return false;
++m_pos;
if (m_pos >= m_source.size() || m_source[m_pos] == L'/' ||
m_source[m_pos] == L'!' || m_source[m_pos] == L'?') return false;
node = XmlNode();
if (!parseName(node.name)) return false;
while (true) {
skipWhitespace();
if (m_pos >= m_source.size()) return false;
if (m_source[m_pos] == L'>') {
++m_pos;
break;
}
if (m_source[m_pos] == L'/' && m_pos + 1 < m_source.size() &&
m_source[m_pos + 1] == L'>') {
m_pos += 2;
node.selfClosing = true;
return true;
}
std::wstring attrName;
if (!parseName(attrName)) return false;
skipWhitespace();
if (m_pos >= m_source.size() || m_source[m_pos] != L'=') return false;
++m_pos;
skipWhitespace();
std::wstring attrValue;
if (!parseQuoted(attrValue)) return false;
node.attributes.push_back(std::make_pair(attrName, attrValue));
}
while (m_pos < m_source.size()) {
if (m_source[m_pos] != L'<') {
size_t start = m_pos;
while (m_pos < m_source.size() && m_source[m_pos] != L'<') ++m_pos;
std::wstring decoded;
if (!decodeXmlEntities(m_source.substr(start, m_pos - start), decoded)) return false;
node.text += decoded;
continue;
}
if (m_source.compare(m_pos, 4, L"<!--") == 0 ||
m_source.compare(m_pos, 2, L"<?") == 0 ||
m_source.compare(m_pos, 2, L"<!") == 0) {
if (!skipMisc()) return false;
continue;
}
if (m_pos + 1 < m_source.size() && m_source[m_pos + 1] == L'/') {
m_pos += 2;
std::wstring closeName;
if (!parseName(closeName) || closeName != node.name) return false;
skipWhitespace();
if (m_pos >= m_source.size() || m_source[m_pos] != L'>') return false;
++m_pos;
return true;
}
XmlNode child;
if (!parseElement(child)) return false;
node.children.push_back(child);
}
return false;
}
};
static bool isPropertyName(const std::wstring& name) {
return name == L"Id" || name == L"ClassOverride" || name == L"Width" ||
name == L"Height" || name == L"Position" || name == L"Scale" ||
name == L"Pivot" || name == L"Rotation" || name == L"Opacity" ||
name == L"Show" || name == L"Anchor" || name == L"BlendMode" ||
name == L"ClipChildren" || name == L"Hittable" ||
name == L"LayoutLineBreak" || name == L"LayoutFloat" ||
name == L"Column" || name == L"Row" || name == L"ColumnSpan" ||
name == L"RowSpan" || name == L"ColorFactor" || name == L"Text" ||
name == L"Font" || name == L"PointSize" || name == L"Enabled" ||
name == L"Value" || name == L"RangeMin" || name == L"RangeMax" ||
name == L"NavLeft" || name == L"NavRight" || name == L"NavUp" ||
name == L"NavDown" || name == L"NavTabForward" ||
name == L"NavTabBackward" || name == L"Step" || name == L"Vertical" ||
name == L"PressKey" || name == L"PressAnimObject" ||
name == L"FocusAnimObject" || name == L"AccelInc" || name == L"AccelTime" ||
name == L"DefaultFocus" || name == L"TransTo" || name == L"TransFrom" ||
name == L"TransBackTo" || name == L"TransBackFrom" || name == L"IgnorePresses" ||
name == L"Source" || name == L"ImagePath" ||
name == L"TextureFileName" || name == L"LeftOffset" ||
name == L"TopOffset" || name == L"RightOffset" || name == L"BottomOffset" ||
name == L"NoCenter" || name == L"FillType" || name == L"FillColor" ||
name == L"Closed" || name == L"StrokeWidth" || name == L"StrokeColor" ||
name == L"Translation" || name == L"WrapX" || name == L"WrapY";
}
static bool findProperty(const XmlNode& node, const std::wstring& name,
std::wstring& value) {
for (size_t i = 0; i < node.attributes.size(); ++i) {
if (node.attributes[i].first == name) {
value = node.attributes[i].second;
return true;
}
}
for (size_t i = 0; i < node.children.size(); ++i) {
const XmlNode& child = node.children[i];
if (child.name == name) {
value = child.text;
return true;
}
if (child.name == L"Properties") {
for (size_t j = 0; j < child.children.size(); ++j) {
if (child.children[j].name == name) {
value = child.children[j].text;
return true;
}
}
}
}
return false;
}
static bool parseFloatValue(const std::wstring& source, float& value) {
std::wstring text = source;
trimXmlWhitespace(text);
if (text.empty()) return false;
wchar_t* end = NULL;
errno = 0;
value = (float)std::wcstod(text.c_str(), &end);
while (end && *end && std::iswspace(*end)) ++end;
return errno != ERANGE && end != text.c_str() && end && *end == L'\0';
}
static bool parseIntValue(const std::wstring& source, int& value) {
std::wstring text = source;
trimXmlWhitespace(text);
if (text.empty()) return false;
wchar_t* end = NULL;
errno = 0;
long parsed = std::wcstol(text.c_str(), &end, 0);
while (end && *end && std::iswspace(*end)) ++end;
if (errno == ERANGE || end == text.c_str() || !end || *end != L'\0') return false;
value = (int)parsed;
return true;
}
static bool parseBoolValue(const std::wstring& source, bool& value) {
std::wstring text = source;
trimXmlWhitespace(text);
for (size_t i = 0; i < text.size(); ++i) text[i] = (wchar_t)std::towlower(text[i]);
if (text == L"true" || text == L"1") { value = true; return true; }
if (text == L"false" || text == L"0") { value = false; return true; }
return false;
}
static bool parseVec3Value(const std::wstring& source, Vec3& value) {
std::wstring text = source;
trimXmlWhitespace(text);
size_t first = text.find(L',');
size_t second = first == std::wstring::npos ? std::wstring::npos : text.find(L',', first + 1);
if (first == std::wstring::npos || second == std::wstring::npos) return false;
float x, y, z;
if (!parseFloatValue(text.substr(0, first), x) ||
!parseFloatValue(text.substr(first + 1, second - first - 1), y) ||
!parseFloatValue(text.substr(second + 1), z)) return false;
value = Vec3(x, y, z);
return true;
}
static bool parseColorValue(const std::wstring& source, Color& value) {
std::wstring text = source;
trimXmlWhitespace(text);
if (text.size() > 2 && text[0] == L'0' && (text[1] == L'x' || text[1] == L'X'))
text = text.substr(2);
if (text.size() != 6 && text.size() != 8) return false;
unsigned long packed = 0;
for (size_t i = 0; i < text.size(); ++i) {
int digit = hexDigit(text[i]);
if (digit < 0) return false;
packed = packed * 16u + (unsigned long)digit;
}
unsigned long alpha = text.size() == 8 ? ((packed >> 24) & 0xffu) : 0xffu;
unsigned long red = text.size() == 8 ? ((packed >> 16) & 0xffu) : ((packed >> 16) & 0xffu);
unsigned long green = text.size() == 8 ? ((packed >> 8) & 0xffu) : ((packed >> 8) & 0xffu);
unsigned long blue = packed & 0xffu;
value = Color((float)red / 255.0f, (float)green / 255.0f,
(float)blue / 255.0f, (float)alpha / 255.0f);
return true;
}
static void applyXmlProperties(const XmlNode& node, Element* element) {
Control* control = dynamic_cast<Control*>(element);
const std::wstring names[] = {
L"Id", L"ClassOverride", L"Width", L"Height", L"Position", L"Scale",
L"Pivot", L"Rotation", L"Opacity", L"Show", L"Anchor", L"BlendMode",
L"ClipChildren", L"Hittable", L"ColorFactor", L"LayoutLineBreak", L"LayoutFloat",
L"Column", L"Row", L"ColumnSpan", L"RowSpan", L"Text", L"Font", L"PointSize", L"Enabled",
L"Value", L"RangeMin", L"RangeMax", L"NavLeft", L"NavRight", L"NavUp",
L"NavDown", L"NavTabForward", L"NavTabBackward", L"Step", L"Vertical",
L"PressKey", L"PressAnimObject", L"FocusAnimObject", L"Source", L"ImagePath",
L"TextureFileName", L"LeftOffset", L"TopOffset", L"RightOffset", L"BottomOffset",
L"NoCenter", L"FillType", L"FillColor", L"Closed", L"StrokeWidth",
L"StrokeColor", L"Translation", L"WrapX", L"WrapY", L"Points"
};
bool sawStroke = false;
for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i) {
std::wstring raw;
if (!findProperty(node, names[i], raw)) continue;
if (names[i] != L"Text") trimXmlWhitespace(raw);
if (names[i] == L"Id") element->setId(raw);
else if (names[i] == L"ClassOverride") { if (control) control->setVisual(raw); }
else if (names[i] == L"Width") { float v; if (parseFloatValue(raw, v)) element->setBounds(v, element->getBounds().y); }
else if (names[i] == L"Height") { float v; if (parseFloatValue(raw, v)) element->setBounds(element->getBounds().x, v); }
else if (names[i] == L"Position") { Vec3 v; if (parseVec3Value(raw, v)) element->setPosition(v); }
else if (names[i] == L"Scale") { Vec3 v; if (parseVec3Value(raw, v)) element->setScale(v); }
else if (names[i] == L"Pivot") { Vec3 v; if (parseVec3Value(raw, v)) element->setPivot(v); }
else if (names[i] == L"Rotation") { Vec3 v; if (parseVec3Value(raw, v)) element->setRotation(v); }
else if (names[i] == L"Opacity") { float v; if (parseFloatValue(raw, v)) element->setOpacity(v); }
else if (names[i] == L"Show") { bool v; if (parseBoolValue(raw, v)) element->setShow(v); }
else if (names[i] == L"Anchor") { int v; if (parseIntValue(raw, v)) element->setAnchor((uint32_t)v); }
else if (names[i] == L"BlendMode") { int v; if (parseIntValue(raw, v)) element->setBlendMode((uint32_t)v); }
else if (names[i] == L"ClipChildren") { bool v; if (parseBoolValue(raw, v)) element->setClipChildren(v); }
else if (names[i] == L"Hittable") { bool v; if (parseBoolValue(raw, v)) element->setHittable(v); }
else if (names[i] == L"ColorFactor") { Color v; if (parseColorValue(raw, v)) element->setColorFactor(v); }
else if (names[i] == L"LayoutLineBreak") { bool v; if (parseBoolValue(raw, v)) element->setLayoutLineBreak(v); }
else if (names[i] == L"LayoutFloat") { bool v; if (parseBoolValue(raw, v)) element->setLayoutFloat(v); }
else if (names[i] == L"Column") { int v; if (parseIntValue(raw, v)) element->setColumn((uint32_t)v); }
else if (names[i] == L"Row") { int v; if (parseIntValue(raw, v)) element->setRow((uint32_t)v); }
else if (names[i] == L"ColumnSpan") { int v; if (parseIntValue(raw, v)) element->setColumnSpan((uint32_t)v); }
else if (names[i] == L"RowSpan") { int v; if (parseIntValue(raw, v)) element->setRowSpan((uint32_t)v); }
else if (names[i] == L"Text") { if (control) control->setText(raw); }
else if (names[i] == L"Font") { if (control) control->setFontName(raw); }
else if (names[i] == L"PointSize") { float v; if (control && parseFloatValue(raw, v)) control->setFontSize(v); }
else if (names[i] == L"Enabled") { bool v; if (control && parseBoolValue(raw, v)) control->setEnable(v); }
else if (names[i] == L"Value") { int v; if (control && parseIntValue(raw, v)) control->setProgressValue(v); }
else if (names[i] == L"RangeMin") { int v; if (control && parseIntValue(raw, v)) control->setProgressRange(v, control->getProgressMax()); }
else if (names[i] == L"RangeMax") { int v; if (control && parseIntValue(raw, v)) control->setProgressRange(control->getProgressMin(), v); }
else if (names[i] == L"NavLeft") { if (control) control->setNavLeft(raw); }
else if (names[i] == L"NavRight") { if (control) control->setNavRight(raw); }
else if (names[i] == L"NavUp") { if (control) control->setNavUp(raw); }
else if (names[i] == L"NavDown") { if (control) control->setNavDown(raw); }
else if (names[i] == L"NavTabForward") { if (control) control->setNavTabForward(raw); }
else if (names[i] == L"NavTabBackward") { if (control) control->setNavTabBackward(raw); }
else if (names[i] == L"Step") { int v; if (control && parseIntValue(raw, v)) control->setStep(v); }
else if (names[i] == L"Vertical") { bool v; if (control && parseBoolValue(raw, v)) control->setVertical(v); }
else if (names[i] == L"PressKey") { int v; if (control && parseIntValue(raw, v)) control->setPressKey((uint32_t)v); }
else if (names[i] == L"PressAnimObject") { if (control) control->setPressAnimObject(raw); }
else if (names[i] == L"FocusAnimObject") { if (control) control->setFocusAnimObject(raw); }
else if (names[i] == L"Source" || names[i] == L"ImagePath") element->setImagePath(raw);
else if (names[i] == L"TextureFileName") element->setNineGridTexture(raw);
else if (names[i] == L"LeftOffset") { int v; if (parseIntValue(raw, v)) element->setNineGridLeft((uint32_t)v); }
else if (names[i] == L"TopOffset") { int v; if (parseIntValue(raw, v)) element->setNineGridTop((uint32_t)v); }
else if (names[i] == L"RightOffset") { int v; if (parseIntValue(raw, v)) element->setNineGridRight((uint32_t)v); }
else if (names[i] == L"BottomOffset") { int v; if (parseIntValue(raw, v)) element->setNineGridBottom((uint32_t)v); }
else if (names[i] == L"NoCenter") { bool v; if (parseBoolValue(raw, v)) element->setNineGridNoCenter(v); }
else if (names[i] == L"FillType") { int v; if (parseIntValue(raw, v)) element->setFigureFillType((uint32_t)v); }
else if (names[i] == L"FillColor") { Color v; if (parseColorValue(raw, v)) element->setFigureFillColor(v); }
else if (names[i] == L"Closed") { bool v; if (parseBoolValue(raw, v)) element->setFigureClosed(v); }
else if (names[i] == L"StrokeWidth") { sawStroke = true; float v; if (parseFloatValue(raw, v)) element->setFigureStrokeWidth(v); }
else if (names[i] == L"StrokeColor") { sawStroke = true; Color v; if (parseColorValue(raw, v)) element->setFigureStrokeColor(v); }
else if (names[i] == L"Translation") { Vec3 v; if (parseVec3Value(raw, v)) element->setFigureFillTranslation(Vec2(v.x, v.y)); }
else if (names[i] == L"WrapX") { int v; if (parseIntValue(raw, v)) element->setFigureFillWrapX((uint32_t)v); }
else if (names[i] == L"WrapY") { int v; if (parseIntValue(raw, v)) element->setFigureFillWrapY((uint32_t)v); }
else if (names[i] == L"Points") {
std::vector<float> nums;
size_t ppos = 0;
while (ppos < raw.size()) {
while (ppos < raw.size() &&
(raw[ppos] == L' ' || raw[ppos] == L',' || raw[ppos] == L'\t' ||
raw[ppos] == L'\r' || raw[ppos] == L'\n')) ppos++;
if (ppos >= raw.size()) break;
wchar_t* end = nullptr;
double d = std::wcstod(raw.c_str() + ppos, &end);
if (end == raw.c_str() + ppos) break;
nums.push_back((float)d);
ppos = (size_t)(end - raw.c_str());
}
if (!nums.empty()) {
int count = (int)nums[0];
float bw = element->getBounds().x > 0.0f ? element->getBounds().x : 1.0f;
float bh = element->getBounds().y > 0.0f ? element->getBounds().y : 1.0f;
std::vector<Vec2> pts;
size_t i = 1;
for (int v = 0; v < count && i + 6 <= nums.size(); v++, i += 7)
pts.push_back(Vec2(nums[i] / bw, nums[i + 1] / bh));
element->setFigurePoints(pts);
if (!sawStroke) element->setFigureStrokeWidth(0.0f);
}
}
}
for (size_t ci = 0; ci < node.children.size(); ++ci) {
if (node.children[ci].name != L"Properties") continue;
for (size_t pj = 0; pj < node.children[ci].children.size(); ++pj) {
if (node.children[ci].children[pj].name != L"Fill") continue;
const XmlNode& fill = node.children[ci].children[pj];
std::wstring v;
if (findProperty(fill, L"FillType", v)) {
int ft;
if (parseIntValue(v, ft)) element->setFigureFillType((uint32_t)ft);
}
if (findProperty(fill, L"FillColor", v)) {
Color c;
if (parseColorValue(v, c)) element->setFigureFillColor(c);
}
break;
}
break;
}
if (node.name == L"XuiNineGrid") element->setIsNineGrid(true);
if (node.name == L"XuiFigure") element->setIsFigure(true);
}
static std::unique_ptr<Element> buildXmlElement(const XmlNode& node) {
std::unique_ptr<Control> element(new Control());
element->setClassName(node.name);
applyXmlProperties(node, element.get());
for (size_t i = 0; i < node.children.size(); ++i) {
const XmlNode& child = node.children[i];
if (child.name == L"Properties" || isPropertyName(child.name)) continue;
std::unique_ptr<Element> childElement = buildXmlElement(child);
if (childElement) element->addChild(std::move(childElement));
}
return std::unique_ptr<Element>(element.release());
}
static void applySceneProperties(const XmlNode& node, Scene* scene) {
std::wstring value;
if (findProperty(node, L"DefaultFocus", value)) { trimXmlWhitespace(value); scene->setDefaultFocus(value); }
if (findProperty(node, L"TransTo", value)) { trimXmlWhitespace(value); scene->setTransitionTo(value); }
if (findProperty(node, L"TransFrom", value)) { trimXmlWhitespace(value); scene->setTransitionFrom(value); }
if (findProperty(node, L"TransBackTo", value)) { trimXmlWhitespace(value); scene->setTransitionBackTo(value); }
if (findProperty(node, L"TransBackFrom", value)) { trimXmlWhitespace(value); scene->setTransitionBackFrom(value); }
bool ignorePresses;
if (findProperty(node, L"IgnorePresses", value) && parseBoolValue(value, ignorePresses))
scene->setIgnorePresses(ignorePresses);
}
static void appendXmlChildren(const XmlNode& parent, Element* destination) {
for (size_t i = 0; i < parent.children.size(); ++i) {
const XmlNode& child = parent.children[i];
if (child.name == L"Properties" || isPropertyName(child.name)) continue;
std::unique_ptr<Element> element = buildXmlElement(child);
if (element) destination->addChild(std::move(element));
}
}
}
Result Canvas::parseXuiXml(const std::wstring& xml) {
XmlParser parser(xml);
XmlNode root;
if (!parser.parseDocument(root)) return Result_Error_InvalidFile;
float width = BASE_SCENE_WIDTH;
float height = BASE_SCENE_HEIGHT;
std::wstring value;
if (findProperty(root, L"Width", value)) parseFloatValue(value, width);
if (findProperty(root, L"Height", value)) parseFloatValue(value, height);
std::unique_ptr<Scene> scene(new Scene());
if (root.name == L"XuiCanvas") {
for (size_t i = 0; i < root.children.size(); ++i) {
const XmlNode& child = root.children[i];
if (child.name == L"Properties" || isPropertyName(child.name)) continue;
if (child.name == L"XuiScene" || child.name == L"Scene") {
applySceneProperties(child, scene.get());
appendXmlChildren(child, scene->getRootElement());
} else {
std::unique_ptr<Element> element = buildXmlElement(child);
if (element) scene->getRootElement()->addChild(std::move(element));
}
}
} else if (root.name == L"XuiScene" || root.name == L"Scene") {
applySceneProperties(root, scene.get());
appendXmlChildren(root, scene->getRootElement());
} else {
std::unique_ptr<Element> element = buildXmlElement(root);
if (element) scene->getRootElement()->addChild(std::move(element));
}
m_width = width;
m_height = height;
scene->setDisplaySize(width, height);
scene->getRootElement()->computeLayout(Rect(0.0f, 0.0f, width, height));
m_scene = std::move(scene);
return Result_Success;
}
std::unique_ptr<Element> Canvas::parseElementNode(const std::wstring& xml, size_t& pos) {
XmlParser parser(xml);
XmlNode node;
if (!parser.parseElementAt(node, pos)) return std::unique_ptr<Element>();
return buildXmlElement(node);
}
std::wstring Canvas::readProperty(const std::wstring& xml, size_t& pos) {
XmlParser parser(xml);
XmlNode node;
if (!parser.parseElementAt(node, pos)) return std::wstring();
return node.text;
}
}
+1147
View File
File diff suppressed because it is too large Load Diff
+211
View File
@@ -0,0 +1,211 @@
#include "ImXui/FontEngine.h"
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
#include <cstdio>
#include <cstring>
#include <fstream>
namespace ImXui {
struct FontEngine::FontData {
stbtt_fontinfo info;
};
FontEngine::FontEngine() : m_font(nullptr), m_blobPtr(nullptr), m_blobSize(0) {}
FontEngine::~FontEngine() {
delete m_font;
}
static bool fileExists(const std::string& path) {
std::ifstream f(path, std::ios::binary);
return f.good();
}
bool FontEngine::loadFontFile(const std::string& path) {
std::ifstream f(path, std::ios::binary | std::ios::ate);
if (!f) return false;
std::streamsize size = f.tellg();
if (size <= 0) return false;
f.seekg(0, std::ios::beg);
m_blob.resize((size_t)size);
if (!f.read((char*)m_blob.data(), size)) return false;
m_blobPtr = m_blob.data();
m_blobSize = (size_t)size;
m_path = path;
delete m_font;
m_font = new FontData();
if (!stbtt_InitFont(&m_font->info, (const unsigned char*)m_blobPtr, 0)) {
delete m_font;
m_font = nullptr;
return false;
}
return true;
}
bool FontEngine::loadFontMemory(const void* data, size_t size) {
if (!data || size == 0) return false;
m_blob.clear();
m_blobPtr = data;
m_blobSize = size;
m_path = "(memory)";
delete m_font;
m_font = new FontData();
if (!stbtt_InitFont(&m_font->info, (const unsigned char*)data, 0)) {
delete m_font;
m_font = nullptr;
return false;
}
return true;
}
bool FontEngine::loadSystemFont(const std::string& requestedName) {
std::string name = requestedName;
bool mono = false;
for (size_t i = 0; i < name.size(); i++)
if (name[i] >= 'A' && name[i] <= 'Z') name[i] = (char)(name[i] - 'A' + 'a');
if (name.find("mono") != std::string::npos || name.find("consola") != std::string::npos ||
name.find("courier") != std::string::npos || name.find("termina") != std::string::npos)
mono = true;
std::vector<std::string> candidates;
const char* fw = getenv("WINDIR");
if (fw) {
std::string wd = fw;
if (mono) {
candidates.push_back(wd + "/Fonts/consola.ttf");
candidates.push_back(wd + "/Fonts/cour.ttf");
} else {
candidates.push_back(wd + "/Fonts/segoeui.ttf");
candidates.push_back(wd + "/Fonts/arial.ttf");
candidates.push_back(wd + "/Fonts/tahoma.ttf");
}
}
if (mono) {
candidates.push_back("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf");
candidates.push_back("/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf");
candidates.push_back("/usr/share/fonts/TTF/DejaVuSansMono.ttf");
} else {
candidates.push_back("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf");
candidates.push_back("/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf");
candidates.push_back("/usr/share/fonts/TTF/DejaVuSans.ttf");
candidates.push_back("/usr/share/fonts/noto/NotoSans-Regular.ttf");
}
candidates.push_back("xarialuni.ttf");
candidates.push_back("media/xarialuni.ttf");
candidates.push_back("fonts/xarialuni.ttf");
candidates.push_back("assets/fonts/xarialuni.ttf");
for (size_t i = 0; i < candidates.size(); i++) {
if (fileExists(candidates[i]) && loadFontFile(candidates[i]))
return true;
}
return false;
}
static uint32_t utf16ToCp(const wchar_t* s, size_t len, size_t& i) {
uint32_t cp = (uint32_t)s[i];
if (len > 0 && (size_t)(i) + 1 < len && cp >= 0xD800 && cp <= 0xDBFF) {
uint32_t lo = (uint32_t)s[i + 1];
if (lo >= 0xDC00 && lo <= 0xDFFF) {
cp = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00);
i++;
}
}
return cp;
}
float FontEngine::measureText(const std::wstring& text, float sizePx) const {
if (!m_font || sizePx <= 0) return 0.0f;
float scale = stbtt_ScaleForPixelHeight(&m_font->info, sizePx);
float total = 0.0f;
size_t len = text.size();
for (size_t i = 0; i < len; i++) {
uint32_t cp = utf16ToCp(text.data(), len, i);
int advance = 0, lsb = 0;
stbtt_GetCodepointHMetrics(&m_font->info, (int)cp, &advance, &lsb);
total += (float)advance * scale;
}
return total;
}
float FontEngine::lineHeight(float sizePx) const {
if (!m_font || sizePx <= 0) return sizePx * 1.2f;
float scale = stbtt_ScaleForPixelHeight(&m_font->info, sizePx);
int ascent = 0, descent = 0, lineGap = 0;
stbtt_GetFontVMetrics(&m_font->info, &ascent, &descent, &lineGap);
return (float)(ascent - descent + lineGap) * scale;
}
bool FontEngine::renderText(const std::wstring& text, float sizePx,
std::vector<uint8_t>& outRgba, int& outW, int& outH) const {
if (!m_font || sizePx <= 0) return false;
float scale = stbtt_ScaleForPixelHeight(&m_font->info, sizePx);
int ascent = 0, descent = 0, lineGap = 0;
stbtt_GetFontVMetrics(&m_font->info, &ascent, &descent, &lineGap);
float fAscent = (float)ascent * scale;
float fLineH = (float)(ascent - descent + lineGap) * scale;
if (fLineH < 1.0f) fLineH = sizePx * 1.2f;
float totalW = 0.0f;
size_t len = text.size();
for (size_t i = 0; i < len; i++) {
uint32_t cp = utf16ToCp(text.data(), len, i);
int advance = 0, lsb = 0;
stbtt_GetCodepointHMetrics(&m_font->info, (int)cp, &advance, &lsb);
totalW += (float)advance * scale;
if (totalW > 16384.0f) { totalW = 16384.0f; break; }
}
int w = (int)(totalW + 2.0f + 0.5f);
int h = (int)(fLineH + 2.0f + 0.5f);
if (w < 1) w = 1;
if (h < 1) h = 1;
outRgba.assign((size_t)w * (size_t)h * 4, 0);
float penX = 1.0f;
float baseline = 1.0f + fAscent;
for (size_t i = 0; i < len; i++) {
uint32_t cp = utf16ToCp(text.data(), len, i);
if (cp == '\n') { penX = 1.0f; baseline += fLineH; continue; }
int advance = 0, lsb = 0;
stbtt_GetCodepointHMetrics(&m_font->info, (int)cp, &advance, &lsb);
int gw = 0, gh = 0, gxoff = 0, gyoff = 0;
unsigned char* gbmp = stbtt_GetCodepointBitmap(&m_font->info, scale, scale,
(int)cp, &gw, &gh, &gxoff, &gyoff);
if (gbmp) {
int dstX = (int)(penX + (float)gxoff);
int dstY = (int)(baseline + (float)gyoff);
for (int gy = 0; gy < gh; gy++) {
int ty = dstY + gy;
if (ty < 0 || ty >= h) continue;
for (int gx = 0; gx < gw; gx++) {
int tx = dstX + gx;
if (tx < 0 || tx >= w) continue;
unsigned char a = gbmp[gy * gw + gx];
if (a == 0) continue;
uint8_t* px = &outRgba[((size_t)ty * (size_t)w + (size_t)tx) * 4];
px[0] = 255; px[1] = 255; px[2] = 255; px[3] = a;
}
}
stbtt_FreeBitmap(gbmp, nullptr);
}
penX += (float)advance * scale;
}
outW = w;
outH = h;
return true;
}
}
+101
View File
@@ -0,0 +1,101 @@
#include "ImXui/ImageManager.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <cstdio>
#include <map>
namespace ImXui {
ImageManager::ImageManager() {}
ImageManager::~ImageManager() {
clear();
}
bool ImageManager::decodeFile(const std::string& path, ImageData& out) {
int w = 0, h = 0, comp = 0;
unsigned char* data = stbi_load(path.c_str(), &w, &h, &comp, 4);
if (!data) {
std::fprintf(stderr, "ImageManager: failed to decode '%s'\n", path.c_str());
return false;
}
out.w = w;
out.h = h;
out.rgba.assign(data, data + (size_t)w * (size_t)h * 4);
stbi_image_free(data);
return true;
}
const ImageData* ImageManager::load(const std::string& path) {
auto it = m_cache.find(path);
if (it != m_cache.end()) return &it->second;
std::string full = path;
if (!m_basePath.empty()) {
full = m_basePath;
if (full.back() != '/' && full.back() != '\\') full += '/';
full += path;
}
ImageData img;
if (!decodeFile(full, img)) return nullptr;
auto res = m_cache.emplace(path, std::move(img));
return &res.first->second;
}
void ImageManager::clear() {
m_cache.clear();
}
namespace {
std::unordered_map<std::string, MemoryTexture>& memoryTextures() {
static std::unordered_map<std::string, MemoryTexture> m;
return m;
}
std::unordered_map<std::string, MemoryTextureRaw>& rawMemoryTextures() {
static std::unordered_map<std::string, MemoryTextureRaw> m;
return m;
}
}
void registerMemoryTexture(const std::string& name, const void* rgba, int w, int h) {
MemoryTexture tex;
tex.w = w;
tex.h = h;
const uint8_t* bytes = (const uint8_t*)rgba;
tex.rgba.assign(bytes, bytes + (size_t)w * (size_t)h * 4);
memoryTextures()[name] = std::move(tex);
}
const MemoryTexture* findMemoryTexture(const std::string& name) {
auto it = memoryTextures().find(name);
return it != memoryTextures().end() ? &it->second : nullptr;
}
void registerMemoryTextureRaw(const std::string& name, const void* data, size_t size) {
MemoryTextureRaw raw;
const uint8_t* bytes = (const uint8_t*)data;
raw.encoded.assign(bytes, bytes + size);
rawMemoryTextures()[name] = std::move(raw);
}
const MemoryTextureRaw* findMemoryTextureRaw(const std::string& name) {
auto it = rawMemoryTextures().find(name);
return it != rawMemoryTextures().end() ? &it->second : nullptr;
}
bool unregisterMemoryTexture(const std::string& name) {
bool removed = memoryTextures().erase(name) > 0;
removed = rawMemoryTextures().erase(name) > 0 || removed;
return removed;
}
void clearMemoryTextures() {
memoryTextures().clear();
rawMemoryTextures().clear();
}
}
+260
View File
@@ -0,0 +1,260 @@
#include "ImXui/RenderCommands.h"
#include <cmath>
namespace ImXui {
namespace {
inline bool nearlyOne(float v) { return std::fabs(v - 1.0f) <= 0.0001f; }
bool computeElementTransform(const Element* el, Transform2D& out) {
const Vec3 scale = el->getScale();
const Vec3 rotation = el->getRotation();
const Vec3 pivot = el->getPivot();
const bool identityScale =
nearlyOne(scale.x) && nearlyOne(scale.y) && nearlyOne(scale.z);
const bool noRotation = rotation.x == 0.0f && rotation.y == 0.0f &&
rotation.z == 0.0f;
if (identityScale && noRotation) return false;
const float s = std::sin(rotation.z);
const float c = std::cos(rotation.z);
const float sx = scale.x;
const float sy = scale.y;
out.m00 = c * sx;
out.m01 = -s * sy;
out.m10 = s * sx;
out.m11 = c * sy;
const Rect rect = el->getComputedRect();
const float px = pivot.x + rect.x;
const float py = pivot.y + rect.y;
out.tx = px - (out.m00 * px + out.m01 * py);
out.ty = py - (out.m10 * px + out.m11 * py);
return true;
}
static void emitElement(const Element* element, IRenderCommandSink* sink,
float inheritedOpacity, const Scene* scene) {
if (!element || !element->isShown()) return;
const Rect rect = element->getComputedRect();
const float opacity = inheritedOpacity * element->getOpacity();
if (opacity <= 0.001f) return;
const Color color = element->getColorFactor();
Transform2D transform;
const bool pushedTransform = computeElementTransform(element, transform);
if (pushedTransform) sink->pushTransform(transform);
if (element->getBlendMode() != 0) sink->setBlendMode(element->getBlendMode());
if (element->getClipChildren()) sink->pushClip(rect);
if (element->getIsNineGrid()) {
sink->drawNineGrid(rect, element->getNineGridTexture(), color, opacity,
element->getNineGridLeft(), element->getNineGridTop(),
element->getNineGridRight(), element->getNineGridBottom(),
element->getNineGridNoCenter());
} else if (element->getIsFigure()) {
std::vector<Vec2> points = element->getFigurePoints();
for (size_t i = 0; i < points.size(); i++) {
points[i].x += rect.x;
points[i].y += rect.y;
}
sink->drawFigure(rect, points, element->getFigureClosed(),
element->getFigureFillColor(), element->getFigureStrokeColor(),
opacity, element->getFigureStrokeWidth(),
element->getBlendMode());
} else if (!element->getImagePath().empty()) {
sink->drawTexturedQuad(rect, element->getImagePath(), color, opacity);
}
const Control* control = dynamic_cast<const Control*>(element);
if (control && !control->getText().empty()) {
sink->drawText(rect, control->getText(), control->getFontName(),
control->getFontSize(), color, opacity, false);
}
if (control && !control->getCustomDrawId().empty()) {
bool handled = false;
if (scene) {
Scene::CustomDrawHandler* handler =
const_cast<Scene*>(scene)->findCustomDrawHandler(control->getCustomDrawId());
if (handler) {
(*handler)(sink, const_cast<Element*>(element), rect, opacity);
handled = true;
}
}
if (!handled) sink->drawCustom(control->getCustomDrawId(), rect, opacity);
}
const std::vector<std::unique_ptr<Element>>& rcChildren = element->getChildren();
for (size_t rci = 0; rci < rcChildren.size(); ++rci) {
emitElement(rcChildren[rci].get(), sink, opacity, scene);
}
if (element->getClipChildren()) sink->popClip();
if (element->getBlendMode() != 0) sink->setBlendMode(0);
if (pushedTransform) sink->popTransform();
}
}
void RenderCommandBuffer::clear() {
m_commands.clear();
m_width = 0.0f;
m_height = 0.0f;
}
void RenderCommandBuffer::beginScene(float width, float height) {
m_width = width;
m_height = height;
RenderCommand command;
command.type = RenderCommandType_BeginScene;
command.rect = Rect(0.0f, 0.0f, width, height);
m_commands.push_back(command);
}
void RenderCommandBuffer::drawColoredQuad(const Rect& rect, const Color& color,
float opacity) {
RenderCommand command;
command.type = RenderCommandType_ColoredQuad;
command.rect = rect;
command.color = color;
command.opacity = opacity;
m_commands.push_back(command);
}
void RenderCommandBuffer::drawTexturedQuad(const Rect& rect,
const std::wstring& resource,
const Color& color,
float opacity) {
RenderCommand command;
command.type = RenderCommandType_TexturedQuad;
command.rect = rect;
command.resource = resource;
command.color = color;
command.opacity = opacity;
m_commands.push_back(command);
}
void RenderCommandBuffer::drawText(const Rect& rect, const std::wstring& text,
const std::wstring& fontName, float fontSize,
const Color& color, float opacity,
bool centered) {
RenderCommand command;
command.type = RenderCommandType_Text;
command.rect = rect;
command.text = text;
command.fontName = fontName;
command.fontSize = fontSize;
command.color = color;
command.opacity = opacity;
command.centered = centered;
m_commands.push_back(command);
}
void RenderCommandBuffer::endScene() {
RenderCommand command;
command.type = RenderCommandType_EndScene;
m_commands.push_back(command);
}
void RenderCommandBuffer::pushTransform(const Transform2D& transform) {
RenderCommand command;
command.type = RenderCommandType_PushTransform;
command.transform = transform;
m_commands.push_back(command);
}
void RenderCommandBuffer::popTransform() {
RenderCommand command;
command.type = RenderCommandType_PopTransform;
m_commands.push_back(command);
}
void RenderCommandBuffer::pushClip(const Rect& rect) {
RenderCommand command;
command.type = RenderCommandType_PushClip;
command.rect = rect;
m_commands.push_back(command);
}
void RenderCommandBuffer::popClip() {
RenderCommand command;
command.type = RenderCommandType_PopClip;
m_commands.push_back(command);
}
void RenderCommandBuffer::drawNineGrid(const Rect& rect, const std::wstring& resource,
const Color& color, float opacity,
uint32_t leftInset, uint32_t topInset,
uint32_t rightInset, uint32_t bottomInset,
bool noCenter) {
RenderCommand command;
command.type = RenderCommandType_NineGrid;
command.rect = rect;
command.resource = resource;
command.color = color;
command.opacity = opacity;
command.leftInset = leftInset;
command.topInset = topInset;
command.rightInset = rightInset;
command.bottomInset = bottomInset;
command.noCenter = noCenter;
m_commands.push_back(command);
}
void RenderCommandBuffer::drawFigure(const Rect& rect, const std::vector<Vec2>& points,
bool closed, const Color& fillColor,
const Color& strokeColor, float opacity,
float strokeWidth, uint32_t blendMode) {
RenderCommand command;
command.type = RenderCommandType_Figure;
command.rect = rect;
command.points = points;
command.closed = closed;
command.color = fillColor;
command.strokeColor = strokeColor;
command.opacity = opacity;
command.strokeWidth = strokeWidth;
command.blendMode = blendMode;
m_commands.push_back(command);
}
void RenderCommandBuffer::setBlendMode(uint32_t blendMode) {
RenderCommand command;
command.type = RenderCommandType_SetBlendMode;
command.blendMode = blendMode;
m_commands.push_back(command);
}
void RenderCommandBuffer::drawCustom(const std::wstring& drawId, const Rect& rect,
float opacity) {
RenderCommand command;
command.type = RenderCommandType_CustomDraw;
command.resource = drawId;
command.rect = rect;
command.opacity = opacity;
m_commands.push_back(command);
}
void emitRenderCommands(const Scene* scene, IRenderCommandSink* sink) {
if (!scene || !sink || !scene->getRootElement()) return;
sink->beginScene(scene->getDisplayWidth(), scene->getDisplayHeight());
emitElement(scene->getRootElement(), sink, 1.0f, scene);
sink->endScene();
}
}
+1309
View File
File diff suppressed because it is too large Load Diff
+208
View File
@@ -0,0 +1,208 @@
#include "ImXui/Skin.h"
#include <cstdio>
#include <fstream>
#include <sstream>
namespace ImXui {
bool Skin::loadFromXui(const std::string& path) {
std::ifstream ifs(path);
if (!ifs) return false;
std::stringstream ss;
ss << ifs.rdbuf();
return loadFromString(ss.str());
}
bool Skin::loadFromString(const std::string& xml) {
m_entries.clear();
m_entryMap.clear();
size_t pos = 0;
while (true) {
size_t start = xml.find("<XuiVisual>", pos);
if (start == std::string::npos) break;
size_t end = xml.find("</XuiVisual>", start);
if (end == std::string::npos) break;
parseVisualBlock(xml, start, end + 12);
pos = end + 12;
}
return !m_entries.empty();
}
static std::string trim(const std::string& s) {
size_t a = s.find_first_not_of(" \t\r\n");
if (a == std::string::npos) return "";
size_t b = s.find_last_not_of(" \t\r\n");
return s.substr(a, b - a + 1);
}
std::string Skin::readProp(const std::string& xml, const std::string& propName, size_t from, size_t to) {
std::string open = "<" + propName + ">";
std::string close = "</" + propName + ">";
size_t p = xml.find(open, from);
if (p == std::string::npos || p >= to) return "";
p += open.size();
size_t q = xml.find(close, p);
if (q == std::string::npos || q > to) return "";
return trim(xml.substr(p, q - p));
}
static uint32_t parseHexColor(const std::string& s) {
if (s.empty()) return 0xFFFFFFFF;
size_t start = 0;
if (s.size() >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) start = 2;
unsigned long val = std::stoul(s.substr(start), nullptr, 16);
return (uint32_t)val;
}
static void findImages(const std::string& xml, size_t blockStart, size_t blockEnd,
std::vector<VisualImage>& outImages,
TextProperties* outTextProps = nullptr) {
size_t pos = blockStart;
while (true) {
size_t childStart = xml.find("<Xui", pos);
if (childStart == std::string::npos || childStart >= blockEnd) break;
size_t nameEnd = xml.find_first_of("> \t\r\n", childStart);
if (nameEnd == std::string::npos) break;
std::string tagName = xml.substr(childStart + 1, nameEnd - childStart - 1);
std::string closeTag = "</" + tagName + ">";
size_t close = xml.find(closeTag, childStart);
if (close == std::string::npos || close > blockEnd) {
pos = childStart + 1;
continue;
}
auto readPropFromBlock = [&](const std::string& pn, size_t ps, size_t pe) -> std::string {
std::string o = "<" + pn + ">";
std::string c = "</" + pn + ">";
size_t a = xml.find(o, ps);
if (a == std::string::npos || a >= pe) return "";
a += o.size();
size_t b = xml.find(c, a);
if (b == std::string::npos || b > pe) return "";
std::string v = xml.substr(a, b - a);
size_t s = v.find_first_not_of(" \t\r\n");
size_t e = v.find_last_not_of(" \t\r\n");
return (s == std::string::npos) ? "" : v.substr(s, e - s + 1);
};
if (tagName == "XuiImage") {
size_t propsStart = xml.find("<Properties>", childStart);
size_t propsEnd = xml.find("</Properties>", childStart);
if (propsStart != std::string::npos && propsEnd != std::string::npos && propsEnd < close) {
VisualImage img;
img.imagePath = readPropFromBlock("ImagePath", propsStart, propsEnd);
if (!img.imagePath.empty()) {
std::string w = readPropFromBlock("Width", propsStart, propsEnd);
std::string h = readPropFromBlock("Height", propsStart, propsEnd);
std::string p = readPropFromBlock("Position", propsStart, propsEnd);
std::string a = readPropFromBlock("Anchor", propsStart, propsEnd);
if (!w.empty()) img.w = (float)std::stod(w);
if (!h.empty()) img.h = (float)std::stod(h);
if (!a.empty()) img.anchor = (uint32_t)std::stoul(a);
if (!p.empty()) {
auto c1 = p.find(',');
if (c1 != std::string::npos) {
img.x = (float)std::stod(p.substr(0, c1));
auto c2 = p.find(',', c1 + 1);
if (c2 != std::string::npos) {
img.y = (float)std::stod(p.substr(c1 + 1, c2 - c1 - 1));
img.z = (float)std::stod(p.substr(c2 + 1));
} else {
img.y = (float)std::stod(p.substr(c1 + 1));
}
}
}
outImages.push_back(img);
}
}
} else if (tagName == "XuiTextPresenter" && outTextProps) {
size_t propsStart = xml.find("<Properties>", childStart);
size_t propsEnd = xml.find("</Properties>", childStart);
if (propsStart != std::string::npos && propsEnd != std::string::npos && propsEnd < close) {
std::string tc = readPropFromBlock("TextColor", propsStart, propsEnd);
if (!tc.empty()) {
uint32_t c = parseHexColor(tc);
outTextProps->hasColor = true;
outTextProps->textColorA = (uint8_t)((c >> 24) & 0xFF);
outTextProps->textColorR = (uint8_t)((c >> 16) & 0xFF);
outTextProps->textColorG = (uint8_t)((c >> 8) & 0xFF);
outTextProps->textColorB = (uint8_t)(c & 0xFF);
}
std::string ps = readPropFromBlock("PointSize", propsStart, propsEnd);
if (!ps.empty()) {
outTextProps->hasPointSize = true;
outTextProps->pointSize = (float)std::stod(ps);
}
std::string ft = readPropFromBlock("Font", propsStart, propsEnd);
if (!ft.empty()) {
outTextProps->hasFont = true;
outTextProps->font = ft;
}
std::string ts = readPropFromBlock("TextStyle", propsStart, propsEnd);
if (!ts.empty()) {
outTextProps->hasTextStyle = true;
outTextProps->textStyle = (uint32_t)std::stoul(ts);
}
}
} else if (tagName.find("Xui") == 0 && tagName != "XuiImage" &&
tagName != "XuiVisual") {
size_t gt = xml.find('>', childStart);
size_t innerStart = (gt != std::string::npos && gt < close) ? gt + 1 : childStart;
findImages(xml, innerStart, close, outImages, outTextProps);
}
pos = close + closeTag.size();
}
}
void Skin::parseVisualBlock(const std::string& xml, size_t start, size_t end) {
VisualEntry entry;
entry.id = readProp(xml, "Id", start, end);
if (entry.id.empty()) return;
size_t propsStart = xml.find("<Properties>", start);
size_t propsEnd = (propsStart != std::string::npos) ? xml.find("</Properties>", propsStart) : std::string::npos;
if (propsStart != std::string::npos && propsEnd != std::string::npos && propsEnd < end) {
std::string wStr = readProp(xml, "Width", propsStart, propsEnd);
std::string hStr = readProp(xml, "Height", propsStart, propsEnd);
std::string pStr = readProp(xml, "Position", propsStart, propsEnd);
if (!wStr.empty()) entry.templateWidth = (float)std::stod(wStr);
if (!hStr.empty()) entry.templateHeight = (float)std::stod(hStr);
if (!pStr.empty()) {
auto c1 = pStr.find(',');
entry.posX = (float)std::stod(pStr.substr(0, c1));
if (c1 != std::string::npos) {
auto c2 = pStr.find(',', c1 + 1);
entry.posY = (float)std::stod(pStr.substr(c1 + 1, c2 != std::string::npos ? c2 - c1 - 1 : std::string::npos));
}
}
}
size_t gt = xml.find('>', start);
size_t innerStart = (gt != std::string::npos && gt < end) ? gt + 1 : start;
findImages(xml, innerStart, end, entry.images, &entry.textProps);
if (!entry.images.empty() || entry.textProps.hasColor || entry.textProps.hasFont || entry.textProps.hasPointSize) {
int idx = (int)m_entries.size();
m_entries.push_back(entry);
m_entryMap[entry.id] = idx;
std::fprintf(stderr, "Skin: %s -> %zu images\n", entry.id.c_str(), entry.images.size());
}
}
const std::vector<VisualImage>* Skin::getImages(const std::string& visualName) const {
auto it = m_entryMap.find(visualName);
if (it == m_entryMap.end()) return nullptr;
return &m_entries[it->second].images;
}
const VisualEntry* Skin::getEntry(const std::string& visualName) const {
auto it = m_entryMap.find(visualName);
if (it == m_entryMap.end()) return nullptr;
return &m_entries[it->second];
}
}
+494
View File
@@ -0,0 +1,494 @@
#include "ImXui/SoftwareRenderer.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
namespace ImXui {
namespace {
inline float clamp01(float v) { return v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v); }
inline uint8_t toByte(float v) { return (uint8_t)(clamp01(v) * 255.0f + 0.5f); }
inline void blendPixel(uint8_t* dst, uint8_t sr, uint8_t sg, uint8_t sb, uint8_t sa) {
if (sa == 255) {
dst[0] = sr; dst[1] = sg; dst[2] = sb; dst[3] = 255;
return;
}
if (sa == 0) return;
unsigned a = sa;
unsigned ia = 255u - a;
dst[0] = (uint8_t)((sr * a + dst[0] * ia) / 255u);
dst[1] = (uint8_t)((sg * a + dst[1] * ia) / 255u);
dst[2] = (uint8_t)((sb * a + dst[2] * ia) / 255u);
dst[3] = (uint8_t)((dst[3] * ia + a * 255u) / 255u);
}
}
SoftwareRenderer::SoftwareRenderer() : m_width(0), m_height(0), m_skin(nullptr) {}
SoftwareRenderer::~SoftwareRenderer() { shutdown(); }
bool SoftwareRenderer::init(void* nativeWindow, int width, int height) {
(void)nativeWindow;
if (width <= 0 || height <= 0) return false;
m_width = width;
m_height = height;
m_fb.assign((size_t)width * (size_t)height * 4, 0);
return true;
}
void SoftwareRenderer::shutdown() {
m_fb.clear();
m_width = 0;
m_height = 0;
}
bool SoftwareRenderer::resize(int width, int height) {
if (width <= 0 || height <= 0) return false;
m_width = width;
m_height = height;
m_fb.assign((size_t)width * (size_t)height * 4, 0);
return true;
}
bool SoftwareRenderer::beginFrame(float clearR, float clearG, float clearB, float clearA) {
uint8_t r = toByte(clearR), g = toByte(clearG), b = toByte(clearB), a = toByte(clearA);
for (size_t i = 0; i < m_fb.size(); i += 4) {
m_fb[i] = r; m_fb[i + 1] = g; m_fb[i + 2] = b; m_fb[i + 3] = a;
}
while (!m_clipStack.empty()) m_clipStack.pop();
return true;
}
void SoftwareRenderer::endFrame(bool vsync) {
(void)vsync;
}
uint32_t SoftwareRenderer::pixel(int x, int y) const {
if (x < 0 || y < 0 || x >= m_width || y >= m_height) return 0;
const uint8_t* p = &m_fb[((size_t)y * (size_t)m_width + (size_t)x) * 4];
return ((uint32_t)p[3] << 24) | ((uint32_t)p[0] << 16) | ((uint32_t)p[1] << 8) | (uint32_t)p[2];
}
void SoftwareRenderer::pushClip(const Rect& r) {
Rect cur = r;
if (!m_clipStack.empty()) {
const Rect& top = m_clipStack.top();
float x0 = std::max(cur.x, top.x);
float y0 = std::max(cur.y, top.y);
float x1 = std::min(cur.right(), top.right());
float y1 = std::min(cur.bottom(), top.bottom());
cur = Rect(x0, y0, std::max(0.0f, x1 - x0), std::max(0.0f, y1 - y0));
}
m_clipStack.push(cur);
}
void SoftwareRenderer::popClip() {
if (!m_clipStack.empty()) m_clipStack.pop();
}
bool SoftwareRenderer::clipRect(Rect& r) const {
if (m_clipStack.empty()) return true;
const Rect& c = m_clipStack.top();
float x0 = std::max(r.x, c.x);
float y0 = std::max(r.y, c.y);
float x1 = std::min(r.right(), c.right());
float y1 = std::min(r.bottom(), c.bottom());
if (x1 <= x0 || y1 <= y0) return false;
r = Rect(x0, y0, x1 - x0, y1 - y0);
return true;
}
void SoftwareRenderer::fillRect(float x, float y, float w, float h,
float r, float g, float b, float a) {
if (m_fb.empty() || a <= 0.001f) return;
Rect rr(x, y, w, h);
if (!clipRect(rr)) return;
int x0 = std::max(0, (int)std::floor(rr.x));
int y0 = std::max(0, (int)std::floor(rr.y));
int x1 = std::min(m_width, (int)std::ceil(rr.right()));
int y1 = std::min(m_height, (int)std::ceil(rr.bottom()));
if (x1 <= x0 || y1 <= y0) return;
uint8_t sr = toByte(r), sg = toByte(g), sb = toByte(b), sa = toByte(a);
for (int py = y0; py < y1; py++) {
uint8_t* row = &m_fb[((size_t)py * (size_t)m_width + (size_t)x0) * 4];
for (int px = x0; px < x1; px++, row += 4)
blendPixel(row, sr, sg, sb, sa);
}
}
static bool pointInTri(float px, float py,
float x0, float y0, float x1, float y1, float x2, float y2) {
float d1 = (px - x1) * (y0 - y1) - (x0 - x1) * (py - y1);
float d2 = (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2);
float d3 = (px - x0) * (y2 - y0) - (x2 - x0) * (py - y0);
bool neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
bool pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
return !(neg && pos);
}
void SoftwareRenderer::fillTriangle(float x0, float y0, float x1, float y1, float x2, float y2,
float r, float g, float b, float a) {
if (m_fb.empty() || a <= 0.001f) return;
float minX = std::min(std::min(x0, x1), x2);
float maxX = std::max(std::max(x0, x1), x2);
float minY = std::min(std::min(y0, y1), y2);
float maxY = std::max(std::max(y0, y1), y2);
Rect rr(minX, minY, maxX - minX, maxY - minY);
if (!clipRect(rr)) return;
int ix0 = std::max(0, (int)std::floor(rr.x));
int iy0 = std::max(0, (int)std::floor(rr.y));
int ix1 = std::min(m_width, (int)std::ceil(rr.right()));
int iy1 = std::min(m_height, (int)std::ceil(rr.bottom()));
uint8_t sr = toByte(r), sg = toByte(g), sb = toByte(b), sa = toByte(a);
for (int py = iy0; py < iy1; py++) {
for (int px = ix0; px < ix1; px++) {
float fx = (float)px + 0.5f, fy = (float)py + 0.5f;
if (pointInTri(fx, fy, x0, y0, x1, y1, x2, y2))
blendPixel(&m_fb[((size_t)py * (size_t)m_width + (size_t)px) * 4], sr, sg, sb, sa);
}
}
}
void SoftwareRenderer::strokeSegment(float x0, float y0, float x1, float y1, float width,
float r, float g, float b, float a) {
if (a <= 0.001f || width <= 0.0f) return;
float dx = x1 - x0, dy = y1 - y0;
float len = std::sqrt(dx * dx + dy * dy);
if (len < 0.001f) return;
float nx = -dy / len * width * 0.5f;
float ny = dx / len * width * 0.5f;
float qx0 = x0 + nx, qy0 = y0 + ny;
float qx1 = x0 - nx, qy1 = y0 - ny;
float qx2 = x1 - nx, qy2 = y1 - ny;
float qx3 = x1 + nx, qy3 = y1 + ny;
fillTriangle(qx0, qy0, qx1, qy1, qx2, qy2, r, g, b, a);
fillTriangle(qx0, qy0, qx2, qy2, qx3, qy3, r, g, b, a);
}
void SoftwareRenderer::blitImage(int dx, int dy, int dw, int dh, const ImageData& img,
float tintR, float tintG, float tintB, float alpha) {
if (m_fb.empty() || alpha <= 0.001f || !img.valid() || dw <= 0 || dh <= 0) return;
Rect rr((float)dx, (float)dy, (float)dw, (float)dh);
if (!clipRect(rr)) return;
int x0 = std::max(0, (int)std::floor(rr.x));
int y0 = std::max(0, (int)std::floor(rr.y));
int x1 = std::min(m_width, (int)std::ceil(rr.right()));
int y1 = std::min(m_height, (int)std::ceil(rr.bottom()));
if (x1 <= x0 || y1 <= y0) return;
uint8_t tr = toByte(tintR), tg = toByte(tintG), tb = toByte(tintB);
unsigned ta = (unsigned)toByte(alpha);
const int iw = img.w, ih = img.h;
for (int py = y0; py < y1; py++) {
for (int px = x0; px < x1; px++) {
int sx = (int)((float)(px - dx) * (float)iw / (float)dw);
int sy = (int)((float)(py - dy) * (float)ih / (float)dh);
sx = std::max(0, std::min(iw - 1, sx));
sy = std::max(0, std::min(ih - 1, sy));
const uint8_t* s = &img.rgba[((size_t)sy * (size_t)iw + (size_t)sx) * 4];
unsigned sa = (unsigned)s[3] * ta / 255u;
if (sa == 0) continue;
uint8_t sr = (uint8_t)((unsigned)s[0] * tr / 255u);
uint8_t sg = (uint8_t)((unsigned)s[1] * tg / 255u);
uint8_t sb = (uint8_t)((unsigned)s[2] * tb / 255u);
blendPixel(&m_fb[((size_t)py * (size_t)m_width + (size_t)px) * 4], sr, sg, sb, (uint8_t)sa);
}
}
}
void SoftwareRenderer::drawNineGridRect(float x, float y, float w, float h, const ImageData& img,
uint32_t leftInset, uint32_t topInset, uint32_t rightInset,
uint32_t bottomInset, bool noCenter,
float r, float g, float b, float a) {
if (!img.valid() || a <= 0.001f) return;
int iw = img.w, ih = img.h;
uint32_t l = std::min((uint32_t)iw, leftInset);
uint32_t t = std::min((uint32_t)ih, topInset);
uint32_t rr = std::min((uint32_t)iw, rightInset);
uint32_t bb = std::min((uint32_t)ih, bottomInset);
struct Piece { float dx, dy, dw, dh; int sx, sy, sw, sh; };
Piece pieces[9];
int n = 0;
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
if (noCenter && row == 1 && col == 1) continue;
int sx = (col == 0) ? 0 : (col == 1) ? (int)l : (int)(iw - rr);
int sy = (row == 0) ? 0 : (row == 1) ? (int)t : (int)(ih - bb);
int sw = (col == 0) ? (int)l : (col == 1) ? (int)(iw - l - rr) : (int)rr;
int sh = (row == 0) ? (int)t : (row == 1) ? (int)(ih - t - bb) : (int)bb;
if (sw <= 0 || sh <= 0) continue;
float dx, dy, dw2, dh2;
if (col == 0) { dx = x; dw2 = (float)l; }
else if (col == 1) { dx = x + (float)l; dw2 = w - (float)l - (float)rr; }
else { dx = x + w - (float)rr; dw2 = (float)rr; }
if (row == 0) { dy = y; dh2 = (float)t; }
else if (row == 1) { dy = y + (float)t; dh2 = h - (float)t - (float)bb; }
else { dy = y + h - (float)bb; dh2 = (float)bb; }
if (dw2 <= 0.0f || dh2 <= 0.0f) continue;
pieces[n++] = { dx, dy, dw2, dh2, sx, sy, sw, sh };
}
}
for (int i = 0; i < n; i++) {
const Piece& p = pieces[i];
Rect rr2(p.dx, p.dy, p.dw, p.dh);
if (!clipRect(rr2)) continue;
int x0 = std::max(0, (int)std::floor(rr2.x));
int y0 = std::max(0, (int)std::floor(rr2.y));
int x1 = std::min(m_width, (int)std::ceil(rr2.right()));
int y1 = std::min(m_height, (int)std::ceil(rr2.bottom()));
uint8_t tr = toByte(r), tg = toByte(g), tb = toByte(b);
unsigned ta = (unsigned)toByte(a);
for (int py = y0; py < y1; py++) {
for (int px = x0; px < x1; px++) {
int sx2 = p.sx + (int)((float)(px - p.dx) * (float)p.sw / p.dw);
int sy2 = p.sy + (int)((float)(py - p.dy) * (float)p.sh / p.dh);
sx2 = std::max(0, std::min(iw - 1, sx2));
sy2 = std::max(0, std::min(ih - 1, sy2));
const uint8_t* s = &img.rgba[((size_t)sy2 * (size_t)iw + (size_t)sx2) * 4];
unsigned sa = (unsigned)s[3] * ta / 255u;
if (sa == 0) continue;
uint8_t sr = (uint8_t)((unsigned)s[0] * tr / 255u);
uint8_t sg = (uint8_t)((unsigned)s[1] * tg / 255u);
uint8_t sb = (uint8_t)((unsigned)s[2] * tb / 255u);
blendPixel(&m_fb[((size_t)py * (size_t)m_width + (size_t)px) * 4], sr, sg, sb, (uint8_t)sa);
}
}
}
}
void SoftwareRenderer::drawColoredQuad(float x, float y, float w, float h,
float r, float g, float b, float a) {
fillRect(x, y, w, h, r, g, b, a);
}
void SoftwareRenderer::drawTexturedQuad(float x, float y, float w, float h,
const wchar_t* texturePath,
float r, float g, float b, float a) {
if (!texturePath) return;
std::string path(texturePath, texturePath + wcslen(texturePath));
const ImageData* img = m_images.load(path);
if (!img) return;
blitImage((int)x, (int)y, (int)w, (int)h, *img, r, g, b, a);
}
void SoftwareRenderer::drawFigure(float x, float y, float w, float h,
const std::vector<Vec2>& points, bool closed,
float fillR, float fillG, float fillB, float fillA,
float strokeR, float strokeG, float strokeB, float strokeA,
float strokeWidth) {
if (points.size() < 2) return;
std::vector<Vec2> screen(points.size());
for (size_t i = 0; i < points.size(); i++) {
screen[i].x = x + points[i].x * w;
screen[i].y = y + points[i].y * h;
}
if (fillA > 0.001f && screen.size() >= 3) {
Vec2 center(0, 0);
for (size_t i = 0; i < screen.size(); i++) { center.x += screen[i].x; center.y += screen[i].y; }
center.x /= (float)screen.size();
center.y /= (float)screen.size();
size_t limit = closed ? screen.size() : screen.size() - 1;
for (size_t i = 0; i < limit; i++) {
size_t next = (i + 1) % screen.size();
fillTriangle(center.x, center.y, screen[i].x, screen[i].y,
screen[next].x, screen[next].y, fillR, fillG, fillB, fillA);
}
}
if (strokeA > 0.001f && strokeWidth > 0.0f) {
size_t limit = closed ? screen.size() : screen.size() - 1;
for (size_t i = 0; i < limit; i++) {
size_t next = (i + 1) % screen.size();
strokeSegment(screen[i].x, screen[i].y, screen[next].x, screen[next].y,
strokeWidth, strokeR, strokeG, strokeB, strokeA);
}
}
}
bool SoftwareRenderer::loadFont(const wchar_t* path) {
if (!path) return false;
std::string p(path, path + wcslen(path));
return m_font.loadFontFile(p);
}
bool SoftwareRenderer::loadSystemFont(const std::string& name) {
return m_font.loadSystemFont(name);
}
bool SoftwareRenderer::initTextRendering() {
if (!m_font.isLoaded()) return m_font.loadSystemFont("");
return true;
}
void SoftwareRenderer::shutdownTextRendering() {}
float SoftwareRenderer::measureText(const std::wstring& text, float sizePx) const {
return m_font.measureText(text, sizePx);
}
float SoftwareRenderer::lineHeight(float sizePx) const {
return m_font.lineHeight(sizePx);
}
void SoftwareRenderer::drawTextString(float x, float y, float w, float h,
const std::wstring& text, const std::wstring& fontName,
float fontSize,
float r, float g, float b, float a,
bool centered) {
if (text.empty() || fontSize <= 0.0f || a <= 0.001f) return;
if (!m_font.isLoaded()) {
std::string narrow(fontName.begin(), fontName.end());
if (!m_font.loadSystemFont(narrow)) return;
}
std::vector<uint8_t> rgba;
int tw = 0, th = 0;
if (!m_font.renderText(text, fontSize, rgba, tw, th)) return;
if (tw < 1 || th < 1) return;
float dx = x, dy = y;
if (centered) {
dx = x + ((w > (float)tw) ? ((w - (float)tw) * 0.5f) : 0.0f);
dy = y + ((h > (float)th) ? ((h - (float)th) * 0.5f) : 0.0f);
}
ImageData img;
img.w = tw;
img.h = th;
img.rgba = std::move(rgba);
blitImage((int)dx, (int)dy, tw, th, img, r, g, b, a);
}
void SoftwareRenderer::drawElement(const Element* el) {
if (!el || !el->isShown() || el->getOpacity() <= 0.001f) return;
const Rect r = el->getComputedRect();
const Color cf = el->getColorFactor();
float alpha = el->getOpacity() * cf.a;
if (alpha < 0.01f) return;
if (el->getIsNineGrid() && !el->getNineGridTexture().empty()) {
std::string path(el->getNineGridTexture().begin(), el->getNineGridTexture().end());
const ImageData* img = m_images.load(path);
if (img) {
drawNineGridRect(r.x, r.y, r.w, r.h, *img,
el->getNineGridLeft(), el->getNineGridTop(),
el->getNineGridRight(), el->getNineGridBottom(),
el->getNineGridNoCenter(), cf.r, cf.g, cf.b, alpha);
}
{ const std::vector<std::unique_ptr<Element>>& c = el->getChildren(); for (size_t i = 0; i < c.size(); ++i) drawElement(c[i].get()); }
return;
}
if (el->getIsFigure() && !el->getFigurePoints().empty()) {
const Color fc = el->getFigureFillColor();
const Color sc = el->getFigureStrokeColor();
drawFigure(r.x, r.y, r.w, r.h, el->getFigurePoints(), el->getFigureClosed(),
fc.r, fc.g, fc.b, alpha * fc.a,
sc.r, sc.g, sc.b, alpha * sc.a,
el->getFigureStrokeWidth());
{ const std::vector<std::unique_ptr<Element>>& c = el->getChildren(); for (size_t i = 0; i < c.size(); ++i) drawElement(c[i].get()); }
return;
}
bool hasClip = el->getClipChildren();
if (hasClip) pushClip(r);
const Control* ctrl = dynamic_cast<const Control*>(el);
bool hasVisualContent = !el->getImagePath().empty() ||
(ctrl && (!ctrl->getVisual().empty() || !ctrl->getText().empty()));
if (!hasVisualContent)
fillRect(r.x, r.y, r.w, r.h, cf.r, cf.g, cf.b, alpha);
{ const std::vector<std::unique_ptr<Element>>& c = el->getChildren(); for (size_t i = 0; i < c.size(); ++i) drawElement(c[i].get()); }
if (hasClip) popClip();
}
void SoftwareRenderer::drawTexturedElement(const Element* el) {
if (!el || !el->isShown() || el->getOpacity() <= 0.001f) return;
const Rect r = el->getComputedRect();
const Color cf = el->getColorFactor();
float alpha = el->getOpacity() * cf.a;
if (alpha < 0.01f) return;
if (!el->getImagePath().empty()) {
std::string path(el->getImagePath().begin(), el->getImagePath().end());
const ImageData* img = m_images.load(path);
if (img) blitImage((int)r.x, (int)r.y, (int)r.w, (int)r.h, *img, cf.r, cf.g, cf.b, alpha);
}
const Control* ctrl = dynamic_cast<const Control*>(el);
if (ctrl && !ctrl->getText().empty()) {
std::wstring fontName = ctrl->getFontName().empty() ? L"UI" : ctrl->getFontName();
float fontSize = ctrl->getFontSize() > 0.0f ? ctrl->getFontSize() : 12.0f;
drawTextString(r.x, r.y, r.w, r.h, ctrl->getText(), fontName, fontSize,
cf.r, cf.g, cf.b, alpha, false);
}
}
void SoftwareRenderer::renderScene(const Scene* scene) {
if (!scene) return;
const Element* root = scene->getRootElement();
if (!root) return;
{ const std::vector<std::unique_ptr<Element>>& rc = root->getChildren(); for (size_t i = 0; i < rc.size(); ++i) drawElement(rc[i].get()); }
{ const std::vector<std::unique_ptr<Element>>& rc2 = root->getChildren(); for (size_t i = 0; i < rc2.size(); ++i) drawTexturedElement(rc2[i].get()); }
}
bool SoftwareRenderer::saveBmp(const char* path) const {
if (m_fb.empty() || !path) return false;
FILE* f = fopen(path, "wb");
if (!f) return false;
int w = m_width, h = m_height;
int rowSize = (w * 3 + 3) & ~3;
int dataSize = rowSize * h;
int fileSize = 54 + dataSize;
unsigned char hdr[54] = { 0 };
hdr[0] = 'B'; hdr[1] = 'M';
hdr[2] = (unsigned char)(fileSize & 0xff); hdr[3] = (unsigned char)((fileSize >> 8) & 0xff);
hdr[4] = (unsigned char)((fileSize >> 16) & 0xff); hdr[5] = (unsigned char)((fileSize >> 24) & 0xff);
hdr[10] = 54;
hdr[14] = 40;
hdr[18] = (unsigned char)(w & 0xff); hdr[19] = (unsigned char)((w >> 8) & 0xff);
hdr[20] = (unsigned char)((w >> 16) & 0xff); hdr[21] = (unsigned char)((w >> 24) & 0xff);
hdr[22] = (unsigned char)(h & 0xff); hdr[23] = (unsigned char)((h >> 8) & 0xff);
hdr[24] = (unsigned char)((h >> 16) & 0xff); hdr[25] = (unsigned char)((h >> 24) & 0xff);
hdr[26] = 1; hdr[28] = 24;
fwrite(hdr, 1, 54, f);
std::vector<unsigned char> row((size_t)rowSize, 0);
for (int py = h - 1; py >= 0; py--) {
for (int px = 0; px < w; px++) {
const uint8_t* s = &m_fb[((size_t)py * (size_t)w + (size_t)px) * 4];
row[(size_t)px * 3] = s[2];
row[(size_t)px * 3 + 1] = s[1];
row[(size_t)px * 3 + 2] = s[0];
}
fwrite(row.data(), 1, (size_t)rowSize, f);
}
fclose(f);
return true;
}
bool SoftwareRenderer::savePng(const char* path) const {
if (m_fb.empty() || !path) return false;
return stbi_write_png(path, m_width, m_height, 4, m_fb.data(), m_width * 4) != 0;
}
}
+133
View File
@@ -0,0 +1,133 @@
#include "ImXui/TextureManager.h"
#include <d3d11.h>
#include <wincodec.h>
#include <vector>
#include <cstdio>
#pragma comment(lib, "windowscodecs.lib")
namespace ImXui {
bool TextureManager::init(ID3D11Device* device) {
m_device = device;
return true;
}
void TextureManager::shutdown() {
for (std::unordered_map<std::string, ID3D11ShaderResourceView*>::iterator it = m_cache.begin(); it != m_cache.end(); ++it) {
if (it->second) it->second->Release();
}
m_cache.clear();
m_widths.clear();
m_heights.clear();
m_device = nullptr;
}
ID3D11ShaderResourceView* TextureManager::load(const std::string& relativePath) {
if (!m_device) return nullptr;
auto it = m_cache.find(relativePath);
if (it != m_cache.end()) return it->second;
std::string fullPath;
if (!m_basePath.empty()) {
fullPath = m_basePath;
if (fullPath.back() != '/' && fullPath.back() != '\\')
fullPath += '/';
}
fullPath += relativePath;
IWICImagingFactory* factory = nullptr;
HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory));
if (FAILED(hr)) { std::fprintf(stderr, "WIC factory failed\n"); return nullptr; }
int wlen = MultiByteToWideChar(CP_UTF8, 0, fullPath.c_str(), -1, nullptr, 0);
wchar_t* wpath = (wchar_t*)_malloca(wlen * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, fullPath.c_str(), -1, wpath, wlen);
IWICBitmapDecoder* decoder = nullptr;
hr = factory->CreateDecoderFromFilename(wpath, nullptr, GENERIC_READ,
WICDecodeMetadataCacheOnDemand, &decoder);
_freea(wpath);
if (FAILED(hr)) {
std::fprintf(stderr, "WIC decoder failed for: %s (0x%08x)\n", fullPath.c_str(), (unsigned)hr);
factory->Release();
return nullptr;
}
IWICBitmapFrameDecode* frame = nullptr;
hr = decoder->GetFrame(0, &frame);
if (FAILED(hr)) { decoder->Release(); factory->Release(); return nullptr; }
UINT texW = 0, texH = 0;
frame->GetSize(&texW, &texH);
IWICFormatConverter* converter = nullptr;
hr = factory->CreateFormatConverter(&converter);
if (SUCCEEDED(hr)) {
hr = converter->Initialize(frame, GUID_WICPixelFormat32bppBGRA,
WICBitmapDitherTypeNone, nullptr, 0,
WICBitmapPaletteTypeMedianCut);
}
frame->Release();
decoder->Release();
factory->Release();
if (FAILED(hr) || !converter) {
if (converter) converter->Release();
return nullptr;
}
std::vector<uint8_t> pixels(texW * texH * 4);
hr = converter->CopyPixels(nullptr, texW * 4, (UINT)pixels.size(), pixels.data());
converter->Release();
if (FAILED(hr)) return nullptr;
D3D11_TEXTURE2D_DESC td = {};
td.Width = texW;
td.Height = texH;
td.MipLevels = 1;
td.ArraySize = 1;
td.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
td.SampleDesc.Count = 1;
td.Usage = D3D11_USAGE_IMMUTABLE;
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
D3D11_SUBRESOURCE_DATA sd = {};
sd.pSysMem = pixels.data();
sd.SysMemPitch = texW * 4;
ID3D11Texture2D* tex = nullptr;
hr = m_device->CreateTexture2D(&td, &sd, &tex);
if (FAILED(hr)) { return nullptr; }
D3D11_SHADER_RESOURCE_VIEW_DESC svd = {};
svd.Format = td.Format;
svd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
svd.Texture2D.MipLevels = 1;
ID3D11ShaderResourceView* srv = nullptr;
hr = m_device->CreateShaderResourceView(tex, &svd, &srv);
tex->Release();
if (FAILED(hr)) { return nullptr; }
m_cache[relativePath] = srv;
m_widths[relativePath] = (int)texW;
m_heights[relativePath] = (int)texH;
std::fprintf(stderr, "Loaded texture: %s (%dx%d)\n", fullPath.c_str(), texW, texH);
return srv;
}
bool TextureManager::getSize(const std::string& relativePath, int& w, int& h) const {
auto itW = m_widths.find(relativePath);
auto itH = m_heights.find(relativePath);
if (itW == m_widths.end() || itH == m_heights.end()) return false;
w = itW->second;
h = itH->second;
return true;
}
}
+326
View File
@@ -0,0 +1,326 @@
#include "ImXui/X360Backend.h"
#include "xui.h"
#include <cmath>
#include <cstring>
namespace ImXui {
X360RenderSink::X360RenderSink()
: m_device(NULL)
, m_delegate(NULL)
, m_fontRenderer(NULL)
, m_font(NULL)
, m_hDC(NULL)
, m_blendMode(0)
, m_width(1280.0f)
, m_height(720.0f)
, m_clipDepth(0)
{
m_typeface = L"Mojangles";
}
void X360RenderSink::setDevice(void* d3dDevice) { m_device = d3dDevice; }
void X360RenderSink::setDelegateSink(IRenderCommandSink* sink) { m_delegate = sink; }
void X360RenderSink::setFontRenderer(IXuiFontRenderer* renderer) {
m_fontRenderer = renderer;
if (renderer && !m_font) {
TypefaceDescriptor desc;
ZeroMemory(&desc, sizeof(desc));
desc.szTypeface = m_typeface.c_str();
renderer->CreateFont(&desc, 14.0f, XUI_FONT_STYLE_NORMAL, 0, &m_font);
}
}
void X360RenderSink::setFontTypeface(const wchar_t* typeface) {
m_typeface = typeface ? typeface : L"Mojangles";
}
namespace {
struct X360DCState {
float opacity;
DWORD shadowColor;
};
struct X360DC {
std::vector<X360DCState> stack;
X360DCState current;
X360DC() : current() { current.opacity = 1.0f; current.shadowColor = 0xFF000000; }
};
}
void X360RenderSink::beginFrame(float width, float height) {
if (!m_hDC) m_hDC = XuiRenderCreateDeviceContext();
(void)width; (void)height;
}
void X360RenderSink::endFrame() {}
void X360RenderSink::beginScene(float width, float height) {
m_width = width;
m_height = height;
m_clipDepth = 0;
m_transform = Transform2D();
m_clip = Rect(0.0f, 0.0f, width, height);
#if defined(IMXUI_X360)
IDirect3DDevice9* dev = (IDirect3DDevice9*)m_device;
if (dev) {
D3DXMATRIX proj, identity;
D3DXMatrixOrthoOffCenterRH(&proj, 0.0f, width, height, 0.0f, 0.0f, 1.0f);
D3DXMatrixIdentity(&identity);
dev->SetTransform(D3DTS_WORLD, &identity);
dev->SetTransform(D3DTS_VIEW, &identity);
dev->SetTransform(D3DTS_PROJECTION, &proj);
dev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
}
#endif
beginFrame(width, height);
if (m_delegate) m_delegate->beginScene(width, height);
}
bool X360RenderSink::drawQuadD3D(const Rect& rect, uint32_t abgr) {
#if defined(IMXUI_X360)
IDirect3DDevice9* dev = (IDirect3DDevice9*)m_device;
if (!dev) return false;
struct V { float x, y, z, w; DWORD c; } verts[4] = {
{ rect.x, rect.y, 0.0f, 1.0f, abgr },
{ rect.x + rect.w, rect.y, 0.0f, 1.0f, abgr },
{ rect.x, rect.y + rect.h, 0.0f, 1.0f, abgr },
{ rect.x + rect.w, rect.y + rect.h, 0.0f, 1.0f, abgr },
};
return SUCCEEDED(dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(V)))
? true : false;
#else
(void)rect; (void)abgr;
return false;
#endif
}
static uint32_t ColorToABGR(const Color& c, float opacity) {
uint8_t r = (uint8_t)(c.r * 255.0f);
uint8_t g = (uint8_t)(c.g * 255.0f);
uint8_t b = (uint8_t)(c.b * 255.0f);
uint8_t a = (uint8_t)(c.a * opacity * 255.0f);
return ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | (uint32_t)r;
}
static void ApplyTransform(const Transform2D& t, const Rect& in, Rect& out) {
float xs[4] = { in.x, in.x + in.w, in.x, in.x + in.w };
float ys[4] = { in.y, in.y, in.y + in.h, in.y + in.h };
float minX = 1e30f, minY = 1e30f, maxX = -1e30f, maxY = -1e30f;
for (int i = 0; i < 4; ++i) {
float x = t.m00 * xs[i] + t.m01 * ys[i] + t.tx;
float y = t.m10 * xs[i] + t.m11 * ys[i] + t.ty;
if (x < minX) minX = x;
if (y < minY) minY = y;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
}
out = Rect(minX, minY, maxX - minX, maxY - minY);
}
void X360RenderSink::drawColoredQuad(const Rect& rectIn, const Color& color, float opacity) {
Rect rect;
ApplyTransform(m_transform, rectIn, rect);
if (!drawQuadD3D(rect, ColorToABGR(color, opacity)) && m_delegate)
m_delegate->drawColoredQuad(rectIn, color, opacity);
}
void X360RenderSink::drawTexturedQuad(const Rect& rect, const std::wstring& resource,
const Color& color, float opacity) {
Rect transformed;
ApplyTransform(m_transform, rect, transformed);
bool drawn = false;
#if defined(IMXUI_X360)
IDirect3DDevice9* dev = (IDirect3DDevice9*)m_device;
if (dev && drawQuadD3D(transformed, ColorToABGR(color, opacity))) drawn = true;
#endif
if (!drawn && m_delegate)
m_delegate->drawTexturedQuad(rect, resource, color, opacity);
}
void X360RenderSink::flushText(const Rect& rect, const std::wstring& text,
const Color& color, float fontSize, bool centered) {
if (text.empty()) return;
if (m_fontRenderer && m_font) {
XUIFontMetrics metrics;
if (FAILED(m_fontRenderer->GetFontMetrics(m_font, &metrics))) return;
float scale = fontSize / (metrics.fLineHeight > 0.0f ? metrics.fLineHeight : fontSize);
INT widthPx = 0;
for (size_t i = 0; i < text.size(); ++i) {
XUICharMetrics cm;
widthPx += SUCCEEDED(m_fontRenderer->GetCharMetrics(m_font, text[i], &cm))
? (INT)cm.nAdvance : (INT)fontSize * 0;
}
float startX = centered ? rect.x + (rect.w - widthPx * scale) * 0.5f
: rect.x;
float baselineY = rect.y + (metrics.fMaxAscent * scale);
std::vector<CharData> chars(text.size());
for (size_t i = 0; i < text.size(); ++i) {
CharData& cd = chars[i];
cd.wch = text[i];
cd.x = startX + i * fontSize * 0.5f;
cd.y = baselineY;
cd.dwColor = ColorToABGR(color, 1.0f);
cd.dwStyle = XUI_FONT_STYLE_SINGLE_LINE;
cd.fScale = scale;
}
RECT clipRect;
clipRect.left = (LONG)m_clip.x;
clipRect.top = (LONG)m_clip.y;
clipRect.right = (LONG)(m_clip.x + m_clip.w);
clipRect.bottom = (LONG)(m_clip.y + m_clip.h);
D3DXMATRIX worldViewProj;
worldViewProj._11 = worldViewProj._22 = worldViewProj._44 = 1.0f;
m_fontRenderer->DrawCharsToDevice(m_font, &chars[0], (DWORD)chars.size(),
&clipRect, m_hDC, &worldViewProj);
return;
}
if (m_delegate)
m_delegate->drawText(rect, text, L"", fontSize, color, 1.0f, centered);
}
void X360RenderSink::drawText(const Rect& rect, const std::wstring& text,
const std::wstring& fontName, float fontSize,
const Color& color, float opacity, bool centered) {
(void)fontName; (void)opacity;
flushText(rect, text, color, fontSize > 0.0f ? fontSize : 14.0f, centered);
}
void X360RenderSink::pushTransform(const Transform2D& t) {
Transform2D composed;
composed.m00 = m_transform.m00 * t.m00 + m_transform.m01 * t.m10;
composed.m01 = m_transform.m00 * t.m01 + m_transform.m01 * t.m11;
composed.m10 = m_transform.m10 * t.m00 + m_transform.m11 * t.m10;
composed.m11 = m_transform.m10 * t.m01 + m_transform.m11 * t.m11;
composed.tx = m_transform.m00 * t.tx + m_transform.m01 * t.ty + m_transform.tx;
composed.ty = m_transform.m10 * t.tx + m_transform.m11 * t.ty + m_transform.ty;
m_transform = composed;
}
void X360RenderSink::popTransform() {
m_transform = Transform2D();
}
void X360RenderSink::pushClip(const Rect& r) {
float nx1 = m_clip.x > r.x ? m_clip.x : r.x;
float ny1 = m_clip.y > r.y ? m_clip.y : r.y;
float nx2 = (m_clip.x + m_clip.w) < (r.x + r.w) ? (m_clip.x + m_clip.w) : (r.x + r.w);
float ny2 = (m_clip.y + m_clip.h) < (r.y + r.h) ? (m_clip.y + m_clip.h) : (r.y + r.h);
m_clip = Rect(nx1, ny1, nx2 - nx1 > 0.0f ? nx2 - nx1 : 0.0f,
ny2 - ny1 > 0.0f ? ny2 - ny1 : 0.0f);
++m_clipDepth;
if (m_delegate) m_delegate->pushClip(r);
}
void X360RenderSink::popClip() {
if (m_clipDepth > 0) --m_clipDepth;
if (m_delegate) m_delegate->popClip();
}
void X360RenderSink::drawNineGrid(const Rect& rect, const std::wstring& resource,
const Color& color, float opacity,
uint32_t l, uint32_t t, uint32_t r, uint32_t b,
bool noCenter) {
#if defined(IMXUI_X360)
Rect cell[9];
float x0 = rect.x, x1 = rect.x + l, x2 = rect.x + rect.w - r, x3 = rect.x + rect.w;
float y0 = rect.y, y1 = rect.y + t, y2 = rect.y + rect.h - b, y3 = rect.y + rect.h;
const float xs[4] = { x0, x1, x2, x3 };
const float ys[4] = { y0, y1, y2, y3 };
int idx = 0;
for (int cy = 0; cy < 3; ++cy) {
for (int cx = 0; cx < 3; ++cx) {
if (noCenter && cx == 1 && cy == 1) continue;
Rect q(xs[cx], ys[cy], xs[cx + 1] - xs[cx], ys[cy + 1] - ys[cy]);
drawTexturedQuad(q, resource, color, opacity);
++idx;
}
}
(void)cell;
#endif
if (m_delegate)
m_delegate->drawNineGrid(rect, resource, color, opacity, l, t, r, b, noCenter);
}
void X360RenderSink::drawFigure(const Rect& rect, const std::vector<Vec2>& points,
bool closed, const Color& fillColor,
const Color& strokeColor, float opacity,
float strokeWidth, uint32_t blendMode) {
bool drawn = false;
#if defined(IMXUI_X360)
IDirect3DDevice9* dev = (IDirect3DDevice9*)m_device;
if (dev && points.size() >= 3) {
struct FV { float x, y, z, rhw; DWORD c; };
std::vector<FV> verts(points.size());
for (size_t i = 0; i < points.size(); ++i) {
verts[i].x = points[i].x;
verts[i].y = points[i].y;
verts[i].z = 0.0f;
verts[i].rhw = 1.0f;
verts[i].c = ColorToABGR(fillColor, opacity);
}
drawn = SUCCEEDED(dev->DrawPrimitiveUP(
closed ? D3DPT_TRIANGLEFAN : D3DPT_TRIANGLESTRIP,
(UINT)points.size() - 2, &verts[0], sizeof(FV)));
}
#else
(void)blendMode; (void)strokeWidth; (void)strokeColor;
#endif
if (!drawn && m_delegate)
m_delegate->drawFigure(rect, points, closed, fillColor, strokeColor,
opacity, strokeWidth, blendMode);
}
void X360RenderSink::setBlendMode(uint32_t mode) {
m_blendMode = mode;
#if defined(IMXUI_X360)
IDirect3DDevice9* dev = (IDirect3DDevice9*)m_device;
if (dev) {
switch (mode) {
case 1:
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
break;
case 2:
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
break;
default:
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
break;
}
}
#endif
if (m_delegate) m_delegate->setBlendMode(mode);
}
void X360RenderSink::drawCustom(const std::wstring& drawId, const Rect& rect,
float opacity) {
if (m_delegate) m_delegate->drawCustom(drawId, rect, opacity);
}
void X360RenderSink::endScene() {
if (m_delegate) m_delegate->endScene();
endFrame();
}
}
+566
View File
@@ -0,0 +1,566 @@
#include "ImXui/XurFormat.h"
#include <unordered_map>
#include <algorithm>
namespace ImXui {
namespace XurFormat {
static std::unordered_map<std::string, XuiClassInfo> s_classRegistry;
static bool s_initialized = false;
struct PropEntry { const char* name; XurPropertyType type; bool indexed; };
static void addProps(const std::string& className, const PropEntry* entries, int count) {
std::vector<XuiPropDef>& props = s_classRegistry[className].props;
for (int i = 0; i < count; i++) {
XuiPropDef pd;
pd.name = entries[i].name;
pd.type = entries[i].type;
pd.indexed = entries[i].indexed;
props.push_back(pd);
}
}
static void addClass(const std::string& name, const std::string& base) {
XuiClassInfo info;
info.name = name;
info.baseClass = base;
s_classRegistry[name] = info;
}
static void addMerged(const std::string& name, const std::string& base, const PropEntry* entries, int count) {
addClass(name, base);
addProps(name, entries, count);
}
static void buildRegistry() {
if (s_initialized) return;
static const PropEntry s_elementProps[] = {
{"Id", XurPropertyType_String, false},
{"Width", XurPropertyType_Float, false},
{"Height", XurPropertyType_Float, false},
{"Position", XurPropertyType_Vector, false},
{"Scale", XurPropertyType_Vector, false},
{"Rotation", XurPropertyType_Quaternion, false},
{"Opacity", XurPropertyType_Float, false},
{"Anchor", XurPropertyType_Unsigned, false},
{"Pivot", XurPropertyType_Vector, false},
{"Show", XurPropertyType_Bool, false},
{"BlendMode", XurPropertyType_Unsigned, false},
{"DisableTimelineRecursion", XurPropertyType_Bool, false},
{"DesignTime", XurPropertyType_Bool, false},
{"ColorWriteFlags", XurPropertyType_Unsigned, false},
{"ClipChildren", XurPropertyType_Bool, false},
{"EnableEffects", XurPropertyType_Bool, false},
{"DisableFocusRecursion", XurPropertyType_Bool, false},
{"GripTarget", XurPropertyType_Bool, false},
{"Hittable", XurPropertyType_Bool, false},
{"LayoutLineBreak", XurPropertyType_Bool, false},
{"LayoutFloat", XurPropertyType_Bool, false},
{"Column", XurPropertyType_Unsigned, false},
{"Row", XurPropertyType_Unsigned, false},
{"ColumnSpan", XurPropertyType_Unsigned, false},
{"RowSpan", XurPropertyType_Unsigned, false},
{"ColorFactor", XurPropertyType_Colour, false},
{"CenterPivot", XurPropertyType_Bool, false},
};
addMerged("XuiElement", "(null)", s_elementProps, sizeof(s_elementProps)/sizeof(s_elementProps[0]));
addClass("XuiCanvas", "XuiElement");
addClass("XuiGroup", "XuiElement");
addClass("XuiVisual", "XuiElement");
static const PropEntry s_figureProps[] = {
{"Stroke", XurPropertyType_Object, false},
{"Fill", XurPropertyType_Object, false},
{"Closed", XurPropertyType_Bool, false},
{"Points", XurPropertyType_Custom, false},
};
addMerged("XuiFigure", "XuiElement", s_figureProps, sizeof(s_figureProps)/sizeof(s_figureProps[0]));
static const PropEntry s_figureFillProps[] = {
{"FillType", XurPropertyType_Unsigned, false},
{"FillColor", XurPropertyType_Colour, false},
{"TextureFileName", XurPropertyType_String, false},
{"Gradient", XurPropertyType_Object, false},
{"Translation", XurPropertyType_Vector, false},
{"Scale", XurPropertyType_Vector, false},
{"Rotation", XurPropertyType_Float, false},
{"WrapX", XurPropertyType_Unsigned, false},
{"WrapY", XurPropertyType_Unsigned, false},
{"BrushFlags", XurPropertyType_Unsigned, false},
{"TransformVersion", XurPropertyType_Unsigned, false},
};
addMerged("XuiFigureFill", "(null)", s_figureFillProps, sizeof(s_figureFillProps)/sizeof(s_figureFillProps[0]));
static const PropEntry s_figureFillGradProps[] = {
{"Radial", XurPropertyType_Bool, false},
{"NumStops", XurPropertyType_Integer, false},
{"StopColor", XurPropertyType_Colour, true},
{"StopPos", XurPropertyType_Float, true},
};
addMerged("XuiFigureFillGradient", "(null)", s_figureFillGradProps, sizeof(s_figureFillGradProps)/sizeof(s_figureFillGradProps[0]));
static const PropEntry s_figureStrokeProps[] = {
{"StrokeWidth", XurPropertyType_Float, false},
{"StrokeColor", XurPropertyType_Colour, false},
};
addMerged("XuiFigureStroke", "(null)", s_figureStrokeProps, sizeof(s_figureStrokeProps)/sizeof(s_figureStrokeProps[0]));
static const PropEntry s_controlProps[] = {
{"ClassOverride", XurPropertyType_String, false},
{"Visual", XurPropertyType_String, false},
{"Enabled", XurPropertyType_Bool, false},
{"UnfocusedInput", XurPropertyType_Bool, false},
{"NavLeft", XurPropertyType_String, false},
{"NavRight", XurPropertyType_String, false},
{"NavUp", XurPropertyType_String, false},
{"NavDown", XurPropertyType_String, false},
{"NavTabForward", XurPropertyType_String, false},
{"NavTabBackward", XurPropertyType_String, false},
{"Text", XurPropertyType_String, false},
{"PointSize", XurPropertyType_Float, false},
{"ImagePath", XurPropertyType_String, false},
};
addMerged("XuiControl", "XuiElement", s_controlProps, sizeof(s_controlProps)/sizeof(s_controlProps[0]));
static const PropEntry s_sceneProps[] = {
{"DefaultFocus", XurPropertyType_String, false},
{"TransFrom", XurPropertyType_String, false},
{"TransTo", XurPropertyType_String, false},
{"TransBackFrom", XurPropertyType_String, false},
{"TransBackTo", XurPropertyType_String, false},
{"InterruptTransitions", XurPropertyType_Unsigned, false},
{"IgnorePresses", XurPropertyType_Bool, false},
{"RecurseTransitions", XurPropertyType_Bool, false},
};
addMerged("XuiScene", "XuiControl", s_sceneProps, sizeof(s_sceneProps)/sizeof(s_sceneProps[0]));
static const PropEntry s_tabSceneProps[] = {
{"TabCount", XurPropertyType_Unsigned, false},
{"Wrap", XurPropertyType_Bool, false},
{"UserInterrupt", XurPropertyType_Bool, false},
{"VerticalTabs", XurPropertyType_Bool, false},
{"NoAutoHide", XurPropertyType_Bool, false},
{"DefaultTab", XurPropertyType_Unsigned, false},
};
addMerged("XuiTabScene", "XuiScene", s_tabSceneProps, sizeof(s_tabSceneProps)/sizeof(s_tabSceneProps[0]));
static const PropEntry s_labelProps[] = {
{"MaxFlowLines", XurPropertyType_Unsigned, false},
};
addMerged("XuiLabel", "XuiControl", s_labelProps, sizeof(s_labelProps)/sizeof(s_labelProps[0]));
static const PropEntry s_editProps[] = {
{"TextLimit", XurPropertyType_Integer, false},
{"AllowedChars", XurPropertyType_String, false},
{"PasswordChar", XurPropertyType_String, false},
{"ReadOnly", XurPropertyType_Bool, false},
{"Multiline", XurPropertyType_Bool, false},
{"SmoothScroll", XurPropertyType_Bool, false},
};
addMerged("XuiEdit", "XuiControl", s_editProps, sizeof(s_editProps)/sizeof(s_editProps[0]));
static const PropEntry s_buttonProps[] = {
{"PressKey", XurPropertyType_Unsigned, false},
{"PressAnimObject", XurPropertyType_String, false},
{"PressAnimStartFrame", XurPropertyType_String, false},
{"PressAnimEndFrame", XurPropertyType_String, false},
{"FocusAnimObject", XurPropertyType_String, false},
{"FocusAnimStartFrame", XurPropertyType_String, false},
{"FocusAnimEndFrame", XurPropertyType_String, false},
};
addMerged("XuiButton", "XuiControl", s_buttonProps, sizeof(s_buttonProps)/sizeof(s_buttonProps[0]));
static const PropEntry s_msgBoxBtnProps[] = {
{"MessageBoxCenter", XurPropertyType_Bool, false},
{"MessageBoxVisual", XurPropertyType_String, false},
{"MessageBoxTitle", XurPropertyType_String, false},
{"MessageBoxText", XurPropertyType_String, false},
{"MessageBoxButtons", XurPropertyType_String, false},
};
addMerged("XuiMessageBoxButton", "XuiButton", s_msgBoxBtnProps, sizeof(s_msgBoxBtnProps)/sizeof(s_msgBoxBtnProps[0]));
static const PropEntry s_navBtnProps[] = {
{"PressPath", XurPropertyType_String, false},
{"StayVisible", XurPropertyType_Bool, false},
{"SrcTransIndex", XurPropertyType_Unsigned, false},
{"DestTransIndex", XurPropertyType_Unsigned, false},
};
addMerged("XuiNavButton", "XuiButton", s_navBtnProps, sizeof(s_navBtnProps)/sizeof(s_navBtnProps[0]));
addClass("XuiBackButton", "XuiButton");
static const PropEntry s_checkboxProps[] = {
{"PressKey", XurPropertyType_Unsigned, false},
};
addMerged("XuiCheckbox", "XuiControl", s_checkboxProps, sizeof(s_checkboxProps)/sizeof(s_checkboxProps[0]));
static const PropEntry s_radioBtnProps[] = {
{"PressKey", XurPropertyType_Unsigned, false},
};
addMerged("XuiRadioButton", "XuiControl", s_radioBtnProps, sizeof(s_radioBtnProps)/sizeof(s_radioBtnProps[0]));
static const PropEntry s_progressProps[] = {
{"RangeMin", XurPropertyType_Integer, false},
{"RangeMax", XurPropertyType_Integer, false},
{"Value", XurPropertyType_Integer, false},
};
addMerged("XuiProgressBar", "XuiControl", s_progressProps, sizeof(s_progressProps)/sizeof(s_progressProps[0]));
static const PropEntry s_sliderProps[] = {
{"RangeMin", XurPropertyType_Integer, false},
{"RangeMax", XurPropertyType_Integer, false},
{"Value", XurPropertyType_Integer, false},
{"Step", XurPropertyType_Integer, false},
{"Vertical", XurPropertyType_Bool, false},
{"AccelInc", XurPropertyType_Integer, false},
{"AccelTime", XurPropertyType_Unsigned, false},
};
addMerged("XuiSlider", "XuiControl", s_sliderProps, sizeof(s_sliderProps)/sizeof(s_sliderProps[0]));
static const PropEntry s_listProps[] = {
{"Wrap", XurPropertyType_Bool, false},
};
addMerged("XuiList", "XuiControl", s_listProps, sizeof(s_listProps)/sizeof(s_listProps[0]));
static const PropEntry s_commonListProps[] = {
{"ItemsText", XurPropertyType_String, false},
{"ItemsImage", XurPropertyType_String, false},
{"ItemsNavPath", XurPropertyType_String, false},
};
addMerged("XuiCommonList", "XuiList", s_commonListProps, sizeof(s_commonListProps)/sizeof(s_commonListProps[0]));
static const PropEntry s_comboProps[] = {
{"ComboBoxStyle", XurPropertyType_Unsigned, false},
{"MaxVisibleVertItems", XurPropertyType_Integer, false},
};
addMerged("XuiComboBox", "XuiControl", s_comboProps, sizeof(s_comboProps)/sizeof(s_comboProps[0]));
static const PropEntry s_imageProps[] = {
{"SizeMode", XurPropertyType_Unsigned, false},
{"ImagePath", XurPropertyType_String, false},
{"BrushFlags", XurPropertyType_Unsigned, false},
{"TextureSurfaceElement", XurPropertyType_String, false},
{"LoadType", XurPropertyType_Unsigned, false},
};
addMerged("XuiImage", "XuiElement", s_imageProps, sizeof(s_imageProps)/sizeof(s_imageProps[0]));
static const PropEntry s_imgPresenterProps[] = {
{"SizeMode", XurPropertyType_Unsigned, false},
{"DataAssociation", XurPropertyType_Unsigned, false},
{"BrushFlags", XurPropertyType_Unsigned, false},
{"LoadType", XurPropertyType_Unsigned, false},
};
addMerged("XuiImagePresenter", "XuiElement", s_imgPresenterProps, sizeof(s_imgPresenterProps)/sizeof(s_imgPresenterProps[0]));
static const PropEntry s_textProps[] = {
{"Text", XurPropertyType_String, false},
{"TextColor", XurPropertyType_Colour, false},
{"DropShadowColor", XurPropertyType_Colour, false},
{"PointSize", XurPropertyType_Float, false},
{"Font", XurPropertyType_String, false},
{"TextStyle", XurPropertyType_Unsigned, false},
{"LineSpacingAdjust", XurPropertyType_Integer, false},
{"TextScale", XurPropertyType_Float, false},
};
addMerged("XuiText", "XuiElement", s_textProps, sizeof(s_textProps)/sizeof(s_textProps[0]));
static const PropEntry s_textPresenterProps[] = {
{"TextColor", XurPropertyType_Colour, false},
{"DropShadowColor", XurPropertyType_Colour, false},
{"PointSize", XurPropertyType_Float, false},
{"Font", XurPropertyType_String, false},
{"TextStyle", XurPropertyType_Unsigned, false},
{"LineSpacingAdjust", XurPropertyType_Integer, false},
{"DataAssociation", XurPropertyType_Unsigned, false},
{"TextScale", XurPropertyType_Float, false},
};
addMerged("XuiTextPresenter", "XuiElement", s_textPresenterProps, sizeof(s_textPresenterProps)/sizeof(s_textPresenterProps[0]));
static const PropEntry s_nineGridProps[] = {
{"TextureFileName", XurPropertyType_String, false},
{"LeftOffset", XurPropertyType_Unsigned, false},
{"TopOffset", XurPropertyType_Unsigned, false},
{"RightOffset", XurPropertyType_Unsigned, false},
{"BottomOffset", XurPropertyType_Unsigned, false},
{"NoCenter", XurPropertyType_Bool, false},
};
addMerged("XuiNineGrid", "XuiElement", s_nineGridProps, sizeof(s_nineGridProps)/sizeof(s_nineGridProps[0]));
addClass("XuiRadioGroup", "XuiControl");
static const PropEntry s_scrollEndProps[] = {
{"Direction", XurPropertyType_Unsigned, false},
};
addMerged("XuiScrollEnd", "XuiControl", s_scrollEndProps, sizeof(s_scrollEndProps)/sizeof(s_scrollEndProps[0]));
static const PropEntry s_scrollBarProps[] = {
{"Direction", XurPropertyType_Unsigned, false},
{"MinThumbSize", XurPropertyType_Unsigned, false},
};
addMerged("XuiScrollBar", "XuiControl", s_scrollBarProps, sizeof(s_scrollBarProps)/sizeof(s_scrollBarProps[0]));
static const PropEntry s_videoProps[] = {
{"File", XurPropertyType_String, false},
{"SizeMode", XurPropertyType_Unsigned, false},
{"Pause", XurPropertyType_Bool, false},
{"Loop", XurPropertyType_Bool, false},
{"Volume", XurPropertyType_Float, false},
};
addMerged("XuiVideo", "XuiElement", s_videoProps, sizeof(s_videoProps)/sizeof(s_videoProps[0]));
static const PropEntry s_soundProps[] = {
{"State", XurPropertyType_Unsigned, false},
{"Loop", XurPropertyType_Bool, false},
{"Finish", XurPropertyType_Bool, false},
{"Volume", XurPropertyType_Float, false},
};
addMerged("XuiSound", "XuiElement", s_soundProps, sizeof(s_soundProps)/sizeof(s_soundProps[0]));
static const PropEntry s_soundXaudioProps[] = {
{"File", XurPropertyType_String, false},
};
addMerged("XuiSoundXAudio", "XuiSound", s_soundXaudioProps, sizeof(s_soundXaudioProps)/sizeof(s_soundXaudioProps[0]));
static const PropEntry s_soundXactProps[] = {
{"Cue", XurPropertyType_String, false},
{"SoundBank", XurPropertyType_String, false},
{"WaveBank", XurPropertyType_String, false},
};
addMerged("XuiSoundXACT", "XuiSound", s_soundXactProps, sizeof(s_soundXactProps)/sizeof(s_soundXactProps[0]));
static const PropEntry s_listItemProps[] = {
{"Layout", XurPropertyType_Unsigned, false},
{"Checkable", XurPropertyType_Bool, false},
{"SelectedSize", XurPropertyType_Vector, false},
{"KeepSizeUnfocused", XurPropertyType_Bool, false},
{"InterItemSpacing", XurPropertyType_Vector, false},
{"SmoothScroll", XurPropertyType_Bool, false},
{"SmoothScrollBaseSpeed", XurPropertyType_Float, false},
{"SmoothScrollMaxSpeed", XurPropertyType_Float, false},
{"SmoothScrollAcceleration", XurPropertyType_Float, false},
};
addMerged("XuiListItem", "XuiCheckbox", s_listItemProps, sizeof(s_listItemProps)/sizeof(s_listItemProps[0]));
addClass("XuiCaret", "XuiControl");
static const PropEntry s_htmlProps[] = {
{"Text", XurPropertyType_String, false},
{"TeletypeCount", XurPropertyType_Integer, false},
};
addMerged("XuiHtmlElement", "XuiElement", s_htmlProps, sizeof(s_htmlProps)/sizeof(s_htmlProps[0]));
static const PropEntry s_htmlPresenterProps[] = {
{"DataAssociation", XurPropertyType_Integer, false},
};
addMerged("XuiHtmlPresenter", "XuiElement", s_htmlPresenterProps, sizeof(s_htmlPresenterProps)/sizeof(s_htmlPresenterProps[0]));
static const PropEntry s_htmlControlProps[] = {
{"TeletypeCount", XurPropertyType_Integer, false},
};
addMerged("XuiHtmlControl", "XuiControl", s_htmlControlProps, sizeof(s_htmlControlProps)/sizeof(s_htmlControlProps[0]));
static const PropEntry s_avatarProps[] = {
{"UseActiveUserAvatar", XurPropertyType_Bool, false},
{"EnableUserControl", XurPropertyType_Bool, false},
{"QueueAnimation", XurPropertyType_Unsigned, false},
{"PlayAnimation", XurPropertyType_Unsigned, false},
{"UseCustomView", XurPropertyType_Bool, false},
{"RenderView", XurPropertyType_Unsigned, false},
{"CustomViewEyePosition", XurPropertyType_Vector, false},
{"CustomViewFocusPosition", XurPropertyType_Vector, false},
{"CustomViewUpDirection", XurPropertyType_Vector, false},
{"ShowSelfShadow", XurPropertyType_Bool, false},
{"ShowShadow", XurPropertyType_Bool, false},
{"ShowCarryable", XurPropertyType_Bool, false},
{"ShowHat", XurPropertyType_Bool, false},
};
addMerged("XuiAvatar", "XuiControl", s_avatarProps, sizeof(s_avatarProps)/sizeof(s_avatarProps[0]));
static const PropEntry s_gamerCardProps[] = {
{"Format", XurPropertyType_String, false},
{"ShowExtendedPanel", XurPropertyType_Bool, false},
};
addMerged("XuiGamerCard", "XuiControl", s_gamerCardProps, sizeof(s_gamerCardProps)/sizeof(s_gamerCardProps[0]));
static const PropEntry s_shaderProps[] = {
{"ShaderId", XurPropertyType_String, false},
{"ShaderFile", XurPropertyType_String, false},
{"TextureFileName", XurPropertyType_String, false},
{"TextureSurfaceElement", XurPropertyType_String, false},
{"WrapX", XurPropertyType_Unsigned, false},
{"WrapY", XurPropertyType_Unsigned, false},
{"BrushFlags", XurPropertyType_Unsigned, false},
{"CompositeEdge", XurPropertyType_Float, false},
{"ForceComposite", XurPropertyType_Bool, false},
{"EffectParams1", XurPropertyType_Vector, false},
{"EffectParams2", XurPropertyType_Vector, false},
{"EffectParams3", XurPropertyType_Vector, false},
{"EffectParams4", XurPropertyType_Vector, false},
{"EffectParams5", XurPropertyType_Vector, false},
};
addMerged("XuiShader", "XuiElement", s_shaderProps, sizeof(s_shaderProps)/sizeof(s_shaderProps[0]));
static const PropEntry s_texSurfaceProps[] = {
{"Offscreen", XurPropertyType_Bool, false},
{"DepthStencil", XurPropertyType_Bool, false},
{"PreRender", XurPropertyType_Bool, false},
{"Buffered", XurPropertyType_Bool, false},
};
addMerged("XuiTextureSurface", "XuiGroup", s_texSurfaceProps, sizeof(s_texSurfaceProps)/sizeof(s_texSurfaceProps[0]));
static const PropEntry s_variableProps[] = {
{"Id", XurPropertyType_String, false},
{"VectorVariable", XurPropertyType_Vector, false},
{"FloatVariable", XurPropertyType_Float, false},
{"IntegerVariable", XurPropertyType_Integer, false},
};
addMerged("XuiVariable", "XuiElement", s_variableProps, sizeof(s_variableProps)/sizeof(s_variableProps[0]));
static const PropEntry s_gridPanelProps[] = {
{"Columns", XurPropertyType_String, false},
{"Rows", XurPropertyType_String, false},
{"CellSpacing", XurPropertyType_Float, false},
{"Param0", XurPropertyType_Float, false},
{"Param1", XurPropertyType_Float, false},
{"Param2", XurPropertyType_Float, false},
{"Param3", XurPropertyType_Float, false},
};
addMerged("XuiGridPanel", "XuiElement", s_gridPanelProps, sizeof(s_gridPanelProps)/sizeof(s_gridPanelProps[0]));
addClass("LegacyControl", "XuiControl");
static const PropEntry s_scriptSceneProps[] = {
{"Script", XurPropertyType_String, false},
};
addMerged("ScriptScene", "XuiScene", s_scriptSceneProps, sizeof(s_scriptSceneProps)/sizeof(s_scriptSceneProps[0]));
static const PropEntry s_dashSceneProps[] = {
{"NavigationBreadcrumbs", XurPropertyType_String, false},
{"DescriptionTexts", XurPropertyType_String, false},
{"MetapaneSceneOverrides", XurPropertyType_String, false},
};
addMerged("DashScene", "XuiScene", s_dashSceneProps, sizeof(s_dashSceneProps)/sizeof(s_dashSceneProps[0]));
static const PropEntry s_hudSceneProps[] = {
{"OpenType", XurPropertyType_Unsigned, false},
{"LegendA", XurPropertyType_String, false},
{"LegendB", XurPropertyType_String, false},
{"LegendX", XurPropertyType_String, false},
{"LegendY", XurPropertyType_String, false},
{"ShowGamerInfo", XurPropertyType_Bool, false},
};
addMerged("HUDScene", "XuiScene", s_hudSceneProps, sizeof(s_hudSceneProps)/sizeof(s_hudSceneProps[0]));
static const PropEntry s_perspSceneProps[] = {
{"ProjectionScale", XurPropertyType_Float, false},
{"ProjectionCenterU", XurPropertyType_Float, false},
{"ProjectionCenterV", XurPropertyType_Float, false},
};
addMerged("XuiPerspectiveScene", "XuiScene", s_perspSceneProps, sizeof(s_perspSceneProps)/sizeof(s_perspSceneProps[0]));
static const PropEntry s_mediaSceneProps[] = {
{"Image", XurPropertyType_String, false},
};
addMerged("MediaScene", "ScriptScene", s_mediaSceneProps, sizeof(s_mediaSceneProps)/sizeof(s_mediaSceneProps[0]));
addClass("MobyRootScene", "XuiPerspectiveScene");
addClass("RomeRootScene", "XuiPerspectiveScene");
addClass("MPSlotScene", "ScriptScene");
addClass("DashData", "ScriptData");
addClass("VideoData", "DashData");
addClass("LiveData", "DashData");
addClass("MediaData", "DashData");
static const PropEntry s_scriptListProps[] = {
{"DataSet", XurPropertyType_String, false},
{"DataAssociation", XurPropertyType_String, false},
{"Embedded", XurPropertyType_String, false},
};
addMerged("ScriptList", "XuiList", s_scriptListProps, sizeof(s_scriptListProps)/sizeof(s_scriptListProps[0]));
static const PropEntry s_scriptDataProps[] = {
{"Query", XurPropertyType_String, false},
{"State", XurPropertyType_Integer, false},
{"ItemCount", XurPropertyType_Unsigned, false},
{"Selected", XurPropertyType_Integer, false},
};
addMerged("ScriptData", "XuiElement", s_scriptDataProps, sizeof(s_scriptDataProps)/sizeof(s_scriptDataProps[0]));
static const PropEntry s_scriptImageProps[] = {
{"DataSet", XurPropertyType_String, false},
{"DataAssociation", XurPropertyType_String, false},
{"Embedded", XurPropertyType_String, false},
{"Item", XurPropertyType_Integer, false},
};
addMerged("ScriptImage", "XuiControl", s_scriptImageProps, sizeof(s_scriptImageProps)/sizeof(s_scriptImageProps[0]));
static const PropEntry s_auraControlProps[] = {
{"ThemeImageIndex", XurPropertyType_Unsigned, false},
{"BackgroundImage", XurPropertyType_String, false},
{"SurfaceSphere", XurPropertyType_Bool, false},
};
addMerged("AuraControl", "XuiElement", s_auraControlProps, sizeof(s_auraControlProps)/sizeof(s_auraControlProps[0]));
static const PropEntry s_guideDashProps[] = {
{"DashCommand", XurPropertyType_Integer, false},
};
addMerged("GuideDashCommandNavButton", "XuiNavButton", s_guideDashProps, sizeof(s_guideDashProps)/sizeof(s_guideDashProps[0]));
static const PropEntry s_guideMainProps[] = {
{"MainScenePressPath", XurPropertyType_String, false},
};
addMerged("GuideMainSceneNavButton", "XuiNavButton", s_guideMainProps, sizeof(s_guideMainProps)/sizeof(s_guideMainProps[0]));
static const PropEntry s_scriptActionProps[] = {
{"Param", XurPropertyType_String, false},
{"Param2", XurPropertyType_String, false},
{"Param3", XurPropertyType_String, false},
{"Param4", XurPropertyType_String, false},
{"Param5", XurPropertyType_String, false},
{"Param6", XurPropertyType_String, false},
};
addMerged("ScriptActionNavButton", "XuiNavButton", s_scriptActionProps, sizeof(s_scriptActionProps)/sizeof(s_scriptActionProps[0]));
addClass("AccountManagementNavButton", "XuiNavButton");
addClass("VideoMarketplaceNavButton", "XuiNavButton");
static const PropEntry s_avatarEditorProps[] = {
{"EntryPoint", XurPropertyType_String, false},
};
addMerged("AvatarEditorNavButton", "XuiNavButton", s_avatarEditorProps, sizeof(s_avatarEditorProps)/sizeof(s_avatarEditorProps[0]));
addClass("MediaImageHttp", "XuiImage");
s_initialized = true;
}
const XuiClassInfo* XuiClassRegistry::findClass(const std::string& name) {
buildRegistry();
std::unordered_map<std::string, XuiClassInfo>::iterator it = s_classRegistry.find(name);
return it != s_classRegistry.end() ? &it->second : NULL;
}
std::vector<const XuiClassInfo*> XuiClassRegistry::getHierarchy(const std::string& className) {
buildRegistry();
std::vector<const XuiClassInfo*> result;
std::string current = className;
const int MAX_DEPTH = 20;
for (int i = 0; i < MAX_DEPTH; i++) {
std::unordered_map<std::string, XuiClassInfo>::iterator it = s_classRegistry.find(current);
if (it == s_classRegistry.end()) break;
result.push_back(&it->second);
if (it->second.baseClass == "(null)" || it->second.baseClass.empty()) break;
current = it->second.baseClass;
}
return result;
}
void XuiClassRegistry::initialize() {
buildRegistry();
}
}
}
+1567
View File
File diff suppressed because it is too large Load Diff
+227
View File
@@ -0,0 +1,227 @@
#include "ImXui/ImXui.h"
namespace ImXui {
Edit::Edit()
: Control()
, m_textLimit(0)
, m_passwordChar(0)
, m_readOnly(false)
, m_caretPos(0)
{
}
Edit::Edit(const std::wstring& id)
: Control(id)
, m_textLimit(0)
, m_passwordChar(0)
, m_readOnly(false)
, m_caretPos(0)
{
}
Edit::~Edit() {}
bool Edit::insertChar(wchar_t ch) {
if (m_readOnly) return false;
if (m_textLimit > 0 && (int)m_text.size() >= m_textLimit) return false;
if (!m_allowedChars.empty() && m_allowedChars.find(ch) == std::wstring::npos) return false;
m_text.insert(m_text.begin() + m_caretPos, ch);
++m_caretPos;
onValueChanged(Value(m_text));
return true;
}
bool Edit::backspace() {
if (m_readOnly || m_caretPos <= 0) return false;
m_text.erase(m_text.begin() + (m_caretPos - 1));
--m_caretPos;
onValueChanged(Value(m_text));
return true;
}
bool Edit::setCaretPosition(int pos) {
if (pos < 0) pos = 0;
if (pos > (int)m_text.size()) pos = (int)m_text.size();
m_caretPos = pos;
return true;
}
void Edit::moveCaret(int delta) {
setCaretPosition(m_caretPos + delta);
}
std::wstring Edit::getDisplayText() const {
if (m_passwordChar == 0) return m_text;
return std::wstring(m_text.size(), m_passwordChar);
}
ComboBox::ComboBox()
: Control()
, m_selected(-1)
, m_dropDown(false)
{
}
ComboBox::ComboBox(const std::wstring& id)
: Control(id)
, m_selected(-1)
, m_dropDown(false)
{
}
ComboBox::~ComboBox() {}
void ComboBox::addItem(const std::wstring& text, int userData) {
ComboItem item;
item.text = text;
item.userData = userData;
m_items.push_back(item);
if (m_selected < 0) m_selected = (int)m_items.size() - 1;
}
void ComboBox::removeAllItems() {
m_items.clear();
m_selected = -1;
m_dropDown = false;
}
bool ComboBox::selectByUserData(int userData) {
for (size_t i = 0; i < m_items.size(); i++) {
if (m_items[i].userData == userData) {
setSelectedIndex((int)i);
return true;
}
}
return false;
}
void ComboBox::setSelectedIndex(int index) {
if (index < 0 || index >= (int)m_items.size()) return;
if (index == m_selected) return;
m_selected = index;
onValueChanged(Value(index));
onSelectionChanged(index);
}
std::wstring ComboBox::getItemText(int index) const {
if (index < 0 || index >= (int)m_items.size()) return std::wstring();
return m_items[index].text;
}
int ComboBox::getItemUserData(int index) const {
if (index < 0 || index >= (int)m_items.size()) return 0;
return m_items[index].userData;
}
void ComboBox::press() {
toggleDropDown();
Control::press();
}
RichTextLabel::RichTextLabel() : Control() {}
RichTextLabel::RichTextLabel(const std::wstring& id) : Control(id) {}
RichTextLabel::~RichTextLabel() {}
static bool parseHexColor(const std::wstring& hex, Color& out) {
size_t start = (!hex.empty() && hex[0] == L'#') ? 1 : 0;
std::wstring digits = hex.substr(start);
if (digits.size() != 3 && digits.size() != 6 && digits.size() != 8) return false;
auto nibble = [](wchar_t c) -> int {
if (c >= L'0' && c <= L'9') return c - L'0';
if (c >= L'a' && c <= L'f') return 10 + (c - L'a');
if (c >= L'A' && c <= L'F') return 10 + (c - L'A');
return -1;
};
float r = 1.0f, g = 1.0f, b = 1.0f, a = 1.0f;
if (digits.size() == 3) {
r = (nibble(digits[0]) * 17) / 255.0f;
g = (nibble(digits[1]) * 17) / 255.0f;
b = (nibble(digits[2]) * 17) / 255.0f;
} else if (digits.size() == 6 || digits.size() == 8) {
auto byte = [&nibble](const std::wstring& s, size_t i) -> float {
return ((nibble(s[i]) << 4) | nibble(s[i + 1])) / 255.0f;
};
r = byte(digits, 0);
g = byte(digits, 2);
b = byte(digits, 4);
a = digits.size() == 8 ? byte(digits, 6) : 1.0f;
} else {
return false;
}
out = Color(r, g, b, a);
return true;
}
void RichTextLabel::setTextMarkup(const std::wstring& markup) {
m_segments.clear();
RichTextSegment current;
size_t i = 0;
std::wstring plain;
auto flush = [&]() {
if (!plain.empty()) {
current.text = plain;
m_segments.push_back(current);
plain.clear();
}
};
while (i < markup.size()) {
if (markup[i] == L'<') {
size_t close = markup.find(L'>', i);
if (close == std::wstring::npos) {
plain += markup[i++];
continue;
}
std::wstring tag = markup.substr(i + 1, close - i - 1);
if (tag == L"b") {
flush();
current.bold = true;
} else if (tag == L"/b") {
flush();
current.bold = false;
} else if (tag == L"i") {
flush();
current.italic = true;
} else if (tag == L"/i") {
flush();
current.italic = false;
} else if (tag.size() > 6 && tag.compare(0, 6, L"color=") == 0) {
flush();
std::wstring hex = tag.substr(7, tag.size() - 8);
Color c;
if (parseHexColor(hex, c)) {
current.color = c;
current.hasColor = true;
}
} else if (tag == L"/color") {
flush();
current.hasColor = false;
} else {
plain += L'<';
plain += tag;
plain += L'>';
}
i = close + 1;
} else {
plain += markup[i++];
}
}
flush();
setText(markup);
}
}
+242
View File
@@ -0,0 +1,242 @@
#include "ImXui/XuiXmlWriter.h"
#include "ImXui/ImXui.h"
#include <iomanip>
#include <climits>
namespace ImXui {
static void appendUtf8(std::string& output, unsigned long codePoint) {
if (codePoint > 0x10ffffu || (codePoint >= 0xd800u && codePoint <= 0xdfffu))
codePoint = 0xfffdu;
if (codePoint < 0x80u) {
output.push_back((char)codePoint);
} else if (codePoint < 0x800u) {
output.push_back((char)(0xc0u | (codePoint >> 6)));
output.push_back((char)(0x80u | (codePoint & 0x3fu)));
} else if (codePoint < 0x10000u) {
output.push_back((char)(0xe0u | (codePoint >> 12)));
output.push_back((char)(0x80u | ((codePoint >> 6) & 0x3fu)));
output.push_back((char)(0x80u | (codePoint & 0x3fu)));
} else {
output.push_back((char)(0xf0u | (codePoint >> 18)));
output.push_back((char)(0x80u | ((codePoint >> 12) & 0x3fu)));
output.push_back((char)(0x80u | ((codePoint >> 6) & 0x3fu)));
output.push_back((char)(0x80u | (codePoint & 0x3fu)));
}
}
static std::string escapeXml(const std::wstring& value, bool attribute) {
std::string output;
for (size_t i = 0; i < value.size(); ++i) {
unsigned long codePoint = (unsigned long)value[i];
#if WCHAR_MAX <= 0xffff
if (codePoint >= 0xd800u && codePoint <= 0xdbffu && i + 1 < value.size()) {
unsigned long low = (unsigned long)value[i + 1];
if (low >= 0xdc00u && low <= 0xdfffu) {
codePoint = 0x10000u + ((codePoint - 0xd800u) << 10) + (low - 0xdc00u);
++i;
} else {
codePoint = 0xfffdu;
}
} else if (codePoint >= 0xdc00u && codePoint <= 0xdfffu) {
codePoint = 0xfffdu;
}
#else
if (codePoint > 0x10ffffu || (codePoint >= 0xd800u && codePoint <= 0xdfffu))
codePoint = 0xfffdu;
#endif
switch (codePoint) {
case (unsigned long)'&': output += "&amp;"; break;
case (unsigned long)'<': output += "&lt;"; break;
case (unsigned long)'>': output += "&gt;"; break;
case (unsigned long)'\"': if (attribute) output += "&quot;"; else output.push_back('"'); break;
case 39u: if (attribute) output += "&apos;"; else output.push_back((char)39); break;
default:
appendUtf8(output, codePoint);
break;
}
}
return output;
}
void XuiXmlWriter::indentLine(std::ostringstream& out, int level) {
for (int i = 0; i < level; i++) out << " ";
}
void XuiXmlWriter::writeElement(std::ostringstream& out, const Element* el, int indent) {
std::wstring className = el->getClassName();
std::string tag(className.begin(), className.end());
if (tag.empty()) tag = "XuiElement";
indentLine(out, indent);
out << "<" << tag << ">\n";
int pi = indent + 1;
std::wstring id = el->getId();
if (!id.empty()) {
indentLine(out, pi);
out << "<Id>" << escapeXml(id, false) << "</Id>\n";
}
std::wstring cn = el->getClassName();
if (!cn.empty()) {
indentLine(out, pi);
out << "<ClassOverride>" << escapeXml(cn, false) << "</ClassOverride>\n";
}
auto writeFloat = [&](const char* name, float val) {
indentLine(out, pi);
out << "<" << name << ">" << val << "</" << name << ">\n";
};
auto writeBool = [&](const char* name, bool val) {
indentLine(out, pi);
out << "<" << name << ">" << (val ? "true" : "false") << "</" << name << ">\n";
};
auto writeUint = [&](const char* name, uint32_t val) {
indentLine(out, pi);
out << "<" << name << ">" << val << "</" << name << ">\n";
};
auto writeStr = [&](const char* name, const std::wstring& val) {
if (!val.empty()) {
indentLine(out, pi);
out << "<" << name << ">" << escapeXml(val, false) << "</" << name << ">\n";
}
};
auto writeVec = [&](const char* name, Vec3 v) {
indentLine(out, pi);
out << "<" << name << ">" << v.x << "," << v.y << "," << v.z << "</" << name << ">\n";
};
auto writeColour = [&](const char* name, Color c) {
indentLine(out, pi);
uint32_t hex = ((uint8_t)(c.a * 255) << 24) | ((uint8_t)(c.r * 255) << 16) |
((uint8_t)(c.g * 255) << 8) | (uint8_t)(c.b * 255);
out << "<" << name << ">0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(8) << hex << std::dec << "</" << name << ">\n";
};
writeFloat("Width", el->getBounds().x);
writeFloat("Height", el->getBounds().y);
writeVec("Position", el->getPosition());
writeVec("Scale", el->getScale());
writeVec("Pivot", el->getPivot());
writeVec("Rotation", el->getRotation());
writeFloat("Opacity", el->getOpacity());
writeBool("Show", el->isShown());
writeUint("Anchor", el->getAnchor());
writeUint("BlendMode", el->getBlendMode());
writeBool("ClipChildren", el->getClipChildren());
writeBool("Hittable", el->isHittable());
writeColour("ColorFactor", el->getColorFactor());
if (!el->getImagePath().empty()) writeStr("Source", el->getImagePath());
if (el->getIsNineGrid()) {
writeStr("TextureFileName", el->getNineGridTexture());
writeUint("LeftOffset", el->getNineGridLeft());
writeUint("TopOffset", el->getNineGridTop());
writeUint("RightOffset", el->getNineGridRight());
writeUint("BottomOffset", el->getNineGridBottom());
writeBool("NoCenter", el->getNineGridNoCenter());
}
const Control* ctrl = dynamic_cast<const Control*>(el);
if (ctrl) writeControlProps(out, ctrl, pi);
const Scene* scene = dynamic_cast<const Scene*>(el);
if (scene) writeSceneProps(out, scene, pi);
{ const std::vector<std::unique_ptr<Element>>& kc = el->getChildren(); for (size_t i = 0; i < kc.size(); ++i) writeElement(out, kc[i].get(), pi); }
indentLine(out, indent);
out << "</" << tag << ">\n";
}
void XuiXmlWriter::writeControlProps(std::ostringstream& out, const Control* ctrl, int indent) {
auto writeStr = [&](const char* name, const std::wstring& val) {
if (!val.empty()) {
indentLine(out, indent);
out << "<" << name << ">" << escapeXml(val, false) << "</" << name << ">\n";
}
};
auto writeFloat = [&](const char* name, float val) {
indentLine(out, indent);
out << "<" << name << ">" << val << "</" << name << ">\n";
};
auto writeBool = [&](const char* name, bool val) {
indentLine(out, indent);
out << "<" << name << ">" << (val ? "true" : "false") << "</" << name << ">\n";
};
auto writeInt = [&](const char* name, int val) {
indentLine(out, indent);
out << "<" << name << ">" << val << "</" << name << ">\n";
};
auto writeUint = [&](const char* name, uint32_t val) {
indentLine(out, indent);
out << "<" << name << ">" << val << "</" << name << ">\n";
};
writeStr("Text", ctrl->getText());
writeStr("Font", ctrl->getFontName());
writeFloat("PointSize", ctrl->getFontSize());
writeBool("Enabled", ctrl->isEnabled());
writeStr("Visual", ctrl->getVisual());
writeInt("Value", ctrl->getProgressValue());
writeInt("RangeMin", ctrl->getProgressMin());
writeInt("RangeMax", ctrl->getProgressMax());
writeStr("NavLeft", ctrl->getNavLeft());
writeStr("NavRight", ctrl->getNavRight());
writeStr("NavUp", ctrl->getNavUp());
writeStr("NavDown", ctrl->getNavDown());
writeStr("NavTabForward", ctrl->getNavTabForward());
writeStr("NavTabBackward", ctrl->getNavTabBackward());
writeUint("PressKey", ctrl->getPressKey());
writeStr("PressAnimObject", ctrl->getPressAnimObject());
writeStr("FocusAnimObject", ctrl->getFocusAnimObject());
writeUint("Step", (uint32_t)ctrl->getStep());
writeBool("Vertical", ctrl->isVertical());
}
void XuiXmlWriter::writeSceneProps(std::ostringstream& out, const Scene* scene, int indent) {
auto writeStr = [&](const char* name, const std::wstring& val) {
if (!val.empty()) {
indentLine(out, indent);
out << "<" << name << ">" << escapeXml(val, false) << "</" << name << ">\n";
}
};
auto writeBool = [&](const char* name, bool val) {
indentLine(out, indent);
out << "<" << name << ">" << (val ? "true" : "false") << "</" << name << ">\n";
};
writeStr("DefaultFocus", scene->getDefaultFocus());
writeStr("TransTo", scene->getTransitionTo());
writeStr("TransFrom", scene->getTransitionFrom());
writeStr("TransBackTo", scene->getTransitionBackTo());
writeStr("TransBackFrom", scene->getTransitionBackFrom());
writeBool("IgnorePresses", scene->getIgnorePresses());
}
std::string XuiXmlWriter::serialize(const Scene* scene) {
std::ostringstream out;
out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
out << "<XuiCanvas>\n";
out << " <Properties>\n";
out << " <Width>" << scene->getDisplayWidth() << "</Width>\n";
out << " <Height>" << scene->getDisplayHeight() << "</Height>\n";
out << " </Properties>\n";
out << " <XuiScene>\n";
writeSceneProps(out, scene, 2);
const Element* root = scene->getRootElement();
if (root) {
{ const std::vector<std::unique_ptr<Element>>& kc = root->getChildren(); for (size_t i = 0; i < kc.size(); ++i) writeElement(out, kc[i].get(), 2); }
}
out << " </XuiScene>\n";
out << "</XuiCanvas>\n";
return out.str();
}
bool XuiXmlWriter::writeFile(const std::string& path, const Scene* scene) {
std::string xml = serialize(scene);
std::ofstream ofs(path);
if (!ofs) return false;
ofs << xml;
return ofs.good();
}
}
+513
View File
@@ -0,0 +1,513 @@
#include "ImXui/XurFormat.h"
#include <fstream>
#include <cstring>
#include <algorithm>
#include <iostream>
namespace ImXui {
namespace XurFormat {
XurPropertyValue::XurPropertyValue() : type(XurPropertyType_Integer), boolVal(false), intVal(0), uintVal(0), floatVal(0.0f) {}
XurPropertyValue::XurPropertyValue(bool v) : type(XurPropertyType_Bool), boolVal(v), intVal(0), uintVal(0), floatVal(0.0f) {}
XurPropertyValue::XurPropertyValue(int32_t v) : type(XurPropertyType_Integer), boolVal(false), intVal(v), uintVal(0), floatVal(0.0f) {}
XurPropertyValue::XurPropertyValue(uint32_t v) : type(XurPropertyType_Unsigned), boolVal(false), intVal(0), uintVal(v), floatVal(0.0f) {}
XurPropertyValue::XurPropertyValue(float v) : type(XurPropertyType_Float), boolVal(false), intVal(0), uintVal(0), floatVal(v) {}
XurPropertyValue::XurPropertyValue(const std::wstring& v) : type(XurPropertyType_String), boolVal(false), intVal(0), uintVal(0), floatVal(0.0f), stringVal(v) {}
XurPropertyValue::XurPropertyValue(const XurVector& v) : type(XurPropertyType_Vector), boolVal(false), intVal(0), uintVal(0), floatVal(0.0f), vectorVal(v) {}
XurPropertyValue::XurPropertyValue(const XurQuaternion& v) : type(XurPropertyType_Quaternion), boolVal(false), intVal(0), uintVal(0), floatVal(0.0f), quatVal(v) {}
XurPropertyValue::XurPropertyValue(const XurColor& v) : type(XurPropertyType_Colour), boolVal(false), intVal(0), uintVal(0), floatVal(0.0f), colorVal(v) {}
XurPropertyValue::XurPropertyValue(const XurFigure& v) : type(XurPropertyType_Custom), boolVal(false), intVal(0), uintVal(0), floatVal(0.0f), figureVal(v) {}
XurPropertyValue::XurPropertyValue(const std::vector<XurProperty>& v) : type(XurPropertyType_Object), boolVal(false), intVal(0), uintVal(0), floatVal(0.0f), compoundVal(v) {}
XurPropertyValue::XurPropertyValue(const XurPropertyValue& other) : type(other.type), boolVal(other.boolVal), intVal(other.intVal), uintVal(other.uintVal), floatVal(other.floatVal), stringVal(other.stringVal), vectorVal(other.vectorVal), quatVal(other.quatVal), colorVal(other.colorVal), figureVal(other.figureVal), compoundVal(other.compoundVal) {}
XurPropertyValue& XurPropertyValue::operator=(const XurPropertyValue& other) {
if (this != &other) {
type = other.type; boolVal = other.boolVal; intVal = other.intVal; uintVal = other.uintVal; floatVal = other.floatVal;
stringVal = other.stringVal; vectorVal = other.vectorVal; quatVal = other.quatVal; colorVal = other.colorVal;
figureVal = other.figureVal; compoundVal = other.compoundVal;
}
return *this;
}
XurPropertyValue::~XurPropertyValue() {}
static const uint8_t* s_readEnd = nullptr;
static bool s_readTruncated = false;
static bool s_maskDesync = false;
static void resetReadState(const uint8_t* end) {
s_readEnd = end;
s_readTruncated = false;
s_maskDesync = false;
}
static bool canRead(const uint8_t* p, size_t n) {
if (p == NULL || s_readEnd == NULL || p + n > s_readEnd) {
s_readTruncated = true;
return false;
}
return true;
}
static uint16_t readU16(const uint8_t*& p) {
if (!canRead(p, 2)) return 0;
uint16_t v; memcpy(&v, p, 2); p += 2; return swap16(v);
}
static int16_t readS16(const uint8_t*& p) {
return (int16_t)readU16(p);
}
static uint32_t readU32(const uint8_t*& p) {
if (!canRead(p, 4)) return 0;
uint32_t v; memcpy(&v, p, 4); p += 4; return swap32(v);
}
static int32_t readS32(const uint8_t*& p) {
return (int32_t)readU32(p);
}
static float readF32(const uint8_t*& p) {
if (!canRead(p, 4)) return 0.0f;
uint32_t v; memcpy(&v, p, 4); p += 4; return swapFloat(v);
}
static uint8_t readU8(const uint8_t*& p) {
if (!canRead(p, 1)) return 0;
return *p++;
}
static std::wstring readUTF16String(const uint8_t*& p, int16_t length) {
std::wstring result(length, L'\0');
for (int16_t i = 0; i < length; i++) {
if (!canRead(p, 2)) return result;
uint16_t ch = readU16(p);
result[i] = (wchar_t)ch;
}
return result;
}
static std::string ws2s(const std::wstring& ws) {
return std::string(ws.begin(), ws.end());
}
static std::wstring s2ws(const std::string& s) {
return std::wstring(s.begin(), s.end());
}
static bool parseStrn(const uint8_t* data, uint32_t length, std::vector<std::wstring>& strings) {
strings.clear();
strings.push_back(L"");
const uint8_t* p = data;
const uint8_t* end = data + length;
while (p + 2 <= end) {
int16_t strLen = readS16(p);
if (strLen < 0 || p + strLen * 2 > end) break;
strings.push_back(readUTF16String(p, strLen));
}
return strings.size() > 0;
}
static bool parseVect(const uint8_t* data, uint32_t length, std::vector<XurVector>& vectors) {
const uint8_t* p = data;
const uint8_t* end = data + length;
while (p + 12 <= end) {
XurVector v;
v.x = readF32(p); v.y = readF32(p); v.z = readF32(p);
vectors.push_back(v);
}
return true;
}
static bool parseQuat(const uint8_t* data, uint32_t length, std::vector<XurQuaternion>& quaternions) {
const uint8_t* p = data;
const uint8_t* end = data + length;
while (p + 16 <= end) {
XurQuaternion q;
q.x = readF32(p); q.y = readF32(p); q.z = readF32(p); q.w = readF32(p);
quaternions.push_back(q);
}
return true;
}
static bool parseCust(const uint8_t* data, uint32_t length, std::vector<XurFigure>& figures) {
const uint8_t* p = data;
const uint8_t* end = data + length;
while (p < end) {
int32_t dataLength = readS32(p);
if (dataLength < 0 || (size_t)dataLength > (size_t)(end - p)) break;
const uint8_t* figureEnd = p + dataLength;
XurFigure fig;
fig.boundingBox.x = readF32(p); fig.boundingBox.y = readF32(p);
int32_t pointCount = readS32(p);
for (int32_t i = 0; i < pointCount && p + 24 <= figureEnd; i++) {
XurBezierPoint bp;
bp.point.x = readF32(p); bp.point.y = readF32(p);
bp.controlOne.x = readF32(p); bp.controlOne.y = readF32(p);
bp.controlTwo.x = readF32(p); bp.controlTwo.y = readF32(p);
fig.points.push_back(bp);
}
figures.push_back(fig);
p = figureEnd;
}
return true;
}
static XurObject readObject(const uint8_t*& p, const uint8_t* end,
const std::vector<std::wstring>& strings,
const std::vector<XurVector>& vectors,
const std::vector<XurQuaternion>& quaternions,
const std::vector<XurFigure>& figures);
static XurPropertyValue readPropValue(const uint8_t*& p, XurPropertyType type,
const std::vector<std::wstring>& strings,
const std::vector<XurVector>& vectors,
const std::vector<XurQuaternion>& quaternions,
const std::vector<XurFigure>& figures) {
switch (type) {
case XurPropertyType_Bool:
return XurPropertyValue((bool)(readU8(p) != 0));
case XurPropertyType_Integer:
return XurPropertyValue(readS32(p));
case XurPropertyType_Unsigned:
return XurPropertyValue(readU32(p));
case XurPropertyType_Float:
return XurPropertyValue(readF32(p));
case XurPropertyType_Colour: {
XurColor c;
c.a = readU8(p); c.r = readU8(p); c.g = readU8(p); c.b = readU8(p);
return XurPropertyValue(c);
}
case XurPropertyType_String: {
int16_t idx = readS16(p);
if (idx >= 0 && idx < (int16_t)strings.size())
return XurPropertyValue(strings[idx]);
return XurPropertyValue(std::wstring(L""));
}
case XurPropertyType_Vector: {
int32_t idx = readS32(p);
if (idx >= 0 && idx < (int32_t)vectors.size())
return XurPropertyValue(vectors[idx]);
XurVector zero = {0,0,0};
return XurPropertyValue(zero);
}
case XurPropertyType_Quaternion: {
int32_t idx = readS32(p);
if (idx >= 0 && idx < (int32_t)quaternions.size())
return XurPropertyValue(quaternions[idx]);
XurQuaternion zero = {0,0,0,0};
return XurPropertyValue(zero);
}
case XurPropertyType_Custom: {
(void)readS32(p);
if (!figures.empty())
return XurPropertyValue(figures[0]);
return XurPropertyValue(XurFigure());
}
case XurPropertyType_Object: {
int16_t valuesCount = readS16(p); (void)valuesCount;
uint8_t depth = readU8(p); (void)depth;
uint8_t packedByte = readU8(p);
if (packedByte == 0) return XurPropertyValue(std::vector<XurProperty>());
int maskCount = packedByte & 0x07;
std::vector<uint8_t> masks;
for (int i = 0; i < maskCount; i++) masks.push_back(readU8(p));
std::reverse(masks.begin(), masks.end());
for (size_t mi = 0; mi < masks.size(); mi++) {
for (int bit = 0; bit < 8; bit++) {
if ((masks[mi] >> bit) & 1) {
if (!canRead(p, 4)) return XurPropertyValue(std::vector<XurProperty>());
p += 4;
}
}
}
return XurPropertyValue(std::vector<XurProperty>());
}
}
return XurPropertyValue((int32_t)0);
}
static std::vector<XurProperty> readProperties(const uint8_t*& p, const uint8_t* end,
const std::string& className,
const std::vector<std::wstring>& strings,
const std::vector<XurVector>& vectors,
const std::vector<XurQuaternion>& quaternions,
const std::vector<XurFigure>& figures) {
std::vector<XurProperty> props;
if (p + 2 > end) return props;
int16_t totalPropertyCount = readS16(p);
auto hierarchy = XuiClassRegistry::getHierarchy(className);
if (hierarchy.empty()) {
return props;
}
std::reverse(hierarchy.begin(), hierarchy.end());
for (size_t hi = 0; hi < hierarchy.size(); ++hi) {
const XuiClassInfo* cls = hierarchy[hi];
if (p >= end) break;
uint8_t packedByte = readU8(p);
if (packedByte == 0x00) continue;
if (cls->props.empty()) continue;
if ((int16_t)props.size() >= totalPropertyCount) continue;
int maskCount = packedByte & 0x07;
std::vector<uint8_t> masks;
for (int i = 0; i < maskCount && p < end; i++)
masks.push_back(readU8(p));
std::reverse(masks.begin(), masks.end());
int bitIdx = 0;
for (size_t mi = 0; mi < masks.size(); ++mi) {
uint8_t mask = masks[mi];
for (int bit = 0; bit < 8; bit++, bitIdx++) {
if (!((mask >> bit) & 1)) continue;
if (bitIdx >= (int)cls->props.size()) {
s_maskDesync = true;
bitIdx = (int)cls->props.size();
break;
}
const auto& propDef = cls->props[bitIdx];
XurProperty prop;
prop.name = propDef.name;
prop.type = propDef.type;
if (propDef.indexed) {
uint8_t indexCount = readU8(p);
prop.value = readPropValue(p, propDef.type, strings, vectors, quaternions, figures);
for (uint8_t idx = 1; idx < indexCount; idx++) {
readPropValue(p, propDef.type, strings, vectors, quaternions, figures);
}
} else {
prop.value = readPropValue(p, propDef.type, strings, vectors, quaternions, figures);
}
props.push_back(prop);
if (s_readTruncated || s_maskDesync) break;
}
if (s_readTruncated || s_maskDesync) break;
}
if (s_readTruncated || s_maskDesync) break;
}
while ((int16_t)props.size() < totalPropertyCount && p < end && !s_readTruncated && !s_maskDesync) {
XurProperty unknown;
unknown.name = "unknown";
unknown.type = XurPropertyType_Integer;
unknown.value = XurPropertyValue((int32_t)0);
props.push_back(unknown);
if (!canRead(p, 4)) break;
p += 4;
}
return props;
}
static XurNamedFrame readNamedFrame(const uint8_t*& p, const uint8_t* end,
const std::vector<std::wstring>& strings) {
XurNamedFrame nf;
if (p + 9 > end) { p = end; return nf; }
int16_t nameIdx = readS16(p);
nf.name = (nameIdx >= 0 && nameIdx < (int16_t)strings.size()) ? strings[nameIdx] : L"";
nf.keyframe = readS32(p);
nf.command = (XurNamedFrameCommand)readU8(p);
int16_t paramIdx = readS16(p);
nf.targetParameter = (paramIdx >= 0 && paramIdx < (int16_t)strings.size()) ? strings[paramIdx] : L"";
return nf;
}
static XurTimeline readTimeline(const uint8_t*& p, const uint8_t* end,
const std::vector<std::wstring>& strings,
const std::vector<XurVector>& vectors,
const std::vector<XurQuaternion>& quaternions,
const std::vector<XurFigure>& figures,
const std::string& parentClassName) {
XurTimeline tl;
if (p + 6 > end) { p = end; return tl; }
int16_t elemNameIdx = readS16(p);
tl.elementName = (elemNameIdx >= 0 && elemNameIdx < (int16_t)strings.size()) ? strings[elemNameIdx] : L"";
int32_t propDefCount = readS32(p);
std::string targetClass = parentClassName;
std::vector<XurPropertyType> animatedTypes;
for (int32_t i = 0; i < propDefCount && p < end; i++) {
uint8_t packedByte = readU8(p);
uint8_t classIndex = readU8(p);
uint8_t classDepth = packedByte & 0x7F;
for (uint8_t d = 0; d < classDepth && p < end; d++) {
readU8(p);
}
if (packedByte & 0x80) {
if (p + 4 > end) break;
readS32(p);
}
animatedTypes.push_back(XurPropertyType_Integer);
}
if (p + 4 > end) return tl;
int32_t kfCount = readS32(p);
for (int32_t k = 0; k < kfCount && p < end; k++) {
XurKeyframe kf;
if (p + 8 > end) break;
kf.time = readS32(p);
kf.interpolation = (XurInterpolationType)readU8(p);
kf.easeIn = readU8(p);
kf.easeOut = readU8(p);
kf.easeScale = readU8(p);
for (size_t ati = 0; ati < animatedTypes.size(); ++ati) {
if (p >= end) break;
XurProperty kfProp;
kfProp.name = "anim";
kfProp.type = animatedTypes[ati];
kfProp.value = readPropValue(p, animatedTypes[ati], strings, vectors, quaternions, figures);
kf.properties.push_back(kfProp);
}
tl.keyframes.push_back(kf);
}
return tl;
}
static int s_readDepth = 0;
static int s_totalObjects = 0;
static XurObject readObject(const uint8_t*& p, const uint8_t* end,
const std::vector<std::wstring>& strings,
const std::vector<XurVector>& vectors,
const std::vector<XurQuaternion>& quaternions,
const std::vector<XurFigure>& figures) {
XurObject obj;
if (p + 3 > end) { p = end; return obj; }
if (++s_readDepth > 500) { p = end; return obj; }
if (++s_totalObjects > 50000) { p = end; return obj; }
int16_t classNameIndex = readS16(p);
uint8_t flags = readU8(p);
bool idxOk = (classNameIndex >= 0 && classNameIndex < (int16_t)strings.size());
obj.className = ws2s(strings[idxOk ? classNameIndex : 0]);
if (obj.className.empty()) { s_readDepth--; return obj; }
if ((flags & 0x01) && p < end) {
obj.properties = readProperties(p, end, obj.className, strings, vectors, quaternions, figures);
}
if ((flags & 0x02) && p + 4 <= end) {
int32_t childCount = readS32(p);
if (childCount > 0 && childCount < 10000) {
for (int32_t i = 0; i < childCount && p < end; i++) {
XurObject child = readObject(p, end, strings, vectors, quaternions, figures);
if (child.className.empty()) break;
obj.children.push_back(std::move(child));
}
}
}
if ((flags & 0x04) && p < end) {
int32_t nfCount = readS32(p);
if (nfCount > 0 && nfCount < 50000) {
for (int32_t i = 0; i < nfCount && p < end; i++) {
obj.namedFrames.push_back(readNamedFrame(p, end, strings));
}
}
if (!obj.children.empty() && p + 4 <= end) {
int32_t tlCount = readS32(p);
if (tlCount > 0 && tlCount < 50000) {
for (int32_t i = 0; i < tlCount && p < end; i++) {
obj.timelines.push_back(readTimeline(p, end, strings, vectors, quaternions, figures, obj.className));
}
}
}
}
s_readDepth--;
return obj;
}
static void resetObjectTracking() {
s_readDepth = 0;
s_totalObjects = 0;
}
std::unique_ptr<XurDocument> XurParser::parse(const void* data, size_t size) {
if (!data || size < sizeof(XurHeader)) return nullptr;
resetObjectTracking();
XuiClassRegistry::initialize();
std::unique_ptr<XurDocument> doc(new XurDocument());
const uint8_t* bytes = static_cast<const uint8_t*>(data);
doc->rawData.assign(bytes, bytes + size);
memcpy(&doc->header, bytes, sizeof(XurHeader));
if (!doc->header.isValid()) return nullptr;
const uint8_t* p = bytes + sizeof(XurHeader);
const uint8_t* fileEnd = bytes + size;
if (doc->header.getFlags() & 0x01) {
if (p + sizeof(XurCountHeader) > fileEnd) return nullptr;
p += sizeof(XurCountHeader);
}
uint16_t sectionCount = doc->header.getSectionsCount();
if (sectionCount > 20) return nullptr;
std::vector<XurSectionEntry> entries;
for (uint16_t i = 0; i < sectionCount; i++) {
if (p + 12 > fileEnd) return nullptr;
XurSectionEntry entry;
memcpy(&entry, p, 12);
entry.fromBE();
entries.push_back(entry);
p += 12;
}
for (size_t ei = 0; ei < entries.size(); ++ei) {
const XurSectionEntry& entry = entries[ei];
if (entry.offset + entry.length > size) continue;
const uint8_t* sectionData = bytes + entry.offset;
resetReadState(sectionData + entry.length);
switch (entry.magic) {
case MAGIC_STRN:
parseStrn(sectionData, entry.length, doc->strings);
break;
case MAGIC_VECT:
parseVect(sectionData, entry.length, doc->vectors);
break;
case MAGIC_QUAT:
parseQuat(sectionData, entry.length, doc->quaternions);
break;
case MAGIC_CUST:
parseCust(sectionData, entry.length, doc->figures);
break;
case MAGIC_DATA: {
resetReadState(sectionData + entry.length);
doc->rootObject = readObject(sectionData, sectionData + entry.length,
doc->strings, doc->vectors,
doc->quaternions, doc->figures);
break;
}
}
}
return doc;
}
std::unique_ptr<XurDocument> XurParser::parseFromFile(const std::string& path) {
std::ifstream ifs(path, std::ios::binary | std::ios::ate);
if (!ifs) return nullptr;
std::streamsize fileSize = ifs.tellg();
ifs.seekg(0, std::ios::beg);
std::vector<char> buf(fileSize);
if (!ifs.read(buf.data(), fileSize)) return nullptr;
return parse(buf.data(), buf.size());
}
bool XurParser::validate(const XurDocument* doc) {
return doc && doc->header.isValid();
}
}
}
+537
View File
@@ -0,0 +1,537 @@
#include "ImXui/XurWriter.h"
#include "ImXui/ImXui.h"
#include <fstream>
#include <cstring>
#include <algorithm>
namespace ImXui {
namespace XurFormat {
void MemBuf::write(const void* d, size_t sz) {
const uint8_t* src = (const uint8_t*)d;
data.insert(data.end(), src, src + sz);
}
template<typename T>
void MemBuf::writeBE(T v) {
T be = v;
if (sizeof(T) == 2) {
uint16_t u = (uint16_t)v;
be = (T)BSWAP16(u);
} else if (sizeof(T) == 4) {
uint32_t u = (uint32_t)v;
be = (T)BSWAP32(u);
}
write(&be, sizeof(T));
}
void MemBuf::writeU8(uint8_t v) { write(&v, 1); }
void MemBuf::writeU16BE(uint16_t v) { writeBE(v); }
void MemBuf::writeU32BE(uint32_t v) { writeBE(v); }
void MemBuf::writeS16BE(int16_t v) { writeBE(v); }
void MemBuf::writeS32BE(int32_t v) { writeBE(v); }
void MemBuf::writeFloatBE(float v) {
uint32_t tmp;
memcpy(&tmp, &v, 4);
writeU32BE(tmp);
}
uint32_t MemBuf::tell() const { return (uint32_t)data.size(); }
template void MemBuf::writeBE<uint16_t>(uint16_t);
template void MemBuf::writeBE<uint32_t>(uint32_t);
template void MemBuf::writeBE<int16_t>(int16_t);
template void MemBuf::writeBE<int32_t>(int32_t);
int WriteContext::addString(const std::wstring& s) {
for (size_t i = 0; i < strings.size(); i++)
if (strings[i] == s) return (int)i;
strings.push_back(s);
return (int)(strings.size() - 1);
}
int WriteContext::addVector(const XurVector& v) {
for (size_t i = 0; i < vectors.size(); i++)
if (vectors[i].x == v.x && vectors[i].y == v.y && vectors[i].z == v.z) return (int)i;
vectors.push_back(v);
return (int)(vectors.size() - 1);
}
int WriteContext::addQuaternion(const XurQuaternion& q) {
for (size_t i = 0; i < quaternions.size(); i++)
if (quaternions[i].x == q.x && quaternions[i].y == q.y &&
quaternions[i].z == q.z && quaternions[i].w == q.w) return (int)i;
quaternions.push_back(q);
return (int)(quaternions.size() - 1);
}
int WriteContext::addFigure(const XurFigure& f) {
figures.push_back(f);
return (int)(figures.size() - 1);
}
void XurWriter::writePropValue(MemBuf& buf, WriteContext& ctx, const XurPropertyValue& val) {
switch (val.type) {
case XurPropertyType_Bool:
buf.writeU8(val.boolVal ? 1 : 0);
break;
case XurPropertyType_Integer:
buf.writeS32BE(val.intVal);
break;
case XurPropertyType_Unsigned:
buf.writeU32BE(val.uintVal);
break;
case XurPropertyType_Float:
buf.writeFloatBE(val.floatVal);
break;
case XurPropertyType_Colour:
buf.writeU8(val.colorVal.a);
buf.writeU8(val.colorVal.r);
buf.writeU8(val.colorVal.g);
buf.writeU8(val.colorVal.b);
break;
case XurPropertyType_String:
buf.writeS16BE((int16_t)ctx.addString(val.stringVal));
break;
case XurPropertyType_Vector:
buf.writeS32BE(ctx.addVector(val.vectorVal));
break;
case XurPropertyType_Quaternion:
buf.writeS32BE(ctx.addQuaternion(val.quatVal));
break;
case XurPropertyType_Custom:
buf.writeS32BE(ctx.addFigure(val.figureVal));
break;
case XurPropertyType_Object: {
int16_t count = 0;
for (auto& sp : val.compoundVal) {
if (sp.type != XurPropertyType_Object && sp.type != XurPropertyType_Custom) count++;
}
buf.writeS16BE(count);
buf.writeU8(0);
if (count == 0) {
buf.writeU8(0);
} else {
buf.writeU8(1);
buf.writeU8(1);
for (auto& sp : val.compoundVal) {
if (sp.type != XurPropertyType_Object && sp.type != XurPropertyType_Custom) {
writePropValue(buf, ctx, sp.value);
break;
}
}
}
break;
}
}
}
void XurWriter::writeProperties(MemBuf& buf, WriteContext& ctx, const XurObject& obj) {
auto hierarchy = XuiClassRegistry::getHierarchy(obj.className);
std::reverse(hierarchy.begin(), hierarchy.end());
int16_t totalCount = 0;
for (auto& p : obj.properties) {
if (p.type != XurPropertyType_Object && p.type != XurPropertyType_Custom)
totalCount++;
}
buf.writeS16BE(totalCount);
for (auto& cls : hierarchy) {
if (cls->props.empty()) {
buf.writeU8(0);
continue;
}
std::vector<uint8_t> tempMasks;
tempMasks.push_back(0);
int currentMaskBits = 0;
bool hasAny = false;
for (size_t pd = 0; pd < cls->props.size(); pd++) {
const std::string& pname = cls->props[pd].name;
XurPropertyType ptype = cls->props[pd].type;
const XurPropertyValue* foundVal = NULL;
for (size_t pi = 0; pi < obj.properties.size(); pi++) {
if (obj.properties[pi].name == pname && obj.properties[pi].type == ptype) {
foundVal = &obj.properties[pi].value;
break;
}
}
if (foundVal &&
foundVal->type != XurPropertyType_Object &&
foundVal->type != XurPropertyType_Custom) {
tempMasks.back() |= (1 << currentMaskBits);
hasAny = true;
}
currentMaskBits++;
if (currentMaskBits >= 8) {
tempMasks.push_back(0);
currentMaskBits = 0;
}
}
if (!hasAny) {
buf.writeU8(0);
continue;
}
std::reverse(tempMasks.begin(), tempMasks.end());
buf.writeU8((uint8_t)(tempMasks.size() & 0x07));
for (size_t i = 0; i < tempMasks.size(); i++)
buf.writeU8(tempMasks[i]);
for (size_t pd = 0; pd < cls->props.size(); pd++) {
const std::string& pname = cls->props[pd].name;
XurPropertyType ptype = cls->props[pd].type;
const XurPropertyValue* foundVal2 = NULL;
for (size_t pj = 0; pj < obj.properties.size(); pj++) {
if (obj.properties[pj].name == pname && obj.properties[pj].type == ptype) {
foundVal2 = &obj.properties[pj].value;
break;
}
}
if (foundVal2 &&
foundVal2->type != XurPropertyType_Object &&
foundVal2->type != XurPropertyType_Custom) {
writePropValue(buf, ctx, *foundVal2);
}
}
}
}
void XurWriter::writeObject(MemBuf& buf, WriteContext& ctx, const XurObject& obj) {
int16_t nameIdx = (int16_t)ctx.addString(std::wstring(obj.className.begin(), obj.className.end()));
buf.writeS16BE(nameIdx);
uint8_t flags = 0;
bool hasProps = false;
for (auto& p : obj.properties) {
if (p.type != XurPropertyType_Object && p.type != XurPropertyType_Custom) {
hasProps = true;
break;
}
}
if (hasProps || !obj.properties.empty()) flags |= 0x01;
if (!obj.children.empty()) flags |= 0x02;
if (!obj.namedFrames.empty() || !obj.timelines.empty()) flags |= 0x04;
buf.writeU8(flags);
if (flags & 0x01) writeProperties(buf, ctx, obj);
if (flags & 0x02) {
buf.writeS32BE((int32_t)obj.children.size());
for (auto& child : obj.children) writeObject(buf, ctx, child);
}
if (flags & 0x04) {
buf.writeS32BE((int32_t)obj.namedFrames.size());
for (auto& nf : obj.namedFrames) {
buf.writeS16BE((int16_t)ctx.addString(nf.name));
buf.writeS32BE(nf.keyframe);
buf.writeU8((uint8_t)nf.command);
buf.writeS16BE((int16_t)ctx.addString(nf.targetParameter));
}
if (!obj.children.empty()) {
buf.writeS32BE((int32_t)obj.timelines.size());
for (auto& tl : obj.timelines) {
buf.writeS16BE((int16_t)ctx.addString(tl.elementName));
buf.writeS32BE(0);
buf.writeS32BE((int32_t)tl.keyframes.size());
for (auto& kf : tl.keyframes) {
buf.writeS32BE(kf.time);
buf.writeU8((uint8_t)kf.interpolation);
buf.writeU8(kf.easeIn);
buf.writeU8(kf.easeOut);
buf.writeU8(kf.easeScale);
for (auto& kp : kf.properties) writePropValue(buf, ctx, kp.value);
}
}
}
}
}
void XurWriter::writeStrnSection(MemBuf& out, WriteContext& ctx) {
for (size_t i = 1; i < ctx.strings.size(); i++) {
auto& s = ctx.strings[i];
int16_t len = (int16_t)s.size();
out.writeS16BE(len);
for (auto& c : s) {
out.writeU8((uint8_t)((c >> 8) & 0xFF));
out.writeU8((uint8_t)(c & 0xFF));
}
}
}
void XurWriter::writeVectSection(MemBuf& out, WriteContext& ctx) {
for (auto& v : ctx.vectors) {
out.writeFloatBE(v.x);
out.writeFloatBE(v.y);
out.writeFloatBE(v.z);
}
}
void XurWriter::writeQuatSection(MemBuf& out, WriteContext& ctx) {
for (auto& q : ctx.quaternions) {
out.writeFloatBE(q.x);
out.writeFloatBE(q.y);
out.writeFloatBE(q.z);
out.writeFloatBE(q.w);
}
}
void XurWriter::writeCustSection(MemBuf& out, WriteContext& ctx) {
for (auto& f : ctx.figures) {
MemBuf figBuf;
figBuf.writeFloatBE(f.boundingBox.x);
figBuf.writeFloatBE(f.boundingBox.y);
figBuf.writeS32BE((int32_t)f.points.size());
for (auto& bp : f.points) {
figBuf.writeFloatBE(bp.point.x);
figBuf.writeFloatBE(bp.point.y);
figBuf.writeFloatBE(bp.controlOne.x);
figBuf.writeFloatBE(bp.controlOne.y);
figBuf.writeFloatBE(bp.controlTwo.x);
figBuf.writeFloatBE(bp.controlTwo.y);
}
out.writeS32BE((int32_t)figBuf.data.size());
out.write(figBuf.data.data(), figBuf.data.size());
}
}
void XurWriter::writeDataSection(MemBuf& out, WriteContext& ctx, const XurObject& root) {
writeObject(out, ctx, root);
}
std::vector<uint8_t> XurWriter::serialize(const XurObject& root) {
WriteContext ctx;
ctx.addString(L"");
MemBuf strnBuf, vectBuf, quatBuf, custBuf, dataBuf;
writeDataSection(dataBuf, ctx, root);
writeStrnSection(strnBuf, ctx);
writeVectSection(vectBuf, ctx);
writeQuatSection(quatBuf, ctx);
writeCustSection(custBuf, ctx);
uint32_t strnLen = (uint32_t)strnBuf.data.size();
uint32_t vectLen = (uint32_t)vectBuf.data.size();
uint32_t quatLen = (uint32_t)quatBuf.data.size();
uint32_t custLen = (uint32_t)custBuf.data.size();
uint32_t dataLen = (uint32_t)dataBuf.data.size();
bool hasCountHeader = false;
uint16_t sectionCount = 0;
if (strnLen > 0) sectionCount++;
if (vectLen > 0) sectionCount++;
if (quatLen > 0) sectionCount++;
if (custLen > 0) sectionCount++;
if (dataLen > 0) sectionCount++;
const uint32_t headerSize = 20;
const uint32_t sectionEntrySize = 12;
uint32_t offset = headerSize + sectionCount * sectionEntrySize;
uint32_t fileSize = offset;
struct Section {
uint32_t magic;
uint32_t offset;
uint32_t length;
MemBuf* buf;
};
std::vector<Section> sections;
if (strnLen > 0) { sections.push_back({MAGIC_STRN, fileSize, strnLen, &strnBuf}); fileSize += strnLen; }
if (vectLen > 0) { sections.push_back({MAGIC_VECT, fileSize, vectLen, &vectBuf}); fileSize += vectLen; }
if (quatLen > 0) { sections.push_back({MAGIC_QUAT, fileSize, quatLen, &quatBuf}); fileSize += quatLen; }
if (custLen > 0) { sections.push_back({MAGIC_CUST, fileSize, custLen, &custBuf}); fileSize += custLen; }
if (dataLen > 0) { sections.push_back({MAGIC_DATA, fileSize, dataLen, &dataBuf}); fileSize += dataLen; }
MemBuf fileBuf;
fileBuf.write("XUIB", 4);
fileBuf.writeU32BE(5);
fileBuf.writeU32BE(hasCountHeader ? 0x01 : 0x00);
fileBuf.writeU16BE(0);
fileBuf.writeU32BE(fileSize);
fileBuf.writeU16BE(sectionCount);
for (auto& sec : sections) {
fileBuf.writeU32BE(sec.magic);
fileBuf.writeU32BE(sec.offset);
fileBuf.writeU32BE(sec.length);
}
for (auto& sec : sections) {
fileBuf.write(sec.buf->data.data(), sec.buf->data.size());
}
return fileBuf.data;
}
bool XurWriter::writeToFile(const std::string& path, const XurObject& root) {
auto data = serialize(root);
std::ofstream ofs(path, std::ios::binary);
if (!ofs) return false;
ofs.write((const char*)data.data(), data.size());
return ofs.good();
}
XurObject elementToXurObject(const Element* el) {
XurObject obj;
std::wstring cn = el->getClassName();
obj.className = std::string(cn.begin(), cn.end());
if (obj.className.empty()) obj.className = "XuiElement";
auto addStr = [&](const std::string& name, const std::wstring& val) {
if (!val.empty()) {
XurProperty p;
p.name = name;
p.type = XurPropertyType_String;
p.value = XurPropertyValue(val);
obj.properties.push_back(p);
}
};
auto addFloat = [&](const std::string& name, float val) {
XurProperty p;
p.name = name;
p.type = XurPropertyType_Float;
p.value = XurPropertyValue(val);
obj.properties.push_back(p);
};
auto addBool = [&](const std::string& name, bool val) {
XurProperty p;
p.name = name;
p.type = XurPropertyType_Bool;
p.value = XurPropertyValue(val);
obj.properties.push_back(p);
};
auto addUint = [&](const std::string& name, uint32_t val) {
XurProperty p;
p.name = name;
p.type = XurPropertyType_Unsigned;
p.value = XurPropertyValue(val);
obj.properties.push_back(p);
};
auto addVec = [&](const std::string& name, Vec3 val) {
XurProperty p;
p.name = name;
p.type = XurPropertyType_Vector;
p.value = XurPropertyValue(XurVector{val.x, val.y, val.z});
obj.properties.push_back(p);
};
auto addColour = [&](const std::string& name, Color c) {
XurProperty p;
p.name = name;
p.type = XurPropertyType_Colour;
XurColor col;
col.a = (uint8_t)(c.a * 255);
col.r = (uint8_t)(c.r * 255);
col.g = (uint8_t)(c.g * 255);
col.b = (uint8_t)(c.b * 255);
p.value = XurPropertyValue(col);
obj.properties.push_back(p);
};
addStr("Id", el->getId());
addFloat("Width", el->getBounds().x);
addFloat("Height", el->getBounds().y);
addVec("Position", el->getPosition());
addVec("Scale", el->getScale());
addVec("Pivot", el->getPivot());
addVec("Rotation", el->getRotation());
addFloat("Opacity", el->getOpacity());
addBool("Show", el->isShown());
addUint("Anchor", el->getAnchor());
addUint("BlendMode", el->getBlendMode());
addBool("ClipChildren", el->getClipChildren());
addBool("Hittable", el->isHittable());
addBool("LayoutLineBreak", el->getLayoutLineBreak());
addBool("LayoutFloat", el->getLayoutFloat());
addUint("Column", el->getColumn());
addUint("Row", el->getRow());
addUint("ColumnSpan", el->getColumnSpan());
addUint("RowSpan", el->getRowSpan());
addColour("ColorFactor", el->getColorFactor());
if (!el->getImagePath().empty())
addStr("Source", el->getImagePath());
if (el->getIsNineGrid()) {
addStr("TextureFileName", el->getNineGridTexture());
addUint("LeftOffset", el->getNineGridLeft());
addUint("TopOffset", el->getNineGridTop());
addUint("RightOffset", el->getNineGridRight());
addUint("BottomOffset", el->getNineGridBottom());
addBool("NoCenter", el->getNineGridNoCenter());
}
const Control* ctrl = dynamic_cast<const Control*>(el);
if (ctrl) {
addStr("Text", ctrl->getText());
addStr("Font", ctrl->getFontName());
addFloat("PointSize", ctrl->getFontSize());
addBool("Enabled", ctrl->isEnabled());
addStr("Visual", ctrl->getVisual());
addUint("Value", (uint32_t)ctrl->getProgressValue());
addUint("RangeMin", (uint32_t)ctrl->getProgressMin());
addUint("RangeMax", (uint32_t)ctrl->getProgressMax());
addStr("NavLeft", ctrl->getNavLeft());
addStr("NavRight", ctrl->getNavRight());
addStr("NavUp", ctrl->getNavUp());
addStr("NavDown", ctrl->getNavDown());
addStr("NavTabForward", ctrl->getNavTabForward());
addStr("NavTabBackward", ctrl->getNavTabBackward());
addUint("PressKey", ctrl->getPressKey());
addStr("PressAnimObject", ctrl->getPressAnimObject());
addStr("FocusAnimObject", ctrl->getFocusAnimObject());
addUint("Step", (uint32_t)ctrl->getStep());
addBool("Vertical", ctrl->isVertical());
}
const Scene* scene = dynamic_cast<const Scene*>(el);
if (scene) {
addStr("DefaultFocus", scene->getDefaultFocus());
addStr("TransTo", scene->getTransitionTo());
addStr("TransFrom", scene->getTransitionFrom());
addStr("TransBackTo", scene->getTransitionBackTo());
addStr("TransBackFrom", scene->getTransitionBackFrom());
addBool("IgnorePresses", scene->getIgnorePresses());
}
for (auto& child : el->getChildren()) {
obj.children.push_back(elementToXurObject(child.get()));
}
return obj;
}
XurObject sceneToXurObject(const Scene* scene) {
XurObject obj;
obj.className = "XuiCanvas";
const Element* root = scene->getRootElement();
if (root) {
XurObject rootObj = elementToXurObject(root);
obj.children.push_back(rootObj);
}
return obj;
}
}
}
+596
View File
@@ -0,0 +1,596 @@
#include "ImXui/XurXml.h"
#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <map>
#include <sstream>
namespace ImXui {
namespace XurFormat {
struct XmlNode {
std::string name;
std::map<std::string, std::string> attrs;
std::string text;
std::vector<XmlNode> children;
};
static std::string trim(const std::string& s) {
size_t start = 0;
while (start < s.size() && (s[start] == ' ' || s[start] == '\t' || s[start] == '\r' || s[start] == '\n'))
start++;
size_t end = s.size();
while (end > start && (s[end-1] == ' ' || s[end-1] == '\t' || s[end-1] == '\r' || s[end-1] == '\n'))
end--;
if (start >= end) return "";
return s.substr(start, end - start);
}
static XmlNode parseXml(const std::string& xml, size_t& pos) {
XmlNode node;
while (pos < xml.size() && (xml[pos] == ' ' || xml[pos] == '\t' || xml[pos] == '\r' || xml[pos] == '\n'))
pos++;
if (pos >= xml.size() || xml[pos] != '<') return node;
pos++;
if (pos < xml.size() && xml[pos] == '/') {
return node;
}
while (pos < xml.size() && xml[pos] != '>' && xml[pos] != ' ' && xml[pos] != '\t' && xml[pos] != '\r' && xml[pos] != '\n')
node.name += xml[pos++];
while (pos < xml.size() && xml[pos] != '>' && xml[pos] != '/') {
while (pos < xml.size() && (xml[pos] == ' ' || xml[pos] == '\t' || xml[pos] == '\r' || xml[pos] == '\n'))
pos++;
if (pos >= xml.size() || xml[pos] == '>' || xml[pos] == '/') break;
std::string attrName, attrValue;
while (pos < xml.size() && xml[pos] != '=' && xml[pos] != '>' && xml[pos] != ' ' && xml[pos] != '\t')
attrName += xml[pos++];
if (pos < xml.size() && xml[pos] == '=') {
pos++;
char quote = xml[pos++];
while (pos < xml.size() && xml[pos] != quote)
attrValue += xml[pos++];
if (pos < xml.size()) pos++;
node.attrs[attrName] = attrValue;
}
}
bool selfClosing = false;
if (pos < xml.size() && xml[pos] == '/') { selfClosing = true; pos++; }
if (pos < xml.size() && xml[pos] == '>') pos++;
if (selfClosing) return node;
std::string text;
while (pos < xml.size()) {
if (xml[pos] == '<') {
if (pos + 1 < xml.size() && xml[pos + 1] == '/') {
pos += 2;
std::string closeName;
while (pos < xml.size() && xml[pos] != '>')
closeName += xml[pos++];
if (pos < xml.size()) pos++;
break;
} else if (pos + 1 < xml.size() && xml[pos + 1] == '!') {
if (pos + 3 < xml.size() && xml[pos+2] == '-' && xml[pos+3] == '-') {
pos = xml.find("-->", pos + 4);
if (pos != std::string::npos) pos += 3;
else break;
} else {
pos++;
}
} else {
if (!text.empty()) {
std::string trimmed = trim(text);
if (!trimmed.empty()) {
XmlNode textNode;
textNode.name = "#text";
textNode.text = trimmed;
node.children.push_back(textNode);
}
text.clear();
}
XmlNode child = parseXml(xml, pos);
if (!child.name.empty())
node.children.push_back(child);
}
} else {
text += xml[pos++];
}
}
if (!text.empty()) {
std::string trimmed = trim(text);
if (!trimmed.empty()) node.text = trimmed;
}
return node;
}
static bool isXuiClass(const std::string& name) {
return name.find("Xui") == 0 || name == "HUDScene" || name == "MediaScene" ||
name == "ScriptScene" || name == "DashScene" || name == "MobyRootScene" ||
name == "RomeRootScene" || name == "MPSlotScene" || name == "DashData" ||
name == "VideoData" || name == "LiveData" || name == "MediaData" ||
name == "ScriptList" || name == "ScriptData" || name == "ScriptImage" ||
name == "AuraControl" || name == "GuideDashCommandNavButton" ||
name == "GuideMainSceneNavButton" || name == "ScriptActionNavButton" ||
name == "AccountManagementNavButton" || name == "VideoMarketplaceNavButton" ||
name == "AvatarEditorNavButton" || name == "MediaImageHttp" ||
name == "LegacyControl";
}
static XurPropertyType parsePropType(const std::string& value) {
if (value == "true" || value == "false") return XurPropertyType_Bool;
if (value.size() >= 10 && value.substr(0, 2) == "0x")
return XurPropertyType_Colour;
if (std::count(value.begin(), value.end(), ',') >= 2)
return XurPropertyType_Vector;
char* end = nullptr;
double d = strtod(value.c_str(), &end);
if (end && *end == '\0') {
if (d == (int)d && d >= -2147483648.0 && d <= 2147483647.0)
return XurPropertyType_Integer;
return XurPropertyType_Float;
}
return XurPropertyType_String;
}
static XurPropertyValue parsePropValue(const std::string& value, XurPropertyType type) {
switch (type) {
case XurPropertyType_Bool:
return XurPropertyValue(value == "true");
case XurPropertyType_Integer:
return XurPropertyValue((int32_t)strtol(value.c_str(), nullptr, 10));
case XurPropertyType_Unsigned:
return XurPropertyValue((uint32_t)strtoul(value.c_str(), nullptr, 10));
case XurPropertyType_Float:
return XurPropertyValue((float)strtod(value.c_str(), nullptr));
case XurPropertyType_Colour: {
unsigned long c = strtoul(value.c_str() + 2, nullptr, 16);
XurColor col;
col.a = (uint8_t)((c >> 24) & 0xFF);
col.r = (uint8_t)((c >> 16) & 0xFF);
col.g = (uint8_t)((c >> 8) & 0xFF);
col.b = (uint8_t)(c & 0xFF);
return XurPropertyValue(col);
}
case XurPropertyType_Vector: {
XurVector v = {0, 0, 0};
sscanf(value.c_str(), "%f,%f,%f", &v.x, &v.y, &v.z);
return XurPropertyValue(v);
}
case XurPropertyType_String:
return XurPropertyValue(std::wstring(value.begin(), value.end()));
default:
return XurPropertyValue((int32_t)0);
}
}
static const XuiPropDef* findPropDef(const std::string& className, const std::string& propName) {
auto hierarchy = XuiClassRegistry::getHierarchy(className);
for (size_t hi = 0; hi < hierarchy.size(); ++hi) {
const XuiClassInfo* cls = hierarchy[hi];
for (size_t pi = 0; pi < cls->props.size(); ++pi) {
const XuiPropDef& pd = cls->props[pi];
if (pd.name == propName) return &pd;
}
}
return nullptr;
}
static XurPropertyValue parseFigurePoints(const std::string& value) {
std::vector<float> nums;
const char* p = value.c_str();
while (*p) {
while (*p == ' ' || *p == ',' || *p == '\t' || *p == '\r' || *p == '\n') p++;
if (!*p) break;
char* end = nullptr;
double d = strtod(p, &end);
if (end == p) break;
nums.push_back((float)d);
p = end;
}
XurFigure fig;
if (!nums.empty()) {
int count = (int)nums[0];
size_t i = 1;
for (int v = 0; v < count && i + 6 <= nums.size(); v++, i += 7) {
XurBezierPoint bp;
bp.point.x = nums[i];
bp.point.y = nums[i + 1];
bp.controlOne.x = nums[i + 2];
bp.controlOne.y = nums[i + 3];
bp.controlTwo.x = nums[i + 4];
bp.controlTwo.y = nums[i + 5];
fig.points.push_back(bp);
}
}
return XurPropertyValue(fig);
}
static void addCompoundProp(XurObject& obj, const std::string& name, const XmlNode& node);
static void buildProperties(XurObject& obj, const XmlNode& node) {
for (size_t bpi = 0; bpi < node.children.size(); ++bpi) {
const XmlNode& child = node.children[bpi];
if (child.name == "#text" || child.name.empty()) continue;
if (child.name == "Points") {
XurProperty xp;
xp.name = child.name;
xp.type = XurPropertyType_Custom;
xp.value = parseFigurePoints(child.text);
obj.properties.push_back(xp);
continue;
}
if (child.name == "Fill" || child.name == "Stroke" || child.name == "Gradient") {
addCompoundProp(obj, child.name, child);
continue;
}
auto propDef = findPropDef(obj.className, child.name);
XurPropertyType ptype = (propDef) ? propDef->type : parsePropType(child.text);
XurPropertyValue pval = parsePropValue(child.text, ptype);
XurProperty xp;
xp.name = child.name;
xp.type = ptype;
xp.value = pval;
obj.properties.push_back(xp);
}
}
static void addCompoundProp(XurObject& obj, const std::string& name, const XmlNode& node) {
XurProperty xp;
xp.name = name;
xp.type = XurPropertyType_Object;
std::vector<XurProperty> compound;
for (size_t acpi = 0; acpi < node.children.size(); ++acpi) {
const XmlNode& child = node.children[acpi];
if (child.name == "#text") continue;
if (child.name == "Properties") {
for (size_t spi = 0; spi < child.children.size(); ++spi) {
const XmlNode& sp = child.children[spi];
if (sp.name == "#text") continue;
auto spropDef = findPropDef(obj.className, sp.name);
XurPropertyType st = (spropDef) ? spropDef->type : parsePropType(sp.text);
XurPropertyValue sv = parsePropValue(sp.text, st);
XurProperty sprop;
sprop.name = sp.name;
sprop.type = st;
sprop.value = sv;
compound.push_back(sprop);
}
}
}
xp.value = XurPropertyValue(compound);
obj.properties.push_back(xp);
}
static void buildObject(XurObject& obj, const XmlNode& node) {
if (node.name == "XuiCanvas") {
obj.className = "XuiCanvas";
} else if (isXuiClass(node.name) || node.name.find("Xui") == 0) {
obj.className = node.name;
} else if (node.name == "Timelines" || node.name == "NamedFrames" ||
node.name == "Timeline" || node.name == "KeyFrame" ||
node.name == "NamedFrame" || node.name == "#text") {
return;
} else {
obj.className = node.name;
}
for (size_t boi = 0; boi < node.children.size(); ++boi) {
const XmlNode& child = node.children[boi];
if (child.name == "Properties") {
buildProperties(obj, child);
} else if (child.name == "Stroke" || child.name == "Fill" || child.name == "Gradient") {
addCompoundProp(obj, child.name, child);
} else if (child.name == "Timelines") {
for (size_t tli = 0; tli < child.children.size(); ++tli) {
const XmlNode& tlNode = child.children[tli];
if (tlNode.name == "NamedFrames") {
for (size_t nfi = 0; nfi < tlNode.children.size(); ++nfi) {
const XmlNode& nfNode = tlNode.children[nfi];
if (nfNode.name != "NamedFrame") continue;
XurNamedFrame nf;
for (size_t nci = 0; nci < nfNode.children.size(); ++nci) {
const XmlNode& nfChild = nfNode.children[nci];
if (nfChild.name == "Name")
nf.name = std::wstring(nfChild.text.begin(), nfChild.text.end());
else if (nfChild.name == "Time")
nf.keyframe = (int32_t)strtol(nfChild.text.c_str(), nullptr, 10);
else if (nfChild.name == "Command") {
if (nfChild.text == "stop") nf.command = XurNamedFrameCommand_Stop;
else if (nfChild.text == "play") nf.command = XurNamedFrameCommand_Play;
else if (nfChild.text == "gotostop") nf.command = XurNamedFrameCommand_GotoAndStop;
else if (nfChild.text == "gotoplay") nf.command = XurNamedFrameCommand_GotoAndPlay;
} else if (nfChild.name == "TargetParameter")
nf.targetParameter = std::wstring(nfChild.text.begin(), nfChild.text.end());
}
obj.namedFrames.push_back(nf);
}
} else if (tlNode.name == "Timeline") {
XurTimeline tl;
for (size_t tci = 0; tci < tlNode.children.size(); ++tci) {
const XmlNode& tlChild = tlNode.children[tci];
if (tlChild.name == "Target")
tl.elementName = std::wstring(tlChild.text.begin(), tlChild.text.end());
else if (tlChild.name == "KeyFrame") {
XurKeyframe kf;
for (size_t kci = 0; kci < tlChild.children.size(); ++kci) {
const XmlNode& kfChild = tlChild.children[kci];
if (kfChild.name == "Time")
kf.time = (int32_t)strtol(kfChild.text.c_str(), nullptr, 10);
else if (kfChild.name == "Interpolation") {
if (kfChild.text == "linear") kf.interpolation = XurInterpolationType_Linear;
else if (kfChild.text == "easein") kf.interpolation = XurInterpolationType_EaseIn;
else if (kfChild.text == "easeout") kf.interpolation = XurInterpolationType_EaseOut;
else if (kfChild.text == "easeinout") kf.interpolation = XurInterpolationType_EaseInOut;
} else {
XurPropertyType pt = parsePropType(kfChild.text);
XurPropertyValue pv = parsePropValue(kfChild.text, pt);
XurProperty kp;
kp.name = kfChild.name;
kp.type = pt;
kp.value = pv;
kf.properties.push_back(kp);
}
}
tl.keyframes.push_back(kf);
}
}
obj.timelines.push_back(tl);
}
}
} else if (isXuiClass(child.name) || child.name.find("Xui") == 0 ||
child.name == "LegacyControl" || child.name == "ScriptScene" ||
child.name == "HUDScene" || child.name == "DashScene" ||
child.name == "MediaScene" || child.name.find("Script") == 0 ||
child.name.find("Guide") == 0 || child.name == "AccountManagementNavButton" ||
child.name == "VideoMarketplaceNavButton" || child.name == "AvatarEditorNavButton" ||
child.name == "MediaImageHttp" || child.name == "AuraControl" ||
child.name == "MobyRootScene" || child.name == "RomeRootScene" ||
child.name == "MPSlotScene") {
XurObject childObj;
buildObject(childObj, child);
if (!childObj.className.empty())
obj.children.push_back(childObj);
}
}
}
XurObject xuiXmlToObject(const std::string& xml) {
XurObject rootObj;
size_t pos = 0;
XmlNode root = parseXml(xml, pos);
if (root.name.empty()) return rootObj;
buildObject(rootObj, root);
return rootObj;
}
XurObject xuiFileToObject(const std::string& path) {
std::ifstream ifs(path);
if (!ifs) return XurObject();
std::stringstream ss;
ss << ifs.rdbuf();
return xuiXmlToObject(ss.str());
}
static std::string escapeXml(const std::string& s) {
std::string r;
for (size_t ci = 0; ci < s.size(); ++ci) {
char c = s[ci];
switch (c) {
case '&': r += "&amp;"; break;
case '<': r += "&lt;"; break;
case '>': r += "&gt;"; break;
case '"': r += "&quot;"; break;
case '\'': r += "&apos;"; break;
default: r += c;
}
}
return r;
}
static std::string ws2s(const std::wstring& ws) {
return std::string(ws.begin(), ws.end());
}
static std::string propValueToString(const XurPropertyValue& v) {
std::ostringstream ss;
ss << std::fixed;
switch (v.type) {
case XurPropertyType_Bool:
ss << (v.boolVal ? "true" : "false");
break;
case XurPropertyType_Integer:
ss << v.intVal;
break;
case XurPropertyType_Unsigned:
ss << v.uintVal;
break;
case XurPropertyType_Float:
ss << v.floatVal;
break;
case XurPropertyType_Colour: {
char buf[16];
snprintf(buf, sizeof(buf), "0x%02x%02x%02x%02x",
(unsigned int)v.colorVal.a, (unsigned int)v.colorVal.r,
(unsigned int)v.colorVal.g, (unsigned int)v.colorVal.b);
ss << buf;
break;
}
case XurPropertyType_String:
ss << escapeXml(ws2s(v.stringVal));
break;
case XurPropertyType_Vector:
ss << v.vectorVal.x << "," << v.vectorVal.y << "," << v.vectorVal.z;
break;
case XurPropertyType_Quaternion:
ss << v.quatVal.x << "," << v.quatVal.y << "," << v.quatVal.z << "," << v.quatVal.w;
break;
case XurPropertyType_Object:
ss << "(object)";
break;
case XurPropertyType_Custom:
ss << "(custom)";
break;
}
return ss.str();
}
static void writeProperties(std::ostream& os, int indent,
const std::vector<XurProperty>& props,
const std::string& indentStr) {
bool hasProps = false;
for (size_t p1 = 0; p1 < props.size(); ++p1) {
const XurProperty& p = props[p1];
if (p.type != XurPropertyType_Object && p.type != XurPropertyType_Custom) {
hasProps = true;
break;
}
}
if (!hasProps) return;
os << indentStr << "<Properties>\n";
for (size_t p2 = 0; p2 < props.size(); ++p2) {
const XurProperty& p = props[p2];
if (p.type == XurPropertyType_Object || p.type == XurPropertyType_Custom)
continue;
os << indentStr << "<" << p.name << ">" << propValueToString(p.value) << "</" << p.name << ">\n";
}
for (size_t p3 = 0; p3 < props.size(); ++p3) {
const XurProperty& p = props[p3];
if (p.type != XurPropertyType_Object && p.type != XurPropertyType_Custom)
continue;
if (p.type != XurPropertyType_Object) continue;
os << indentStr << "<" << p.name << ">\n";
bool hasObjProps = false;
for (size_t s1 = 0; s1 < p.value.compoundVal.size(); ++s1) {
const XurProperty& sp = p.value.compoundVal[s1];
if (sp.type != XurPropertyType_Object && sp.type != XurPropertyType_Custom) {
hasObjProps = true;
break;
}
}
if (hasObjProps) {
os << indentStr << " <Properties>\n";
for (size_t s2 = 0; s2 < p.value.compoundVal.size(); ++s2) {
const XurProperty& sp = p.value.compoundVal[s2];
if (sp.type == XurPropertyType_Object || sp.type == XurPropertyType_Custom) continue;
os << indentStr << " <" << sp.name << ">" << propValueToString(sp.value) << "</" << sp.name << ">\n";
}
os << indentStr << " </Properties>\n";
}
os << indentStr << "</" << p.name << ">\n";
}
os << indentStr << "</Properties>\n";
}
static void writeObjectContent(std::ostream& os, const XurObject& obj,
int depth, const std::string& indentStr) {
writeProperties(os, depth, obj.properties, indentStr);
if (!obj.namedFrames.empty() || !obj.timelines.empty()) {
os << indentStr << "<Timelines>\n";
if (!obj.namedFrames.empty()) {
os << indentStr << " <NamedFrames>\n";
for (size_t nfi = 0; nfi < obj.namedFrames.size(); ++nfi) {
const XurNamedFrame& nf = obj.namedFrames[nfi];
os << indentStr << " <NamedFrame>\n";
os << indentStr << " <Name>" << ws2s(nf.name) << "</Name>\n";
os << indentStr << " <Time>" << nf.keyframe << "</Time>\n";
if (nf.command != XurNamedFrameCommand_None) {
const char* cmdStr = "stop";
switch (nf.command) {
case XurNamedFrameCommand_Stop: cmdStr = "stop"; break;
case XurNamedFrameCommand_GotoAndStop: cmdStr = "gotostop"; break;
case XurNamedFrameCommand_GotoAndPlay: cmdStr = "gotoplay"; break;
case XurNamedFrameCommand_Play: cmdStr = "play"; break;
default: break;
}
os << indentStr << " <Command>" << cmdStr << "</Command>\n";
}
if (!nf.targetParameter.empty()) {
os << indentStr << " <TargetParameter>" << ws2s(nf.targetParameter) << "</TargetParameter>\n";
}
os << indentStr << " </NamedFrame>\n";
}
os << indentStr << " </NamedFrames>\n";
}
if (!obj.timelines.empty()) {
for (size_t tlw = 0; tlw < obj.timelines.size(); ++tlw) {
const XurTimeline& tl = obj.timelines[tlw];
os << indentStr << " <Timeline>\n";
os << indentStr << " <Target>" << ws2s(tl.elementName) << "</Target>\n";
for (size_t kwi = 0; kwi < tl.keyframes.size(); ++kwi) {
const XurKeyframe& kf = tl.keyframes[kwi];
os << indentStr << " <KeyFrame>\n";
os << indentStr << " <Time>" << kf.time << "</Time>\n";
const char* interpStr = "none";
switch (kf.interpolation) {
case XurInterpolationType_None: interpStr = "none"; break;
case XurInterpolationType_Linear: interpStr = "linear"; break;
case XurInterpolationType_EaseIn: interpStr = "easein"; break;
case XurInterpolationType_EaseOut: interpStr = "easeout"; break;
case XurInterpolationType_EaseInOut: interpStr = "easeinout"; break;
}
os << indentStr << " <Interpolation>" << interpStr << "</Interpolation>\n";
for (size_t kpi = 0; kpi < kf.properties.size(); ++kpi) {
const XurProperty& kfp = kf.properties[kpi];
os << indentStr << " <" << kfp.name << ">" << propValueToString(kfp.value) << "</" << kfp.name << ">\n";
}
os << indentStr << " </KeyFrame>\n";
}
os << indentStr << " </Timeline>\n";
}
}
os << indentStr << "</Timelines>\n";
}
for (size_t wci = 0; wci < obj.children.size(); ++wci) {
const XurObject& child = obj.children[wci];
std::string childIndent((size_t)(depth + 1) * 2, ' ');
os << childIndent << "<" << child.className << ">\n";
writeObjectContent(os, child, depth + 1, std::string((size_t)(depth + 2) * 2, ' '));
os << childIndent << "</" << child.className << ">\n";
}
}
std::string xurObjectToXuiXml(const XurObject& root) {
std::ostringstream os;
os << "<XuiCanvas version=\"000c\">\n";
writeObjectContent(os, root, 1, " ");
os << "</XuiCanvas>\n";
return os.str();
}
bool xurObjectToXuiXml(const XurObject& root, const std::string& path) {
std::ofstream ofs(path);
if (!ofs) return false;
ofs << xurObjectToXuiXml(root);
return ofs.good();
}
}
}
+231
View File
@@ -0,0 +1,231 @@
#include "ImXui/XzpPackage.h"
#include <algorithm>
#include <cstdio>
#include <cstring>
namespace ImXui {
namespace {
const uint32_t kXzpMagic = 0x55505A58;
uint32_t readU32BE(const uint8_t* p) {
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
((uint32_t)p[2] << 8) | (uint32_t)p[3];
}
uint16_t readU16BE(const uint8_t* p) {
return (uint16_t)(((uint16_t)p[0] << 8) | (uint16_t)p[1]);
}
void writeU32BE(std::vector<uint8_t>& out, uint32_t v) {
out.push_back((uint8_t)(v >> 24));
out.push_back((uint8_t)(v >> 16));
out.push_back((uint8_t)(v >> 8));
out.push_back((uint8_t)v);
}
std::string toLowerAscii(const std::string& s) {
std::string out = s;
for (size_t i = 0; i < out.size(); i++) {
if (out[i] >= 'A' && out[i] <= 'Z') out[i] = (char)(out[i] - 'A' + 'a');
}
return out;
}
}
XzpPackage::XzpPackage() : m_open(false), m_version(0) {}
XzpPackage::~XzpPackage() {}
void XzpPackage::reset() {
m_open = false;
m_version = 0;
m_buffer.clear();
m_entries.clear();
m_byName.clear();
}
bool XzpPackage::openMemory(const void* data, size_t size) {
reset();
if (!data || size < 24) return false;
const uint8_t* bytes = (const uint8_t*)data;
if (readU32BE(bytes) != kXzpMagic) return false;
m_version = (int)readU32BE(bytes + 4);
if (m_version != 1 && m_version != 3) return false;
int64_t dataOffset = (int64_t)readU32BE(bytes + 16) + 22;
int entryCount = (int)(int16_t)readU16BE(bytes + 20);
if (entryCount < 0 || entryCount > 65535) return false;
size_t pos = 22;
m_entries.resize((size_t)entryCount);
m_buffer.assign(bytes, bytes + size);
for (int i = 0; i < entryCount; i++) {
Entry& e = m_entries[(size_t)i];
if (pos + 9 > size) { reset(); return false; }
e.offset = readU32BE(m_buffer.data() + pos); pos += 4;
e.size = readU32BE(m_buffer.data() + pos); pos += 4;
uint8_t nameLenBytes = m_buffer[pos]; pos += 1;
if (pos + nameLenBytes > size) { reset(); return false; }
if (m_version == 1) {
std::wstring wname;
wname.reserve(nameLenBytes / 2);
for (int c = 0; c + 1 < (int)nameLenBytes; c += 2) {
wchar_t ch = (wchar_t)readU16BE(m_buffer.data() + pos + (size_t)c);
if (ch == 0) break;
wname.push_back(ch);
}
e.name.reserve(wname.size());
for (size_t c = 0; c < wname.size(); c++) {
wchar_t ch = wname[c];
e.name.push_back(ch <= 0x7F ? (char)ch : '?');
}
} else {
e.name.assign((const char*)m_buffer.data() + pos, nameLenBytes);
}
pos += nameLenBytes;
}
for (size_t i = 0; i < m_entries.size(); i++) {
Entry& e = m_entries[i];
uint64_t absOffset = (uint64_t)dataOffset + e.offset;
if (absOffset + e.size > size) { reset(); return false; }
e.offset = (uint32_t)absOffset;
}
for (size_t i = 0; i < m_entries.size(); i++) {
m_byName[toLowerAscii(m_entries[i].name)] = i;
}
m_open = true;
return true;
}
bool XzpPackage::openFile(const std::string& path) {
FILE* f = fopen(path.c_str(), "rb");
if (!f) return false;
bool ok = false;
fseek(f, 0, SEEK_END);
long fileSize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fileSize > 0) {
std::vector<uint8_t> buf((size_t)fileSize);
if (fread(buf.data(), 1, buf.size(), f) == buf.size()) {
ok = openMemory(buf.data(), buf.size());
}
}
fclose(f);
return ok;
}
const XzpPackage::Entry* XzpPackage::findEntry(const std::string& name) const {
std::map<std::string, size_t>::const_iterator it =
m_byName.find(toLowerAscii(name));
if (it == m_byName.end()) return nullptr;
return &m_entries[it->second];
}
const uint8_t* XzpPackage::entryData(const Entry& entry) const {
if (!m_open) return nullptr;
if ((uint64_t)entry.offset + entry.size > m_buffer.size()) return nullptr;
return m_buffer.data() + entry.offset;
}
bool XzpPackage::readEntry(const Entry& entry, std::vector<uint8_t>& out) const {
const uint8_t* src = entryData(entry);
if (!src) return false;
out.assign(src, src + entry.size);
return true;
}
bool XzpPackage::readEntryByName(const std::string& name, std::vector<uint8_t>& out) const {
const Entry* e = findEntry(name);
if (!e) return false;
return readEntry(*e, out);
}
void XzpWriter::addFile(const std::string& name, const void* data, size_t size) {
Item item;
item.name = name;
const uint8_t* bytes = (const uint8_t*)data;
item.data.assign(bytes, bytes + size);
m_items.push_back(item);
}
bool XzpWriter::build(std::vector<uint8_t>& out) const {
out.clear();
struct Layout {
std::string name;
uint32_t size;
uint32_t offset;
};
std::vector<Layout> layout;
layout.reserve(m_items.size());
uint32_t runningOffset = 0;
for (size_t i = 0; i < m_items.size(); i++) {
Layout l;
l.name = m_items[i].name;
l.size = (uint32_t)m_items[i].data.size();
l.offset = runningOffset;
runningOffset += l.size;
layout.push_back(l);
}
uint32_t tableSize = 0;
for (size_t i = 0; i < layout.size(); i++) {
tableSize += 4 + 4 + 1 + (uint32_t)layout[i].name.size();
}
uint32_t dataOffsetField = 22 + tableSize - 22;
writeU32BE(out, kXzpMagic);
writeU32BE(out, 3);
writeU32BE(out, 0);
writeU32BE(out, 0);
writeU32BE(out, dataOffsetField);
out.push_back((uint8_t)((layout.size() >> 8) & 0xFF));
out.push_back((uint8_t)(layout.size() & 0xFF));
for (size_t i = 0; i < layout.size(); i++) {
writeU32BE(out, layout[i].offset);
writeU32BE(out, layout[i].size);
out.push_back((uint8_t)layout[i].name.size());
out.insert(out.end(), layout[i].name.begin(), layout[i].name.end());
}
for (size_t i = 0; i < m_items.size(); i++) {
out.insert(out.end(), m_items[i].data.begin(), m_items[i].data.end());
}
uint32_t total = (uint32_t)out.size();
out[8] = (uint8_t)(total >> 24);
out[9] = (uint8_t)(total >> 16);
out[10] = (uint8_t)(total >> 8);
out[11] = (uint8_t)total;
return true;
}
}
+7988
View File
File diff suppressed because it is too large Load Diff
+1724
View File
File diff suppressed because it is too large Load Diff
+5079
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
Copyright notice:
(C) 1995-2022 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
+164
View File
@@ -0,0 +1,164 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2011, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#include "zutil.h"
#define BASE 65521U /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
/* use NO_DIVIDE if your processor does not do division in hardware --
try it both ways to see which is faster */
#ifdef NO_DIVIDE
/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
(thank you to John Reiser for pointing this out) */
# define CHOP(a) \
do { \
unsigned long tmp = a >> 16; \
a &= 0xffffUL; \
a += (tmp << 4) - tmp; \
} while (0)
# define MOD28(a) \
do { \
CHOP(a); \
if (a >= BASE) a -= BASE; \
} while (0)
# define MOD(a) \
do { \
CHOP(a); \
MOD28(a); \
} while (0)
# define MOD63(a) \
do { /* this assumes a is not negative */ \
z_off64_t tmp = a >> 32; \
a &= 0xffffffffL; \
a += (tmp << 8) - (tmp << 5) + tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
if (a >= BASE) a -= BASE; \
} while (0)
#else
# define MOD(a) a %= BASE
# define MOD28(a) a %= BASE
# define MOD63(a) a %= BASE
#endif
/* ========================================================================= */
uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) {
unsigned long sum2;
unsigned n;
/* split Adler-32 into component sums */
sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (len == 1) {
adler += buf[0];
if (adler >= BASE)
adler -= BASE;
sum2 += adler;
if (sum2 >= BASE)
sum2 -= BASE;
return adler | (sum2 << 16);
}
/* initial Adler-32 value (deferred check for len == 1 speed) */
if (buf == Z_NULL)
return 1L;
/* in case short lengths are provided, keep it somewhat fast */
if (len < 16) {
while (len--) {
adler += *buf++;
sum2 += adler;
}
if (adler >= BASE)
adler -= BASE;
MOD28(sum2); /* only added so many BASE's */
return adler | (sum2 << 16);
}
/* do length NMAX blocks -- requires just one modulo operation */
while (len >= NMAX) {
len -= NMAX;
n = NMAX / 16; /* NMAX is divisible by 16 */
do {
DO16(buf); /* 16 sums unrolled */
buf += 16;
} while (--n);
MOD(adler);
MOD(sum2);
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if (len) { /* avoid modulos if none remaining */
while (len >= 16) {
len -= 16;
DO16(buf);
buf += 16;
}
while (len--) {
adler += *buf++;
sum2 += adler;
}
MOD(adler);
MOD(sum2);
}
/* return recombined sums */
return adler | (sum2 << 16);
}
/* ========================================================================= */
uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) {
return adler32_z(adler, buf, len);
}
/* ========================================================================= */
local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) {
unsigned long sum1;
unsigned long sum2;
unsigned rem;
/* for negative len, return invalid adler32 as a clue for debugging */
if (len2 < 0)
return 0xffffffffUL;
/* the derivation of this formula is left as an exercise for the reader */
MOD63(len2); /* assumes len2 >= 0 */
rem = (unsigned)len2;
sum1 = adler1 & 0xffff;
sum2 = rem * sum1;
MOD(sum2);
sum1 += (adler2 & 0xffff) + BASE - 1;
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if (sum1 >= BASE) sum1 -= BASE;
if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}
/* ========================================================================= */
uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) {
return adler32_combine_(adler1, adler2, len2);
}
uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) {
return adler32_combine_(adler1, adler2, len2);
}
+75
View File
@@ -0,0 +1,75 @@
/* compress.c -- compress a memory buffer
* Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#define ZLIB_INTERNAL
#include "zlib.h"
/* ===========================================================================
Compresses the source buffer into the destination buffer. The level
parameter has the same meaning as in deflateInit. sourceLen is the byte
length of the source buffer. Upon entry, destLen is the total size of the
destination buffer, which must be at least 0.1% larger than sourceLen plus
12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
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,
Z_STREAM_ERROR if the level parameter is invalid.
*/
int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen, int level) {
z_stream stream;
int err;
const uInt max = (uInt)-1;
uLong left;
left = *destLen;
*destLen = 0;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = deflateInit(&stream, level);
if (err != Z_OK) return err;
stream.next_out = dest;
stream.avail_out = 0;
stream.next_in = (z_const Bytef *)source;
stream.avail_in = 0;
do {
if (stream.avail_out == 0) {
stream.avail_out = left > (uLong)max ? max : (uInt)left;
left -= stream.avail_out;
}
if (stream.avail_in == 0) {
stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen;
sourceLen -= stream.avail_in;
}
err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);
} while (err == Z_OK);
*destLen = stream.total_out;
deflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK : err;
}
/* ===========================================================================
*/
int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen) {
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
}
/* ===========================================================================
If the default memLevel or windowBits for deflateInit() is changed, then
this function needs to be updated.
*/
uLong ZEXPORT compressBound(uLong sourceLen) {
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
(sourceLen >> 25) + 13;
}
+1049
View File
File diff suppressed because it is too large Load Diff
+9446
View File
File diff suppressed because it is too large Load Diff
+2139
View File
File diff suppressed because it is too large Load Diff
+377
View File
@@ -0,0 +1,377 @@
/* deflate.h -- internal compression state
* Copyright (C) 1995-2024 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
/* @(#) $Id$ */
#ifndef DEFLATE_H
#define DEFLATE_H
#include "zutil.h"
/* define NO_GZIP when compiling if you want to disable gzip header and
trailer creation by deflate(). NO_GZIP would be used to avoid linking in
the crc code when it is not needed. For shared libraries, gzip encoding
should be left enabled. */
#ifndef NO_GZIP
# define GZIP
#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.
*/
#define LENGTH_CODES 29
/* number of length codes, not counting the special END_BLOCK code */
#define LITERALS 256
/* number of literal bytes 0..255 */
#define L_CODES (LITERALS+1+LENGTH_CODES)
/* number of Literal or Length codes, including the END_BLOCK code */
#define D_CODES 30
/* number of distance codes */
#define BL_CODES 19
/* number of codes used to transfer the bit lengths */
#define HEAP_SIZE (2*L_CODES+1)
/* maximum heap size */
#define MAX_BITS 15
/* All codes must not exceed MAX_BITS bits */
#define Buf_size 16
/* size of bit buffer in bi_buf */
#define INIT_STATE 42 /* zlib header -> BUSY_STATE */
#ifdef GZIP
# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */
#endif
#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */
#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */
#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 */
/* Data structure describing a single value and its code string. */
typedef struct ct_data_s {
union {
ush freq; /* frequency count */
ush code; /* bit string */
} fc;
union {
ush dad; /* father node in Huffman tree */
ush len; /* length of bit string */
} dl;
} FAR ct_data;
#define Freq fc.freq
#define Code fc.code
#define Dad dl.dad
#define Len dl.len
typedef struct static_tree_desc_s static_tree_desc;
typedef struct tree_desc_s {
ct_data *dyn_tree; /* the dynamic tree */
int max_code; /* largest code with non zero frequency */
const static_tree_desc *stat_desc; /* the corresponding static tree */
} FAR tree_desc;
typedef ush Pos;
typedef Pos FAR Posf;
typedef unsigned IPos;
/* A Pos is an index in the character window. We use short instead of int to
* save space in the various tables. IPos is used only for parameter passing.
*/
typedef struct internal_state {
z_streamp strm; /* pointer back to this zlib stream */
int status; /* as the name implies */
Bytef *pending_buf; /* output still pending */
ulg pending_buf_size; /* size of pending_buf */
Bytef *pending_out; /* next pending byte to output to the stream */
ulg pending; /* nb of bytes in the pending buffer */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
gz_headerp gzhead; /* gzip header information to write */
ulg gzindex; /* where in extra, name, or comment */
Byte method; /* can only be DEFLATED */
int last_flush; /* value of flush param for previous deflate call */
/* used by deflate.c: */
uInt w_size; /* LZ77 window size (32K by default) */
uInt w_bits; /* log2(w_size) (8..16) */
uInt w_mask; /* w_size - 1 */
Bytef *window;
/* Sliding window. Input bytes are read into the second half of the window,
* and move to the first half later to keep a dictionary of at least wSize
* bytes. With this organization, matches are limited to a distance of
* wSize-MAX_MATCH bytes, but this ensures that IO is always
* performed with a length multiple of the block size. Also, it limits
* the window size to 64K, which is quite useful on MSDOS.
* To do: use the user input buffer as sliding window.
*/
ulg window_size;
/* Actual size of window: 2*wSize, except when the user input buffer
* is directly used as sliding window.
*/
Posf *prev;
/* Link to older string with same hash index. To limit the size of this
* array to 64K, this link is maintained only for the last 32K strings.
* An index in this array is thus a window index modulo 32K.
*/
Posf *head; /* Heads of the hash chains or NIL. */
uInt ins_h; /* hash index of string to be inserted */
uInt hash_size; /* number of elements in hash table */
uInt hash_bits; /* log2(hash_size) */
uInt hash_mask; /* hash_size-1 */
uInt hash_shift;
/* Number of bits by which ins_h must be shifted at each input
* step. It must be such that after MIN_MATCH steps, the oldest
* byte no longer takes part in the hash key, that is:
* hash_shift * MIN_MATCH >= hash_bits
*/
long block_start;
/* Window position at the beginning of the current output block. Gets
* negative when the window is moved backwards.
*/
uInt match_length; /* length of best match */
IPos prev_match; /* previous match */
int match_available; /* set if previous match exists */
uInt strstart; /* start of string to insert */
uInt match_start; /* start of matching string */
uInt lookahead; /* number of valid bytes ahead in window */
uInt prev_length;
/* Length of the best match at previous step. Matches not greater than this
* are discarded. This is used in the lazy match evaluation.
*/
uInt max_chain_length;
/* To speed up deflation, hash chains are never searched beyond this
* length. A higher limit improves compression ratio but degrades the
* speed.
*/
uInt max_lazy_match;
/* Attempt to find a better match only when the current match is strictly
* smaller than this value. This mechanism is used only for compression
* levels >= 4.
*/
# define max_insert_length max_lazy_match
/* Insert new strings in the hash table only if the match length is not
* greater than this length. This saves time but degrades compression.
* max_insert_length is used only for compression levels <= 3.
*/
int level; /* compression level (1..9) */
int strategy; /* favor or force Huffman coding*/
uInt good_match;
/* Use a faster search when the previous match is longer than this */
int nice_match; /* Stop searching when current match exceeds this */
/* used by trees.c: */
/* Didn't use ct_data typedef below to suppress compiler warning */
struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
struct tree_desc_s l_desc; /* desc. for literal tree */
struct tree_desc_s d_desc; /* desc. for distance tree */
struct tree_desc_s bl_desc; /* desc. for bit length tree */
ush bl_count[MAX_BITS+1];
/* number of codes at each bit length for an optimal tree */
int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
int heap_len; /* number of elements in the heap */
int heap_max; /* element of largest frequency */
/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
* The same heap array is used to build all trees.
*/
uch depth[2*L_CODES+1];
/* Depth of each subtree used as tie breaker for trees of equal frequency
*/
#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;
/* Size of match buffer for literals/lengths. There are 4 reasons for
* limiting lit_bufsize to 64K:
* - frequencies can be kept in 16 bit counters
* - if compression is not successful for the first block, all input
* data is still in the window so we can still emit a stored block even
* when input comes from standard input. (This can also be done for
* all blocks if lit_bufsize is not greater than 32K.)
* - if compression is not successful for a file smaller than 64K, we can
* even emit a stored file instead of a stored block (saving 5 bytes).
* This is applicable only for zip (not gzip or zlib).
* - creating new Huffman trees less frequently may not provide fast
* adaptation to changes in the input data statistics. (Take for
* example a binary file with poorly compressible code followed by
* a highly compressible string table.) Smaller buffer sizes give
* fast adaptation but have of course the overhead of transmitting
* trees more frequently.
* - I can't count above 4
*/
uInt sym_next; /* running index in symbol buffer */
uInt sym_end; /* symbol table full when sym_next reaches this */
ulg opt_len; /* bit length of current block with optimal trees */
ulg static_len; /* bit length of current block with static trees */
uInt matches; /* number of string matches in current block */
uInt insert; /* bytes at end of window left to insert */
#ifdef ZLIB_DEBUG
ulg compressed_len; /* total bit length of compressed file mod 2^32 */
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
#endif
ush bi_buf;
/* Output buffer. bits are inserted starting at the bottom (least
* significant bits).
*/
int bi_valid;
/* Number of valid bits in bi_buf. All bits above the last valid bit
* are always zero.
*/
ulg high_water;
/* High water mark offset in window for initialized bytes -- bytes above
* this are set to zero in order to avoid memory check warnings when
* longest match routines access bytes past the input. This is then
* updated to the new high water mark.
*/
} FAR deflate_state;
/* Output a byte on the stream.
* IN assertion: there is enough room in pending_buf.
*/
#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);}
#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
/* Minimum amount of lookahead, except at the end of the input file.
* See deflate.c for comments about the MIN_MATCH+1.
*/
#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
/* In order to simplify the code, particularly on 16 bit machines, match
* distances are limited to MAX_DIST instead of WSIZE.
*/
#define WIN_INIT MAX_MATCH
/* Number of bytes after end of data in window to initialize in order to avoid
memory checker errors from longest match routines */
/* in trees.c */
void ZLIB_INTERNAL _tr_init(deflate_state *s);
int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc);
void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
ulg stored_len, int last);
void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s);
void ZLIB_INTERNAL _tr_align(deflate_state *s);
void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
ulg stored_len, int last);
#define d_code(dist) \
((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
/* Mapping from a distance to a distance code. dist is the distance - 1 and
* must not have side effects. _dist_code[256] and _dist_code[257] are never
* used.
*/
#ifndef ZLIB_DEBUG
/* Inline versions of _tr_tally for speed: */
#if defined(GEN_TREES_H) || !defined(STDC)
extern uch ZLIB_INTERNAL _length_code[];
extern uch ZLIB_INTERNAL _dist_code[];
#else
extern const uch ZLIB_INTERNAL _length_code[];
extern const uch ZLIB_INTERNAL _dist_code[];
#endif
#ifdef LIT_MEM
# define _tr_tally_lit(s, c, flush) \
{ uch cc = (c); \
s->d_buf[s->sym_next] = 0; \
s->l_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->d_buf[s->sym_next] = dist; \
s->l_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); \
}
#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_dist(s, distance, length, flush) \
flush = _tr_tally(s, distance, length)
#endif
#endif /* DEFLATE_H */
+214
View File
@@ -0,0 +1,214 @@
/* gzguts.h -- zlib internal header definitions for gz* operations
* Copyright (C) 2004-2024 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef _LARGEFILE64_SOURCE
# ifndef _LARGEFILE_SOURCE
# define _LARGEFILE_SOURCE 1
# endif
# undef _FILE_OFFSET_BITS
# undef _TIME_BITS
#endif
#ifdef HAVE_HIDDEN
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
# define ZLIB_INTERNAL
#endif
#include <stdio.h>
#include "zlib.h"
#ifdef STDC
# include <string.h>
# include <stdlib.h>
# include <limits.h>
#endif
#ifndef _POSIX_SOURCE
# define _POSIX_SOURCE
#endif
#include <fcntl.h>
#ifdef _WIN32
# include <stddef.h>
#endif
#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
# include <io.h>
#endif
#if defined(_WIN32)
# define WIDECHAR
#endif
#ifdef WINAPI_FAMILY
# define open _open
# define read _read
# define write _write
# define close _close
#endif
#ifdef NO_DEFLATE /* for compatibility with old definition */
# define NO_GZCOMPRESS
#endif
#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#if defined(__CYGWIN__)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#ifndef HAVE_VSNPRINTF
# ifdef MSDOS
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
but for now we just assume it doesn't. */
# define NO_vsnprintf
# endif
# ifdef __TURBOC__
# define NO_vsnprintf
# endif
# ifdef WIN32
/* 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 )
# define vsnprintf _vsnprintf
# endif
# endif
# endif
# ifdef __SASC
# define NO_vsnprintf
# endif
# ifdef VMS
# define NO_vsnprintf
# endif
# ifdef __OS400__
# define NO_vsnprintf
# endif
# ifdef __MVS__
# define NO_vsnprintf
# endif
#endif
/* unlike snprintf (which is required in C99), _snprintf does not guarantee
null termination of the result -- however this is only used in gzlib.c where
the result is assured to fit in the space provided */
#if defined(_MSC_VER) && _MSC_VER < 1900
# define snprintf _snprintf
#endif
#ifndef local
# define local static
#endif
/* 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 */
#ifndef STDC
extern voidp malloc(uInt size);
extern void free(voidpf ptr);
#endif
/* get errno and strerror definition */
#if defined UNDER_CE
# include <windows.h>
# define zstrerror() gz_strwinerror((DWORD)GetLastError())
#else
# ifndef NO_STRERROR
# include <errno.h>
# define zstrerror() strerror(errno)
# else
# define zstrerror() "stdio error (consult errno)"
# endif
#endif
/* provide prototypes for these when building zlib without LFS */
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int);
ZEXTERN z_off64_t ZEXPORT gztell64(gzFile);
ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile);
#endif
/* default memLevel */
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif
/* default i/o buffer size -- double this for output when reading (this and
twice this must be able to fit in an unsigned type) */
#define GZBUFSIZE 8192
/* gzip modes, also provide a little integrity check on the passed structure */
#define GZ_NONE 0
#define GZ_READ 7247
#define GZ_WRITE 31153
#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */
/* values for gz_state how */
#define LOOK 0 /* look for a gzip header */
#define COPY 1 /* copy input directly */
#define GZIP 2 /* decompress a gzip stream */
/* internal gzip file state data structure */
typedef struct {
/* exposed contents for gzgetc() macro */
struct gzFile_s x; /* "x" for exposed */
/* x.have: number of bytes available at x.next */
/* x.next: next output data to deliver or write */
/* x.pos: current position in uncompressed data */
/* used for both reading and writing */
int mode; /* see gzip modes above */
int fd; /* file descriptor */
char *path; /* path or fd for error messages */
unsigned size; /* buffer size, zero if not allocated yet */
unsigned want; /* requested buffer size, default is GZBUFSIZE */
unsigned char *in; /* input buffer (double-sized when writing) */
unsigned char *out; /* output buffer (double-sized when reading) */
int direct; /* 0 if processing gzip, 1 if transparent */
/* just for reading */
int how; /* 0: get header, 1: copy, 2: decompress */
z_off64_t start; /* where the gzip data started, for rewinding */
int eof; /* true if end of input file reached */
int past; /* true if read requested past end */
/* just for writing */
int level; /* compression level */
int strategy; /* compression strategy */
int reset; /* true if a reset is pending after a Z_FINISH */
/* seek request */
z_off64_t skip; /* amount to skip (already rewound if backwards) */
int seek; /* true if seek request pending */
/* error information */
int err; /* error code */
char *msg; /* error message */
/* zlib inflate or deflate stream */
z_stream strm; /* stream structure in-place (not a pointer) */
} gz_state;
typedef gz_state FAR *gz_statep;
/* shared functions */
void ZLIB_INTERNAL gz_error(gz_statep, int, const char *);
#if defined UNDER_CE
char ZLIB_INTERNAL *gz_strwinerror(DWORD error);
#endif
/* 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
(possible z_off64_t types off_t, off64_t, and long are all signed) */
unsigned ZLIB_INTERNAL gz_intmax(void);
#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
+628
View File
@@ -0,0 +1,628 @@
/* infback.c -- inflate using a call-back interface
* Copyright (C) 1995-2022 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/*
This code is largely copied from inflate.c. Normally either infback.o or
inflate.o would be linked into an application--not both. The interface
with inffast.c is retained so that optimized assembler-coded versions of
inflate_fast() can be used with either inflate.c or infback.c.
*/
#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"
/*
strm provides memory allocation functions in zalloc and zfree, or
Z_NULL to use the library memory allocation functions.
windowBits is in the range 8..15, and window is a user-supplied
window and output buffer that is 2**windowBits bytes.
*/
int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,
unsigned char FAR *window, const char *version,
int stream_size) {
struct inflate_state FAR *state;
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
stream_size != (int)(sizeof(z_stream)))
return Z_VERSION_ERROR;
if (strm == Z_NULL || window == Z_NULL ||
windowBits < 8 || windowBits > 15)
return Z_STREAM_ERROR;
strm->msg = Z_NULL; /* in case we return an error */
if (strm->zalloc == (alloc_func)0) {
#ifdef Z_SOLO
return Z_STREAM_ERROR;
#else
strm->zalloc = zcalloc;
strm->opaque = (voidpf)0;
#endif
}
if (strm->zfree == (free_func)0)
#ifdef Z_SOLO
return Z_STREAM_ERROR;
#else
strm->zfree = zcfree;
#endif
state = (struct inflate_state FAR *)ZALLOC(strm, 1,
sizeof(struct inflate_state));
if (state == Z_NULL) return Z_MEM_ERROR;
Tracev((stderr, "inflate: allocated\n"));
strm->state = (struct internal_state FAR *)state;
state->dmax = 32768U;
state->wbits = (uInt)windowBits;
state->wsize = 1U << windowBits;
state->window = window;
state->wnext = 0;
state->whave = 0;
state->sane = 1;
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(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(): */
/* Load returned state from inflate_fast() */
#define LOAD() \
do { \
put = strm->next_out; \
left = strm->avail_out; \
next = strm->next_in; \
have = strm->avail_in; \
hold = state->hold; \
bits = state->bits; \
} while (0)
/* Set state from registers for inflate_fast() */
#define RESTORE() \
do { \
strm->next_out = put; \
strm->avail_out = left; \
strm->next_in = next; \
strm->avail_in = have; \
state->hold = hold; \
state->bits = bits; \
} while (0)
/* Clear the input bit accumulator */
#define INITBITS() \
do { \
hold = 0; \
bits = 0; \
} while (0)
/* Assure that some input is available. If input is requested, but denied,
then return a Z_BUF_ERROR from inflateBack(). */
#define PULL() \
do { \
if (have == 0) { \
have = in(in_desc, &next); \
if (have == 0) { \
next = Z_NULL; \
ret = Z_BUF_ERROR; \
goto inf_leave; \
} \
} \
} while (0)
/* Get a byte of input into the bit accumulator, or return from inflateBack()
with an error if there is no input available. */
#define PULLBYTE() \
do { \
PULL(); \
have--; \
hold += (unsigned long)(*next++) << bits; \
bits += 8; \
} while (0)
/* Assure that there are at least n bits in the bit accumulator. If there is
not enough available input to do that, then return from inflateBack() with
an error. */
#define NEEDBITS(n) \
do { \
while (bits < (unsigned)(n)) \
PULLBYTE(); \
} while (0)
/* Return the low n bits of the bit accumulator (n < 16) */
#define BITS(n) \
((unsigned)hold & ((1U << (n)) - 1))
/* Remove n bits from the bit accumulator */
#define DROPBITS(n) \
do { \
hold >>= (n); \
bits -= (unsigned)(n); \
} while (0)
/* Remove zero to seven bits as needed to go to a byte boundary */
#define BYTEBITS() \
do { \
hold >>= bits & 7; \
bits -= bits & 7; \
} while (0)
/* Assure that some output space is available, by writing out the window
if it's full. If the write fails, return from inflateBack() with a
Z_BUF_ERROR. */
#define ROOM() \
do { \
if (left == 0) { \
put = state->window; \
left = state->wsize; \
state->whave = left; \
if (out(out_desc, put, left)) { \
ret = Z_BUF_ERROR; \
goto inf_leave; \
} \
} \
} while (0)
/*
strm provides the memory allocation functions and window buffer on input,
and provides information on the unused input on return. For Z_DATA_ERROR
returns, strm will also provide an error message.
in() and out() are the call-back input and output functions. When
inflateBack() needs more input, it calls in(). When inflateBack() has
filled the window with output, or when it completes with data in the
window, it calls out() to write out the data. The application must not
change the provided input until in() is called again or inflateBack()
returns. The application must not change the window/output buffer until
inflateBack() returns.
in() and out() are called with a descriptor parameter provided in the
inflateBack() call. This parameter can be a structure that provides the
information required to do the read or write, as well as accumulated
information on the input and output such as totals and check values.
in() should return zero on failure. out() should return non-zero on
failure. If either in() or out() fails, than inflateBack() returns a
Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
was in() or out() that caused in the error. Otherwise, inflateBack()
returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
error, or Z_MEM_ERROR if it could not allocate memory for the state.
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.
*/
int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
out_func out, void FAR *out_desc) {
struct inflate_state FAR *state;
z_const unsigned char FAR *next; /* next input */
unsigned char FAR *put; /* next output */
unsigned have, left; /* available input and output */
unsigned long hold; /* bit buffer */
unsigned bits; /* bits in bit buffer */
unsigned copy; /* number of stored or match bytes to copy */
unsigned char FAR *from; /* where to copy match bytes from */
code here; /* current decoding table entry */
code last; /* parent table entry */
unsigned len; /* length to copy for repeats, bits to drop */
int ret; /* return code */
static const unsigned short order[19] = /* permutation of code lengths */
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
/* Check that the strm exists and that the state was initialized */
if (strm == Z_NULL || strm->state == Z_NULL)
return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
/* Reset the state */
strm->msg = Z_NULL;
state->mode = TYPE;
state->last = 0;
state->whave = 0;
next = strm->next_in;
have = next != Z_NULL ? strm->avail_in : 0;
hold = 0;
bits = 0;
put = state->window;
left = state->wsize;
/* Inflate until end of block marked as last */
for (;;)
switch (state->mode) {
case TYPE:
/* determine and dispatch block type */
if (state->last) {
BYTEBITS();
state->mode = DONE;
break;
}
NEEDBITS(3);
state->last = BITS(1);
DROPBITS(1);
switch (BITS(2)) {
case 0: /* stored block */
Tracev((stderr, "inflate: stored block%s\n",
state->last ? " (last)" : ""));
state->mode = STORED;
break;
case 1: /* fixed block */
fixedtables(state);
Tracev((stderr, "inflate: fixed codes block%s\n",
state->last ? " (last)" : ""));
state->mode = LEN; /* decode codes */
break;
case 2: /* dynamic block */
Tracev((stderr, "inflate: dynamic codes block%s\n",
state->last ? " (last)" : ""));
state->mode = TABLE;
break;
case 3:
strm->msg = (char *)"invalid block type";
state->mode = BAD;
}
DROPBITS(2);
break;
case STORED:
/* get and verify stored block length */
BYTEBITS(); /* go to byte boundary */
NEEDBITS(32);
if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
strm->msg = (char *)"invalid stored block lengths";
state->mode = BAD;
break;
}
state->length = (unsigned)hold & 0xffff;
Tracev((stderr, "inflate: stored length %u\n",
state->length));
INITBITS();
/* copy stored block from input to output */
while (state->length != 0) {
copy = state->length;
PULL();
ROOM();
if (copy > have) copy = have;
if (copy > left) copy = left;
zmemcpy(put, next, copy);
have -= copy;
next += copy;
left -= copy;
put += copy;
state->length -= copy;
}
Tracev((stderr, "inflate: stored end\n"));
state->mode = TYPE;
break;
case TABLE:
/* get dynamic table entries descriptor */
NEEDBITS(14);
state->nlen = BITS(5) + 257;
DROPBITS(5);
state->ndist = BITS(5) + 1;
DROPBITS(5);
state->ncode = BITS(4) + 4;
DROPBITS(4);
#ifndef PKZIP_BUG_WORKAROUND
if (state->nlen > 286 || state->ndist > 30) {
strm->msg = (char *)"too many length or distance symbols";
state->mode = BAD;
break;
}
#endif
Tracev((stderr, "inflate: table sizes ok\n"));
/* get code length code lengths (not a typo) */
state->have = 0;
while (state->have < state->ncode) {
NEEDBITS(3);
state->lens[order[state->have++]] = (unsigned short)BITS(3);
DROPBITS(3);
}
while (state->have < 19)
state->lens[order[state->have++]] = 0;
state->next = state->codes;
state->lencode = (code const FAR *)(state->next);
state->lenbits = 7;
ret = inflate_table(CODES, state->lens, 19, &(state->next),
&(state->lenbits), state->work);
if (ret) {
strm->msg = (char *)"invalid code lengths set";
state->mode = BAD;
break;
}
Tracev((stderr, "inflate: code lengths ok\n"));
/* get length and distance code code lengths */
state->have = 0;
while (state->have < state->nlen + state->ndist) {
for (;;) {
here = state->lencode[BITS(state->lenbits)];
if ((unsigned)(here.bits) <= bits) break;
PULLBYTE();
}
if (here.val < 16) {
DROPBITS(here.bits);
state->lens[state->have++] = here.val;
}
else {
if (here.val == 16) {
NEEDBITS(here.bits + 2);
DROPBITS(here.bits);
if (state->have == 0) {
strm->msg = (char *)"invalid bit length repeat";
state->mode = BAD;
break;
}
len = (unsigned)(state->lens[state->have - 1]);
copy = 3 + BITS(2);
DROPBITS(2);
}
else if (here.val == 17) {
NEEDBITS(here.bits + 3);
DROPBITS(here.bits);
len = 0;
copy = 3 + BITS(3);
DROPBITS(3);
}
else {
NEEDBITS(here.bits + 7);
DROPBITS(here.bits);
len = 0;
copy = 11 + BITS(7);
DROPBITS(7);
}
if (state->have + copy > state->nlen + state->ndist) {
strm->msg = (char *)"invalid bit length repeat";
state->mode = BAD;
break;
}
while (copy--)
state->lens[state->have++] = (unsigned short)len;
}
}
/* handle error breaks in while */
if (state->mode == BAD) break;
/* check for end-of-block code (better have one) */
if (state->lens[256] == 0) {
strm->msg = (char *)"invalid code -- missing end-of-block";
state->mode = BAD;
break;
}
/* build code tables -- note: do not change the lenbits or distbits
values here (9 and 6) without reading the comments in inftrees.h
concerning the ENOUGH constants, which depend on those values */
state->next = state->codes;
state->lencode = (code const FAR *)(state->next);
state->lenbits = 9;
ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
&(state->lenbits), state->work);
if (ret) {
strm->msg = (char *)"invalid literal/lengths set";
state->mode = BAD;
break;
}
state->distcode = (code const FAR *)(state->next);
state->distbits = 6;
ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
&(state->next), &(state->distbits), state->work);
if (ret) {
strm->msg = (char *)"invalid distances set";
state->mode = BAD;
break;
}
Tracev((stderr, "inflate: codes ok\n"));
state->mode = LEN;
/* fallthrough */
case LEN:
/* use inflate_fast() if we have enough input and output */
if (have >= 6 && left >= 258) {
RESTORE();
if (state->whave < state->wsize)
state->whave = state->wsize - left;
inflate_fast(strm, state->wsize);
LOAD();
break;
}
/* get a literal, length, or end-of-block code */
for (;;) {
here = state->lencode[BITS(state->lenbits)];
if ((unsigned)(here.bits) <= bits) break;
PULLBYTE();
}
if (here.op && (here.op & 0xf0) == 0) {
last = here;
for (;;) {
here = state->lencode[last.val +
(BITS(last.bits + last.op) >> last.bits)];
if ((unsigned)(last.bits + here.bits) <= bits) break;
PULLBYTE();
}
DROPBITS(last.bits);
}
DROPBITS(here.bits);
state->length = (unsigned)here.val;
/* process literal */
if (here.op == 0) {
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
"inflate: literal '%c'\n" :
"inflate: literal 0x%02x\n", here.val));
ROOM();
*put++ = (unsigned char)(state->length);
left--;
state->mode = LEN;
break;
}
/* process end of block */
if (here.op & 32) {
Tracevv((stderr, "inflate: end of block\n"));
state->mode = TYPE;
break;
}
/* invalid code */
if (here.op & 64) {
strm->msg = (char *)"invalid literal/length code";
state->mode = BAD;
break;
}
/* length code -- get extra bits, if any */
state->extra = (unsigned)(here.op) & 15;
if (state->extra != 0) {
NEEDBITS(state->extra);
state->length += BITS(state->extra);
DROPBITS(state->extra);
}
Tracevv((stderr, "inflate: length %u\n", state->length));
/* get distance code */
for (;;) {
here = state->distcode[BITS(state->distbits)];
if ((unsigned)(here.bits) <= bits) break;
PULLBYTE();
}
if ((here.op & 0xf0) == 0) {
last = here;
for (;;) {
here = state->distcode[last.val +
(BITS(last.bits + last.op) >> last.bits)];
if ((unsigned)(last.bits + here.bits) <= bits) break;
PULLBYTE();
}
DROPBITS(last.bits);
}
DROPBITS(here.bits);
if (here.op & 64) {
strm->msg = (char *)"invalid distance code";
state->mode = BAD;
break;
}
state->offset = (unsigned)here.val;
/* get distance extra bits, if any */
state->extra = (unsigned)(here.op) & 15;
if (state->extra != 0) {
NEEDBITS(state->extra);
state->offset += BITS(state->extra);
DROPBITS(state->extra);
}
if (state->offset > state->wsize - (state->whave < state->wsize ?
left : 0)) {
strm->msg = (char *)"invalid distance too far back";
state->mode = BAD;
break;
}
Tracevv((stderr, "inflate: distance %u\n", state->offset));
/* copy match from window to output */
do {
ROOM();
copy = state->wsize - state->offset;
if (copy < left) {
from = put + copy;
copy = left - copy;
}
else {
from = put - state->offset;
copy = left;
}
if (copy > state->length) copy = state->length;
state->length -= copy;
left -= copy;
do {
*put++ = *from++;
} while (--copy);
} while (state->length != 0);
break;
case DONE:
/* inflate stream terminated properly */
ret = Z_STREAM_END;
goto inf_leave;
case BAD:
ret = Z_DATA_ERROR;
goto inf_leave;
default:
/* can't happen, but makes compilers happy */
ret = Z_STREAM_ERROR;
goto inf_leave;
}
/* Write leftover output and return unused input */
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->avail_in = have;
return ret;
}
int ZEXPORT inflateBackEnd(z_streamp strm) {
if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
return Z_STREAM_ERROR;
ZFREE(strm, strm->state);
strm->state = Z_NULL;
Tracev((stderr, "inflate: end\n"));
return Z_OK;
}
+320
View File
@@ -0,0 +1,320 @@
/* inffast.c -- fast decoding
* Copyright (C) 1995-2017 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"
#ifdef ASMINF
# pragma message("Assembler code may have bugs -- use at your own risk")
#else
/*
Decode literal, length, and distance codes and write out the resulting
literal and match bytes until either not enough input or output is
available, an end-of-block is encountered, or a data error is encountered.
When large enough input and output buffers are supplied to inflate(), for
example, a 16K input buffer and a 64K output buffer, more than 95% of the
inflate execution time is spent in this routine.
Entry assumptions:
state->mode == LEN
strm->avail_in >= 6
strm->avail_out >= 258
start >= strm->avail_out
state->bits < 8
On return, state->mode is one of:
LEN -- ran out of enough output space or enough available input
TYPE -- reached end of block code, inflate() to interpret next block
BAD -- error in block data
Notes:
- The maximum input bits used by a length/distance pair is 15 bits for the
length code, 5 bits for the length extra, 15 bits for the distance code,
and 13 bits for the distance extra. This totals 48 bits, or six bytes.
Therefore if strm->avail_in >= 6, then there is enough input to avoid
checking for available input while decoding.
- The maximum bytes that a single length/distance pair can output is 258
bytes, which is the maximum length that can be coded. inflate_fast()
requires strm->avail_out >= 258 for each loop to avoid checking for
output space.
*/
void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
struct inflate_state FAR *state;
z_const unsigned char FAR *in; /* local strm->next_in */
z_const unsigned char FAR *last; /* have enough input while in < last */
unsigned char FAR *out; /* local strm->next_out */
unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
unsigned char FAR *end; /* while out < end, enough space available */
#ifdef INFLATE_STRICT
unsigned dmax; /* maximum distance from zlib header */
#endif
unsigned wsize; /* window size or zero if not using window */
unsigned whave; /* valid bytes in the window */
unsigned wnext; /* window write index */
unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
unsigned long hold; /* local strm->hold */
unsigned bits; /* local strm->bits */
code const FAR *lcode; /* local strm->lencode */
code const FAR *dcode; /* local strm->distcode */
unsigned lmask; /* mask for first level of length codes */
unsigned dmask; /* mask for first level of distance codes */
code const *here; /* retrieved table entry */
unsigned op; /* code bits, operation, extra bits, or */
/* window position, window bytes to copy */
unsigned len; /* match length, unused bytes */
unsigned dist; /* match distance */
unsigned char FAR *from; /* where to copy match from */
/* copy state to local variables */
state = (struct inflate_state FAR *)strm->state;
in = strm->next_in;
last = in + (strm->avail_in - 5);
out = strm->next_out;
beg = out - (start - strm->avail_out);
end = out + (strm->avail_out - 257);
#ifdef INFLATE_STRICT
dmax = state->dmax;
#endif
wsize = state->wsize;
whave = state->whave;
wnext = state->wnext;
window = state->window;
hold = state->hold;
bits = state->bits;
lcode = state->lencode;
dcode = state->distcode;
lmask = (1U << state->lenbits) - 1;
dmask = (1U << state->distbits) - 1;
/* decode literals and length/distances until end-of-block or not enough
input data or output space */
do {
if (bits < 15) {
hold += (unsigned long)(*in++) << bits;
bits += 8;
hold += (unsigned long)(*in++) << bits;
bits += 8;
}
here = lcode + (hold & lmask);
dolen:
op = (unsigned)(here->bits);
hold >>= op;
bits -= op;
op = (unsigned)(here->op);
if (op == 0) { /* literal */
Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
"inflate: literal '%c'\n" :
"inflate: literal 0x%02x\n", here->val));
*out++ = (unsigned char)(here->val);
}
else if (op & 16) { /* length base */
len = (unsigned)(here->val);
op &= 15; /* number of extra bits */
if (op) {
if (bits < op) {
hold += (unsigned long)(*in++) << bits;
bits += 8;
}
len += (unsigned)hold & ((1U << op) - 1);
hold >>= op;
bits -= op;
}
Tracevv((stderr, "inflate: length %u\n", len));
if (bits < 15) {
hold += (unsigned long)(*in++) << bits;
bits += 8;
hold += (unsigned long)(*in++) << bits;
bits += 8;
}
here = dcode + (hold & dmask);
dodist:
op = (unsigned)(here->bits);
hold >>= op;
bits -= op;
op = (unsigned)(here->op);
if (op & 16) { /* distance base */
dist = (unsigned)(here->val);
op &= 15; /* number of extra bits */
if (bits < op) {
hold += (unsigned long)(*in++) << bits;
bits += 8;
if (bits < op) {
hold += (unsigned long)(*in++) << bits;
bits += 8;
}
}
dist += (unsigned)hold & ((1U << op) - 1);
#ifdef INFLATE_STRICT
if (dist > dmax) {
strm->msg = (char *)"invalid distance too far back";
state->mode = BAD;
break;
}
#endif
hold >>= op;
bits -= op;
Tracevv((stderr, "inflate: distance %u\n", dist));
op = (unsigned)(out - beg); /* max distance in output */
if (dist > op) { /* see if copy from window */
op = dist - op; /* distance back in window */
if (op > whave) {
if (state->sane) {
strm->msg =
(char *)"invalid distance too far back";
state->mode = BAD;
break;
}
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
if (len <= op - whave) {
do {
*out++ = 0;
} while (--len);
continue;
}
len -= op - whave;
do {
*out++ = 0;
} while (--op > whave);
if (op == 0) {
from = out - dist;
do {
*out++ = *from++;
} while (--len);
continue;
}
#endif
}
from = window;
if (wnext == 0) { /* very common case */
from += wsize - op;
if (op < len) { /* some from window */
len -= op;
do {
*out++ = *from++;
} while (--op);
from = out - dist; /* rest from output */
}
}
else if (wnext < op) { /* wrap around window */
from += wsize + wnext - op;
op -= wnext;
if (op < len) { /* some from end of window */
len -= op;
do {
*out++ = *from++;
} while (--op);
from = window;
if (wnext < len) { /* some from start of window */
op = wnext;
len -= op;
do {
*out++ = *from++;
} while (--op);
from = out - dist; /* rest from output */
}
}
}
else { /* contiguous in window */
from += wnext - op;
if (op < len) { /* some from window */
len -= op;
do {
*out++ = *from++;
} while (--op);
from = out - dist; /* rest from output */
}
}
while (len > 2) {
*out++ = *from++;
*out++ = *from++;
*out++ = *from++;
len -= 3;
}
if (len) {
*out++ = *from++;
if (len > 1)
*out++ = *from++;
}
}
else {
from = out - dist; /* copy direct from output */
do { /* minimum length is three */
*out++ = *from++;
*out++ = *from++;
*out++ = *from++;
len -= 3;
} while (len > 2);
if (len) {
*out++ = *from++;
if (len > 1)
*out++ = *from++;
}
}
}
else if ((op & 64) == 0) { /* 2nd level distance code */
here = dcode + here->val + (hold & ((1U << op) - 1));
goto dodist;
}
else {
strm->msg = (char *)"invalid distance code";
state->mode = BAD;
break;
}
}
else if ((op & 64) == 0) { /* 2nd level length code */
here = lcode + here->val + (hold & ((1U << op) - 1));
goto dolen;
}
else if (op & 32) { /* end-of-block */
Tracevv((stderr, "inflate: end of block\n"));
state->mode = TYPE;
break;
}
else {
strm->msg = (char *)"invalid literal/length code";
state->mode = BAD;
break;
}
} while (in < last && out < end);
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */
len = bits >> 3;
in -= len;
bits -= len << 3;
hold &= (1U << bits) - 1;
/* update state and return */
strm->next_in = in;
strm->next_out = out;
strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
strm->avail_out = (unsigned)(out < end ?
257 + (end - out) : 257 - (out - end));
state->hold = hold;
state->bits = bits;
return;
}
/*
inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
- Using bit fields for code structure
- Different op definition to avoid & for extra bits (do & for table bits)
- Three separate decoding do-loops for direct, window, and wnext == 0
- Special case for distance > 1 copies to do overlapped load and store copy
- Explicit branch predictions (based on measured branch probabilities)
- Deferring match copy and interspersed it with decoding subsequent codes
- Swapping literal/length else
- Swapping window/direct else
- Larger unrolled copy loops (three is about right)
- Moving len -= 3 statement into middle of loop
*/
#endif /* !ASMINF */
+11
View File
@@ -0,0 +1,11 @@
/* inffast.h -- header to use inffast.c
* Copyright (C) 1995-2003, 2010 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start);
+94
View File
@@ -0,0 +1,94 @@
/* inffixed.h -- table for decoding fixed codes
* Generated automatically by makefixed().
*/
/* WARNING: this file should *not* be used by applications.
It is part of the implementation of this library and is
subject to change. Applications should only use zlib.h.
*/
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},
{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,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},
{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,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},
{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,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},
{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,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},
{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,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,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,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},
{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,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},
{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,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},
{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,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},
{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,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},
{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,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},
{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,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},
{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,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,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,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},
{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,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},
{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,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},
{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,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},
{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,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},
{0,9,255}
};
static const code distfix[32] = {
{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},
{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},
{16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
{22,5,193},{64,5,0}
};
+1526
View File
File diff suppressed because it is too large Load Diff
+126
View File
@@ -0,0 +1,126 @@
/* inflate.h -- internal inflate state definition
* Copyright (C) 1995-2019 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
/* define NO_GZIP when compiling if you want to disable gzip header and
trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
the crc code when it is not needed. For shared libraries, gzip decoding
should be left enabled. */
#ifndef NO_GZIP
# define GUNZIP
#endif
/* Possible inflate modes between inflate() calls */
typedef enum {
HEAD = 16180, /* i: waiting for magic header */
FLAGS, /* i: waiting for method and flags (gzip) */
TIME, /* i: waiting for modification time (gzip) */
OS, /* i: waiting for extra flags and operating system (gzip) */
EXLEN, /* i: waiting for extra length (gzip) */
EXTRA, /* i: waiting for extra bytes (gzip) */
NAME, /* i: waiting for end of file name (gzip) */
COMMENT, /* i: waiting for end of comment (gzip) */
HCRC, /* i: waiting for header crc (gzip) */
DICTID, /* i: waiting for dictionary check value */
DICT, /* waiting for inflateSetDictionary() call */
TYPE, /* i: waiting for type bits, including last-flag bit */
TYPEDO, /* i: same, but skip check to exit inflate on new block */
STORED, /* i: waiting for stored size (length and complement) */
COPY_, /* i/o: same as COPY below, but only first time in */
COPY, /* i/o: waiting for input or output to copy stored block */
TABLE, /* i: waiting for dynamic block table lengths */
LENLENS, /* i: waiting for code length code lengths */
CODELENS, /* i: waiting for length/lit and distance code lengths */
LEN_, /* i: same as LEN below, but only first time in */
LEN, /* i: waiting for length/lit/eob code */
LENEXT, /* i: waiting for length extra bits */
DIST, /* i: waiting for distance code */
DISTEXT, /* i: waiting for distance extra bits */
MATCH, /* o: waiting for output space to copy string */
LIT, /* o: waiting for output space to write literal */
CHECK, /* i: waiting for 32-bit check value */
LENGTH, /* i: waiting for 32-bit length (gzip) */
DONE, /* finished check, done -- remain here until reset */
BAD, /* got a data error -- remain here until reset */
MEM, /* got an inflate() memory error -- remain here until reset */
SYNC /* looking for synchronization bytes to restart inflate() */
} inflate_mode;
/*
State transitions between above modes -
(most modes can go to BAD or MEM on error -- not shown for clarity)
Process header:
HEAD -> (gzip) or (zlib) or (raw)
(gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
HCRC -> TYPE
(zlib) -> DICTID or TYPE
DICTID -> DICT -> TYPE
(raw) -> TYPEDO
Read deflate blocks:
TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
STORED -> COPY_ -> COPY -> TYPE
TABLE -> LENLENS -> CODELENS -> LEN_
LEN_ -> LEN
Read deflate codes in fixed or dynamic block:
LEN -> LENEXT or LIT or TYPE
LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
LIT -> LEN
Process trailer:
CHECK -> LENGTH -> DONE
*/
/* State maintained between inflate() calls -- approximately 7K bytes, not
including the allocated sliding window, which is up to 32K bytes. */
struct inflate_state {
z_streamp strm; /* pointer back to this zlib stream */
inflate_mode mode; /* current inflate mode */
int last; /* true if processing last block */
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 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 long check; /* protected copy of check value */
unsigned long total; /* protected copy of output count */
gz_headerp head; /* where to save gzip header information */
/* sliding window */
unsigned wbits; /* log base 2 of requested window size */
unsigned wsize; /* window size or zero if not using window */
unsigned whave; /* valid bytes in the window */
unsigned wnext; /* window write index */
unsigned char FAR *window; /* allocated sliding window, if needed */
/* bit accumulator */
unsigned long hold; /* input bit accumulator */
unsigned bits; /* number of bits in "in" */
/* for string and stored block copying */
unsigned length; /* literal or length of data to copy */
unsigned offset; /* distance back to copy string from */
/* for table and code decoding */
unsigned extra; /* extra bits needed */
/* fixed and dynamic code tables */
code const FAR *lencode; /* starting table for length/literal codes */
code const FAR *distcode; /* starting table for distance codes */
unsigned lenbits; /* index bits for lencode */
unsigned distbits; /* index bits for distcode */
/* dynamic table building */
unsigned ncode; /* number of code length code lengths */
unsigned nlen; /* number of length code lengths */
unsigned ndist; /* number of distance code lengths */
unsigned have; /* number of code lengths in lens[] */
code FAR *next; /* next available space in codes[] */
unsigned short lens[320]; /* temporary storage for code lengths */
unsigned short work[288]; /* work area for code table building */
code codes[ENOUGH]; /* space for code tables */
int sane; /* if false, allow invalid distance too far */
int back; /* bits back of last unprocessed length/lit */
unsigned was; /* initial length of match */
};
+299
View File
@@ -0,0 +1,299 @@
/* inftrees.c -- generate Huffman trees for efficient decoding
* Copyright (C) 1995-2024 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "inftrees.h"
#define MAXBITS 15
const char inflate_copyright[] =
" inflate 1.3.1 Copyright 1995-2024 Mark Adler ";
/*
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
include such an acknowledgment, I would appreciate that you keep this
copyright string in the executable of your product.
*/
/*
Build a set of tables to decode the provided canonical Huffman code.
The code lengths are lens[0..codes-1]. The result starts at *table,
whose indices are 0..2^bits-1. work is a writable array of at least
lens shorts, which is used as a work area. type is the type of code
to be generated, CODES, LENS, or DISTS. On return, zero is success,
-1 is an invalid code, and +1 means that ENOUGH isn't enough. table
on return points to the next available entry's address. bits is the
requested root table index bits, and on return it is the actual root
table index bits. It will differ if the request is greater than the
longest code or if it is less than the shortest code.
*/
int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
unsigned codes, code FAR * FAR *table,
unsigned FAR *bits, unsigned short FAR *work) {
unsigned len; /* a code's length in bits */
unsigned sym; /* index of code symbols */
unsigned min, max; /* minimum and maximum code lengths */
unsigned root; /* number of index bits for root table */
unsigned curr; /* number of index bits for current table */
unsigned drop; /* code bits to drop for sub-table */
int left; /* number of prefix codes available */
unsigned used; /* code entries in table used */
unsigned huff; /* Huffman code */
unsigned incr; /* for incrementing code, index */
unsigned fill; /* index for replicating entries */
unsigned low; /* low bits for current root entry */
unsigned mask; /* mask for low root bits */
code here; /* table entry for duplication */
code FAR *next; /* next available space in table */
const unsigned short FAR *base; /* base value table to use */
const unsigned short FAR *extra; /* extra bits table to use */
unsigned match; /* use base and extra for symbol >= match */
unsigned short count[MAXBITS+1]; /* number of codes of each length */
unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
static const unsigned short lbase[31] = { /* Length codes 257..285 base */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
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 */
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, 203, 77};
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,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577, 0, 0};
static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
28, 28, 29, 29, 64, 64};
/*
Process a set of code lengths to create a canonical Huffman code. The
code lengths are lens[0..codes-1]. Each length corresponds to the
symbols 0..codes-1. The Huffman code is generated by first sorting the
symbols by length from short to long, and retaining the symbol order
for codes with equal lengths. Then the code starts with all zero bits
for the first code of the shortest length, and the codes are integer
increments for the same length, and zeros are appended as the length
increases. For the deflate format, these bits are stored backwards
from their more natural integer increment ordering, and so when the
decoding tables are built in the large loop below, the integer codes
are incremented backwards.
This routine assumes, but does not check, that all of the entries in
lens[] are in the range 0..MAXBITS. The caller must assure this.
1..MAXBITS is interpreted as that code length. zero means that that
symbol does not occur in this code.
The codes are sorted by computing a count of codes for each length,
creating from that a table of starting indices for each length in the
sorted table, and then entering the symbols in order in the sorted
table. The sorted table is work[], with that space being provided by
the caller.
The length counts are used for other purposes as well, i.e. finding
the minimum and maximum length codes, determining if there are any
codes at all, checking for a valid set of lengths, and looking ahead
at length counts to determine sub-table sizes when building the
decoding tables.
*/
/* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
for (len = 0; len <= MAXBITS; len++)
count[len] = 0;
for (sym = 0; sym < codes; sym++)
count[lens[sym]]++;
/* bound code lengths, force root to be within code lengths */
root = *bits;
for (max = MAXBITS; max >= 1; max--)
if (count[max] != 0) break;
if (root > max) root = max;
if (max == 0) { /* no symbols to code at all */
here.op = (unsigned char)64; /* invalid code marker */
here.bits = (unsigned char)1;
here.val = (unsigned short)0;
*(*table)++ = here; /* make a table to force an error */
*(*table)++ = here;
*bits = 1;
return 0; /* no symbols, but wait for decoding to report error */
}
for (min = 1; min < max; min++)
if (count[min] != 0) break;
if (root < min) root = min;
/* check for an over-subscribed or incomplete set of lengths */
left = 1;
for (len = 1; len <= MAXBITS; len++) {
left <<= 1;
left -= count[len];
if (left < 0) return -1; /* over-subscribed */
}
if (left > 0 && (type == CODES || max != 1))
return -1; /* incomplete set */
/* generate offsets into symbol table for each length for sorting */
offs[1] = 0;
for (len = 1; len < MAXBITS; len++)
offs[len + 1] = offs[len] + count[len];
/* sort symbols by length, by symbol order within each length */
for (sym = 0; sym < codes; sym++)
if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
/*
Create and fill in decoding tables. In this loop, the table being
filled is at next and has curr index bits. The code being used is huff
with length len. That code is converted to an index by dropping drop
bits off of the bottom. For codes where len is less than drop + curr,
those top drop + curr - len bits are incremented through all values to
fill the table with replicated entries.
root is the number of index bits for the root table. When len exceeds
root, sub-tables are created pointed to by the root entry with an index
of the low root bits of huff. This is saved in low to check for when a
new sub-table should be started. drop is zero when the root table is
being filled, and drop is root when sub-tables are being filled.
When a new sub-table is needed, it is necessary to look ahead in the
code lengths to determine what size sub-table is needed. The length
counts are used for this, and so count[] is decremented as codes are
entered in the tables.
used keeps track of how many table entries have been allocated from the
provided *table space. It is checked for LENS and DIST tables against
the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
the initial root table size constants. See the comments in inftrees.h
for more information.
sym increments through all symbols, and the loop terminates when
all codes of length max, i.e. all codes, have been processed. This
routine permits incomplete codes, so another loop after this one fills
in the rest of the decoding tables with invalid code markers.
*/
/* set up for code type */
switch (type) {
case CODES:
base = extra = work; /* dummy value--not used */
match = 20;
break;
case LENS:
base = lbase;
extra = lext;
match = 257;
break;
default: /* DISTS */
base = dbase;
extra = dext;
match = 0;
}
/* initialize state for loop */
huff = 0; /* starting code */
sym = 0; /* starting code symbol */
len = min; /* starting code length */
next = *table; /* current table to fill in */
curr = root; /* current table index bits */
drop = 0; /* current bits to drop from code for index */
low = (unsigned)(-1); /* trigger new sub-table when len > root */
used = 1U << root; /* use root table entries */
mask = used - 1; /* mask for comparing low */
/* check available table space */
if ((type == LENS && used > ENOUGH_LENS) ||
(type == DISTS && used > ENOUGH_DISTS))
return 1;
/* process all codes and make table entries */
for (;;) {
/* create table entry */
here.bits = (unsigned char)(len - drop);
if (work[sym] + 1U < match) {
here.op = (unsigned char)0;
here.val = work[sym];
}
else if (work[sym] >= match) {
here.op = (unsigned char)(extra[work[sym] - match]);
here.val = base[work[sym] - match];
}
else {
here.op = (unsigned char)(32 + 64); /* end of block */
here.val = 0;
}
/* replicate for those indices with low len bits equal to huff */
incr = 1U << (len - drop);
fill = 1U << curr;
min = fill; /* save offset to next table */
do {
fill -= incr;
next[(huff >> drop) + fill] = here;
} while (fill != 0);
/* backwards increment the len-bit code huff */
incr = 1U << (len - 1);
while (huff & incr)
incr >>= 1;
if (incr != 0) {
huff &= incr - 1;
huff += incr;
}
else
huff = 0;
/* go to next symbol, update count, len */
sym++;
if (--(count[len]) == 0) {
if (len == max) break;
len = lens[work[sym]];
}
/* create new sub-table if needed */
if (len > root && (huff & mask) != low) {
/* if first time, transition to sub-tables */
if (drop == 0)
drop = root;
/* increment past last table */
next += min; /* here min is 1 << curr */
/* determine length of next table */
curr = len - drop;
left = (int)(1 << curr);
while (curr + drop < max) {
left -= count[curr + drop];
if (left <= 0) break;
curr++;
left <<= 1;
}
/* check for enough space */
used += 1U << curr;
if ((type == LENS && used > ENOUGH_LENS) ||
(type == DISTS && used > ENOUGH_DISTS))
return 1;
/* point entry in root table to sub-table */
low = huff & mask;
(*table)[low].op = (unsigned char)curr;
(*table)[low].bits = (unsigned char)root;
(*table)[low].val = (unsigned short)(next - *table);
}
}
/* fill in remaining table entry if code is incomplete (guaranteed to have
at most one remaining entry, since if the code is incomplete, the
maximum code length that was allowed to get this far is one bit) */
if (huff != 0) {
here.op = (unsigned char)64; /* invalid code marker */
here.bits = (unsigned char)(len - drop);
here.val = (unsigned short)0;
next[huff] = here;
}
/* set return parameters */
*table += used;
*bits = root;
return 0;
}
+62
View File
@@ -0,0 +1,62 @@
/* inftrees.h -- header to use inftrees.c
* Copyright (C) 1995-2005, 2010 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
/* Structure for decoding tables. Each entry provides either the
information needed to do the operation requested by the code that
indexed that table entry, or it provides a pointer to another
table that indexes more bits of the code. op indicates whether
the entry is a pointer to another table, a literal, a length or
distance, an end-of-block, or an invalid code. For a table
pointer, the low four bits of op is the number of index bits of
that table. For a length or distance, the low four bits of op
is the number of extra bits to get after the code. bits is
the number of bits in this code or part of the code to drop off
of the bit buffer. val is the actual byte to output in the case
of a literal, the base length or distance, or the offset from
the current table to the next table. Each entry is four bytes. */
typedef struct {
unsigned char op; /* operation, extra bits, table bits */
unsigned char bits; /* bits in this part of the code */
unsigned short val; /* offset in table or code value */
} code;
/* op values as set by inflate_table():
00000000 - literal
0000tttt - table link, tttt != 0 is the number of table index bits
0001eeee - length or distance, eeee is the number of extra bits
01100000 - end of block
01000000 - invalid code
*/
/* 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
codes. These values were found by exhaustive searches using the program
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
maximum bit length of a code. "enough 286 9 15" for literal/length codes
returns 852, and "enough 30 6 15" for distance codes returns 592. 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
changed, then these maximum sizes would be need to be recalculated and
updated. */
#define ENOUGH_LENS 852
#define ENOUGH_DISTS 592
#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
/* Type of code to build for inflate_table() */
typedef enum {
CODES,
LENS,
DISTS
} codetype;
int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
unsigned codes, code FAR * FAR *table,
unsigned FAR *bits, unsigned short FAR *work);
+1117
View File
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
/* header created automatically with -DGEN_TREES_H */
local const ct_data static_ltree[L_CODES+2] = {
{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
};
local const ct_data static_dtree[D_CODES] = {
{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
};
const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
};
const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
};
local const int base_length[LENGTH_CODES] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
64, 80, 96, 112, 128, 160, 192, 224, 0
};
local const int base_dist[D_CODES] = {
0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
};
+85
View File
@@ -0,0 +1,85 @@
/* uncompr.c -- decompress a memory buffer
* Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#define ZLIB_INTERNAL
#include "zlib.h"
/* ===========================================================================
Decompresses the source buffer into the destination buffer. *sourceLen is
the byte length of the source buffer. Upon entry, *destLen is the total size
of the destination buffer, which must be large enough to hold the entire
uncompressed data. (The size of the uncompressed data must have been saved
previously by the compressor and transmitted to the decompressor by some
mechanism outside the scope of this compression library.) Upon exit,
*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 enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
Z_DATA_ERROR if the input data was corrupted, including if the input data is
an incomplete zlib stream.
*/
int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong *sourceLen) {
z_stream stream;
int err;
const uInt max = (uInt)-1;
uLong len, left;
Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */
len = *sourceLen;
if (*destLen) {
left = *destLen;
*destLen = 0;
}
else {
left = 1;
dest = buf;
}
stream.next_in = (z_const Bytef *)source;
stream.avail_in = 0;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = inflateInit(&stream);
if (err != Z_OK) return err;
stream.next_out = dest;
stream.avail_out = 0;
do {
if (stream.avail_out == 0) {
stream.avail_out = left > (uLong)max ? max : (uInt)left;
left -= stream.avail_out;
}
if (stream.avail_in == 0) {
stream.avail_in = len > (uLong)max ? max : (uInt)len;
len -= stream.avail_in;
}
err = inflate(&stream, Z_NO_FLUSH);
} while (err == Z_OK);
*sourceLen -= len + stream.avail_in;
if (dest != buf)
*destLen = stream.total_out;
else if (stream.total_out && err == Z_BUF_ERROR)
left = 1;
inflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK :
err == Z_NEED_DICT ? Z_DATA_ERROR :
err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
err;
}
int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen) {
return uncompress2(dest, destLen, source, &sourceLen);
}
+543
View File
@@ -0,0 +1,543 @@
/* zconf.h -- configuration of the zlib compression library
* Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#ifndef ZCONF_H
#define ZCONF_H
/*
* If you *really* need a unique prefix for all types and library functions,
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
* Even better than compiling with -DZ_PREFIX would be to use configure to set
* this permanently in zconf.h using "./configure --zprefix".
*/
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
# define Z_PREFIX_SET
/* all linked symbols and init macros */
# define _dist_code z__dist_code
# define _length_code z__length_code
# define _tr_align z__tr_align
# define _tr_flush_bits z__tr_flush_bits
# define _tr_flush_block z__tr_flush_block
# define _tr_init z__tr_init
# define _tr_stored_block z__tr_stored_block
# define _tr_tally z__tr_tally
# define adler32 z_adler32
# define adler32_combine z_adler32_combine
# define adler32_combine64 z_adler32_combine64
# define adler32_z z_adler32_z
# ifndef Z_SOLO
# define compress z_compress
# define compress2 z_compress2
# define compressBound z_compressBound
# endif
# define crc32 z_crc32
# define crc32_combine z_crc32_combine
# 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 deflateBound z_deflateBound
# define deflateCopy z_deflateCopy
# define deflateEnd z_deflateEnd
# define deflateGetDictionary z_deflateGetDictionary
# define deflateInit z_deflateInit
# define deflateInit2 z_deflateInit2
# define deflateInit2_ z_deflateInit2_
# define deflateInit_ z_deflateInit_
# define deflateParams z_deflateParams
# define deflatePending z_deflatePending
# define deflatePrime z_deflatePrime
# define deflateReset z_deflateReset
# define deflateResetKeep z_deflateResetKeep
# define deflateSetDictionary z_deflateSetDictionary
# define deflateSetHeader z_deflateSetHeader
# define deflateTune z_deflateTune
# define deflate_copyright z_deflate_copyright
# define get_crc_table z_get_crc_table
# ifndef Z_SOLO
# define gz_error z_gz_error
# define gz_intmax z_gz_intmax
# define gz_strwinerror z_gz_strwinerror
# define gzbuffer z_gzbuffer
# define gzclearerr z_gzclearerr
# define gzclose z_gzclose
# define gzclose_r z_gzclose_r
# define gzclose_w z_gzclose_w
# define gzdirect z_gzdirect
# define gzdopen z_gzdopen
# define gzeof z_gzeof
# define gzerror z_gzerror
# define gzflush z_gzflush
# define gzfread z_gzfread
# define gzfwrite z_gzfwrite
# define gzgetc z_gzgetc
# define gzgetc_ z_gzgetc_
# define gzgets z_gzgets
# define gzoffset z_gzoffset
# define gzoffset64 z_gzoffset64
# define gzopen z_gzopen
# define gzopen64 z_gzopen64
# ifdef _WIN32
# define gzopen_w z_gzopen_w
# endif
# define gzprintf z_gzprintf
# define gzputc z_gzputc
# define gzputs z_gzputs
# define gzread z_gzread
# define gzrewind z_gzrewind
# define gzseek z_gzseek
# define gzseek64 z_gzseek64
# define gzsetparams z_gzsetparams
# define gztell z_gztell
# define gztell64 z_gztell64
# define gzungetc z_gzungetc
# define gzvprintf z_gzvprintf
# define gzwrite z_gzwrite
# endif
# define inflate z_inflate
# define inflateBack z_inflateBack
# define inflateBackEnd z_inflateBackEnd
# define inflateBackInit z_inflateBackInit
# define inflateBackInit_ z_inflateBackInit_
# define inflateCodesUsed z_inflateCodesUsed
# define inflateCopy z_inflateCopy
# define inflateEnd z_inflateEnd
# define inflateGetDictionary z_inflateGetDictionary
# define inflateGetHeader z_inflateGetHeader
# define inflateInit z_inflateInit
# define inflateInit2 z_inflateInit2
# define inflateInit2_ z_inflateInit2_
# define inflateInit_ z_inflateInit_
# define inflateMark z_inflateMark
# define inflatePrime z_inflatePrime
# define inflateReset z_inflateReset
# define inflateReset2 z_inflateReset2
# define inflateResetKeep z_inflateResetKeep
# define inflateSetDictionary z_inflateSetDictionary
# define inflateSync z_inflateSync
# define inflateSyncPoint z_inflateSyncPoint
# define inflateUndermine z_inflateUndermine
# define inflateValidate z_inflateValidate
# define inflate_copyright z_inflate_copyright
# define inflate_fast z_inflate_fast
# define inflate_table z_inflate_table
# ifndef Z_SOLO
# define uncompress z_uncompress
# define uncompress2 z_uncompress2
# endif
# define zError z_zError
# ifndef Z_SOLO
# define zcalloc z_zcalloc
# define zcfree z_zcfree
# endif
# define zlibCompileFlags z_zlibCompileFlags
# define zlibVersion z_zlibVersion
/* all zlib typedefs in zlib.h and zconf.h */
# define Byte z_Byte
# define Bytef z_Bytef
# define alloc_func z_alloc_func
# define charf z_charf
# define free_func z_free_func
# ifndef Z_SOLO
# define gzFile z_gzFile
# endif
# define gz_header z_gz_header
# define gz_headerp z_gz_headerp
# define in_func z_in_func
# define intf z_intf
# define out_func z_out_func
# define uInt z_uInt
# define uIntf z_uIntf
# define uLong z_uLong
# define uLongf z_uLongf
# define voidp z_voidp
# define voidpc z_voidpc
# define voidpf z_voidpf
/* all zlib structs in zlib.h and zconf.h */
# define gz_header_s z_gz_header_s
# define internal_state z_internal_state
#endif
#if defined(__MSDOS__) && !defined(MSDOS)
# define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
# define OS2
#endif
#if defined(_WINDOWS) && !defined(WINDOWS)
# define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
# ifndef WIN32
# define WIN32
# endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
# ifndef SYS16BIT
# define SYS16BIT
# endif
# endif
#endif
/*
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
* than 64k bytes at a time (needed on systems with 16-bit int).
*/
#ifdef SYS16BIT
# define MAXSEG_64K
#endif
#ifdef MSDOS
# define UNALIGNED_OK
#endif
#ifdef __STDC_VERSION__
# ifndef STDC
# define STDC
# endif
# if __STDC_VERSION__ >= 199901L
# ifndef STDC99
# define STDC99
# endif
# endif
#endif
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
# define STDC
#endif
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
# define STDC
#endif
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
# define STDC
#endif
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
# define STDC
#endif
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
# define STDC
#endif
#ifndef STDC
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
# define const /* note: need a more gentle solution here */
# endif
#endif
#if defined(ZLIB_CONST) && !defined(z_const)
# define z_const const
#else
# define z_const
#endif
#ifdef Z_SOLO
# ifdef _WIN64
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
/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
# ifdef MAXSEG_64K
# define MAX_MEM_LEVEL 8
# else
# define MAX_MEM_LEVEL 9
# endif
#endif
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
* created by gzip. (Files created by minigzip can still be extracted by
* gzip.)
*/
#ifndef MAX_WBITS
# define MAX_WBITS 15 /* 32K LZ77 window */
#endif
/* The memory requirements for deflate are (in bytes):
(1 << (windowBits+2)) + (1 << (memLevel+9))
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
plus a few kilobytes for small objects. For example, if you want to reduce
the default memory requirements from 256K to 128K, compile with
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits
that is, 32K for windowBits=15 (default value) plus about 7 kilobytes
for small objects.
*/
/* Type declarations */
#ifndef OF /* function prototypes */
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
/* The following definitions for FAR are needed only for MSDOS mixed
* model programming (small or medium model with some far allocations).
* This was tested only with MSC; for other MSDOS compilers you may have
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
* just define FAR to be empty.
*/
#ifdef SYS16BIT
# if defined(M_I86SM) || defined(M_I86MM)
/* MSC small or medium model */
# define SMALL_MEDIUM
# ifdef _MSC_VER
# define FAR _far
# else
# define FAR far
# endif
# endif
# if (defined(__SMALL__) || defined(__MEDIUM__))
/* Turbo C small or medium model */
# define SMALL_MEDIUM
# ifdef __BORLANDC__
# define FAR _far
# else
# define FAR far
# endif
# endif
#endif
#if defined(WINDOWS) || defined(WIN32)
/* If building or using zlib as a DLL, define ZLIB_DLL.
* This is not mandatory, but it offers a little performance increase.
*/
# ifdef ZLIB_DLL
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
# ifdef ZLIB_INTERNAL
# define ZEXTERN extern __declspec(dllexport)
# else
# define ZEXTERN extern __declspec(dllimport)
# endif
# endif
# endif /* ZLIB_DLL */
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
# define ZEXPORTVA FAR CDECL
# endif
# endif
#endif
#if defined (__BEOS__)
# ifdef ZLIB_DLL
# ifdef ZLIB_INTERNAL
# define ZEXPORT __declspec(dllexport)
# define ZEXPORTVA __declspec(dllexport)
# else
# define ZEXPORT __declspec(dllimport)
# define ZEXPORTVA __declspec(dllimport)
# endif
# endif
#endif
#ifndef ZEXTERN
# define ZEXTERN extern
#endif
#ifndef ZEXPORT
# define ZEXPORT
#endif
#ifndef ZEXPORTVA
# define ZEXPORTVA
#endif
#ifndef FAR
# define FAR
#endif
#if !defined(__MACTYPES__)
typedef unsigned char Byte; /* 8 bits */
#endif
typedef unsigned int uInt; /* 16 bits or more */
typedef unsigned long uLong; /* 32 bits or more */
#ifdef SMALL_MEDIUM
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
# define Bytef Byte FAR
#else
typedef Byte FAR Bytef;
#endif
typedef char FAR charf;
typedef int FAR intf;
typedef uInt FAR uIntf;
typedef uLong FAR uLongf;
#ifdef STDC
typedef void const *voidpc;
typedef void FAR *voidpf;
typedef void *voidp;
#else
typedef Byte const *voidpc;
typedef Byte FAR *voidpf;
typedef Byte *voidp;
#endif
#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
# include <limits.h>
# if (UINT_MAX == 0xffffffffUL)
# define Z_U4 unsigned
# elif (ULONG_MAX == 0xffffffffUL)
# define Z_U4 unsigned long
# elif (USHRT_MAX == 0xffffffffUL)
# define Z_U4 unsigned short
# endif
#endif
#ifdef Z_U4
typedef Z_U4 z_crc_t;
#else
typedef unsigned long z_crc_t;
#endif
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
# define Z_HAVE_UNISTD_H
#endif
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
# define Z_HAVE_STDARG_H
#endif
#ifdef STDC
# ifndef Z_SOLO
# include <sys/types.h> /* for off_t */
# endif
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifndef Z_SOLO
# include <stdarg.h> /* for va_list */
# endif
#endif
#ifdef _WIN32
# ifndef Z_SOLO
# include <stddef.h> /* for wchar_t */
# endif
#endif
/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
* "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
* though the former does not conform to the LFS document), but considering
* both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
* equivalently requesting no 64-bit operations
*/
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
# undef _LARGEFILE64_SOURCE
#endif
#ifndef Z_HAVE_UNISTD_H
# ifdef __WATCOMC__
# define Z_HAVE_UNISTD_H
# endif
#endif
#ifndef Z_HAVE_UNISTD_H
# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32)
# define Z_HAVE_UNISTD_H
# endif
#endif
#ifndef Z_SOLO
# if defined(Z_HAVE_UNISTD_H)
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
# ifdef VMS
# include <unixio.h> /* for off_t */
# endif
# ifndef z_off_t
# define z_off_t off_t
# endif
# endif
#endif
#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
# define Z_LFS64
#endif
#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
# define Z_LARGE64
#endif
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
# define Z_WANT64
#endif
#if !defined(SEEK_SET) && !defined(Z_SOLO)
# define SEEK_SET 0 /* Seek from beginning of file. */
# define SEEK_CUR 1 /* Seek from current position. */
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
#endif
#ifndef z_off_t
# define z_off_t long
#endif
#if !defined(_WIN32) && defined(Z_LARGE64)
# define z_off64_t off64_t
#else
# if defined(_WIN32) && !defined(__GNUC__)
# define z_off64_t __int64
# else
# define z_off64_t z_off_t
# endif
#endif
/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
#pragma map(deflateInit_,"DEIN")
#pragma map(deflateInit2_,"DEIN2")
#pragma map(deflateEnd,"DEEND")
#pragma map(deflateBound,"DEBND")
#pragma map(inflateInit_,"ININ")
#pragma map(inflateInit2_,"ININ2")
#pragma map(inflateEnd,"INEND")
#pragma map(inflateSync,"INSY")
#pragma map(inflateSetDictionary,"INSEDI")
#pragma map(compressBound,"CMBND")
#pragma map(inflate_table,"INTABL")
#pragma map(inflate_fast,"INFA")
#pragma map(inflate_copyright,"INCOPY")
#endif
#endif /* ZCONF_H */
+1938
View File
File diff suppressed because it is too large Load Diff
+299
View File
@@ -0,0 +1,299 @@
/* zutil.c -- target dependent utility functions for the compression library
* Copyright (C) 1995-2017 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#include "zutil.h"
#ifndef Z_SOLO
# include "gzguts.h"
#endif
z_const char * const z_errmsg[10] = {
(z_const char *)"need dictionary", /* Z_NEED_DICT 2 */
(z_const char *)"stream end", /* Z_STREAM_END 1 */
(z_const char *)"", /* Z_OK 0 */
(z_const char *)"file error", /* Z_ERRNO (-1) */
(z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */
(z_const char *)"data error", /* Z_DATA_ERROR (-3) */
(z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */
(z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */
(z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */
(z_const char *)""
};
const char * ZEXPORT zlibVersion(void) {
return ZLIB_VERSION;
}
uLong ZEXPORT zlibCompileFlags(void) {
uLong flags;
flags = 0;
switch ((int)(sizeof(uInt))) {
case 2: break;
case 4: flags += 1; break;
case 8: flags += 2; break;
default: flags += 3;
}
switch ((int)(sizeof(uLong))) {
case 2: break;
case 4: flags += 1 << 2; break;
case 8: flags += 2 << 2; break;
default: flags += 3 << 2;
}
switch ((int)(sizeof(voidpf))) {
case 2: break;
case 4: flags += 1 << 4; break;
case 8: flags += 2 << 4; break;
default: flags += 3 << 4;
}
switch ((int)(sizeof(z_off_t))) {
case 2: break;
case 4: flags += 1 << 6; break;
case 8: flags += 2 << 6; break;
default: flags += 3 << 6;
}
#ifdef ZLIB_DEBUG
flags += 1 << 8;
#endif
/*
#if defined(ASMV) || defined(ASMINF)
flags += 1 << 9;
#endif
*/
#ifdef ZLIB_WINAPI
flags += 1 << 10;
#endif
#ifdef BUILDFIXED
flags += 1 << 12;
#endif
#ifdef DYNAMIC_CRC_TABLE
flags += 1 << 13;
#endif
#ifdef NO_GZCOMPRESS
flags += 1L << 16;
#endif
#ifdef NO_GZIP
flags += 1L << 17;
#endif
#ifdef PKZIP_BUG_WORKAROUND
flags += 1L << 20;
#endif
#ifdef FASTEST
flags += 1L << 21;
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifdef NO_vsnprintf
flags += 1L << 25;
# ifdef HAS_vsprintf_void
flags += 1L << 26;
# endif
# else
# ifdef HAS_vsnprintf_void
flags += 1L << 26;
# endif
# endif
#else
flags += 1L << 24;
# ifdef NO_snprintf
flags += 1L << 25;
# ifdef HAS_sprintf_void
flags += 1L << 26;
# endif
# else
# ifdef HAS_snprintf_void
flags += 1L << 26;
# endif
# endif
#endif
return flags;
}
#ifdef ZLIB_DEBUG
#include <stdlib.h>
# ifndef verbose
# define verbose 0
# endif
int ZLIB_INTERNAL z_verbose = verbose;
void ZLIB_INTERNAL z_error(char *m) {
fprintf(stderr, "%s\n", m);
exit(1);
}
#endif
/* exported to allow conversion of error code to string for compress() and
* uncompress()
*/
const char * ZEXPORT zError(int err) {
return ERR_MSG(err);
}
#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800
/* The older Microsoft C Run-Time Library for Windows CE doesn't have
* errno. We define it as a global variable to simplify porting.
* Its value is always 0 and should not be used.
*/
int errno = 0;
#endif
#ifndef HAVE_MEMCPY
void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) {
if (len == 0) return;
do {
*dest++ = *source++; /* ??? to be unrolled */
} while (--len != 0);
}
int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) {
uInt j;
for (j = 0; j < len; j++) {
if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
}
return 0;
}
void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) {
if (len == 0) return;
do {
*dest++ = 0; /* ??? to be unrolled */
} while (--len != 0);
}
#endif
#ifndef Z_SOLO
#ifdef SYS16BIT
#ifdef __TURBOC__
/* Turbo C in 16-bit mode */
# define MY_ZCALLOC
/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
* and farmalloc(64K) returns a pointer with an offset of 8, so we
* must fix the pointer. Warning: the pointer must be put back to its
* original form in order to free it, use zcfree().
*/
#define MAX_PTR 10
/* 10*64K = 640K */
local int next_ptr = 0;
typedef struct ptr_table_s {
voidpf org_ptr;
voidpf new_ptr;
} ptr_table;
local ptr_table table[MAX_PTR];
/* This table is used to remember the original form of pointers
* to large buffers (64K). Such pointers are normalized with a zero offset.
* Since MSDOS is not a preemptive multitasking OS, this table is not
* protected from concurrent access. This hack doesn't work anyway on
* a protected system like OS/2. Use Microsoft C instead.
*/
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
voidpf buf;
ulg bsize = (ulg)items*size;
(void)opaque;
/* If we allocate less than 65520 bytes, we assume that farmalloc
* will return a usable pointer which doesn't have to be normalized.
*/
if (bsize < 65520L) {
buf = farmalloc(bsize);
if (*(ush*)&buf != 0) return buf;
} else {
buf = farmalloc(bsize + 16L);
}
if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
table[next_ptr].org_ptr = buf;
/* Normalize the pointer to seg:0 */
*((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
*(ush*)&buf = 0;
table[next_ptr++].new_ptr = buf;
return buf;
}
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
int n;
(void)opaque;
if (*(ush*)&ptr != 0) { /* object < 64K */
farfree(ptr);
return;
}
/* Find the original pointer */
for (n = 0; n < next_ptr; n++) {
if (ptr != table[n].new_ptr) continue;
farfree(table[n].org_ptr);
while (++n < next_ptr) {
table[n-1] = table[n];
}
next_ptr--;
return;
}
Assert(0, "zcfree: ptr not found");
}
#endif /* __TURBOC__ */
#ifdef M_I86
/* Microsoft C in 16-bit mode */
# define MY_ZCALLOC
#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
# define _halloc halloc
# define _hfree hfree
#endif
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) {
(void)opaque;
return _halloc((long)items, size);
}
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
(void)opaque;
_hfree(ptr);
}
#endif /* M_I86 */
#endif /* SYS16BIT */
#ifndef MY_ZCALLOC /* Any system without a special alloc function */
#ifndef STDC
extern voidp malloc(uInt size);
extern voidp calloc(uInt items, uInt size);
extern void free(voidpf ptr);
#endif
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
(void)opaque;
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
(voidpf)calloc(items, size);
}
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
(void)opaque;
free(ptr);
}
#endif /* MY_ZCALLOC */
#endif /* !Z_SOLO */
+254
View File
@@ -0,0 +1,254 @@
/* zutil.h -- internal interface and configuration of the compression library
* Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
/* @(#) $Id$ */
#ifndef ZUTIL_H
#define ZUTIL_H
#ifdef HAVE_HIDDEN
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
# define ZLIB_INTERNAL
#endif
#include "zlib.h"
#if defined(STDC) && !defined(Z_SOLO)
# if !(defined(_WIN32_WCE) && defined(_MSC_VER))
# include <stddef.h>
# endif
# include <string.h>
# include <stdlib.h>
#endif
#ifndef local
# define local static
#endif
/* 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) */
typedef unsigned char uch;
typedef uch FAR uchf;
typedef unsigned short ush;
typedef ush FAR ushf;
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 (UINT_MAX == 0xffffffffffffffff)
# define Z_U8 unsigned
# endif
#endif
extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* (size given to avoid silly warnings with Visual C++) */
#define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)]
#define ERR_RETURN(strm,err) \
return (strm->msg = ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */
/* common constants */
#ifndef DEF_WBITS
# define DEF_WBITS MAX_WBITS
#endif
/* default windowBits for decompression. MAX_WBITS is for compression only */
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif
/* default memLevel */
#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES 2
/* The three kinds of block type */
#define MIN_MATCH 3
#define MAX_MATCH 258
/* The minimum and maximum match lengths */
#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
/* target dependencies */
#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
# define OS_CODE 0x00
# ifndef Z_SOLO
# if defined(__TURBOC__) || defined(__BORLANDC__)
# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
/* Allow compilation with ANSI keywords only enabled */
void _Cdecl farfree( void *block );
void *_Cdecl farmalloc( unsigned long nbytes );
# else
# include <alloc.h>
# endif
# else /* MSC or DJGPP */
# include <malloc.h>
# endif
# endif
#endif
#ifdef AMIGA
# define OS_CODE 1
#endif
#if defined(VAXC) || defined(VMS)
# define OS_CODE 2
# define F_OPEN(name, mode) \
fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#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)
# define OS_CODE 5
#endif
#ifdef OS2
# define OS_CODE 6
# if defined(M_I86) && !defined(Z_SOLO)
# include <malloc.h>
# endif
#endif
#if defined(MACOS)
# define OS_CODE 7
#endif
#ifdef __acorn
# define OS_CODE 13
#endif
#if defined(WIN32) && !defined(__CYGWIN__)
# define OS_CODE 10
#endif
#ifdef _BEOS_
# define OS_CODE 16
#endif
#ifdef __TOS_OS400__
# define OS_CODE 18
#endif
#ifdef __APPLE__
# define OS_CODE 19
#endif
#if defined(__BORLANDC__) && !defined(MSDOS)
#pragma warn -8004
#pragma warn -8008
#pragma warn -8066
#endif
/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) && \
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
#endif
/* common defaults */
#ifndef OS_CODE
# define OS_CODE 3 /* assume Unix */
#endif
#ifndef F_OPEN
# define F_OPEN(name, mode) fopen((name), (mode))
#endif
/* functions */
#if defined(pyr) || defined(Z_SOLO)
# define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
/* Use our own functions for small and medium model with MSC <= 5.0.
* You may have to use the same strategy for Borland C (untested).
* The __SC__ check is for Symantec.
*/
# define NO_MEMCPY
#endif
#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
# define HAVE_MEMCPY
#endif
#ifdef HAVE_MEMCPY
# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
# define zmemcpy _fmemcpy
# define zmemcmp _fmemcmp
# define zmemzero(dest, len) _fmemset(dest, 0, len)
# else
# define zmemcpy memcpy
# define zmemcmp memcmp
# define zmemzero(dest, len) memset(dest, 0, len)
# endif
#else
void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len);
int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len);
void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len);
#endif
/* Diagnostic functions */
#ifdef ZLIB_DEBUG
# include <stdio.h>
extern int ZLIB_INTERNAL z_verbose;
extern void ZLIB_INTERNAL z_error(char *m);
# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
# define Trace(x) {if (z_verbose>=0) fprintf x ;}
# define Tracev(x) {if (z_verbose>0) fprintf x ;}
# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
#else
# define Assert(cond,msg)
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
# define Tracec(c,x)
# define Tracecv(c,x)
#endif
#ifndef Z_SOLO
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items,
unsigned size);
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr);
#endif
#define ZALLOC(strm, items, size) \
(*((strm)->zalloc))((strm)->opaque, (items), (size))
#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
/* Reverse the bytes in a 32-bit value */
#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
(((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
#endif /* ZUTIL_H */
+1014
View File
File diff suppressed because it is too large Load Diff