initial commit
This commit is contained in:
+19
@@ -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
@@ -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)
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
#include "xui.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "xui.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "xui.h"
|
||||
@@ -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
@@ -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>
|
||||
@@ -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
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+208
@@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 += "&"; break;
|
||||
case (unsigned long)'<': output += "<"; break;
|
||||
case (unsigned long)'>': output += ">"; break;
|
||||
case (unsigned long)'\"': if (attribute) output += """; else output.push_back('"'); break;
|
||||
case 39u: if (attribute) output += "'"; 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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 += "&"; break;
|
||||
case '<': r += "<"; break;
|
||||
case '>': r += ">"; break;
|
||||
case '"': r += """; break;
|
||||
case '\'': r += "'"; 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+7988
File diff suppressed because it is too large
Load Diff
Vendored
+1724
File diff suppressed because it is too large
Load Diff
Vendored
+5079
File diff suppressed because it is too large
Load Diff
Vendored
+22
@@ -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
|
||||
Vendored
+164
@@ -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);
|
||||
}
|
||||
Vendored
+75
@@ -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;
|
||||
}
|
||||
Vendored
+1049
File diff suppressed because it is too large
Load Diff
Vendored
+9446
File diff suppressed because it is too large
Load Diff
Vendored
+2139
File diff suppressed because it is too large
Load Diff
Vendored
+377
@@ -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 */
|
||||
Vendored
+214
@@ -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())
|
||||
Vendored
+628
@@ -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;
|
||||
}
|
||||
Vendored
+320
@@ -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 */
|
||||
Vendored
+11
@@ -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);
|
||||
Vendored
+94
@@ -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}
|
||||
};
|
||||
Vendored
+1526
File diff suppressed because it is too large
Load Diff
Vendored
+126
@@ -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 */
|
||||
};
|
||||
Vendored
+299
@@ -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;
|
||||
}
|
||||
Vendored
+62
@@ -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);
|
||||
Vendored
+1117
File diff suppressed because it is too large
Load Diff
Vendored
+128
@@ -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
|
||||
};
|
||||
|
||||
Vendored
+85
@@ -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);
|
||||
}
|
||||
Vendored
+543
@@ -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 */
|
||||
Vendored
+1938
File diff suppressed because it is too large
Load Diff
Vendored
+299
@@ -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 */
|
||||
Vendored
+254
@@ -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
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user